am 6b44056d: am 6e837041: am 09d3d318: am c13e5c1c: Merge "ndk: Fix android-3/arch-arm crt{begin,end}_so.o"

* commit '6b44056dcffed6ac23140969b60257fdfd82b1ac':
  ndk: Fix android-3/arch-arm crt{begin,end}_so.o
diff --git a/apps/Development/src/com/android/development/AccountsTester.java b/apps/Development/src/com/android/development/AccountsTester.java
index e2a0789..b4155e7 100644
--- a/apps/Development/src/com/android/development/AccountsTester.java
+++ b/apps/Development/src/com/android/development/AccountsTester.java
@@ -21,6 +21,7 @@
 import android.app.AlertDialog;
 import android.content.*;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.accounts.*;
 import android.os.Bundle;
 import android.os.Parcelable;
@@ -32,6 +33,8 @@
 import android.text.TextUtils;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 public class AccountsTester extends Activity implements OnAccountsUpdateListener {
     private static final String TAG = "AccountsTester";
@@ -142,7 +145,7 @@
 
     private void initializeAuthenticatorsSpinner() {
         mAuthenticatorDescs = mAccountManager.getAuthenticatorTypes();
-        String[] names = new String[mAuthenticatorDescs.length];
+        List<String> names = new ArrayList(mAuthenticatorDescs.length);
         for (int i = 0; i < mAuthenticatorDescs.length; i++) {
             Context authContext;
             try {
@@ -150,12 +153,17 @@
             } catch (PackageManager.NameNotFoundException e) {
                 continue;
             }
-            names[i] = authContext.getString(mAuthenticatorDescs[i].labelId);
+            try  {
+                names.add(authContext.getString(mAuthenticatorDescs[i].labelId));
+            } catch (Resources.NotFoundException e) {
+                continue;
+            }
         }
 
+        String[] namesArray = names.toArray(new String[names.size()]);
         ArrayAdapter<String> adapter =
                 new ArrayAdapter<String>(AccountsTester.this,
-                android.R.layout.simple_spinner_item, names);
+                android.R.layout.simple_spinner_item, namesArray);
         mAccountTypesSpinner.setAdapter(adapter);
     }
 
diff --git a/apps/SpareParts/Android.mk b/apps/SpareParts/Android.mk
deleted file mode 100644
index 1a1ea0a..0000000
--- a/apps/SpareParts/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := eng
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := SpareParts
-
-include $(BUILD_PACKAGE)
diff --git a/apps/SpareParts/AndroidManifest.xml b/apps/SpareParts/AndroidManifest.xml
deleted file mode 100644
index 137f907..0000000
--- a/apps/SpareParts/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.spare_parts">
-    <uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
-    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
-    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
-    
-    <application android:label="@string/app_label"
-            android:icon="@mipmap/app_icon">
-
-        <activity android:name="SpareParts">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-
-    </application>
-</manifest>
diff --git a/apps/SpareParts/res/layout/spare_parts.xml b/apps/SpareParts/res/layout/spare_parts.xml
deleted file mode 100644
index c1cd3c8..0000000
--- a/apps/SpareParts/res/layout/spare_parts.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/Settings/assets/res/any/layout/keyboard_version.xml
-**
-** 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.
-*/
--->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <RelativeLayout 
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <Spinner android:id="@+id/window_animation_scale"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentLeft="true">
-        </Spinner>
-
-        <Spinner android:id="@+id/transition_animation_scale"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/window_animation_scale"
-            android:layout_alignParentLeft="true">
-        </Spinner>
-
-    </RelativeLayout>
-
-</ScrollView>
-
diff --git a/apps/SpareParts/res/mipmap-hdpi/app_icon.png b/apps/SpareParts/res/mipmap-hdpi/app_icon.png
deleted file mode 100755
index 60fbdf5..0000000
--- a/apps/SpareParts/res/mipmap-hdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/apps/SpareParts/res/mipmap-mdpi/app_icon.png b/apps/SpareParts/res/mipmap-mdpi/app_icon.png
deleted file mode 100644
index cb40a19..0000000
--- a/apps/SpareParts/res/mipmap-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/apps/SpareParts/res/values/arrays.xml b/apps/SpareParts/res/values/arrays.xml
deleted file mode 100644
index e6026da..0000000
--- a/apps/SpareParts/res/values/arrays.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 
- * 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.
- -->
-
-<resources>
-    <string-array name="entries_animations">
-        <item>Off</item>
-        <item>Fast</item>
-        <item>Normal</item>
-        <item>Slow</item>
-        <item>Very Slow</item>
-    </string-array>
-
-    <string-array name="entryvalues_animations">
-        <item>0.0</item>
-        <item>0.5</item>
-        <item>1.0</item>
-        <item>1.5</item>
-        <item>2.0</item>
-    </string-array>
-    
-    <string-array name="entries_font_size">
-        <item>Extremely Small</item>
-        <item>Extra Small</item>
-        <item>Small</item>
-        <item>Normal</item>
-        <item>Large</item>
-        <item>Extra Large</item>
-        <item>Extremely Large</item>
-    </string-array>
-
-    <string-array name="entryvalues_font_size">
-        <item>0.70</item>
-        <item>0.85</item>
-        <item>0.95</item>
-        <item>1.0</item>
-        <item>1.05</item>
-        <item>1.15</item>
-        <item>1.30</item>
-    </string-array>
-    
-    <string-array name="entries_end_button">
-        <item>Nothing</item>
-        <item>Go to home</item>
-        <item>Go to sleep</item>
-        <item>Home, then sleep</item>
-    </string-array>
-    
-    <string-array name="entryvalues_end_button">
-        <item>0</item>
-        <item>1</item>
-        <item>2</item>
-        <item>3</item>
-    </string-array>
-</resources>
diff --git a/apps/SpareParts/res/values/strings.xml b/apps/SpareParts/res/values/strings.xml
deleted file mode 100644
index 9e78be0..0000000
--- a/apps/SpareParts/res/values/strings.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/strings.xml
-**
-** 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.
-*/
--->
-<resources>
-    <string name="app_label">Spare Parts</string>
-
-    <string name="device_info_title">Device info</string>
-    
-    <string name="title_battery_history">Battery history</string>
-    <string name="summary_battery_history">Summary of how battery has been used</string>
-    
-    <string name="title_battery_information">Battery information</string>
-    <string name="summary_battery_information">Current battery status information</string>
-    
-    <string name="title_usage_statistics">Usage statistics</string>
-    <string name="summary_usage_statistics">Summary of application usage</string>
-    
-    <string name="general_title">General</string>
-    
-    <string name="title_window_animations">Window animations</string>
-    <string name="summary_window_animations">Speed of animations in individual windows</string>
-    <string name="dialog_title_window_animations">Select window speed</string>
-    
-    <string name="title_transition_animations">Transition animations</string>
-    <string name="summary_transition_animations">Speed of animations moving between screens</string>
-    <string name="dialog_title_transition_animations">Select transition speed</string>
-    
-    <string name="title_fancy_ime_animations">Fancy input animations</string>
-    <string name="summary_on_fancy_ime_animations">Use fancier animations for input method windows</string>
-    <string name="summary_off_fancy_ime_animations">Use normal animations for input method windows</string>
-    
-    <string name="title_haptic_feedback">Haptic feedback</string>
-    <string name="summary_on_haptic_feedback">Use haptic feedback with user interaction</string>
-    <string name="summary_off_haptic_feedback">Use haptic feedback with user interaction</string>
-    
-    <string name="title_font_size">Font size</string>
-    <string name="summary_font_size">Overall size of fonts</string>
-    <string name="dialog_title_font_size">Select font size</string>
-    
-    <string name="title_end_button">End button behavior</string>
-    <string name="summary_end_button">Select End (red) button action</string>
-    <string name="dialog_title_end_button">Select End button</string>
-    
-    <string name="applications_title">Applications</string>
-    
-    <!-- Sound & display settings screen, compatibility mode check box label -->
-    <string name="compatibility_mode_title">Compatibility Mode</string>
-    <!-- Sound & display settings screen, compatibility mode option summary text when check box is selected -->
-    <string name="compatibility_mode_summary_on">Run older apps in Compatibility mode. This requires rebooting. </string>
-    <!-- Sound & display settings screen, compatibility mode option summary text when check box is clear -->
-    <string name="compatibility_mode_summary_off">Run older apps in Compatibility mode. This requires rebooting. </string>
-</resources>
diff --git a/apps/SpareParts/res/xml/spare_parts.xml b/apps/SpareParts/res/xml/spare_parts.xml
deleted file mode 100644
index 0d06e26..0000000
--- a/apps/SpareParts/res/xml/spare_parts.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
- * 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.
- */
--->
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <PreferenceCategory
-        android:title="@string/device_info_title">
-
-        <PreferenceScreen android:key="battery_history_settings"
-                android:title="@string/title_battery_history" 
-                android:summary="@string/summary_battery_history">
-            <intent android:action="android.intent.action.MAIN"
-                    android:targetPackage="com.android.settings"
-                    android:targetClass="com.android.settings.fuelgauge.PowerUsageSummary" />
-        </PreferenceScreen>
-        
-        <PreferenceScreen android:key="battery_information_settings"
-                android:title="@string/title_battery_information" 
-                android:summary="@string/summary_battery_information">
-            <intent android:action="android.intent.action.MAIN"
-                    android:targetPackage="com.android.settings"
-                    android:targetClass="com.android.settings.BatteryInfo" />
-        </PreferenceScreen>
-        
-        <PreferenceScreen android:key="usage_statistics_settings"
-                android:title="@string/title_usage_statistics" 
-                android:summary="@string/summary_usage_statistics">
-            <intent android:action="android.intent.action.MAIN"
-                    android:targetPackage="com.android.settings"
-                    android:targetClass="com.android.settings.UsageStats" />
-        </PreferenceScreen>
-        
-    </PreferenceCategory>
-            
-    <PreferenceCategory
-        android:title="@string/general_title">
-        
-        <ListPreference
-                android:key="window_animations"
-                android:title="@string/title_window_animations"
-                android:summary="@string/summary_window_animations"
-                android:entries="@array/entries_animations"
-                android:entryValues="@array/entryvalues_animations"
-                android:dialogTitle="@string/dialog_title_window_animations" />
-                
-        <ListPreference
-                android:key="transition_animations"
-                android:title="@string/title_transition_animations"
-                android:summary="@string/summary_transition_animations"
-                android:entries="@array/entries_animations"
-                android:entryValues="@array/entryvalues_animations"
-                android:dialogTitle="@string/dialog_title_transition_animations" />
-        
-        <CheckBoxPreference 
-            android:key="fancy_ime_animations" 
-            android:title="@string/title_fancy_ime_animations" 
-            android:summaryOn="@string/summary_on_fancy_ime_animations"
-            android:summaryOff="@string/summary_off_fancy_ime_animations"/>
-        
-        <ListPreference
-                android:key="font_size"
-                android:title="@string/title_font_size"
-                android:summary="@string/summary_font_size"
-                android:entries="@array/entries_font_size"
-                android:entryValues="@array/entryvalues_font_size"
-                android:dialogTitle="@string/dialog_title_font_size" />
-        
-        <ListPreference
-                android:key="end_button"
-                android:title="@string/title_end_button"
-                android:summary="@string/summary_end_button"
-                android:entries="@array/entries_end_button"
-                android:entryValues="@array/entryvalues_end_button"
-                android:dialogTitle="@string/dialog_title_end_button" />
-        
-        <CheckBoxPreference 
-            android:key="haptic_feedback" 
-            android:title="@string/title_haptic_feedback" 
-            android:summaryOn="@string/summary_on_haptic_feedback"
-            android:summaryOff="@string/summary_off_haptic_feedback"/>
-        
-
-        <CheckBoxPreference
-                android:key="compatibility_mode"
-                android:title="@string/compatibility_mode_title"
-                android:summaryOn="@string/compatibility_mode_summary_on"
-                android:summaryOff="@string/compatibility_mode_summary_off" />
-    </PreferenceCategory>
-
-</PreferenceScreen>
diff --git a/apps/SpareParts/src/com/android/spare_parts/SpareParts.java b/apps/SpareParts/src/com/android/spare_parts/SpareParts.java
deleted file mode 100644
index 099f27a..0000000
--- a/apps/SpareParts/src/com/android/spare_parts/SpareParts.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/* //device/apps/Settings/src/com/android/settings/Keyguard.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 com.android.spare_parts;
-
-import android.app.ActivityManagerNative;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.preference.CheckBoxPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceScreen;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.IWindowManager;
-
-import java.util.List;
-
-public class SpareParts extends PreferenceActivity
-        implements Preference.OnPreferenceChangeListener,
-        SharedPreferences.OnSharedPreferenceChangeListener {
-    private static final String TAG = "SpareParts";
-
-    private static final String BATTERY_HISTORY_PREF = "battery_history_settings";
-    private static final String BATTERY_INFORMATION_PREF = "battery_information_settings";
-    private static final String USAGE_STATISTICS_PREF = "usage_statistics_settings";
-    
-    private static final String WINDOW_ANIMATIONS_PREF = "window_animations";
-    private static final String TRANSITION_ANIMATIONS_PREF = "transition_animations";
-    private static final String FANCY_IME_ANIMATIONS_PREF = "fancy_ime_animations";
-    private static final String HAPTIC_FEEDBACK_PREF = "haptic_feedback";
-    private static final String FONT_SIZE_PREF = "font_size";
-    private static final String END_BUTTON_PREF = "end_button";
-    private static final String KEY_COMPATIBILITY_MODE = "compatibility_mode";
-
-    private final Configuration mCurConfig = new Configuration();
-    
-    private ListPreference mWindowAnimationsPref;
-    private ListPreference mTransitionAnimationsPref;
-    private CheckBoxPreference mFancyImeAnimationsPref;
-    private CheckBoxPreference mHapticFeedbackPref;
-    private ListPreference mFontSizePref;
-    private ListPreference mEndButtonPref;
-    private CheckBoxPreference mCompatibilityMode;
-
-    private IWindowManager mWindowManager;
-
-    public static boolean updatePreferenceToSpecificActivityOrRemove(Context context,
-            PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) {
-        
-        Preference preference = parentPreferenceGroup.findPreference(preferenceKey);
-        if (preference == null) {
-            return false;
-        }
-        
-        Intent intent = preference.getIntent();
-        if (intent != null) {
-            // Find the activity that is in the system image
-            PackageManager pm = context.getPackageManager();
-            List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
-            int listSize = list.size();
-            for (int i = 0; i < listSize; i++) {
-                ResolveInfo resolveInfo = list.get(i);
-                if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
-                        != 0) {
-                    
-                    // Replace the intent with this specific activity
-                    preference.setIntent(new Intent().setClassName(
-                            resolveInfo.activityInfo.packageName,
-                            resolveInfo.activityInfo.name));
-                    
-                    return true;
-                }
-            }
-        }
-
-        // Did not find a matching activity, so remove the preference
-        parentPreferenceGroup.removePreference(preference);
-        
-        return true;
-    }
-    
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        addPreferencesFromResource(R.xml.spare_parts);
-
-        PreferenceScreen prefSet = getPreferenceScreen();
-        
-        mWindowAnimationsPref = (ListPreference) prefSet.findPreference(WINDOW_ANIMATIONS_PREF);
-        mWindowAnimationsPref.setOnPreferenceChangeListener(this);
-        mTransitionAnimationsPref = (ListPreference) prefSet.findPreference(TRANSITION_ANIMATIONS_PREF);
-        mTransitionAnimationsPref.setOnPreferenceChangeListener(this);
-        mFancyImeAnimationsPref = (CheckBoxPreference) prefSet.findPreference(FANCY_IME_ANIMATIONS_PREF);
-        mHapticFeedbackPref = (CheckBoxPreference) prefSet.findPreference(HAPTIC_FEEDBACK_PREF);
-        mFontSizePref = (ListPreference) prefSet.findPreference(FONT_SIZE_PREF);
-        mFontSizePref.setOnPreferenceChangeListener(this);
-        mEndButtonPref = (ListPreference) prefSet.findPreference(END_BUTTON_PREF);
-        mEndButtonPref.setOnPreferenceChangeListener(this);
-        mCompatibilityMode = (CheckBoxPreference) findPreference(KEY_COMPATIBILITY_MODE);
-        mCompatibilityMode.setPersistent(false);
-        mCompatibilityMode.setChecked(Settings.System.getInt(getContentResolver(),
-                Settings.System.COMPATIBILITY_MODE, 1) != 0);
-
-        mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
-        
-        final PreferenceGroup parentPreference = getPreferenceScreen();
-        updatePreferenceToSpecificActivityOrRemove(this, parentPreference,
-                BATTERY_HISTORY_PREF, 0);
-        updatePreferenceToSpecificActivityOrRemove(this, parentPreference,
-                BATTERY_INFORMATION_PREF, 0);
-        updatePreferenceToSpecificActivityOrRemove(this, parentPreference,
-                USAGE_STATISTICS_PREF, 0);
-        
-        parentPreference.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
-    }
-
-    private void updateToggles() {
-        mFancyImeAnimationsPref.setChecked(Settings.System.getInt(
-                getContentResolver(), 
-                Settings.System.FANCY_IME_ANIMATIONS, 0) != 0);
-        mHapticFeedbackPref.setChecked(Settings.System.getInt(
-                getContentResolver(), 
-                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) != 0);
-    }
-    
-    public boolean onPreferenceChange(Preference preference, Object objValue) {
-        if (preference == mWindowAnimationsPref) {
-            writeAnimationPreference(0, objValue);
-        } else if (preference == mTransitionAnimationsPref) {
-            writeAnimationPreference(1, objValue);
-        } else if (preference == mFontSizePref) {
-            writeFontSizePreference(objValue);
-        } else if (preference == mEndButtonPref) {
-            writeEndButtonPreference(objValue);
-        }
-        // always let the preference setting proceed.
-        return true;
-    }
-
-    @Override
-    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
-        if (preference == mCompatibilityMode) {
-            Settings.System.putInt(getContentResolver(),
-                    Settings.System.COMPATIBILITY_MODE,
-                    mCompatibilityMode.isChecked() ? 1 : 0);
-            return true;
-        }
-        return false;
-    }
-
-    public void writeAnimationPreference(int which, Object objValue) {
-        try {
-            float val = Float.parseFloat(objValue.toString());
-            mWindowManager.setAnimationScale(which, val);
-        } catch (NumberFormatException e) {
-        } catch (RemoteException e) {
-        }
-    }
-    
-    public void writeFontSizePreference(Object objValue) {
-        try {
-            mCurConfig.fontScale = Float.parseFloat(objValue.toString());
-            ActivityManagerNative.getDefault().updateConfiguration(mCurConfig);
-        } catch (RemoteException e) {
-        }
-    }
-    
-    public void writeEndButtonPreference(Object objValue) {
-        try {
-            int val = Integer.parseInt(objValue.toString());
-            Settings.System.putInt(getContentResolver(),
-                    Settings.System.END_BUTTON_BEHAVIOR, val);
-        } catch (NumberFormatException e) {
-        }
-    }
-    
-    int floatToIndex(float val, int resid) {
-        String[] indices = getResources().getStringArray(resid);
-        float lastVal = Float.parseFloat(indices[0]);
-        for (int i=1; i<indices.length; i++) {
-            float thisVal = Float.parseFloat(indices[i]);
-            if (val < (lastVal + (thisVal-lastVal)*.5f)) {
-                return i-1;
-            }
-            lastVal = thisVal;
-        }
-        return indices.length-1;
-    }
-    
-    public void readAnimationPreference(int which, ListPreference pref) {
-        try {
-            float scale = mWindowManager.getAnimationScale(which);
-            pref.setValueIndex(floatToIndex(scale,
-                    R.array.entryvalues_animations));
-        } catch (RemoteException e) {
-        }
-    }
-    
-    public void readFontSizePreference(ListPreference pref) {
-        try {
-            mCurConfig.updateFrom(
-                ActivityManagerNative.getDefault().getConfiguration());
-        } catch (RemoteException e) {
-        }
-        pref.setValueIndex(floatToIndex(mCurConfig.fontScale,
-                R.array.entryvalues_font_size));
-    }
-    
-    public void readEndButtonPreference(ListPreference pref) {
-        try {
-            pref.setValueIndex(Settings.System.getInt(getContentResolver(),
-                    Settings.System.END_BUTTON_BEHAVIOR));
-        } catch (SettingNotFoundException e) {
-        }
-    }
-    
-    public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
-        if (FANCY_IME_ANIMATIONS_PREF.equals(key)) {
-            Settings.System.putInt(getContentResolver(),
-                    Settings.System.FANCY_IME_ANIMATIONS,
-                    mFancyImeAnimationsPref.isChecked() ? 1 : 0);
-        } else if (HAPTIC_FEEDBACK_PREF.equals(key)) {
-            Settings.System.putInt(getContentResolver(),
-                    Settings.System.HAPTIC_FEEDBACK_ENABLED,
-                    mHapticFeedbackPref.isChecked() ? 1 : 0);
-        }
-    }
-    
-    @Override
-    public void onResume() {
-        super.onResume();
-        readAnimationPreference(0, mWindowAnimationsPref);
-        readAnimationPreference(1, mTransitionAnimationsPref);
-        readFontSizePreference(mFontSizePref);
-        readEndButtonPreference(mEndButtonPref);
-        updateToggles();
-    }
-}
diff --git a/build/sdk.atree b/build/sdk.atree
index 113dce5..476bf16 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -87,6 +87,7 @@
 #development/tools/emulator/skins/HVGA      platforms/${PLATFORM_NAME}/skins/HVGA
 #development/tools/emulator/skins/WVGA800   platforms/${PLATFORM_NAME}/skins/WVGA800
 #development/tools/emulator/skins/WVGA854   platforms/${PLATFORM_NAME}/skins/WVGA854
+development/tools/emulator/skins/WSVGA      platforms/${PLATFORM_NAME}/skins/WSVGA
 development/tools/emulator/skins/WXGA       platforms/${PLATFORM_NAME}/skins/WXGA
 
 # Platform SDK properties
@@ -181,9 +182,11 @@
 development/samples/SpinnerTest                samples/${PLATFORM_NAME}/SpinnerTest
 development/samples/TicTacToeLib               samples/${PLATFORM_NAME}/TicTacToeLib
 development/samples/TicTacToeMain              samples/${PLATFORM_NAME}/TicTacToeMain
+development/samples/TtsEngine                  samples/${PLATFORM_NAME}/TtsEngine
 development/samples/USB/MissileLauncher        samples/${PLATFORM_NAME}/USB/MissileLauncher
 development/samples/USB/AdbTest                samples/${PLATFORM_NAME}/USB/AdbTest
 development/samples/VoiceRecognitionService    samples/${PLATFORM_NAME}/VoiceRecognitionService
+development/samples/VoicemailProviderDemo      samples/${PLATFORM_NAME}/VoicemailProviderDemo
 development/samples/WeatherListWidget          samples/${PLATFORM_NAME}/WeatherListWidget
 development/apps/WidgetPreview                 samples/${PLATFORM_NAME}/WidgetPreview
 development/samples/Wiktionary                 samples/${PLATFORM_NAME}/Wiktionary
@@ -218,3 +221,9 @@
 ${OUT_DIR}/target/common/obj/PACKAGING/android-support-v13_intermediates/android-support-v13.jar  extras/android/compatibility/v13/android-support-v13.jar
 frameworks/support/v13                                                                            extras/android/compatibility/v13/src
 development/samples/Support13Demos                                                                extras/android/compatibility/v13/samples/Support13Demos
+
+##############################################################################
+# Tests Component
+##############################################################################
+framework/layoutlib-tests.jar tests/libtests/layoutlib-tests.jar
+
diff --git a/build/tools/mk_sdk_repo_xml.sh b/build/tools/mk_sdk_repo_xml.sh
index f7bbec1..56f426b 100755
--- a/build/tools/mk_sdk_repo_xml.sh
+++ b/build/tools/mk_sdk_repo_xml.sh
@@ -45,7 +45,7 @@
 shift
 
 # Get XML:NS for SDK from the schema
-XMLNS=$(sed -n '/xmlns:.*schemas.android.com\/sdk\/android\//s/.*"\(.*\)".*/\1/p' "$SCHEMA")
+XMLNS=$(sed -n '/xmlns:sdk="/s/.*"\(.*\)".*/\1/p' "$SCHEMA")
 [[ -z "$XMLNS" ]] && error "Failed to find xmlns:sdk in $SCHEMA."
 echo "## Using xmlns:sdk=$XMLNS"
 
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyGetFrameRateEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyGetFrameRateEvent.java
new file mode 100644
index 0000000..164d936
--- /dev/null
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyGetFrameRateEvent.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.commands.monkey;
+
+import android.app.IActivityManager;
+import android.util.Log;
+import android.view.IWindowManager;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.text.DecimalFormat;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * Events for running a special shell command to capture the frame rate.
+ * To run this test, the system property viewancestor.profile_rendering
+ * must be set to true to force the currently focused window to render at
+ * 60 Hz.
+ */
+public class MonkeyGetFrameRateEvent extends MonkeyEvent {
+
+    private String GET_FRAMERATE_CMD = "service call SurfaceFlinger 1013";
+    private String mStatus;
+    private static long mStartTime; // in millisecond
+    private static long mEndTime; // in millisecond
+    private static float mDuration; // in seconds
+    private static String mTestCaseName = null;
+    private static int mStartFrameNo;
+    private static int mEndFrameNo;
+
+    private static final String TAG = "MonkeyGetFrameRateEvent";
+    private static final String LOG_FILE = "/sdcard/avgFrameRateOut.txt";
+
+    private static final Pattern NO_OF_FRAMES_PATTERN =
+        Pattern.compile(".*\\(([a-f[A-F][0-9]].*?)\\s.*\\)");
+
+    public MonkeyGetFrameRateEvent(String status, String testCaseName) {
+        super(EVENT_TYPE_ACTIVITY);
+        mStatus = status;
+        mTestCaseName = testCaseName;
+    }
+
+    public MonkeyGetFrameRateEvent(String status) {
+        super(EVENT_TYPE_ACTIVITY);
+        mStatus = status;
+    }
+
+    //Calculate the average frame rate
+    private float getAverageFrameRate(int totalNumberOfFrame, float duration) {
+        float avgFrameRate = 0;
+        if (duration > 0) {
+            avgFrameRate = (totalNumberOfFrame / duration);
+        }
+        return avgFrameRate;
+    }
+
+    /**
+     * Calculate the frame rate and write the output to a file on the SD card.
+     */
+    private void writeAverageFrameRate() {
+        FileWriter writer = null;
+        float avgFrameRate;
+        int totalNumberOfFrame = 0;
+        try {
+            writer = new FileWriter(LOG_FILE, true); // true = append
+            totalNumberOfFrame = mEndFrameNo - mStartFrameNo;
+            avgFrameRate = getAverageFrameRate(totalNumberOfFrame, mDuration);
+            writer.write(String.format("%s:%.2f\n",mTestCaseName,avgFrameRate));
+            writer.close();
+        } catch (IOException e) {
+            Log.w(TAG, "Can't write sdcard log file", e);
+        } finally {
+            try {
+                if (writer != null) writer.close();
+            } catch (IOException e) {
+                Log.e(TAG, "IOException " + e.toString());
+            }
+        }
+    }
+
+    // Parse the output of the surfaceFlinge shell command call
+    private String getNumberOfFrames(String input){
+        String noOfFrames = null;
+        Matcher m = NO_OF_FRAMES_PATTERN.matcher(input);
+        if (m.matches()){
+            noOfFrames = m.group(1);
+        }
+        return noOfFrames;
+    }
+
+    @Override
+    public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) {
+        java.lang.Process p = null;
+        BufferedReader result = null;
+        try {
+            p = Runtime.getRuntime().exec(GET_FRAMERATE_CMD);
+            int status = p.waitFor();
+            if (status != 0) {
+                System.err.println(String.format("// Shell command %s status was %s",
+                        GET_FRAMERATE_CMD, status));
+            }
+            result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+
+            //Only need the first line of the output
+            String output = result.readLine();
+
+            if (output != null) {
+                if (mStatus == "start") {
+                    mStartFrameNo = Integer.parseInt(getNumberOfFrames(output), 16);
+                    mStartTime = System.currentTimeMillis();
+                } else if (mStatus == "end") {
+                    mEndFrameNo = Integer.parseInt(getNumberOfFrames(output), 16);
+                    mEndTime = System.currentTimeMillis();
+                    long diff = mEndTime - mStartTime;
+                    mDuration = (float)(diff/1000.0);
+                    writeAverageFrameRate();
+                }
+            }
+        } catch (Exception e) {
+            System.err.println("// Exception from " + GET_FRAMERATE_CMD + ":");
+            System.err.println(e.toString());
+        } finally {
+            try {
+                if (result != null) {
+                    result.close();
+                }
+                if (p != null) {
+                    p.destroy();
+                }
+            } catch (IOException e) {
+                System.err.println(e.toString());
+            }
+        }
+        return MonkeyEvent.INJECT_SUCCESS;
+    }
+}
\ No newline at end of file
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyNetworkMonitor.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyNetworkMonitor.java
index 13cab44..6af9940 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeyNetworkMonitor.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyNetworkMonitor.java
@@ -84,7 +84,7 @@
 
     public void register(IActivityManager am) throws RemoteException {
         if (LDEBUG) System.out.println("registering Receiver");
-        am.registerReceiver(null, this, filter, null); 
+        am.registerReceiver(null, null, this, filter, null); 
     }
     
     public void unregister(IActivityManager am) throws RemoteException {
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceScript.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceScript.java
index 09ec8e9..a9a0609 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceScript.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceScript.java
@@ -117,6 +117,12 @@
 
     private static final String EVENT_KEYWORD_DRAG = "Drag";
 
+    private static final String EVENT_KEYWORD_PINCH_ZOOM = "PinchZoom";
+
+    private static final String EVENT_KEYWORD_START_FRAMERATE_CAPTURE = "StartCaptureFramerate";
+
+    private static final String EVENT_KEYWORD_END_FRAMERATE_CAPTURE = "EndCaptureFramerate";
+
     // a line at the end of the header
     private static final String STARTING_DATA_LINE = "start data >>";
 
@@ -294,23 +300,29 @@
         }
 
         // Handle tap event
-        if ((s.indexOf(EVENT_KEYWORD_TAP) >= 0) && args.length == 2) {
+        if ((s.indexOf(EVENT_KEYWORD_TAP) >= 0) && args.length >= 2) {
             try {
                 float x = Float.parseFloat(args[0]);
                 float y = Float.parseFloat(args[1]);
+                long tapDuration = 0;
+                if (args.length == 3) {
+                    tapDuration = Long.parseLong(args[2]);
+                }
 
                 // Set the default parameters
                 long downTime = SystemClock.uptimeMillis();
-
                 MonkeyMotionEvent e1 = new MonkeyTouchEvent(MotionEvent.ACTION_DOWN)
                         .setDownTime(downTime)
                         .setEventTime(downTime)
                         .addPointer(0, x, y, 1, 5);
+                mQ.addLast(e1);
+                if (tapDuration > 0){
+                    mQ.addLast(new MonkeyWaitEvent(tapDuration));
+                }
                 MonkeyMotionEvent e2 = new MonkeyTouchEvent(MotionEvent.ACTION_UP)
                         .setDownTime(downTime)
                         .setEventTime(downTime)
                         .addPointer(0, x, y, 1, 5);
-                mQ.addLast(e1);
                 mQ.addLast(e2);
             } catch (NumberFormatException e) {
                 System.err.println("// " + e.toString());
@@ -385,6 +397,61 @@
             }
         }
 
+        // Handle pinch or zoom action
+        if ((s.indexOf(EVENT_KEYWORD_PINCH_ZOOM) >= 0) && args.length == 9) {
+            //Parse the parameters
+            float pt1xStart = Float.parseFloat(args[0]);
+            float pt1yStart = Float.parseFloat(args[1]);
+            float pt1xEnd = Float.parseFloat(args[2]);
+            float pt1yEnd = Float.parseFloat(args[3]);
+
+            float pt2xStart = Float.parseFloat(args[4]);
+            float pt2yStart = Float.parseFloat(args[5]);
+            float pt2xEnd = Float.parseFloat(args[6]);
+            float pt2yEnd = Float.parseFloat(args[7]);
+
+            int stepCount = Integer.parseInt(args[8]);
+
+            float x1 = pt1xStart;
+            float y1 = pt1yStart;
+            float x2 = pt2xStart;
+            float y2 = pt2yStart;
+
+            long downTime = SystemClock.uptimeMillis();
+            long eventTime = SystemClock.uptimeMillis();
+
+            if (stepCount > 0) {
+                float pt1xStep = (pt1xEnd - pt1xStart) / stepCount;
+                float pt1yStep = (pt1yEnd - pt1yStart) / stepCount;
+
+                float pt2xStep = (pt2xEnd - pt2xStart) / stepCount;
+                float pt2yStep = (pt2yEnd - pt2yStart) / stepCount;
+
+                mQ.addLast(new MonkeyTouchEvent(MotionEvent.ACTION_DOWN).setDownTime(downTime)
+                        .setEventTime(eventTime).addPointer(0, x1, y1, 1, 5));
+
+                mQ.addLast(new MonkeyTouchEvent(MotionEvent.ACTION_POINTER_DOWN
+                        | (1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT)).setDownTime(downTime)
+                        .addPointer(0, x1, y1).addPointer(1, x2, y2).setIntermediateNote(true));
+
+                for (int i = 0; i < stepCount; ++i) {
+                    x1 += pt1xStep;
+                    y1 += pt1yStep;
+                    x2 += pt2xStep;
+                    y2 += pt2yStep;
+
+                    eventTime = SystemClock.uptimeMillis();
+                    mQ.addLast(new MonkeyTouchEvent(MotionEvent.ACTION_MOVE).setDownTime(downTime)
+                            .setEventTime(eventTime).addPointer(0, x1, y1, 1, 5).addPointer(1, x2,
+                                    y2, 1, 5));
+                }
+                eventTime = SystemClock.uptimeMillis();
+                mQ.addLast(new MonkeyTouchEvent(MotionEvent.ACTION_POINTER_UP)
+                        .setDownTime(downTime).setEventTime(eventTime).addPointer(0, x1, y1)
+                        .addPointer(1, x2, y2));
+            }
+        }
+
         // Handle flip events
         if (s.indexOf(EVENT_KEYWORD_FLIP) >= 0 && args.length == 1) {
             boolean keyboardOpen = Boolean.parseBoolean(args[0]);
@@ -523,6 +590,21 @@
             return;
         }
 
+        if (s.indexOf(EVENT_KEYWORD_START_FRAMERATE_CAPTURE) >= 0) {
+            MonkeyGetFrameRateEvent e = new MonkeyGetFrameRateEvent("start");
+            mQ.addLast(e);
+            return;
+        }
+
+        if (s.indexOf(EVENT_KEYWORD_END_FRAMERATE_CAPTURE) >= 0 && args.length == 1) {
+            String input = args[0];
+            MonkeyGetFrameRateEvent e = new MonkeyGetFrameRateEvent("end", input);
+            mQ.addLast(e);
+            return;
+        }
+
+
+
     }
 
     /**
diff --git a/ide/eclipse/.classpath b/ide/eclipse/.classpath
index 1323287..470c584 100644
--- a/ide/eclipse/.classpath
+++ b/ide/eclipse/.classpath
@@ -11,7 +11,8 @@
 	<classpathentry kind="src" path="packages/apps/Email/src"/>
 	<classpathentry kind="src" path="packages/apps/Email/emailcommon/src"/>
 	<classpathentry kind="src" path="packages/apps/Exchange/src"/>
-	<classpathentry kind="src" path="packages/apps/Gallery3D/src"/>
+	<classpathentry kind="src" path="packages/apps/Gallery3D/new3d/src"/>
+	<classpathentry kind="src" path="packages/apps/Gallery3D/PicasaProvider/src"/>
 	<classpathentry kind="src" path="packages/apps/HTMLViewer/src"/>
 	<classpathentry kind="src" path="packages/apps/Launcher2/src"/>
 	<classpathentry kind="src" path="packages/apps/Mms/src"/>
@@ -51,11 +52,13 @@
 	<classpathentry kind="src" path="frameworks/base/telephony/java"/>
 	<classpathentry kind="src" path="frameworks/base/test-runner/src"/>
 	<classpathentry kind="src" path="frameworks/base/voip/java"/>
-	<classpathentry kind="src" path="frameworks/base/vpn/java"/>
 	<classpathentry kind="src" path="frameworks/base/wifi/java"/>
 	<classpathentry kind="src" path="frameworks/ex/carousel/java"/>
+	<classpathentry kind="src" path="frameworks/ex/chips/src"/>
 	<classpathentry kind="src" path="frameworks/ex/common/java"/>
+	<classpathentry kind="src" path="frameworks/opt/calendar/src"/>
 	<classpathentry kind="src" path="frameworks/opt/vcard/java"/>
+	<classpathentry kind="src" path="frameworks/support/v13/java"/>
 	<classpathentry kind="src" path="development/samples/ApiDemos/src"/>
 	<classpathentry kind="src" path="development/samples/ApiDemos/tests/src"/>
 	<classpathentry kind="src" path="development/samples/Compass/src"/>
@@ -89,11 +92,11 @@
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/android-common-carousel_intermediates/src/renderscript/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon_intermediates/src/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java"/>
+	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/keystore/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/location/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/voip/java"/>
-	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/vpn/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/wifi/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/services_intermediates/src"/>
 	<classpathentry kind="src" path="out/target/common/R"/>
diff --git a/ide/eclipse/android-formatting-35.xml b/ide/eclipse/android-formatting-35.xml
new file mode 100644
index 0000000..b827782
--- /dev/null
+++ b/ide/eclipse/android-formatting-35.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<profiles version="10">
+<profile name="Android" version="10">
+<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="100"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
+</profile>
+</profiles>
diff --git a/ide/eclipse/android.importorder b/ide/eclipse/android.importorder
index 09966ec..f11daae 100644
--- a/ide/eclipse/android.importorder
+++ b/ide/eclipse/android.importorder
@@ -1,7 +1,7 @@
-#Organize Import Order
-#Wed Apr 04 11:32:05 CDT 2007
-4=javax
-3=java
-2=android
-1=org
-0=com
+6=javax
+5=java
+4=org
+3=net
+2=junit
+1=com
+0=android
diff --git a/libraries/stereocamera/README.txt b/libraries/stereocamera/README.txt
new file mode 100644
index 0000000..c3552c9
--- /dev/null
+++ b/libraries/stereocamera/README.txt
@@ -0,0 +1,4 @@
+Stereo Camera Libraries for Android.
+
+This SDK component contains static libraries for computing the depth map of a pair of stereo images.
+To use the libraries, simply copy them as static libraries into your project.
diff --git a/libraries/stereocamera/source.properties b/libraries/stereocamera/source.properties
new file mode 100644
index 0000000..8292d7f
--- /dev/null
+++ b/libraries/stereocamera/source.properties
@@ -0,0 +1,9 @@
+### Android Tool: Source of this archive.
+Extra.Vendor=android
+Pkg.Desc=Stereo Camera libraries, revision 1
+Pkg.DescUrl=http\://developer.android.com/
+Archive.Os=ANY
+Pkg.Revision=1
+Archive.Arch=ANY
+Extra.Path=stereocamera
+Pkg.SourceUrl=https\://dl-ssl.google.com/android/repository/repository.xml
diff --git a/ndk/platforms/android-9/include/EGL/eglext.h b/ndk/platforms/android-9/include/EGL/eglext.h
index 1ffcd56..1123e16 100644
--- a/ndk/platforms/android-9/include/EGL/eglext.h
+++ b/ndk/platforms/android-9/include/EGL/eglext.h
@@ -225,7 +225,7 @@
 
 #ifndef EGL_ANDROID_image_native_buffer
 #define EGL_ANDROID_image_native_buffer 1
-struct android_native_buffer_t;
+struct ANativeWindowBuffer;
 #define EGL_NATIVE_BUFFER_ANDROID       0x3140  /* eglCreateImageKHR target */
 #endif
 
diff --git a/ndk/platforms/android-9/samples/native-activity/Android.mk b/ndk/platforms/android-9/samples/native-activity/Android.mk
index ea961ca..73b3d87 100644
--- a/ndk/platforms/android-9/samples/native-activity/Android.mk
+++ b/ndk/platforms/android-9/samples/native-activity/Android.mk
@@ -44,7 +44,7 @@
 
 LOCAL_SHARED_LIBRARIES := liblog libandroid libEGL libGLESv1_CM
 
-LOCAL_PRELINK_MODULE := false
+
 
 LOCAL_MODULE := libnative-activity
 
diff --git a/pdk/docs/compatibility/downloads.jd b/pdk/docs/compatibility/downloads.jd
index 27a2109..79ad81b 100644
--- a/pdk/docs/compatibility/downloads.jd
+++ b/pdk/docs/compatibility/downloads.jd
@@ -11,7 +11,7 @@
 </p>
 <ul>
   <li><a href="{@docRoot}compatibility/android-2.3.3-cdd.pdf">Android 2.3.3 Compatibility Definition Document (CDD)</a></li>
-  <li><a href="http://dl.google.com/dl/android/cts/android-cts-2.3_r1-x86.zip">Android 2.3 R1 Compatibility Test Suite (CTS)</a></li>
+  <li><a href="http://dl.google.com/dl/android/cts/android-cts-2.3_r2-x86.zip">Android 2.3 R2 Compatibility Test Suite (CTS)</a></li>
 </ul>
 
 <h2>Android 2.2</h2>
@@ -21,7 +21,7 @@
 </p>
 <ul>
   <li><a href="{@docRoot}compatibility/android-2.2-cdd.pdf">Android 2.2 Compatibility Definition Document (CDD)</a></li>
-  <li><a href="http://dl.google.com/dl/android/cts/android-cts-2.2_r4-x86.zip">Android 2.2 R4 Compatibility Test Suite (CTS)</a></li>
+  <li><a href="http://dl.google.com/dl/android/cts/android-cts-2.2_r5-x86.zip">Android 2.2 R5 Compatibility Test Suite (CTS)</a></li>
 </ul>
 
 <h2>Android 2.1</h2>
@@ -41,6 +41,7 @@
 in the 'donut' branch in the open-source tree.
 <ul>
   <li><a href="{@docRoot}compatibility/android-1.6-cdd.pdf">Android 1.6 Compatibility Definition Document (CDD)</a></li>
+  <li><a href="http://dl.google.com/dl/android/cts/android-cts-1.6_r1-x86.zip">Android 1.6 R1 Compatibility Test Suite (CTS)</a></li>
 </ul>
 
 <h2>Compatibility Test Suite Manual</h2>
diff --git a/pdk/docs/porting/bluetooth.jd b/pdk/docs/porting/bluetooth.jd
index c792bd2..03b2d94 100755
--- a/pdk/docs/porting/bluetooth.jd
+++ b/pdk/docs/porting/bluetooth.jd
@@ -17,12 +17,15 @@
 </div>
 </div>
 
-<p>Android's Bluetooth stack uses BlueZ for GAP, SDP, and RFCOMM profiles, and
-is a SIG-qualified Bluetooth stack. </p>
+<p>Android's Bluetooth stack uses BlueZ as the host stack.</p>
 
 <p>Bluez is GPL licensed, so the Android framework interacts with userspace bluez code through D-BUS IPC to avoid proprietary code.</p>
 
-<p>Headset and Handsfree (v1.5) profiles are implemented in the Android framework and are both tightly coupled with the Phone App. These profiles are also SIG qualified.</p>
+<p>The qualification notes mentioned below are example qualifications of the particular device in question. Each company has to re-qualify their product with Bluetooth SIG even if no changes are made to the Bluetooth stack.</p>
+
+<p>Headset and Handsfree (v1.5) profiles are implemented in the Android framework and are both tightly coupled with the Phone App. Profiles like OPP and PBAP are based on java obex. These profiles open a rfcomm socket connection into Bluez kernel bypassing the Bluez userspace stack.</p>
+
+<p> Profiles like A2DP, AVRCP, HID, PAN and other bluetooth functionality like pairing and scanning use the Bluez userspace stack.</p>
 
 <p>The diagram below offers a library-oriented view of the Bluetooth stack. Click <a href="bluetooth/bluetooth_process.html">Bluetooth Process Diagram</a> for a process-oriented view.</p>
 
@@ -79,7 +82,7 @@
 </pre>
 
 <p><strong>Deamon Logs</strong></p>
-<p>Deamon logs for <code>hcid</code> (<code>STDOUT</code>) and <code>hciattach</code> (<code>STDERR</code>) are sent to <code>/dev/null</code> by default. Edit <code>init.rc</code></span> and <code>init.PLATFORM.rc</code></span> to run these daemons under <code>logwrapper</code>, which redirects output to <code>logcat</code>.</p>
+<p>Deamon logs for <code>bluetoothd</code> (<code>STDOUT</code>) and <code>hciattach</code> (<code>STDERR</code>) are sent to <code>/dev/null</code> by default. Edit <code>init.rc</code></span> and <code>init.PLATFORM.rc</code></span> to run these daemons under <code>logwrapper</code>, which redirects output to <code>logcat</code>.</p>
 <p><strong>hciconfig -a and hcitool</strong></p>
 <p>If you compile your own system.img for Android, and <code>hciconfig -a</code> works but <code>hcitool</code> scan doesn't, try installing the firmware for the Bluetooth chipset. This firmware isn't yet available in the open source codebase, but you can <code>adb pull</code> and then <code>adb push</code>it from a stock T-Mobile G1 (located in <code>/etc/firmware/brf6300.bin</code>).<br />
   <a name="androidBluetoothTools"></a></p>
@@ -112,7 +115,7 @@
     </li>
   </ul>
 </ul>
-<h5>Qualifications</h5>
+<h5>Qualifications for HTC G1 product. Each company reusing this software version has to re-qualify with Bluetooth SIG</h5>
 <ul>
   <li>QDID B014524: Host stack (SDP, L2CAP, GAP, RFCOMM, SPP)</li>
   <li>QDID B014624: EPL for HTC Dream (HSP, HFP)</li>
@@ -154,7 +157,7 @@
     <li>play/pause/stop/prev/next</li>
   </ul>
 </ul>
-<h4>Qualifications</h4>
+<h5>Qualifications for HTC Sapphire product. Each company reusing this software version has to re-qualify with Bluetooth SIG</h5>
 <ul>
   <li>QDID B015261: Host stack (SDP, L2CAP, GAP, RFCOMM, SPP, AVCTP, AVRCP, GAVDP, AVDTP, A2DP)</li>
   <li>QDID B015262: EPL for HTC Sapphire (HSP, HFP)</li>
@@ -224,6 +227,22 @@
   <li>Improved compatibility with headsets and car kits. </li>
 </ul>
 
+<h4>Android 2.3  release (Gingerbread)</h4>
+<h4>Platform features</h4>
+<ul>
+  <li>Based on Bluez 4.69 with Linux Kernel 2.6.35</li>
+  <li>No new profiles added.</li>
+  <li>Improved compatibility with headsets and car kits. </li>
+</ul>
+
+<h4>Android 3.0 release (Honeycomb)</h4>
+<h4>Platform features</h4>
+<ul>
+  <li>Based on Bluez 4.69 with Linux Kernel 2.6.36</li>
+  <li>HID and PAN (NAP and PANU role) are the new profiles added.
+  <li>Improved compatibility with headsets and car kits. </li>
+</ul>
+
 <h5>&nbsp;</h5>
 <h4>Future releases</h4>
 <p>This section offers a rough guide of which features the team is developing for the next release. This feature list may change without notice. It isn't possible to post scheduling advice to the mailing lists.</p>
@@ -234,20 +253,3 @@
   <li>Bluetooth Low Energy </li>
 </ul>
 
-<p><strong>Development Notes</strong></p>
-<ul>
-  <li><strong>HID Support <br />
-  </strong>Cupcake features some early work&#151;Bluez has an HID plugin, <code>external/bluez/utils/input/Android.mk</code>, which gets compiled. <br />
-    <br />
-You can interact directly with this plugin using <code>dbus-send</code></span> and <code>dbus-monitor</code>. While not officially supported, you should be able to connect and use a HID keyboard and mouse using the Bluez HID plugin API. Next steps include plumbing the plugin API in the Android Java framework and offering better support for HID input methods (new keymaps and mouse support).<br />
-  <br />
-  </li>
-  <li>  <strong>Tethering - DUN and PAN Support</strong><br />
-    Cupcake features some early work&#151;Bluez has has DUN and PAN daemons which get compiled and <code>external/bluez/utils/dun/Android.mk
-  external/bluez/utils/pan/Android.mk
-BNEP</code> support is compiled into the kernel with cupcake. <br />
-<br />
-While not officially supported, you should be able to run <code>dund</code> or <code>pand</code> daemons and, using <code>pppd</code> or <code>iptables</code>, test tethering support. Next steps include plubming the DBUS APIs to these daemons up into the Android Java framework and adding code to setup the network paths via <code>pppd</code> and / or <code>iptables</code>.<br />
-  <br />
-  </li>
-</ul>
diff --git a/pdk/docs/porting/images/androidBluetooth.gif b/pdk/docs/porting/images/androidBluetooth.gif
index e62f5a8..1c1aa3f 100755
--- a/pdk/docs/porting/images/androidBluetooth.gif
+++ b/pdk/docs/porting/images/androidBluetooth.gif
Binary files differ
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index 97399c3..1fcf7ee 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -36,16 +36,7 @@
     <!-- For android.media.audiofx.Visualizer -->
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
 
-    <!-- For NetworkDetector sample: listen for phone state changes -->
-    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
-    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="11" />
-
-    <!-- The smallest screen this app works on is a phone.  The app will
-         scale its UI to larger screens but doesn't make good use of them
-         so allow the compatibility mode button to be shown (mostly because
-         this is just convenient for testing). -->
-    <supports-screens android:requiresSmallestWidthDp="320"
-            android:compatibleWidthLimitDp="480" />
+    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="13" />
 
     <!-- We will request access to the camera, saying we require a camera
          of some sort but not one with autofocus capability. -->
@@ -428,7 +419,7 @@
 
         <!-- Service Samples -->
 
-        <service android:name=".app.LocalService" />
+        <service android:name=".app.LocalService" android:stopWithTask="true" />
 
         <activity android:name=".app.LocalServiceActivities$Controller"
                 android:label="@string/activity_local_service_controller"
@@ -808,6 +799,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".app.ActionBarActionProviderActivity"
+                android:label="@string/action_bar_action_provider"
+                android:enabled="@bool/atLeastIceCreamSandwich">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <!-- Application Updating Samples -->
 
 <!-- BEGIN_INCLUDE(app_update_declaration) -->
@@ -916,6 +916,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".content.ResourcesLayoutReference"
+                android:label="@string/activity_resources_layout_reference">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+                <category android:name="android.intent.category.EMBED" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".content.ResourcesWidthAndHeight"
                 android:label="@string/activity_resources_width_and_height"
                 android:enabled="@bool/atLeastHoneycombMR2">
@@ -2040,6 +2049,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".view.Hover" android:label="Views/Hover Events">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <!-- ************************************* -->
         <!--           GRAPHICS SAMPLES            -->
         <!-- ************************************* -->
@@ -2509,17 +2525,6 @@
         </receiver>
 
         <!-- ************************************* -->
-        <!--           TELEPHONY SAMPLES           -->
-        <!-- ************************************* -->
-
-        <activity android:name=".telephony.NetworkDetector" android:label="Telephony/NetworkDetector">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.SAMPLE_CODE" />
-            </intent-filter>
-        </activity>
-
-        <!-- ************************************* -->
         <!--             OTHER SAMPLES             -->
         <!-- ************************************* -->
 
diff --git a/samples/ApiDemos/_index.html b/samples/ApiDemos/_index.html
index a80930a..399ef86 100644
--- a/samples/ApiDemos/_index.html
+++ b/samples/ApiDemos/_index.html
@@ -36,7 +36,6 @@
 "    <li><a href='src/com/example/android/apis/graphics/index.html'>Graphics</a></li>"+
 "    <li><a href='src/com/example/android/apis/media/index.html'>Media</a></li>"+
 "    <li><a href='src/com/example/android/apis/os/index.html'>OS</a></li>"+
-"    <li><a href='src/com/example/android/apis/telephony/index.html'>Telephony</a></li>"+
 "    <li><a href='src/com/example/android/apis/text/index.html'>Text</a></li>"+
 "    <li><a href='src/com/example/android/apis/view/index.html'>Views</a></li></ul>");
 
diff --git a/samples/ApiDemos/res/drawable/hover_background.xml b/samples/ApiDemos/res/drawable/hover_background.xml
new file mode 100644
index 0000000..ce9efca
--- /dev/null
+++ b/samples/ApiDemos/res/drawable/hover_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/hover_background_active" android:state_hovered="true" />
+    <item android:drawable="@drawable/hover_background_inactive" />
+</selector>
diff --git a/samples/ApiDemos/res/drawable/hover_background_active.xml b/samples/ApiDemos/res/drawable/hover_background_active.xml
new file mode 100644
index 0000000..8819ce2
--- /dev/null
+++ b/samples/ApiDemos/res/drawable/hover_background_active.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#ffdddd00"/>
+    <stroke android:width="3dp" color="#ff000000"/>
+    <corners android:radius="3dp" />
+    <padding android:left="10dp" android:top="10dp"
+        android:right="10dp" android:bottom="10dp" />
+</shape>
diff --git a/samples/ApiDemos/res/drawable/hover_background_inactive.xml b/samples/ApiDemos/res/drawable/hover_background_inactive.xml
new file mode 100644
index 0000000..5ddab3a
--- /dev/null
+++ b/samples/ApiDemos/res/drawable/hover_background_inactive.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#f0600000"/>
+    <stroke android:width="3dp" color="#ffff8080"/>
+    <corners android:radius="3dp" />
+    <padding android:left="10dp" android:top="10dp"
+        android:right="10dp" android:bottom="10dp" />
+</shape>
diff --git a/samples/ApiDemos/res/layout-h974dp/resources_height.xml b/samples/ApiDemos/res/layout-h974dp/resources_height.xml
new file mode 100644
index 0000000..5eb120d
--- /dev/null
+++ b/samples/ApiDemos/res/layout-h974dp/resources_height.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Part of resources_width_and_height that varies based on height. -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"
+            android:orientation="vertical">
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#8000ff00">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#80ff0000">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#8000ff00">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#80ff0000">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#8000ff00">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#80ff0000">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#8000ff00">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#80ff0000">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#8000ff00">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#80ff0000">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#8000ff00">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+        <FrameLayout android:layout_width="match_parent" android:layout_height="0px"
+                android:layout_weight="1" android:padding="4dp"
+                android:background="#80ff0000">
+            <include layout="@layout/resources_width" />
+        </FrameLayout>
+    </LinearLayout>
+</merge>
diff --git a/samples/ApiDemos/res/layout-w1024dp/resources_width.xml b/samples/ApiDemos/res/layout-w1024dp/resources_width.xml
new file mode 100644
index 0000000..05ea7ba
--- /dev/null
+++ b/samples/ApiDemos/res/layout-w1024dp/resources_width.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Part of resources_width_and_height that varies based on width. -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"
+            android:orientation="horizontal">
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#1">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#2">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#3">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#4">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#5">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#6">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#7">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#8">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#9">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#10">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#11">
+        </TextView>
+        <TextView android:layout_width="0px" android:layout_height="match_parent"
+                android:layout_weight="1" android:gravity="center"
+                android:layout_marginLeft="4dp" android:layout_marginRight="4dp"
+                android:background="#800000ff" android:text="w1024dp Width\n#12">
+        </TextView>
+    </LinearLayout>
+</merge>
diff --git a/samples/ApiDemos/res/layout/fragment_pager.xml b/samples/ApiDemos/res/layout/fragment_pager_support.xml
similarity index 65%
rename from samples/ApiDemos/res/layout/fragment_pager.xml
rename to samples/ApiDemos/res/layout/fragment_pager_support.xml
index 3867f46..a082e2e 100644
--- a/samples/ApiDemos/res/layout/fragment_pager.xml
+++ b/samples/ApiDemos/res/layout/fragment_pager_support.xml
@@ -28,10 +28,17 @@
             android:layout_weight="1">
     </android.support.v4.app.FragmentPager>
 
-    <Button android:id="@+id/new_fragment"
-        android:layout_width="wrap_content" android:layout_height="wrap_content"
-        android:layout_weight="0"
-        android:text="@string/new_fragment">
-        <requestFocus />
-    </Button>
+    <LinearLayout android:orientation="horizontal"
+            android:gravity="center" android:measureWithLargestChild="true"
+            android:layout_width="match_parent" android:layout_height="wrap_content"
+            android:layout_weight="0">
+        <Button android:id="@+id/goto_first"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@string/first">
+        </Button>
+        <Button android:id="@+id/goto_last"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@string/last">
+        </Button>
+    </LinearLayout>
 </LinearLayout>
diff --git a/samples/ApiDemos/res/layout/fragment_pager_list.xml b/samples/ApiDemos/res/layout/fragment_pager_support_list.xml
similarity index 100%
rename from samples/ApiDemos/res/layout/fragment_pager_list.xml
rename to samples/ApiDemos/res/layout/fragment_pager_support_list.xml
diff --git a/samples/ApiDemos/res/layout/hover.xml b/samples/ApiDemos/res/layout/hover.xml
new file mode 100644
index 0000000..399e8af
--- /dev/null
+++ b/samples/ApiDemos/res/layout/hover.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Hover event handling demo. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/description"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/hover_description"
+        android:padding="12dip" />
+
+    <TextView
+        android:id="@+id/message"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/hover_message_initial"
+        android:padding="12dip" />
+
+    <CheckBox
+        android:id="@+id/intercept_checkbox"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/hover_intercept_checkbox" />
+
+    <com.example.android.apis.view.HoverInterceptorView
+        android:id="@+id/interceptor"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <TextView
+            android:id="@+id/intercept_message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/hover_intercept_message_initial"
+            android:padding="12dip" />
+
+        <!-- This button uses a state-list drawable to select among
+             different shapes based on its current hover state. -->
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@drawable/hover_background"
+            android:text="@string/hover_button" />
+    </com.example.android.apis.view.HoverInterceptorView>
+</LinearLayout>
diff --git a/samples/ApiDemos/res/layout/network_detector.xml b/samples/ApiDemos/res/layout/network_detector.xml
deleted file mode 100644
index cd43b50..0000000
--- a/samples/ApiDemos/res/layout/network_detector.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    >
-    <TextView android:id="@+id/phone_type"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content" />
-    <TextView android:id="@+id/network_name"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content" />
-    <TextView android:id="@+id/sim_state"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content" />
-    <TextView android:id="@+id/network_type"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content" />
-</LinearLayout>
diff --git a/samples/ApiDemos/res/layout/resources_layout_reference.xml b/samples/ApiDemos/res/layout/resources_layout_reference.xml
new file mode 100644
index 0000000..2d41143
--- /dev/null
+++ b/samples/ApiDemos/res/layout/resources_layout_reference.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Demonstrates using -wNNNdp and -hNNNdp resource configs. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent" android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView android:layout_width="match_parent" android:layout_height="wrap_content"
+        android:layout_weight="0" android:gravity="center_horizontal"
+        android:paddingTop="8dp" android:paddingBottom="8dp"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:text="@string/resources_layout_reference_description"/>
+
+    <TextView android:layout_width="match_parent" android:layout_height="wrap_content"
+        android:layout_weight="0" android:gravity="center_horizontal"
+        android:paddingTop="8dp" android:paddingBottom="8dp"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:text="@string/resources_layout_reference_default"/>
+
+</LinearLayout>
diff --git a/samples/ApiDemos/res/layout/resources_layout_reference_tablet.xml b/samples/ApiDemos/res/layout/resources_layout_reference_tablet.xml
new file mode 100644
index 0000000..a2cf17a
--- /dev/null
+++ b/samples/ApiDemos/res/layout/resources_layout_reference_tablet.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Demonstrates using -wNNNdp and -hNNNdp resource configs. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent" android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView android:layout_width="match_parent" android:layout_height="wrap_content"
+        android:layout_weight="0" android:gravity="center_horizontal"
+        android:paddingTop="8dp" android:paddingBottom="8dp"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:text="@string/resources_layout_reference_description"/>
+
+    <TextView android:layout_width="match_parent" android:layout_height="wrap_content"
+        android:layout_weight="0" android:gravity="center_horizontal"
+        android:paddingTop="8dp" android:paddingBottom="8dp"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:text="@string/resources_layout_reference_tablet"/>
+
+</LinearLayout>
diff --git a/samples/ApiDemos/res/menu/action_bar_action_provider.xml b/samples/ApiDemos/res/menu/action_bar_action_provider.xml
new file mode 100644
index 0000000..7633f9f
--- /dev/null
+++ b/samples/ApiDemos/res/menu/action_bar_action_provider.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 Google 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:id="@+id/menu_item_share_action_provider_action_bar"
+        android:showAsAction="always"
+        android:title="@string/action_bar_share_with"
+        android:actionProviderClass="android.widget.ShareActionProvider" />
+
+    <item android:id="@+id/menu_item_share_action_provider_overflow"
+        android:showAsAction="never"
+        android:title="@string/action_bar_share_with"
+        android:actionProviderClass="android.widget.ShareActionProvider" />
+
+</menu>
diff --git a/samples/ApiDemos/res/values-sw600dp/layout.xml b/samples/ApiDemos/res/values-sw600dp/layout.xml
new file mode 100644
index 0000000..1f9771f
--- /dev/null
+++ b/samples/ApiDemos/res/values-sw600dp/layout.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Define a new configuration for the resources_layout_reference layout,
+         which uses the special tablet layout. -->
+    <item type="layout" name="resources_layout_reference">
+            @layout/resources_layout_reference_tablet</item>
+</resources>
diff --git a/samples/ApiDemos/res/values-xlarge/layout.xml b/samples/ApiDemos/res/values-xlarge/layout.xml
new file mode 100644
index 0000000..1f9771f
--- /dev/null
+++ b/samples/ApiDemos/res/values-xlarge/layout.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Define a new configuration for the resources_layout_reference layout,
+         which uses the special tablet layout. -->
+    <item type="layout" name="resources_layout_reference">
+            @layout/resources_layout_reference_tablet</item>
+</resources>
diff --git a/samples/ApiDemos/res/values/bools.xml b/samples/ApiDemos/res/values/bools.xml
index 266c8ca..5d2eaa0 100644
--- a/samples/ApiDemos/res/values/bools.xml
+++ b/samples/ApiDemos/res/values/bools.xml
@@ -23,4 +23,10 @@
          API level.  The default value is false; an alternative value
          for Honeycomb MR2 is true. -->
     <bool name="atLeastHoneycombMR2">false</bool>
+
+    <!-- This resource is true if running under at least IceCreamSandwich
+         API level.  The default value is false; an alternative value
+         for IceCreamSandwich is true. -->
+    <bool name="atLeastIceCreamSandwich">true</bool>
+
 </resources>
diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml
index da20a8f..c87c563 100644
--- a/samples/ApiDemos/res/values/strings.xml
+++ b/samples/ApiDemos/res/values/strings.xml
@@ -150,6 +150,9 @@
     <string name="fragment_stack">App/Fragment/Stack</string>
     <string name="new_fragment">New fragment</string>
 
+    <string name="first">First</string>
+    <string name="last">Last</string>
+
     <string name="fragment_tabs">App/Fragment/Tabs</string>
 
     <string name="loader_cursor">App/Loader/Cursor</string>
@@ -324,6 +327,13 @@
     <string name="styled_text">Plain, <b>bold</b>, <i>italic</i>, <b><i>bold-italic</i></b></string>
     <string name="styled_text_prog">Assigned programmatically:</string>
 
+    <string name="activity_resources_layout_reference">Content/Resources/Layout Reference</string>
+    <string name="resources_layout_reference_description">Shows how to write layout
+        resource references, so that you can define multiple different configurations of
+        a layout resource that refer to one actual XML definition.</string>
+    <string name="resources_layout_reference_default">Default layout</string>
+    <string name="resources_layout_reference_tablet">Tablet layout</string>
+
     <string name="activity_resources_width_and_height">Content/Resources/Width and Height</string>
     <string name="resources_width_and_height_description">The layouts below use -wNNNdp and
         -hNNNdp to select between different versions based on the size of the screen.</string>
@@ -515,12 +525,13 @@
     <string name="launch_preferences">Launch preferences</string>
     <string name="preference_attributes">Preference attributes</string>
 
-    <string name="title_toggle_preference">Toggle preference</string>
-    <string name="summary_toggle_preference">This is a toggle button</string>
-
     <string name="title_checkbox_preference">Checkbox preference</string>
     <string name="summary_checkbox_preference">This is a checkbox</string>
 
+    <string name="title_switch_preference">Switch preference</string>
+    <string name="summary_switch_preference">This is a switch</string>
+    <string name="summary_switch_preference_yes_no">This is a switch with custom text</string>
+
     <string name="title_yesno_preference">Yes or no preference</string>
     <string name="summary_yesno_preference">An example that uses a yes/no dialog</string>
     <string name="dialog_title_yesno_preference">Do you like bananas?</string>
@@ -552,9 +563,9 @@
     <string name="summary_on_advanced_toggle_preference">I\'m on! :)</string>
     <string name="summary_off_advanced_toggle_preference">I\'m off! :(</string>
 
-    <string name="title_parent_preference">Parent toggle</string>
+    <string name="title_parent_preference">Parent checkbox preference</string>
     <string name="summary_parent_preference">This is visually a parent</string>
-    <string name="title_child_preference">Child toggle</string>
+    <string name="title_child_preference">Child checkbox preference</string>
     <string name="summary_child_preference">This is visually a child</string>
 
     <string name="example_preference_dependency">Example preference dependency</string>
@@ -616,6 +627,10 @@
     <string name="header_encryption">Encryption</string>
 
     <string name="enable_admin">Enable admin</string>
+    <string name="device_capabilities_category">Device capabilities</string>
+    <string name="disable_camera">Disable all device cameras</string>
+    <string name="camera_disabled">Device cameras disabled</string>
+    <string name="camera_enabled">Device cameras enabled</string>
     <string name="password_controls_category">Password controls</string>
     <string name="set_password_user">Set password (user)</string>
     <string name="set_password_api">Set password (via API)</string>
@@ -707,6 +722,7 @@
     <string name="action_bar_mechanics">App/Action Bar/Action Bar Mechanics</string>
     <string name="action_bar_usage">App/Action Bar/Action Bar Usage</string>
     <string name="action_bar_tabs">App/Action Bar/Action Bar Tabs</string>
+    <string name="action_bar_action_provider">App/Action Bar/Action Provider</string>
 
     <string name="action_bar_search">Search</string>
     <string name="action_bar_add">Add</string>
@@ -715,6 +731,7 @@
     <string name="action_bar_sort">Sort</string>
     <string name="action_bar_sort_alpha">Alphabetically</string>
     <string name="action_bar_sort_size">By size</string>
+    <string name="action_bar_share_with">Share with...</string>
 
     <string name="action_bar_display_options">App/Action Bar/Display Options</string>
     <string name="toggle_home_as_up">DISPLAY_HOME_AS_UP</string>
@@ -861,6 +878,19 @@
     <string name="game_controller_input_key_pressed">Pressed</string>
     <string name="game_controller_input_key_released">Released</string>
 
+    <string name="hover_description">
+        This activity demonstrates how to handle hover events with View.onHoverEvent,
+        ViewGroup.onInterceptHoverEvent, and View.setOnHoverListener.
+    </string>
+    <string name="hover_intercept_checkbox">Make container intercept hover events</string>
+    <string name="hover_message_initial">Try using a mouse or touch pad to hover over views within this activity.</string>
+    <string name="hover_message_entered_at">Entered the container at (%1$f,%2$f).</string>
+    <string name="hover_message_moved_at">Moved within the container at (%1$f,%2$f).</string>
+    <string name="hover_message_exited_at">Exited the container at (%1$f,%2$f).  The pointer may be inside the bounds of a child instead.</string>
+    <string name="hover_intercept_message_initial">Try hovering over the button.</string>
+    <string name="hover_intercept_message_intercepted">Intercepted hover event instead of sending it to the button.  Om nom nom!</string>
+    <string name="hover_button">Hover Here</string>
+
     <!-- ============================== -->
     <!--  GoogleLogin examples strings  -->
     <!-- ============================== -->
diff --git a/samples/ApiDemos/res/xml/default_values.xml b/samples/ApiDemos/res/xml/default_values.xml
index da15a62..5638c00 100644
--- a/samples/ApiDemos/res/xml/default_values.xml
+++ b/samples/ApiDemos/res/xml/default_values.xml
@@ -20,11 +20,17 @@
         xmlns:android="http://schemas.android.com/apk/res/android">
 
     <CheckBoxPreference
-            android:key="default_toggle"
+            android:key="default_checkbox"
             android:defaultValue="true"
             android:title="@string/title_checkbox_preference"
             android:summary="@string/summary_checkbox_preference" />
 
+    <SwitchPreference
+            android:key="default_switch"
+            android:defaultValue="false"
+            android:title="@string/title_switch_preference"
+            android:summary="@string/summary_switch_preference" />
+
     <EditTextPreference
             android:key="default_edittext"
             android:defaultValue="@string/default_value_edittext_preference"
diff --git a/samples/ApiDemos/res/xml/device_admin_general.xml b/samples/ApiDemos/res/xml/device_admin_general.xml
index ef46238..61ccd32 100644
--- a/samples/ApiDemos/res/xml/device_admin_general.xml
+++ b/samples/ApiDemos/res/xml/device_admin_general.xml
@@ -28,4 +28,13 @@
 
     </PreferenceCategory>
 
+    <PreferenceCategory
+        android:title="@string/device_capabilities_category" >
+
+        <CheckBoxPreference
+            android:key="key_disable_camera"
+            android:title="@string/disable_camera" />
+
+    </PreferenceCategory>
+
 </PreferenceScreen>
diff --git a/samples/ApiDemos/res/xml/device_admin_sample.xml b/samples/ApiDemos/res/xml/device_admin_sample.xml
index 10edb7e..2468919 100644
--- a/samples/ApiDemos/res/xml/device_admin_sample.xml
+++ b/samples/ApiDemos/res/xml/device_admin_sample.xml
@@ -24,6 +24,7 @@
         <wipe-data />
         <expire-password />
         <encrypted-storage />
+        <disable-camera />
     </uses-policies>
 </device-admin>
 <!-- END_INCLUDE(meta_data) -->
diff --git a/samples/ApiDemos/res/xml/fragmented_preferences.xml b/samples/ApiDemos/res/xml/fragmented_preferences.xml
index 5033ab8..da6f3f1 100644
--- a/samples/ApiDemos/res/xml/fragmented_preferences.xml
+++ b/samples/ApiDemos/res/xml/fragmented_preferences.xml
@@ -24,8 +24,13 @@
 
         <CheckBoxPreference
                 android:key="checkbox_preference"
-                android:title="@string/title_toggle_preference"
-                android:summary="@string/summary_toggle_preference" />
+                android:title="@string/title_checkbox_preference"
+                android:summary="@string/summary_checkbox_preference" />
+
+        <SwitchPreference
+                android:key="checkbox_preference"
+                android:title="@string/title_switch_preference"
+                android:summary="@string/summary_switch_preference" />
 
     </PreferenceCategory>
 
diff --git a/samples/ApiDemos/res/xml/preferences.xml b/samples/ApiDemos/res/xml/preferences.xml
index 4d982ac..3316aa5 100644
--- a/samples/ApiDemos/res/xml/preferences.xml
+++ b/samples/ApiDemos/res/xml/preferences.xml
@@ -24,8 +24,20 @@
             
         <CheckBoxPreference
                 android:key="checkbox_preference"
-                android:title="@string/title_toggle_preference"
-                android:summary="@string/summary_toggle_preference" />
+                android:title="@string/title_checkbox_preference"
+                android:summary="@string/summary_checkbox_preference" />
+
+        <SwitchPreference
+                android:key="checkbox_preference"
+                android:title="@string/title_switch_preference"
+                android:summary="@string/summary_switch_preference" />
+
+        <SwitchPreference
+                android:key="checkbox_preference"
+                android:title="@string/title_switch_preference"
+                android:summary="@string/summary_switch_preference_yes_no"
+                android:switchTextOn = "YES"
+                android:switchTextOff = "NO" />
             
     </PreferenceCategory>
                 
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/ActionBarActionProviderActivity.java b/samples/ApiDemos/src/com/example/android/apis/app/ActionBarActionProviderActivity.java
new file mode 100644
index 0000000..44bc0df
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/ActionBarActionProviderActivity.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.apis.app;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ShareActionProvider;
+
+import java.io.File;
+
+import com.example.android.apis.R;
+
+/**
+ * This activity demonstrates how to use an {@link android.view.ActionProvider}
+ * for adding functionality to the Action Bar. In particular this demo is adding
+ * a menu item with ShareActionProvider as its action provider. The
+ * ShareActionProvider is responsible for managing the UI for sharing actions.
+ */
+public class ActionBarActionProviderActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate your menu.
+        getMenuInflater().inflate(R.menu.action_bar_action_provider, menu);
+
+        // Set file with share history to the provider and set the share intent.
+        MenuItem actionItem = menu.findItem(R.id.menu_item_share_action_provider_action_bar);
+        ShareActionProvider actionProvider = (ShareActionProvider) actionItem.getActionProvider();
+        actionProvider.setShareHistoryFileName(ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME);
+        actionProvider.setShareIntent(createShareIntent());
+
+        // Set file with share history to the provider and set the share intent.
+        MenuItem overflowItem = menu.findItem(R.id.menu_item_share_action_provider_overflow);
+        ShareActionProvider overflowProvider =
+            (ShareActionProvider) overflowItem.getActionProvider();
+        overflowProvider.setShareHistoryFileName(
+            ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME);
+        overflowProvider.setShareIntent(createShareIntent());
+
+        return true;
+    }
+
+    /**
+     * Creates a sharing {@link Intent}.
+     *
+     * @return The sharing intent.
+     */
+    private Intent createShareIntent() {
+        Intent shareIntent = new Intent(Intent.ACTION_SEND);
+        shareIntent.setType("image/*");
+        Uri uri = Uri.fromFile(new File(getFilesDir(), "SomeFileToShare"));
+        shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString());
+        return shareIntent;
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java b/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
index a9af983..324b8ce 100644
--- a/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
+++ b/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
@@ -67,6 +67,7 @@
 
     // The following keys are used to find each preference item
     private static final String KEY_ENABLE_ADMIN = "key_enable_admin";
+    private static final String KEY_DISABLE_CAMERA = "key_disable_camera";
 
     private static final String KEY_CATEGORY_QUALITY = "key_category_quality";
     private static final String KEY_SET_PASSWORD = "key_set_password";
@@ -243,6 +244,7 @@
             implements OnPreferenceChangeListener {
         // UI elements
         private CheckBoxPreference mEnableCheckbox;
+        private CheckBoxPreference mDisableCameraCheckbox;
 
         @Override
         public void onCreate(Bundle savedInstanceState) {
@@ -250,6 +252,8 @@
             addPreferencesFromResource(R.xml.device_admin_general);
             mEnableCheckbox = (CheckBoxPreference) findPreference(KEY_ENABLE_ADMIN);
             mEnableCheckbox.setOnPreferenceChangeListener(this);
+            mDisableCameraCheckbox = (CheckBoxPreference) findPreference(KEY_DISABLE_CAMERA);
+            mDisableCameraCheckbox.setOnPreferenceChangeListener(this);
         }
 
         // At onResume time, reload UI with current values as required
@@ -257,6 +261,12 @@
         public void onResume() {
             super.onResume();
             mEnableCheckbox.setChecked(mAdminActive);
+            enableDeviceCapabilitiesArea(mAdminActive);
+
+            if (mAdminActive) {
+                mDPM.setCameraDisabled(mDeviceAdminSample, mDisableCameraCheckbox.isChecked());
+                reloadSummaries();
+            }
         }
 
         @Override
@@ -264,10 +274,10 @@
             if (super.onPreferenceChange(preference, newValue)) {
                 return true;
             }
+            boolean value = (Boolean) newValue;
             if (preference == mEnableCheckbox) {
-                boolean newActive = (Boolean) newValue;
-                if (newActive != mAdminActive) {
-                    if (newActive) {
+                if (value != mAdminActive) {
+                    if (value) {
                         // Launch the activity to have the user enable our admin.
                         Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
                         intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdminSample);
@@ -278,12 +288,29 @@
                         return false;
                     } else {
                         mDPM.removeActiveAdmin(mDeviceAdminSample);
+                        enableDeviceCapabilitiesArea(false);
                         mAdminActive = false;
                     }
                 }
+            } else if (preference == mDisableCameraCheckbox) {
+                mDPM.setCameraDisabled(mDeviceAdminSample, value);
+                reloadSummaries();
             }
             return true;
         }
+
+        @Override
+        protected void reloadSummaries() {
+            super.reloadSummaries();
+            String cameraSummary = getString(mDPM.getCameraDisabled(mDeviceAdminSample)
+                    ? R.string.camera_disabled : R.string.camera_enabled);
+            mDisableCameraCheckbox.setSummary(cameraSummary);
+        }
+
+        /** Updates the device capabilities area (dis/enabling) as the admin is (de)activated */
+        private void enableDeviceCapabilitiesArea(boolean enabled) {
+            mDisableCameraCheckbox.setEnabled(enabled);
+        }
     }
 
     /**
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java b/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
index 9f84be1..123e369 100644
--- a/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
+++ b/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
@@ -66,7 +66,7 @@
     
     void invokeMethod(Method method, Object[] args) {
         try {
-            mStartForeground.invoke(this, mStartForegroundArgs);
+            method.invoke(this, args);
         } catch (InvocationTargetException e) {
             // Should not happen.
             Log.w("ApiDemos", "Unable to invoke method", e);
@@ -103,15 +103,7 @@
         // If we have the new stopForeground API, then use it.
         if (mStopForeground != null) {
             mStopForegroundArgs[0] = Boolean.TRUE;
-            try {
-                mStopForeground.invoke(this, mStopForegroundArgs);
-            } catch (InvocationTargetException e) {
-                // Should not happen.
-                Log.w("ApiDemos", "Unable to invoke stopForeground", e);
-            } catch (IllegalAccessException e) {
-                // Should not happen.
-                Log.w("ApiDemos", "Unable to invoke stopForeground", e);
-            }
+            invokeMethod(mStopForeground, mStopForegroundArgs);
             return;
         }
         
@@ -130,10 +122,10 @@
                     mStartForegroundSignature);
             mStopForeground = getClass().getMethod("stopForeground",
                     mStopForegroundSignature);
+            return;
         } catch (NoSuchMethodException e) {
             // Running on an older platform.
             mStartForeground = mStopForeground = null;
-            return;
         }
         try {
             mSetForeground = getClass().getMethod("setForeground",
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java b/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java
index a62a524..aade659 100644
--- a/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java
+++ b/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java
@@ -135,8 +135,13 @@
     };
 // END_INCLUDE(exposing_a_service)
     
-    private static final int REPORT_MSG = 1;
+    @Override
+    public void onTaskRemoved(Intent rootIntent) {
+        Toast.makeText(this, "Task removed: " + rootIntent, Toast.LENGTH_LONG).show();
+    }
     
+    private static final int REPORT_MSG = 1;
+
     /**
      * Our Handler used to execute operations on the main thread.  This is used
      * to schedule increments of our value.
diff --git a/samples/ApiDemos/src/com/example/android/apis/content/ResourcesLayoutReference.java b/samples/ApiDemos/src/com/example/android/apis/content/ResourcesLayoutReference.java
new file mode 100644
index 0000000..0682bcb
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/content/ResourcesLayoutReference.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.apis.content;
+
+import com.example.android.apis.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class ResourcesLayoutReference extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // This layout uses different configurations to adjust
+        // what is shown based on the smallest width that will occur.
+        setContentView(R.layout.resources_layout_reference);
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/content/_index.html b/samples/ApiDemos/src/com/example/android/apis/content/_index.html
index fc484a9..f49b8d9 100644
--- a/samples/ApiDemos/src/com/example/android/apis/content/_index.html
+++ b/samples/ApiDemos/src/com/example/android/apis/content/_index.html
@@ -8,4 +8,17 @@
 
   <dt><a href="ResourcesSample.html">Resources</a></dt>
   <dd>Demonstrates loading styled strings from a resource file, and extracting the raw text. </dd>
+
+  <dt><a href="ResourcesLayoutReference.html">Resources Layout Reference</a></dt>
+  <dd>Shows how to make references between resources; this examples shows how this
+      can be used to define multiple configurations for a layout resource that
+      reference the same layout XML.</dd>
+
+  <dt><a href="ResourcesSmallestWidth.html">Resources Smallest Width</a></dt>
+  <dd>Shows how you can vary a layout resource based on the device's smallest
+      width configuration</dd>
+
+  <dt><a href="ResourcesWidthAndHeight.html">Resources Width and Height</a></dt>
+  <dd>Shows how you can vary a layout resource based on the device's current
+      width dp and height dp configurations.</dd>
 </dl>
diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/Compass.java b/samples/ApiDemos/src/com/example/android/apis/graphics/Compass.java
index 85471d9..241d98f 100644
--- a/samples/ApiDemos/src/com/example/android/apis/graphics/Compass.java
+++ b/samples/ApiDemos/src/com/example/android/apis/graphics/Compass.java
@@ -23,7 +23,6 @@
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.os.Bundle;
-import android.util.Config;
 import android.util.Log;
 import android.view.View;
 
@@ -38,7 +37,7 @@
 
     private final SensorEventListener mListener = new SensorEventListener() {
         public void onSensorChanged(SensorEvent event) {
-            if (Config.DEBUG) Log.d(TAG,
+            if (false) Log.d(TAG,
                     "sensorChanged (" + event.values[0] + ", " + event.values[1] + ", " + event.values[2] + ")");
             mValues = event.values;
             if (mView != null) {
@@ -62,7 +61,7 @@
     @Override
     protected void onResume()
     {
-        if (Config.DEBUG) Log.d(TAG, "onResume");
+        if (false) Log.d(TAG, "onResume");
         super.onResume();
 
         mSensorManager.registerListener(mListener, mSensor,
@@ -72,7 +71,7 @@
     @Override
     protected void onStop()
     {
-        if (Config.DEBUG) Log.d(TAG, "onStop");
+        if (false) Log.d(TAG, "onStop");
         mSensorManager.unregisterListener(mListener);
         super.onStop();
     }
@@ -117,14 +116,14 @@
         @Override
         protected void onAttachedToWindow() {
             mAnimate = true;
-            if (Config.DEBUG) Log.d(TAG, "onAttachedToWindow. mAnimate=" + mAnimate);
+            if (false) Log.d(TAG, "onAttachedToWindow. mAnimate=" + mAnimate);
             super.onAttachedToWindow();
         }
 
         @Override
         protected void onDetachedFromWindow() {
             mAnimate = false;
-            if (Config.DEBUG) Log.d(TAG, "onDetachedFromWindow. mAnimate=" + mAnimate);
+            if (false) Log.d(TAG, "onDetachedFromWindow. mAnimate=" + mAnimate);
             super.onDetachedFromWindow();
         }
     }
diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/SensorTest.java b/samples/ApiDemos/src/com/example/android/apis/graphics/SensorTest.java
index dc07a27..7273cae 100644
--- a/samples/ApiDemos/src/com/example/android/apis/graphics/SensorTest.java
+++ b/samples/ApiDemos/src/com/example/android/apis/graphics/SensorTest.java
@@ -23,7 +23,6 @@
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.os.Bundle;
-import android.util.Config;
 import android.util.Log;
 import android.view.View;
 
@@ -142,21 +141,21 @@
         mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
         mView = new SampleView(this);
         setContentView(mView);
-        if (Config.DEBUG) Log.d(TAG, "create " + mSensorManager);
+        if (false) Log.d(TAG, "create " + mSensorManager);
     }
 
     @Override
     protected void onResume() {
         super.onResume();
         mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_FASTEST);
-        if (Config.DEBUG) Log.d(TAG, "resume " + mSensorManager);
+        if (false) Log.d(TAG, "resume " + mSensorManager);
     }
 
     @Override
     protected void onStop() {
         mSensorManager.unregisterListener(mListener);
         super.onStop();
-        if (Config.DEBUG) Log.d(TAG, "stop " + mSensorManager);
+        if (false) Log.d(TAG, "stop " + mSensorManager);
     }
 
     private class SampleView extends View {
@@ -200,14 +199,14 @@
         @Override
         protected void onAttachedToWindow() {
             mAnimate = true;
-            if (Config.DEBUG) Log.d(TAG, "onAttachedToWindow. mAnimate="+mAnimate);
+            if (false) Log.d(TAG, "onAttachedToWindow. mAnimate="+mAnimate);
             super.onAttachedToWindow();
         }
 
         @Override
         protected void onDetachedFromWindow() {
             mAnimate = false;
-            if (Config.DEBUG) Log.d(TAG, "onAttachedToWindow. mAnimate="+mAnimate);
+            if (false) Log.d(TAG, "onAttachedToWindow. mAnimate="+mAnimate);
             super.onDetachedFromWindow();
         }
     }
diff --git a/samples/ApiDemos/src/com/example/android/apis/preference/PreferencesFromCode.java b/samples/ApiDemos/src/com/example/android/apis/preference/PreferencesFromCode.java
index 8ce6b42..884991b 100644
--- a/samples/ApiDemos/src/com/example/android/apis/preference/PreferencesFromCode.java
+++ b/samples/ApiDemos/src/com/example/android/apis/preference/PreferencesFromCode.java
@@ -16,6 +16,8 @@
 
 package com.example.android.apis.preference;
 
+import com.example.android.apis.R;
+
 import android.content.Intent;
 import android.content.res.TypedArray;
 import android.net.Uri;
@@ -26,8 +28,7 @@
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceScreen;
-
-import com.example.android.apis.R;
+import android.preference.SwitchPreference;
 
 public class PreferencesFromCode extends PreferenceActivity {
 
@@ -47,12 +48,19 @@
         inlinePrefCat.setTitle(R.string.inline_preferences);
         root.addPreference(inlinePrefCat);
 
-        // Toggle preference
-        CheckBoxPreference togglePref = new CheckBoxPreference(this);
-        togglePref.setKey("toggle_preference");
-        togglePref.setTitle(R.string.title_toggle_preference);
-        togglePref.setSummary(R.string.summary_toggle_preference);
-        inlinePrefCat.addPreference(togglePref);
+        // Checkbox preference
+        CheckBoxPreference checkboxPref = new CheckBoxPreference(this);
+        checkboxPref.setKey("checkbox_preference");
+        checkboxPref.setTitle(R.string.title_checkbox_preference);
+        checkboxPref.setSummary(R.string.summary_checkbox_preference);
+        inlinePrefCat.addPreference(checkboxPref);
+
+        // Switch preference
+        SwitchPreference switchPref = new SwitchPreference(this);
+        switchPref.setKey("switch_preference");
+        switchPref.setTitle(R.string.title_switch_preference);
+        switchPref.setSummary(R.string.summary_switch_preference);
+        inlinePrefCat.addPreference(switchPref);
 
         // Dialog based preferences
         PreferenceCategory dialogBasedPrefCat = new PreferenceCategory(this);
diff --git a/samples/ApiDemos/src/com/example/android/apis/telephony/NetworkDetector.java b/samples/ApiDemos/src/com/example/android/apis/telephony/NetworkDetector.java
deleted file mode 100644
index 80da6c3..0000000
--- a/samples/ApiDemos/src/com/example/android/apis/telephony/NetworkDetector.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.example.android.apis.telephony;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.TelephonyManager;
-import android.widget.TextView;
-
-// Need the following import to get access to the app resources, since this
-// class is in a sub-package.
-import com.example.android.apis.R;
-
-/**
- * Activity that uses {@link android.telephony.TelephonyManager} to obtain
- * telephony parameters like network state, phone type and SIM state.
- */
-public class NetworkDetector extends Activity {
-
-    /*
-     * SIM state constants
-     */
-    public static final String SIM_ABSENT = "Absent";
-    public static final String SIM_READY = "Ready";
-    public static final String SIM_PIN_REQUIRED = "PIN required";
-    public static final String SIM_PUK_REQUIRED = "PUK required";
-    public static final String SIM_NETWORK_LOCKED = "Network locked";
-    public static final String SIM_UNKNOWN = "Unknown";
-
-    /*
-     * Network type constants
-     */
-    public static final String NETWORK_CDMA = "CDMA: Either IS95A or IS95B (2G)";
-    public static final String NETWORK_EDGE = "EDGE (2.75G)";
-    public static final String NETWORK_GPRS = "GPRS (2.5G)";
-    public static final String NETWORK_UMTS = "UMTS (3G)";
-    public static final String NETWORK_EVDO_0 = "EVDO revision 0 (3G)";
-    public static final String NETWORK_EVDO_A = "EVDO revision A (3G - Transitional)";
-    public static final String NETWORK_EVDO_B = "EVDO revision B (3G - Transitional)";
-    public static final String NETWORK_1X_RTT = "1xRTT  (2G - Transitional)";
-    public static final String NETWORK_HSDPA = "HSDPA (3G - Transitional)";
-    public static final String NETWORK_HSUPA = "HSUPA (3G - Transitional)";
-    public static final String NETWORK_HSPA = "HSPA (3G - Transitional)";
-    public static final String NETWORK_IDEN = "iDen (2G)";
-    public static final String NETWORK_LTE = "LTE (4G)";
-    public static final String NETWORK_EHRPD = "EHRPD (3G)";
-    public static final String NETWORK_HSPAP = "HSPAP (3G)";
-    public static final String NETWORK_UNKOWN = "Unknown";
-
-    /*
-     * Phone type constants
-     */
-    public static final String PHONE_CDMA = "CDMA";
-    public static final String PHONE_GSM = "GSM";
-    public static final String PHONE_SIP = "SIP";
-    public static final String PHONE_NONE = "No radio";
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.network_detector);
-
-        // Get the telephony system service to find out network details
-        final TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
-
-        // Update text views with readable values.
-        updateViews(tm);
-
-        // Since these attributes can change, we will register a
-        // {@code PhoneStateListener} to listen for these changes and
-        // update the view.
-        tm.listen(new PhoneStateListener() {
-            @Override
-            public void onServiceStateChanged(ServiceState serviceState) {
-                // Update our TextViews
-                updateViews(tm);
-            }
-
-            @Override
-            public void onDataConnectionStateChanged(int state) {
-                // A change in data connection state may be due to availability
-                // of a different network type
-                updateViews(tm);
-            }
-
-        }, PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        final TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
-
-        // Update text views with readable values.
-        updateViews(tm);
-    }
-
-    /**
-     * Update text views with telephony attributes.
-     */
-    private final void updateViews(TelephonyManager tm) {
-
-        // The telephony system service returns integer constants for various
-        // telephony attributes.
-        TextView view = null;
-
-        view = (TextView) findViewById(R.id.sim_state);
-        view.setText("SIM State: " + mapSimStateToName(tm.getSimState()));
-
-        view = (TextView) findViewById(R.id.network_type);
-        view.setText("Network Type: " + mapNetworkTypeToName(tm.getNetworkType()));
-
-        view = (TextView) findViewById(R.id.phone_type);
-        view.setText("Phone Type: " + mapDeviceTypeToName(tm.getPhoneType()));
-
-        view = (TextView) findViewById(R.id.network_name);
-        view.setText("Network Operator: " + tm.getNetworkOperatorName());
-    }
-
-    /**
-     * Returns a string describing the current SIM state.
-     */
-    private static String mapSimStateToName(int simState) {
-        switch (simState) {
-            case TelephonyManager.SIM_STATE_ABSENT:
-                return SIM_ABSENT;
-            case TelephonyManager.SIM_STATE_READY:
-                return SIM_READY;
-            case TelephonyManager.SIM_STATE_PIN_REQUIRED:
-                return SIM_PIN_REQUIRED;
-            case TelephonyManager.SIM_STATE_PUK_REQUIRED:
-                return SIM_PUK_REQUIRED;
-            case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
-                return SIM_NETWORK_LOCKED;
-            case TelephonyManager.SIM_STATE_UNKNOWN:
-                return SIM_UNKNOWN;
-            default:
-                // shouldn't happen.
-                return null;
-        }
-    }
-
-    /**
-     * Returns a string indicating the phone radio type.
-     */
-    private static String mapDeviceTypeToName(int device) {
-
-        switch (device) {
-            case TelephonyManager.PHONE_TYPE_CDMA:
-                return PHONE_CDMA;
-            case TelephonyManager.PHONE_TYPE_GSM:
-                return PHONE_GSM;
-            case TelephonyManager.PHONE_TYPE_SIP:
-               return PHONE_SIP;
-            case TelephonyManager.PHONE_TYPE_NONE:
-                return PHONE_NONE;
-            default:
-                // shouldn't happen.
-                return null;
-        }
-    }
-
-    /**
-     * Returns a string describing the network type.
-     */
-    public static String mapNetworkTypeToName(int networkType) {
-
-        switch (networkType) {
-            case TelephonyManager.NETWORK_TYPE_CDMA:
-                return NETWORK_CDMA;
-            case TelephonyManager.NETWORK_TYPE_EDGE:
-                return NETWORK_EDGE;
-            case TelephonyManager.NETWORK_TYPE_GPRS:
-                return NETWORK_EDGE;
-            case TelephonyManager.NETWORK_TYPE_UMTS:
-                return NETWORK_UMTS;
-            case TelephonyManager.NETWORK_TYPE_EVDO_0:
-                return NETWORK_EVDO_0;
-            case TelephonyManager.NETWORK_TYPE_EVDO_A:
-                return NETWORK_EVDO_A;
-            case TelephonyManager.NETWORK_TYPE_EVDO_B:
-                return NETWORK_EVDO_B;
-            case TelephonyManager.NETWORK_TYPE_1xRTT:
-                return NETWORK_1X_RTT;
-            case TelephonyManager.NETWORK_TYPE_HSDPA:
-                return NETWORK_HSDPA;
-            case TelephonyManager.NETWORK_TYPE_HSPA:
-                return NETWORK_HSPA;
-            case TelephonyManager.NETWORK_TYPE_HSUPA:
-                return NETWORK_HSUPA;
-            case TelephonyManager.NETWORK_TYPE_IDEN:
-                return NETWORK_IDEN;
-            case TelephonyManager.NETWORK_TYPE_LTE:
-                return NETWORK_LTE;
-            case TelephonyManager.NETWORK_TYPE_EHRPD:
-                return NETWORK_EHRPD;
-            case TelephonyManager.NETWORK_TYPE_HSPAP:
-                return NETWORK_HSPAP;
-            case TelephonyManager.NETWORK_TYPE_UNKNOWN:
-            default:
-                return NETWORK_UNKOWN;
-        }
-    }
-}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/GameControllerInput.java b/samples/ApiDemos/src/com/example/android/apis/view/GameControllerInput.java
index 8aea949..fdc30e2 100644
--- a/samples/ApiDemos/src/com/example/android/apis/view/GameControllerInput.java
+++ b/samples/ApiDemos/src/com/example/android/apis/view/GameControllerInput.java
@@ -41,6 +41,7 @@
 import android.widget.Toast;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicLong;
 
 
@@ -155,7 +156,8 @@
             mDevice = device;
 
             int numAxes = 0;
-            for (MotionRange range : device.getMotionRanges()) {
+            final List<MotionRange> ranges = device.getMotionRanges();
+            for (MotionRange range : ranges) {
                 if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
                     numAxes += 1;
                 }
@@ -164,11 +166,10 @@
             mAxes = new int[numAxes];
             mAxisValues = new float[numAxes];
             int i = 0;
-            for (MotionRange range : device.getMotionRanges()) {
+            for (MotionRange range : ranges) {
                 if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
-                    numAxes += 1;
+                    mAxes[i++] = range.getAxis();
                 }
-                mAxes[i++] = range.getAxis();
             }
 
             mKeys = new SparseIntArray();
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Hover.java b/samples/ApiDemos/src/com/example/android/apis/view/Hover.java
new file mode 100644
index 0000000..9dc7bad
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/Hover.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.apis.view;
+
+import com.example.android.apis.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+
+/**
+ * Demonstrates how to use {@link View#onHoverEvent}, {@link ViewGroup#onInterceptHoverEvent},
+ * and {@link View#setOnHoverListener}.
+ *
+ * This activity displays a few buttons and text fields and entices the user
+ * to hover over them using a mouse or touch pad.  It displays feedback reporting
+ * the position of the pointing device and the label of the view being hovered.
+ *
+ * A button changes from dark green to bright yellow when hovered.
+ * This effect is achieved by using a state-list drawable to select among different
+ * background shapes and colors based on the hover state of the button.
+ *
+ * A {@link View#OnHoverEventListener} is used to listen for hover events within the
+ * container.  The container will re
+ *
+ * A checkbox is used to control whether a special view, the Interceptor, will intercept
+ * events before they are sent to its child (a button).  When the Interceptor
+ * is intercepting events, the button will not change state as the pointer hovers
+ * over it because the interceptor itself will grab the events.
+ */
+public class Hover extends Activity {
+    private TextView mMessageTextView;
+    private CheckBox mInterceptCheckBox;
+    private HoverInterceptorView mInterceptor;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.hover);
+
+        mMessageTextView = (TextView) findViewById(R.id.message);
+        mInterceptCheckBox = (CheckBox) findViewById(R.id.intercept_checkbox);
+        mInterceptor = (HoverInterceptorView) findViewById(R.id.interceptor);
+
+        View container = findViewById(R.id.container);
+        container.setOnHoverListener(new View.OnHoverListener() {
+            @Override
+            public boolean onHover(View v, MotionEvent event) {
+                switch (event.getAction()) {
+                    case MotionEvent.ACTION_HOVER_ENTER:
+                        mMessageTextView.setText(Hover.this.getResources().getString(
+                                R.string.hover_message_entered_at,
+                                event.getX(), event.getY()));
+                        break;
+                    case MotionEvent.ACTION_HOVER_MOVE:
+                        mMessageTextView.setText(Hover.this.getResources().getString(
+                                R.string.hover_message_moved_at,
+                                event.getX(), event.getY()));
+                        break;
+                    case MotionEvent.ACTION_HOVER_EXIT:
+                        mMessageTextView.setText(Hover.this.getResources().getString(
+                                R.string.hover_message_exited_at,
+                                event.getX(), event.getY()));
+                        break;
+                }
+                return false;
+            }
+        });
+
+        mInterceptCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                mInterceptor.setInterceptHover(isChecked);
+            }
+        });
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/HoverInterceptorView.java b/samples/ApiDemos/src/com/example/android/apis/view/HoverInterceptorView.java
new file mode 100644
index 0000000..f5a1319
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/HoverInterceptorView.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.apis.view;
+
+import com.example.android.apis.R;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Part of the {@link Hover} demo activity.
+ * 
+ * The Interceptor view is a simple subclass of LinearLayout whose sole purpose
+ * is to override {@link #onInterceptHoverEvent}.  When the checkbox in the
+ * hover activity is checked, the interceptor view will intercept hover events.
+ *
+ * When this view intercepts hover events, its children will not receive
+ * hover events.  This can be useful in some cases when implementing a custom
+ * view group that would like to prevent its children from being hovered
+ * under certain situations.  Usually such custom views will be much more
+ * interesting and complex than our little Interceptor example here.
+ */
+public class HoverInterceptorView extends LinearLayout {
+    private boolean mInterceptHover;
+
+    public HoverInterceptorView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public boolean onInterceptHoverEvent(MotionEvent event) {
+        if (mInterceptHover) {
+            return true;
+        }
+        return super.onInterceptHoverEvent(event);
+    }
+
+    @Override
+    public boolean onHoverEvent(MotionEvent event) {
+        TextView textView = (TextView) findViewById(R.id.intercept_message);
+        if (mInterceptHover && event.getAction() != MotionEvent.ACTION_HOVER_EXIT) {
+            textView.setText(getResources().getString(
+                    R.string.hover_intercept_message_intercepted));
+            return true;
+        }
+        textView.setText(getResources().getString(
+                R.string.hover_intercept_message_initial));
+        return super.onHoverEvent(event);
+    }
+
+    public void setInterceptHover(boolean intercept) {
+        mInterceptHover = intercept;
+    }
+}
diff --git a/samples/BrowserPlugin/jni/Android.mk b/samples/BrowserPlugin/jni/Android.mk
index b153e37..641ac63 100644
--- a/samples/BrowserPlugin/jni/Android.mk
+++ b/samples/BrowserPlugin/jni/Android.mk
@@ -41,6 +41,8 @@
 	video/VideoPlugin.cpp \
 	jni-bridge.cpp \
 
+WEBCORE_PATH := external/webkit/Source/WebCore
+
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
 	$(LOCAL_PATH) \
@@ -51,10 +53,10 @@
 	$(LOCAL_PATH)/navigation \
 	$(LOCAL_PATH)/paint \
 	$(LOCAL_PATH)/video \
-	external/webkit/WebCore/bridge \
-	external/webkit/WebCore/plugins \
-	external/webkit/WebCore/platform/android/JavaVM \
-	external/webkit/WebKit/android/plugins \
+	$(WEBCORE_PATH)/bridge \
+	$(WEBCORE_PATH)/plugins \
+	$(WEBCORE_PATH)/platform/android/JavaVM \
+	external/webkit/Source/WebKit/android/plugins \
 	external/skia/include/core
 
 LOCAL_SHARED_LIBRARIES := \
@@ -66,7 +68,7 @@
 	libskia
 
 LOCAL_CFLAGS += -fvisibility=hidden 
-LOCAL_PRELINK_MODULE:=false
+
 
 LOCAL_MODULE:= libsampleplugin
 
diff --git a/samples/RenderScript/Balls/Android.mk b/samples/RenderScript/Balls/Android.mk
index 3899752..b109584 100644
--- a/samples/RenderScript/Balls/Android.mk
+++ b/samples/RenderScript/Balls/Android.mk
@@ -14,8 +14,6 @@
 # limitations under the License.
 #
 
-ifneq ($(TARGET_SIMULATOR),true)
-
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -26,5 +24,3 @@
 LOCAL_PACKAGE_NAME := RsBalls
 
 include $(BUILD_PACKAGE)
-
-endif
diff --git a/samples/RenderScript/Balls/src/com/example/android/rs/balls/Balls.java b/samples/RenderScript/Balls/src/com/example/android/rs/balls/Balls.java
index d3b900a..2a7436a 100644
--- a/samples/RenderScript/Balls/src/com/example/android/rs/balls/Balls.java
+++ b/samples/RenderScript/Balls/src/com/example/android/rs/balls/Balls.java
@@ -26,7 +26,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.provider.Settings.System;
-import android.util.Config;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -51,7 +50,7 @@
 
     private static final String LOG_TAG = "libRS_jni";
     private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+    private static final boolean LOG_ENABLED = false;
 
     private BallsView mView;
     private SensorManager mSensorManager;
diff --git a/samples/RenderScript/Balls/src/com/example/android/rs/balls/balls.rs b/samples/RenderScript/Balls/src/com/example/android/rs/balls/balls.rs
index d86b804..f94e3e2 100644
--- a/samples/RenderScript/Balls/src/com/example/android/rs/balls/balls.rs
+++ b/samples/RenderScript/Balls/src/com/example/android/rs/balls/balls.rs
@@ -56,12 +56,12 @@
     Ball_t *bout;
 
     if (frame & 1) {
-        rsSetObject(&bc.ain, rsGetAllocation(balls2));
-        rsSetObject(&bc.aout, rsGetAllocation(balls1));
+        bc.ain = rsGetAllocation(balls2);
+        bc.aout = rsGetAllocation(balls1);
         bout = balls2;
     } else {
-        rsSetObject(&bc.ain, rsGetAllocation(balls1));
-        rsSetObject(&bc.aout, rsGetAllocation(balls2));
+        bc.ain = rsGetAllocation(balls1);
+        bc.aout = rsGetAllocation(balls2);
         bout = balls1;
     }
 
@@ -78,8 +78,6 @@
     frame++;
     rsgBindProgramFragment(gPFPoints);
     rsgDrawMesh(partMesh);
-    rsClearObject(&bc.ain);
-    rsClearObject(&bc.aout);
     return 1;
 }
 
diff --git a/samples/RenderScript/Fountain/Android.mk b/samples/RenderScript/Fountain/Android.mk
index 27994ba..ecc330c 100644
--- a/samples/RenderScript/Fountain/Android.mk
+++ b/samples/RenderScript/Fountain/Android.mk
@@ -14,8 +14,6 @@
 # limitations under the License.
 #
 
-ifneq ($(TARGET_SIMULATOR),true)
-
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -26,5 +24,3 @@
 LOCAL_PACKAGE_NAME := RsFountain
 
 include $(BUILD_PACKAGE)
-
-endif
diff --git a/samples/RenderScript/Fountain/AndroidManifest.xml b/samples/RenderScript/Fountain/AndroidManifest.xml
index 3d72552..d19b8c3 100644
--- a/samples/RenderScript/Fountain/AndroidManifest.xml
+++ b/samples/RenderScript/Fountain/AndroidManifest.xml
@@ -1,9 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.example.android.rs.fountain">
-    <uses-sdk android:minSdkVersion="11" />
+    <uses-sdk android:minSdkVersion="14" />
     <application
         android:label="RsFountain"
+        android:hardwareAccelerated="true"
         android:icon="@drawable/test_pattern">
         <activity android:name="Fountain">
             <intent-filter>
diff --git a/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/Fountain.java b/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/Fountain.java
index 53b4f26..311455a 100644
--- a/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/Fountain.java
+++ b/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/Fountain.java
@@ -26,7 +26,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.provider.Settings.System;
-import android.util.Config;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -42,7 +41,7 @@
 
     private static final String LOG_TAG = "libRS_jni";
     private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+    private static final boolean LOG_ENABLED = false;
 
     private FountainView mView;
 
diff --git a/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/FountainRS.java b/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/FountainRS.java
index eff6b89..646c807 100644
--- a/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/FountainRS.java
+++ b/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/FountainRS.java
@@ -30,7 +30,7 @@
     private Resources mRes;
     private RenderScriptGL mRS;
     private ScriptC_fountain mScript;
-    public void init(RenderScriptGL rs, Resources res, int width, int height) {
+    public void init(RenderScriptGL rs, Resources res) {
         mRS = rs;
         mRes = res;
 
diff --git a/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/FountainView.java b/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/FountainView.java
index 933b3e9..ba09421 100644
--- a/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/FountainView.java
+++ b/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/FountainView.java
@@ -20,7 +20,7 @@
 import java.util.ArrayList;
 import java.util.concurrent.Semaphore;
 
-import android.renderscript.RSSurfaceView;
+import android.renderscript.RSTextureView;
 import android.renderscript.RenderScript;
 import android.renderscript.RenderScriptGL;
 
@@ -39,7 +39,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
-public class FountainView extends RSSurfaceView {
+public class FountainView extends RSTextureView {
 
     public FountainView(Context context) {
         super(context);
@@ -49,19 +49,22 @@
     private RenderScriptGL mRS;
     private FountainRS mRender;
 
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        android.util.Log.e("rs", "onAttachedToWindow");
         if (mRS == null) {
             RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
             mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
             mRender = new FountainRS();
-            mRender.init(mRS, getResources(), w, h);
+            mRender.init(mRS, getResources());
         }
     }
 
     @Override
     protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        android.util.Log.e("rs", "onDetachedFromWindow");
         if (mRS != null) {
             mRS = null;
             destroyRenderScriptGL();
diff --git a/samples/RenderScript/HelloCompute/Android.mk b/samples/RenderScript/HelloCompute/Android.mk
index 27bc92e..e19f351 100644
--- a/samples/RenderScript/HelloCompute/Android.mk
+++ b/samples/RenderScript/HelloCompute/Android.mk
@@ -14,8 +14,6 @@
 # limitations under the License.
 #
 
-ifneq ($(TARGET_SIMULATOR),true)
-
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -27,5 +25,3 @@
 LOCAL_PACKAGE_NAME := RsHelloCompute
 
 include $(BUILD_PACKAGE)
-
-endif
diff --git a/samples/RenderScript/HelloCompute/src/com/example/android/rs/hellocompute/HelloCompute.java b/samples/RenderScript/HelloCompute/src/com/example/android/rs/hellocompute/HelloCompute.java
index a017273..0d6c47b 100644
--- a/samples/RenderScript/HelloCompute/src/com/example/android/rs/hellocompute/HelloCompute.java
+++ b/samples/RenderScript/HelloCompute/src/com/example/android/rs/hellocompute/HelloCompute.java
@@ -62,10 +62,7 @@
 
         mScript = new ScriptC_mono(mRS, getResources(), R.raw.mono);
 
-        mScript.set_gIn(mInAllocation);
-        mScript.set_gOut(mOutAllocation);
-        mScript.set_gScript(mScript);
-        mScript.invoke_filter();
+        mScript.forEach_root(mInAllocation, mOutAllocation);
         mOutAllocation.copyTo(mBitmapOut);
     }
 
diff --git a/samples/RenderScript/HelloCompute/src/com/example/android/rs/hellocompute/mono.rs b/samples/RenderScript/HelloCompute/src/com/example/android/rs/hellocompute/mono.rs
index a7c9b8b..08592f5 100644
--- a/samples/RenderScript/HelloCompute/src/com/example/android/rs/hellocompute/mono.rs
+++ b/samples/RenderScript/HelloCompute/src/com/example/android/rs/hellocompute/mono.rs
@@ -17,20 +17,12 @@
 #pragma version(1)
 #pragma rs java_package_name(com.example.android.rs.hellocompute)
 
-rs_allocation gIn;
-rs_allocation gOut;
-rs_script gScript;
-
 const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
 
-void root(const uchar4 *v_in, uchar4 *v_out, const void *usrData, uint32_t x, uint32_t y) {
+void root(const uchar4 *v_in, uchar4 *v_out) {
     float4 f4 = rsUnpackColor8888(*v_in);
 
     float3 mono = dot(f4.rgb, gMonoMult);
     *v_out = rsPackColorTo8888(mono);
 }
 
-void filter() {
-    rsForEach(gScript, gIn, gOut, 0);
-}
-
diff --git a/samples/RenderScript/HelloWorld/Android.mk b/samples/RenderScript/HelloWorld/Android.mk
index 2e194ef..48a6ffd 100644
--- a/samples/RenderScript/HelloWorld/Android.mk
+++ b/samples/RenderScript/HelloWorld/Android.mk
@@ -14,8 +14,6 @@
 # limitations under the License.
 #
 
-ifneq ($(TARGET_SIMULATOR),true)
-
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -26,5 +24,3 @@
 LOCAL_PACKAGE_NAME := RsHelloWorld
 
 include $(BUILD_PACKAGE)
-
-endif
diff --git a/samples/RenderScript/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs b/samples/RenderScript/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs
index 34e940a..bcf624e 100644
--- a/samples/RenderScript/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs
+++ b/samples/RenderScript/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs
@@ -31,7 +31,7 @@
     gTouchY = 50.0f;
 }
 
-int root(int launchID) {
+int root(void) {
 
     // Clear the background color
     rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
diff --git a/samples/RenderScript/MiscSamples/Android.mk b/samples/RenderScript/MiscSamples/Android.mk
index fcdefb7..6bab9c6 100644
--- a/samples/RenderScript/MiscSamples/Android.mk
+++ b/samples/RenderScript/MiscSamples/Android.mk
@@ -14,8 +14,6 @@
 # limitations under the License.
 #
 
-ifneq ($(TARGET_SIMULATOR),true)
-
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -26,5 +24,3 @@
 LOCAL_PACKAGE_NAME := RsMiscSamples
 
 include $(BUILD_PACKAGE)
-
-endif
diff --git a/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs b/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs
index 7b2dae2..d9d450d 100644
--- a/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs
+++ b/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs
@@ -34,7 +34,7 @@
 
 int textPos = 0;
 
-int root(int launchID) {
+int root(void) {
 
     rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
@@ -45,7 +45,7 @@
     rsgBindFont(gItalic);
 
     rs_allocation listAlloc;
-    rsSetObject(&listAlloc, rsGetAllocation(gList));
+    listAlloc = rsGetAllocation(gList);
     int allocSize = rsAllocationGetDimX(listAlloc);
 
     int width = rsgGetWidth();
diff --git a/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs b/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs
index b8ec8aa..5dabd00 100644
--- a/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs
+++ b/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs
@@ -633,7 +633,7 @@
     }
 }
 
-int root(int launchID) {
+int root(void) {
 
     gDt = rsGetDt();
 
diff --git a/samples/SampleSyncAdapter/Android.mk b/samples/SampleSyncAdapter/Android.mk
index a27a68f..0f87c17 100644
--- a/samples/SampleSyncAdapter/Android.mk
+++ b/samples/SampleSyncAdapter/Android.mk
@@ -6,10 +6,12 @@
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := Voiper
+LOCAL_PACKAGE_NAME := SampleSyncAdapter
 
 LOCAL_SDK_VERSION := current
 
+LOCAL_DX_FLAGS=--target-api=11
+
 include $(BUILD_PACKAGE)
 
 # Use the folloing include to make our test apk.
diff --git a/samples/SampleSyncAdapter/AndroidManifest.xml b/samples/SampleSyncAdapter/AndroidManifest.xml
index 202ed0e..fd53a16 100644
--- a/samples/SampleSyncAdapter/AndroidManifest.xml
+++ b/samples/SampleSyncAdapter/AndroidManifest.xml
@@ -46,7 +46,7 @@
     <uses-permission
         android:name="android.permission.WRITE_SYNC_SETTINGS" />
 
-    <uses-sdk android:minSdkVersion="5" />
+    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="11"/>
         
     <application
         android:icon="@drawable/icon"
@@ -82,11 +82,36 @@
             android:label="@string/ui_activity_title"
             android:theme="@android:style/Theme.Dialog"
             android:excludeFromRecents="true"
+            android:configChanges="orientation"
             >
             <!--
                 No intent-filter here! This activity is only ever launched by
                 someone who explicitly knows the class name
             -->
         </activity>
+
+        <activity
+            android:name=".editor.ContactEditorActivity"
+            android:theme="@style/ContactEditTheme"
+            android:windowSoftInputMode="adjustResize">
+            <intent-filter>
+                <action
+                    android:name="android.intent.action.INSERT" />
+                <data
+                    android:mimeType="vnd.android.cursor.item/contact" />
+            </intent-filter>
+
+            <!--
+                Note that the editor gets a raw contact URI, but is expected to call
+                setResult with the corresponding aggregate contact URI, not raw contact
+                URI.
+            -->
+            <intent-filter>
+                <action
+                    android:name="android.intent.action.EDIT" />
+                <data
+                    android:mimeType="vnd.android.cursor.item/raw_contact" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/samples/SampleSyncAdapter/_index.html b/samples/SampleSyncAdapter/_index.html
index 4191ba5..603083a 100644
--- a/samples/SampleSyncAdapter/_index.html
+++ b/samples/SampleSyncAdapter/_index.html
@@ -2,7 +2,8 @@
 cloud-based service and synchronize its data with data stored locally in a
 content provider. The sample uses two related parts of the Android framework
 &mdash; the account manager and the synchronization manager (through a sync
-adapter).</p>
+adapter). It also demonstrates how to provide users the ability to create
+and edit synchronized contacts using a custom editor.</p>
 
 <p> The <a
 href="../../../reference/android/accounts/AccountManager.html">account
@@ -26,7 +27,7 @@
 issues a sync operation for that sync adapter. </p>
 
 <p> The cloud-based service for this sample application is running at: </p>
-<p style="margin-left:2em;">http://samplesyncadapter.appspot.com/users</p>
+<p style="margin-left:2em;">http://samplesyncadapter2.appspot.com/</p>
 
 <p>When you install this sample application, a new syncable "SampleSyncAdapter"
 account will be added to your phone's account manager. You can go to "Settings |
diff --git a/samples/SampleSyncAdapter/res/drawable/border.xml b/samples/SampleSyncAdapter/res/drawable/border.xml
new file mode 100644
index 0000000..ab71f2c
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/drawable/border.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+  <solid android:color="@color/EditPanelBackgroundColor" />
+  <stroke android:width="2dip" android:color="@color/EditPanelBorderColor" />
+  <padding android:left="5dip" android:top="5dip" android:right="5dip" android:bottom="5dip" />
+</shape>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/drawable/done_menu_icon.png b/samples/SampleSyncAdapter/res/drawable/done_menu_icon.png
new file mode 100644
index 0000000..3468bbd
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/drawable/done_menu_icon.png
Binary files differ
diff --git a/samples/SampleSyncAdapter/res/layout-xlarge/editor.xml b/samples/SampleSyncAdapter/res/layout-xlarge/editor.xml
new file mode 100644
index 0000000..3b7d97b
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/layout-xlarge/editor.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:gravity="center_horizontal">
+    <LinearLayout
+      xmlns:android="http://schemas.android.com/apk/res/android"
+      android:layout_width="600dip"
+      android:layout_height="match_parent"
+      android:orientation="vertical"
+      android:background="@drawable/border">
+      <include layout="@layout/editor_header" />
+      <ScrollView
+          android:layout_width="match_parent"
+          android:layout_height="0dip"
+          android:paddingTop="20dip"
+          android:paddingRight="20dip"
+          android:paddingBottom="20dip"
+          android:paddingLeft="20dip"
+          android:layout_weight="1">
+          <include layout="@layout/editor_fields" />
+      </ScrollView>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/layout-xlarge/editor_header.xml b/samples/SampleSyncAdapter/res/layout-xlarge/editor_header.xml
new file mode 100644
index 0000000..648e6f9
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/layout-xlarge/editor_header.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+
+<!-- Account info header -->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="64dip"
+    android:layout_width="match_parent"
+    android:background="?android:attr/selectableItemBackground">
+
+    <ImageView
+        android:id="@+id/header_account_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="7dip"
+        android:layout_marginRight="7dip"
+        android:layout_centerVertical="true"
+        android:layout_alignParentRight="true"
+        android:src="@drawable/icon" />
+
+    <TextView
+        android:id="@+id/header_account_type"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toLeftOf="@+id/header_account_icon"
+        android:layout_alignTop="@id/header_account_icon"
+        android:layout_marginTop="-4dip"
+        android:textSize="24sp"
+        android:textColor="?android:attr/textColorPrimary"
+        android:singleLine="true"
+        android:text="@string/header_account_type" />
+
+    <TextView
+        android:id="@+id/header_account_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toLeftOf="@+id/header_account_icon"
+        android:layout_alignBottom="@+id/header_account_icon"
+        android:layout_marginBottom="2dip"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="?android:attr/textColorPrimary"
+        android:singleLine="true" />
+
+</RelativeLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/editor.xml b/samples/SampleSyncAdapter/res/layout/editor.xml
new file mode 100644
index 0000000..a0c36d2
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/layout/editor.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:paddingTop="20dip"
+        android:paddingRight="20dip"
+        android:paddingBottom="20dip"
+        android:paddingLeft="20dip"
+        android:layout_weight="1">
+        <include layout="@layout/editor_fields" />
+    </ScrollView>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/layout/editor_fields.xml b/samples/SampleSyncAdapter/res/layout/editor_fields.xml
new file mode 100644
index 0000000..31d0128
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/layout/editor_fields.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="fill_parent"
+  android:layout_height="fill_parent"
+  android:stretchColumns="2">
+
+  <TableRow>
+    <TextView
+      android:layout_column="1"
+      android:textStyle="bold"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text="@string/label_name"
+      android:padding="3dip" />
+    <EditText
+      android:layout_column="2"
+      android:id="@+id/editor_name"
+      android:singleLine="true"
+      android:inputType="textPersonName"
+      android:layout_width="fill_parent"
+      android:layout_height="wrap_content"
+      android:minWidth="250dip"
+      android:scrollHorizontally="true"
+      android:capitalize="none"
+      android:textSize="@dimen/contact_name_text_size"
+      android:gravity="fill_horizontal"
+      android:autoText="false" />
+  </TableRow>
+  <TableRow>
+    <TextView
+      android:layout_column="1"
+      android:textStyle="bold"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text="@string/label_phone_home"
+      android:padding="3dip" />
+    <EditText
+      android:id="@+id/editor_phone_home"
+      android:singleLine="true"
+      android:inputType="phone"
+      android:layout_width="fill_parent"
+      android:layout_height="wrap_content"
+      android:minWidth="250dip"
+      android:scrollHorizontally="true"
+      android:capitalize="none"
+      android:gravity="fill_horizontal"
+      android:autoText="false" />
+  </TableRow>
+  <TableRow>
+    <TextView
+      android:layout_column="1"
+      android:textStyle="bold"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text="@string/label_phone_mobile"
+      android:padding="3dip" />
+    <EditText
+      android:id="@+id/editor_phone_mobile"
+      android:singleLine="true"
+      android:inputType="phone"
+      android:layout_width="fill_parent"
+      android:layout_height="wrap_content"
+      android:minWidth="250dip"
+      android:scrollHorizontally="true"
+      android:capitalize="none"
+      android:gravity="fill_horizontal"
+      android:autoText="false" />
+  </TableRow>
+  <TableRow>
+    <TextView
+      android:layout_column="1"
+      android:textStyle="bold"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text="@string/label_phone_work"
+      android:padding="3dip" />
+    <EditText
+      android:id="@+id/editor_phone_work"
+      android:singleLine="true"
+      android:phoneNumber="true"
+      android:autoText="true"
+      android:layout_width="fill_parent"
+      android:layout_height="wrap_content"
+      android:minWidth="250dip"
+      android:scrollHorizontally="true"
+      android:capitalize="none"
+      android:gravity="fill_horizontal" />
+  </TableRow>
+  <TableRow>
+    <TextView
+      android:layout_column="1"
+      android:textStyle="bold"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text="@string/label_email"
+      android:padding="3dip" />
+    <EditText
+      android:id="@+id/editor_email"
+      android:singleLine="true"
+      android:inputType="textEmailAddress"
+      android:layout_width="fill_parent"
+      android:layout_height="wrap_content"
+      android:minWidth="250dip"
+      android:scrollHorizontally="true"
+      android:capitalize="none"
+      android:gravity="fill_horizontal"
+      android:autoText="false" />
+  </TableRow>
+</TableLayout>
diff --git a/samples/SampleSyncAdapter/res/menu/edit.xml b/samples/SampleSyncAdapter/res/menu/edit.xml
new file mode 100644
index 0000000..1227584
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/menu/edit.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/menu_done"
+        android:alphabeticShortcut="\n"
+        android:icon="@drawable/done_menu_icon"
+        android:title="@string/menu_done"
+        android:showAsAction="always|withText" />
+
+    <item
+        android:id="@+id/menu_cancel"
+        android:alphabeticShortcut="q"
+        android:title="@string/menu_cancel"
+        android:showAsAction="always|withText" />
+</menu>
diff --git a/simulator/app/executablepath.h b/samples/SampleSyncAdapter/res/values-xlarge/dimens.xml
similarity index 60%
copy from simulator/app/executablepath.h
copy to samples/SampleSyncAdapter/res/values-xlarge/dimens.xml
index 889982d..f9d74a7 100644
--- a/simulator/app/executablepath.h
+++ b/samples/SampleSyncAdapter/res/values-xlarge/dimens.xml
@@ -1,11 +1,13 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,16 +15,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+-->
+<resources>
 
-#ifndef _SIM_EXECUTABLEPATH_H
-#define _SIM_EXECUTABLEPATH_H
+    <!-- Font size used for the contact name in the editor -->
+    <dimen name="contact_name_text_size">26sp</dimen>
 
-#include <limits.h>
-
-// returns the path to this executable
-#if __cplusplus
-extern "C"
-#endif
-void executablepath(char s[PATH_MAX]);
-
-#endif // _SIM_EXECUTABLEPATH_H
+</resources>
diff --git a/simulator/app/executablepath.h b/samples/SampleSyncAdapter/res/values/dimens.xml
similarity index 60%
rename from simulator/app/executablepath.h
rename to samples/SampleSyncAdapter/res/values/dimens.xml
index 889982d..7518c07 100644
--- a/simulator/app/executablepath.h
+++ b/samples/SampleSyncAdapter/res/values/dimens.xml
@@ -1,11 +1,13 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,16 +15,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+-->
 
-#ifndef _SIM_EXECUTABLEPATH_H
-#define _SIM_EXECUTABLEPATH_H
+<resources>
 
-#include <limits.h>
+    <!-- Font size used for the contact name in the editor -->
+    <dimen name="contact_name_text_size">18sp</dimen>
 
-// returns the path to this executable
-#if __cplusplus
-extern "C"
-#endif
-void executablepath(char s[PATH_MAX]);
-
-#endif // _SIM_EXECUTABLEPATH_H
+</resources>
diff --git a/samples/SampleSyncAdapter/res/values/strings.xml b/samples/SampleSyncAdapter/res/values/strings.xml
index 8139d65..3b5ac58 100644
--- a/samples/SampleSyncAdapter/res/values/strings.xml
+++ b/samples/SampleSyncAdapter/res/values/strings.xml
@@ -20,7 +20,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Label for this package -->
     <string
-        name="label">SamplesyncAdapter</string>
+        name="label">Sample SyncAdapter</string>
 
     <!-- Permission label -->
     <string
@@ -90,4 +90,16 @@
         name="profile_action">Sample profile</string>
     <string
         name="view_profile">View Profile</string>
+
+    <string name="header_account_type">SampleSync contact</string>
+
+    <string name="label_name">Name</string>
+    <string name="label_phone_home">Home Phone</string>
+    <string name="label_phone_mobile">Mobile Phone</string>
+    <string name="label_phone_work">Work Phone</string>
+    <string name="label_email">Email</string>
+    <string
+        name="menu_done">Done</string>
+    <string
+        name="menu_cancel">Cancel</string>
 </resources>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/values/styles.xml b/samples/SampleSyncAdapter/res/values/styles.xml
new file mode 100644
index 0000000..074613e
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/values/styles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!--
+        These styles will only be used in Honeycomb and later because
+        Android doesn't support third-party contact editing in pre-
+        Honeycomb versions.
+    -->
+    <color name="EditPanelBackgroundColor">#ffffff</color>
+    <color name="EditPanelBorderColor">#cccccc</color>
+    <style name="ContactEditTheme" parent="android:Theme.Holo.Light">
+    </style>
+</resources>
diff --git a/samples/SampleSyncAdapter/res/xml-v11/contacts.xml b/samples/SampleSyncAdapter/res/xml-v11/contacts.xml
new file mode 100644
index 0000000..62dfa80
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/xml-v11/contacts.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<ContactsAccountType
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    editContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
+    createContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
+>
+
+    <ContactsDataKind
+        android:mimeType="vnd.android.cursor.item/vnd.samplesyncadapter.profile"
+        android:icon="@drawable/icon"
+        android:summaryColumn="data2"
+        android:detailColumn="data3"
+        android:detailSocialSummary="true" />
+
+</ContactsAccountType>
diff --git a/samples/SampleSyncAdapter/res/xml-v11/syncadapter.xml b/samples/SampleSyncAdapter/res/xml-v11/syncadapter.xml
new file mode 100644
index 0000000..dac8ade
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/xml-v11/syncadapter.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 attributes in this XML file provide configuration information
+  for the SampleSyncAdapter.
+
+  See xml/syncadapter.xml for greater details, but this version of
+  the file specifies that uploading (and thus editing) is supported.
+-->
+
+<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+    android:contentAuthority="com.android.contacts"
+    android:accountType="com.example.android.samplesync"
+    android:supportsUploading="true"
+    android:userVisible="true"
+/>
diff --git a/samples/SampleSyncAdapter/res/xml/contacts.xml b/samples/SampleSyncAdapter/res/xml/contacts.xml
index 1ff9c05..b46257d 100644
--- a/samples/SampleSyncAdapter/res/xml/contacts.xml
+++ b/samples/SampleSyncAdapter/res/xml/contacts.xml
@@ -17,7 +17,11 @@
  */
 -->
 
-<ContactsSource xmlns:android="http://schemas.android.com/apk/res/android">
+<ContactsSource
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    editContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
+    createContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
+>
 
     <ContactsDataKind
         android:mimeType="vnd.android.cursor.item/vnd.samplesyncadapter.profile"
diff --git a/samples/SampleSyncAdapter/res/xml/syncadapter.xml b/samples/SampleSyncAdapter/res/xml/syncadapter.xml
index 1f75947..3053a24 100644
--- a/samples/SampleSyncAdapter/res/xml/syncadapter.xml
+++ b/samples/SampleSyncAdapter/res/xml/syncadapter.xml
@@ -17,11 +17,21 @@
  */
 -->
 
-<!-- The attributes in this XML file provide configuration information -->
-<!-- for the SyncAdapter. -->
+<!--
+  The attributes in this XML file provide configuration information
+  for the SampleSyncAdapter.
+
+  We have two versions of this file - one here, and one in the
+  xml-v11 directory (Honeycomb and beyond). This one specifies that
+  the syncadapter does not support uploading (and thus the contacts
+  associated with this syncadapter are not editable).  The SDK 11
+  version of the file specifies that the adapter DOES support
+  uploading, so the contacts on SDK 11 and greater are editable.
+-->
 
 <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
     android:contentAuthority="com.android.contacts"
     android:accountType="com.example.android.samplesync"
     android:supportsUploading="false"
+    android:userVisible="true"
 />
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/app.yaml b/samples/SampleSyncAdapter/samplesyncadapter_server/app.yaml
index 109eff3..8526177 100644
--- a/samples/SampleSyncAdapter/samplesyncadapter_server/app.yaml
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/app.yaml
@@ -1,44 +1,59 @@
-application: samplesyncadapter
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+application: samplesyncadapter2
 version: 1
 runtime: python
 api_version: 1
 
 handlers:
+
+#
+# Define a handler for our static files (css, images, etc)
+#
+- url: /static
+  static_dir: static
+
+#
+# Route all "web services" requests to the main.py file
+#
 - url: /auth
-  script: main.py
+  script: web_services.py
 
-- url: /login
-  script: main.py
+- url: /sync
+  script: web_services.py
 
-- url: /fetch_friend_updates
-  script: main.py
-
-- url: /fetch_status
-  script: main.py
-
-- url: /add_user
+- url: /reset_database
+  script: web_services.py
+  
+#
+# Route all page requests to the dashboard.py file
+#
+- url: /
   script: dashboard.py
 
-- url: /edit_user
+- url: /add_contact
   script: dashboard.py
 
-- url: /users
+- url: /edit_contact
   script: dashboard.py
 
-- url: /delete_friend
+- url: /delete_contact
   script: dashboard.py
 
-- url: /edit_user
+- url: /avatar
   script: dashboard.py
 
-- url: /add_credentials
-  script: dashboard.py
-
-- url: /user_credentials
-  script: dashboard.py
-
-- url: /add_friend
-  script: dashboard.py
-
-- url: /user_friends
+- url: /edit_avatar
   script: dashboard.py
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/cron.yaml b/samples/SampleSyncAdapter/samplesyncadapter_server/cron.yaml
new file mode 100644
index 0000000..1a0badb
--- /dev/null
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/cron.yaml
@@ -0,0 +1,24 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+cron:
+#
+# Create a weekly cron job that cleans up the SampleSyncAdapter server database.
+# We remove all existing contacts from the db, and create three initial
+# contacts: Romeo, Juliet, and Tybalt.
+#
+- description: weekly cleanup job
+  url: /reset_database
+  schedule: every sunday 00:00
+  timezone: America/Los_Angeles
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/dashboard.py b/samples/SampleSyncAdapter/samplesyncadapter_server/dashboard.py
index c986f7e..b9bac5e 100644
--- a/samples/SampleSyncAdapter/samplesyncadapter_server/dashboard.py
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/dashboard.py
@@ -1,21 +1,23 @@
 #!/usr/bin/python2.5
 
 # Copyright (C) 2010 The Android Open Source Project
-# 
+#
 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
 # use this file except in compliance with the License. You may obtain a copy of
 # the License at
-# 
+#
 # http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 # License for the specific language governing permissions and limitations under
 # the License.
 
-"""Defines Django forms for inserting/updating/viewing data
-   to/from SampleSyncAdapter datastore."""
+"""
+Defines Django forms for inserting/updating/viewing contact data
+to/from SampleSyncAdapter datastore.
+"""
 
 import cgi
 import datetime
@@ -26,248 +28,181 @@
 from google.appengine.ext.webapp import template
 from google.appengine.ext.db import djangoforms
 from model import datastore
+from google.appengine.api import images
 
 import wsgiref.handlers
 
+class BaseRequestHandler(webapp.RequestHandler):
+    """
+    Base class for our page-based request handlers that contains
+    some helper functions we use in most pages.
+    """
 
-class UserForm(djangoforms.ModelForm):
-  """Represents django form for entering user info."""
+    """
+    Return a form (potentially partially filled-in) to
+    the user.
+    """
+    def send_form(self, title, action, contactId, handle, content_obj):
+        if (contactId >= 0):
+            idInfo = '<input type="hidden" name="_id" value="%s">'
+        else:
+            idInfo = ''
 
-  class Meta:
-    model = datastore.User
+        template_values = {
+                'title': title,
+                'header': title,
+                'action': action,
+                'contactId': contactId,
+                'handle': handle,
+                'has_contactId': (contactId >= 0),
+                'has_handle': (handle != None),
+                'form_data_rows': str(content_obj)
+                }
+
+        path = os.path.join(os.path.dirname(__file__), 'templates', 'simple_form.html')
+        self.response.out.write(template.render(path, template_values))
+
+class ContactForm(djangoforms.ModelForm):
+    """Represents django form for entering contact info."""
+
+    class Meta:
+        model = datastore.Contact
 
 
-class UserInsertPage(webapp.RequestHandler):
-  """Inserts new users. GET presents a blank form. POST processes it."""
+class ContactInsertPage(BaseRequestHandler):
+    """
+    Processes requests to add a new contact. GET presents an empty
+    contact form for the user to fill in.  POST saves the new contact
+    with the POSTed information.
+    """
 
-  def get(self):
-    self.response.out.write('<html><body>'
-                            '<form method="POST" '
-                            'action="/add_user">'
-                            '<table>')
-    # This generates our shopping list form and writes it in the response
-    self.response.out.write(UserForm())
-    self.response.out.write('</table>'
-                            '<input type="submit">'
-                            '</form></body></html>')
+    def get(self):
+        self.send_form('Add Contact', '/add_contact', -1, None, ContactForm())
 
-  def post(self):
-    data = UserForm(data=self.request.POST)
-    if data.is_valid():
-      # Save the data, and redirect to the view page
-      entity = data.save(commit=False)
-      entity.put()
-      self.redirect('/users')
-    else:
-      # Reprint the form
-      self.response.out.write('<html><body>'
-                              '<form method="POST" '
-                              'action="/">'
-                              '<table>')
-      self.response.out.write(data)
-      self.response.out.write('</table>'
-                              '<input type="submit">'
-                              '</form></body></html>')
+    def post(self):
+        data = ContactForm(data=self.request.POST)
+        if data.is_valid():
+            # Save the data, and redirect to the view page
+            entity = data.save(commit=False)
+            entity.put()
+            self.redirect('/')
+        else:
+            # Reprint the form
+            self.send_form('Add Contact', '/add_contact', -1, None, data)
 
 
-class UserEditPage(webapp.RequestHandler):
-  """Edits users. GET presents a form prefilled with user info
-     from datastore. POST processes it."""
+class ContactEditPage(BaseRequestHandler):
+    """
+    Process requests to edit a contact's information.  GET presents a form
+    with the current contact information filled in. POST saves new information
+    into the contact record.
+    """
 
-  def get(self):
-    id = int(self.request.get('user'))
-    user = datastore.User.get(db.Key.from_path('User', id))
-    self.response.out.write('<html><body>'
-                            '<form method="POST" '
-                            'action="/edit_user">'
-                            '<table>')
-    # This generates our shopping list form and writes it in the response
-    self.response.out.write(UserForm(instance=user))
-    self.response.out.write('</table>'
-                            '<input type="hidden" name="_id" value="%s">'
-                            '<input type="submit">'
-                            '</form></body></html>' % id)
+    def get(self):
+        id = int(self.request.get('id'))
+        contact = datastore.Contact.get(db.Key.from_path('Contact', id))
+        self.send_form('Edit Contact', '/edit_contact', id, contact.handle, 
+                       ContactForm(instance=contact))
 
-  def post(self):
-    id = int(self.request.get('_id'))
-    user = datastore.User.get(db.Key.from_path('User', id))
-    data = UserForm(data=self.request.POST, instance=user)
-    if data.is_valid():
-      # Save the data, and redirect to the view page
-      entity = data.save(commit=False)
-      entity.updated = datetime.datetime.utcnow()
-      entity.put()
-      self.redirect('/users')
-    else:
-      # Reprint the form
-      self.response.out.write('<html><body>'
-                              '<form method="POST" '
-                              'action="/edit_user">'
-                              '<table>')
-      self.response.out.write(data)
-      self.response.out.write('</table>'
-                              '<input type="hidden" name="_id" value="%s">'
-                              '<input type="submit">'
-                              '</form></body></html>' % id)
+    def post(self):
+        id = int(self.request.get('id'))
+        contact = datastore.Contact.get(db.Key.from_path('Contact', id))
+        data = ContactForm(data=self.request.POST, instance=contact)
+        if data.is_valid():
+            # Save the data, and redirect to the view page
+            entity = data.save(commit=False)
+            entity.updated = datetime.datetime.utcnow()
+            entity.put()
+            self.redirect('/')
+        else:
+            # Reprint the form
+            self.send_form('Edit Contact', '/edit_contact', id, contact.handle, data)
 
+class ContactDeletePage(BaseRequestHandler):
+    """Processes delete contact request."""
 
-class UsersListPage(webapp.RequestHandler):
-  """Lists all Users. In addition displays links for editing user info,
-     viewing user's friends and adding new users."""
+    def get(self):
+        id = int(self.request.get('id'))
+        contact = datastore.Contact.get(db.Key.from_path('Contact', id))
+        contact.deleted = True
+        contact.updated = datetime.datetime.utcnow()
+        contact.put()
 
-  def get(self):
-    users = datastore.User.all()
-    template_values = {
-        'users': users
-        }
+        self.redirect('/')
 
-    path = os.path.join(os.path.dirname(__file__), 'templates', 'users.html')
-    self.response.out.write(template.render(path, template_values))
+class AvatarEditPage(webapp.RequestHandler):
+    """
+    Processes requests to edit contact's avatar. GET is used to fetch
+    a page that displays the contact's current avatar and allows the user 
+    to specify a file containing a new avatar image.  POST is used to
+    submit the form which will change the contact's avatar.
+    """
 
+    def get(self):
+        id = int(self.request.get('id'))
+        contact = datastore.Contact.get(db.Key.from_path('Contact', id))
+        template_values = {
+                'avatar': contact.avatar,
+                'contactId': id
+                }
+        
+        path = os.path.join(os.path.dirname(__file__), 'templates', 'edit_avatar.html')
+        self.response.out.write(template.render(path, template_values))
 
-class UserCredentialsForm(djangoforms.ModelForm):
-  """Represents django form for entering user's credentials."""
+    def post(self):
+        id = int(self.request.get('id'))
+        contact = datastore.Contact.get(db.Key.from_path('Contact', id))
+        #avatar = images.resize(self.request.get("avatar"), 128, 128)
+        avatar = self.request.get("avatar")
+        contact.avatar = db.Blob(avatar)
+        contact.updated = datetime.datetime.utcnow()
+        contact.put()
+        self.redirect('/')
 
-  class Meta:
-    model = datastore.UserCredentials
+class AvatarViewPage(BaseRequestHandler):
+    """
+    Processes request to view contact's avatar. This is different from
+    the GET AvatarEditPage request in that this doesn't return a page -
+    it just returns the raw image itself.
+    """
 
+    def get(self):
+        id = int(self.request.get('id'))
+        contact = datastore.Contact.get(db.Key.from_path('Contact', id))
+        if (contact.avatar):
+            self.response.headers['Content-Type'] = "image/png"
+            self.response.out.write(contact.avatar)
+        else:
+            self.redirect(self.request.host_url + '/static/img/default_avatar.gif')
 
-class UserCredentialsInsertPage(webapp.RequestHandler):
-  """Inserts user credentials. GET shows a blank form, POST processes it."""
+class ContactsListPage(webapp.RequestHandler):
+    """
+    Display a page that lists all the contacts associated with
+    the specifies user account.
+    """
 
-  def get(self):
-    self.response.out.write('<html><body>'
-                            '<form method="POST" '
-                            'action="/add_credentials">'
-                            '<table>')
-    # This generates our shopping list form and writes it in the response
-    self.response.out.write(UserCredentialsForm())
-    self.response.out.write('</table>'
-                            '<input type="submit">'
-                            '</form></body></html>')
+    def get(self):
+        contacts = datastore.Contact.all()
+        template_values = {
+                'contacts': contacts,
+                'username': 'user'
+                }
 
-  def post(self):
-    data = UserCredentialsForm(data=self.request.POST)
-    if data.is_valid():
-      # Save the data, and redirect to the view page
-      entity = data.save(commit=False)
-      entity.put()
-      self.redirect('/users')
-    else:
-      # Reprint the form
-      self.response.out.write('<html><body>'
-                              '<form method="POST" '
-                              'action="/add_credentials">'
-                              '<table>')
-      self.response.out.write(data)
-      self.response.out.write('</table>'
-                              '<input type="submit">'
-                              '</form></body></html>')
-
-
-class UserFriendsForm(djangoforms.ModelForm):
-  """Represents django form for entering user's friends."""
-
-  class Meta:
-    model = datastore.UserFriends
-    exclude = ['deleted', 'username']
-
-
-class UserFriendsInsertPage(webapp.RequestHandler):
-  """Inserts user's new friends. GET shows a blank form, POST processes it."""
-
-  def get(self):
-    user = self.request.get('user')
-    self.response.out.write('<html><body>'
-                            '<form method="POST" '
-                            'action="/add_friend">'
-                            '<table>')
-    # This generates our shopping list form and writes it in the response
-    self.response.out.write(UserFriendsForm())
-    self.response.out.write('</table>'
-                            '<input type = hidden name = "user" value = "%s">'
-                            '<input type="submit">'
-                            '</form></body></html>' % user)
-
-  def post(self):
-    data = UserFriendsForm(data=self.request.POST)
-    if data.is_valid():
-      user = self.request.get('user')
-      # Save the data, and redirect to the view page
-      entity = data.save(commit=False)
-      entity.username = user
-      query = datastore.UserFriends.all()
-      query.filter('username = ', user)
-      query.filter('friend_handle = ', entity.friend_handle)
-      result = query.get()
-      if result:
-	result.deleted = False
-	result.updated = datetime.datetime.utcnow()
-	result.put()
-      else:
-        entity.deleted = False
-        entity.put()
-      self.redirect('/user_friends?user=' + user)
-    else:
-      # Reprint the form
-      self.response.out.write('<html><body>'
-                              '<form method="POST" '
-                              'action="/add_friend">'
-                              '<table>')
-      self.response.out.write(data)
-      self.response.out.write('</table>'
-                              '<input type="submit">'
-                              '</form></body></html>')
-
-
-class UserFriendsListPage(webapp.RequestHandler):
-  """Lists all friends for a user. In addition displays links for removing
-     friends and adding new friends."""
-
-  def get(self):
-    user = self.request.get('user')
-    query = datastore.UserFriends.all()
-    query.filter('deleted = ', False)
-    query.filter('username = ', user)
-    friends = query.fetch(50)
-    template_values = {
-        'friends': friends,
-        'user': user
-        }
-    path = os.path.join(os.path.dirname(__file__),
-                        'templates', 'view_friends.html')
-    self.response.out.write(template.render(path, template_values))
-
-
-class DeleteFriendPage(webapp.RequestHandler):
-  """Processes delete friend request."""
-
-  def get(self):
-    user = self.request.get('user')
-    friend = self.request.get('friend')
-    query = datastore.UserFriends.all()
-    query.filter('username =', user)
-    query.filter('friend_handle =', friend)
-    result = query.get()
-    result.deleted = True
-    result.updated = datetime.datetime.utcnow()
-    result.put()
-
-    self.redirect('/user_friends?user=' + user)
+        path = os.path.join(os.path.dirname(__file__), 'templates', 'contacts.html')
+        self.response.out.write(template.render(path, template_values))
 
 
 def main():
-  application = webapp.WSGIApplication(
-      [('/add_user', UserInsertPage),
-       ('/users', UsersListPage),
-       ('/add_credentials', UserCredentialsInsertPage),
-       ('/add_friend', UserFriendsInsertPage),
-       ('/user_friends', UserFriendsListPage),
-       ('/delete_friend', DeleteFriendPage),
-       ('/edit_user', UserEditPage)
-      ],
-      debug=True)
-  wsgiref.handlers.CGIHandler().run(application)
+    application = webapp.WSGIApplication(
+        [('/', ContactsListPage),
+         ('/add_contact', ContactInsertPage),
+         ('/edit_contact', ContactEditPage),
+         ('/delete_contact', ContactDeletePage),
+         ('/avatar', AvatarViewPage),
+         ('/edit_avatar', AvatarEditPage)
+        ],
+        debug=True)
+    wsgiref.handlers.CGIHandler().run(application)
 
 if __name__ == '__main__':
   main()
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/index.yaml b/samples/SampleSyncAdapter/samplesyncadapter_server/index.yaml
index 83ceea0..6f02db5 100644
--- a/samples/SampleSyncAdapter/samplesyncadapter_server/index.yaml
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/index.yaml
@@ -1,14 +1,15 @@
-indexes:
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 index.yaml is automatically updated whenever the dev_appserver
-# detects that a new type of query is run.  If you want to manage the
-# index.yaml file manually, remove the above marker line (the line
-# saying "# AUTOGENERATED").  If you want to manage some indexes
-# manually, move them above the marker line.  The index.yaml file is
-# automatically uploaded to the admin console when you next deploy
-# your application using appcfg.py.
-
-- kind: UserFriends
-  properties:
-  - name: username
-  - name: updated
\ No newline at end of file
+# AUTOGENERATED
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/main.py b/samples/SampleSyncAdapter/samplesyncadapter_server/main.py
deleted file mode 100644
index 2d7c5c7..0000000
--- a/samples/SampleSyncAdapter/samplesyncadapter_server/main.py
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/python2.5
-
-# Copyright (C) 2010 The Android Open Source Project
-# 
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not
-# use this file except in compliance with the License. You may obtain a copy of
-# the License at
-# 
-# http://www.apache.org/licenses/LICENSE-2.0
-# 
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations under
-# the License.
-
-"""Handlers for Sample SyncAdapter services.
-
-Contains several RequestHandler subclasses used to handle post operations.
-This script is designed to be run directly as a WSGI application.
-
-  Authenticate: Handles user requests for authentication.
-  FetchFriends: Handles user requests for friend list.
-  FriendData: Stores information about user's friends.
-"""
-
-import cgi
-from datetime import datetime
-from django.utils import simplejson
-from google.appengine.api import users
-from google.appengine.ext import db
-from google.appengine.ext import webapp
-from model import datastore
-import wsgiref.handlers
-
-
-class Authenticate(webapp.RequestHandler):
-  """Handles requests for login and authentication.
-
-  UpdateHandler only accepts post events. It expects each
-  request to include username and password fields. It returns authtoken
-  after successful authentication and "invalid credentials" error otherwise.
-  """
-
-  def post(self):
-    self.username = self.request.get('username')
-    self.password = self.request.get('password')
-    password = datastore.UserCredentials.get(self.username)
-    if password == self.password:
-      self.response.set_status(200, 'OK')
-      # return the password as AuthToken
-      self.response.out.write(password)
-    else:
-      self.response.set_status(401, 'Invalid Credentials')
-
-
-class FetchFriends(webapp.RequestHandler):
-  """Handles requests for fetching user's friendlist.
-
-  UpdateHandler only accepts post events. It expects each
-  request to include username and authtoken. If the authtoken is valid
-  it returns user's friend info in JSON format.It uses helper
-  class FriendData to fetch user's friendlist.
-  """
-
-  def post(self):
-    self.username = self.request.get('username')
-    self.password = self.request.get('password')
-    self.timestamp = None
-    timestamp = self.request.get('timestamp')
-    if timestamp:
-      self.timestamp = datetime.strptime(timestamp, '%Y/%m/%d %H:%M')
-    password = datastore.UserCredentials.get(self.username)
-    if password == self.password:
-      self.friend_list = []
-      friends = datastore.UserFriends.get_friends(self.username)
-      if friends:
-        for friend in friends:
-          friend_handle = getattr(friend, 'friend_handle')
-
-          if self.timestamp is None or getattr(friend, 'updated') > self.timestamp:
-            if (getattr(friend, 'deleted')) == True:
-              friend = {}
-              friend['u'] = friend_handle
-              friend['d'] = 'true'
-              friend['i'] = str(datastore.User.get_user_id(friend_handle))
-              self.friend_list.append(friend)
-            else:
-              FriendsData(self.friend_list, friend_handle)
-          else:
-            if datastore.User.get_user_last_updated(friend_handle) > self.timestamp:
-              FriendsData(self.friend_list, friend_handle)
-      self.response.set_status(200)
-      self.response.out.write(toJSON(self.friend_list))
-    else:
-      self.response.set_status(401, 'Invalid Credentials')
-
-class FetchStatus(webapp.RequestHandler):
-  """Handles requests fetching friend statuses.
-
-  UpdateHandler only accepts post events. It expects each
-  request to include username and authtoken. If the authtoken is valid
-  it returns status info in JSON format.
-  """
-
-  def post(self):
-    self.username = self.request.get('username')
-    self.password = self.request.get('password')
-    password = datastore.UserCredentials.get(self.username)
-    if password == self.password:
-      self.status_list = []
-      friends = datastore.UserFriends.get_friends(self.username)
-      if friends:
-        for friend in friends:
-          friend_handle = getattr(friend, 'friend_handle')
-          status_text = datastore.User.get_user_status(friend_handle)
-	  user_id = datastore.User.get_user_id(friend_handle)
-          status = {}
-          status['i'] = str(user_id)
-          status['s'] = status_text
-          self.status_list.append(status)
-      self.response.set_status(200)
-      self.response.out.write(toJSON(self.status_list))
-    else:
-      self.response.set_status(401, 'Invalid Credentials')
-
-  def toJSON(self):
-    """Dumps the data represented by the object to JSON for wire transfer."""
-    return simplejson.dumps(self.friend_list)
-
-
-def toJSON(object):
-  """Dumps the data represented by the object to JSON for wire transfer."""
-  return simplejson.dumps(object)
-
-class FriendsData(object):
-  """Holds data for user's friends.
-
-  This class knows how to serialize itself to JSON.
-  """
-  __FIELD_MAP = {
-      'handle': 'u',
-      'firstname': 'f',
-      'lastname': 'l',
-      'status': 's',
-      'phone_home': 'h',
-      'phone_office': 'o',
-      'phone_mobile': 'm',
-      'email': 'e',
-  }
-
-  def __init__(self, friend_list, username):
-    obj = datastore.User.get_user_info(username)
-    friend = {}
-    for obj_name, json_name in self.__FIELD_MAP.items():
-      if hasattr(obj, obj_name):
-        friend[json_name] = str(getattr(obj, obj_name))
-        friend['i'] = str(obj.key().id())
-    friend_list.append(friend)
-
-
-def main():
-  application = webapp.WSGIApplication(
-      [('/auth', Authenticate),
-       ('/login', Authenticate),
-       ('/fetch_friend_updates', FetchFriends),
-       ('/fetch_status', FetchStatus),
-      ],
-      debug=True)
-  wsgiref.handlers.CGIHandler().run(application)
-
-if __name__ == "__main__":
-  main()
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/model/datastore.py b/samples/SampleSyncAdapter/samplesyncadapter_server/model/datastore.py
index 71bd18a..1f91633 100644
--- a/samples/SampleSyncAdapter/samplesyncadapter_server/model/datastore.py
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/model/datastore.py
@@ -14,80 +14,51 @@
 # License for the specific language governing permissions and limitations under
 # the License.
 
-"""Represents user's contact information, friends and credentials."""
+"""Represents user's contact information"""
 
 from google.appengine.ext import db
 
 
-class User(db.Model):
+class Contact(db.Model):
   """Data model class to hold user objects."""
 
   handle = db.StringProperty(required=True)
-  firstname = db.TextProperty()
-  lastname = db.TextProperty()
-  status = db.TextProperty()
+  firstname = db.StringProperty()
+  lastname = db.StringProperty()
   phone_home = db.PhoneNumberProperty()
   phone_office = db.PhoneNumberProperty()
   phone_mobile = db.PhoneNumberProperty()
   email = db.EmailProperty()
+  status = db.TextProperty()
+  avatar = db.BlobProperty()
   deleted = db.BooleanProperty()
   updated = db.DateTimeProperty(auto_now_add=True)
 
   @classmethod
-  def get_user_info(cls, username):
+  def get_contact_info(cls, username):
     if username not in (None, ''):
       query = cls.gql('WHERE handle = :1', username)
       return query.get()
     return None
 
   @classmethod
-  def get_user_last_updated(cls, username):
+  def get_contact_last_updated(cls, username):
     if username not in (None, ''):
       query = cls.gql('WHERE handle = :1', username)
       return query.get().updated
     return None
 
   @classmethod
-  def get_user_id(cls, username):
+  def get_contact_id(cls, username):
     if username not in (None, ''):
       query = cls.gql('WHERE handle = :1', username)
       return query.get().key().id()
     return None
 
   @classmethod
-  def get_user_status(cls, username):
+  def get_contact_status(cls, username):
     if username not in (None, ''):
       query = cls.gql('WHERE handle = :1', username)
       return query.get().status
     return None
 
-
-class UserCredentials(db.Model):
-  """Data model class to hold credentials for a Voiper user."""
-
-  username = db.StringProperty(required=True)
-  password = db.StringProperty()
-
-  @classmethod
-  def get(cls, username):
-    if username not in (None, ''):
-      query = cls.gql('WHERE username = :1', username)
-      return query.get().password
-    return None
-
-
-class UserFriends(db.Model):
-  """Data model class to hold user's friendlist info."""
-
-  username = db.StringProperty()
-  friend_handle = db.StringProperty(required=True)
-  updated = db.DateTimeProperty(auto_now_add=True)
-  deleted = db.BooleanProperty()
-
-  @classmethod
-  def get_friends(cls, username):
-    if username not in (None, ''):
-      query = cls.gql('WHERE username = :1', username)
-      friends = query.fetch(50)
-      return friends
-    return None
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/static/css/main.css b/samples/SampleSyncAdapter/samplesyncadapter_server/static/css/main.css
new file mode 100644
index 0000000..eab304d
--- /dev/null
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/static/css/main.css
@@ -0,0 +1,77 @@
+/**
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+*/
+
+html,body {
+    height: 100%;
+}
+
+body {
+    padding: 20px;
+    margin: 0;
+    background-color: #fff;
+    font-family: Verdana, Arial, Helvetica, sans-serif;
+    text-align: left;
+}
+
+a {
+    color: #0033cc;
+}
+
+h1 {
+    font-family: Arial;
+    font-weight: normal;
+    border-bottom: solid 1px #ccc;
+    margin: 0 0 20px 0;
+    padding: 0 0 5px 0;
+}
+
+h3 {
+    font-family: Arial;
+    font-weight: bold;
+    line-height: 2em;
+}
+
+table {
+    border-collapse: collapse;
+    margin-bottom: 20px;
+}
+
+th,td {
+    padding: 5px 8px;
+    text-align: left;
+}
+
+td.center {
+    text-align: center;
+}
+
+.deleted td {
+    text-decoration: line-through;
+}
+
+.data th {
+    font-weight: normal;
+    border-bottom: solid 1px #000;
+}
+
+.data td {
+    border-bottom: solid 1px #eee;
+}
+
+.form th {
+    font-weight: normal;
+    text-align: right;
+}
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/static/img/default_avatar.gif b/samples/SampleSyncAdapter/samplesyncadapter_server/static/img/default_avatar.gif
new file mode 100644
index 0000000..5089e95
--- /dev/null
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/static/img/default_avatar.gif
Binary files differ
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/templates/contacts.html b/samples/SampleSyncAdapter/samplesyncadapter_server/templates/contacts.html
new file mode 100644
index 0000000..b668d33
--- /dev/null
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/templates/contacts.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+<!--
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+-->
+    <head>
+        <title>SampleSync: Contacts for '{{ username }}'</title>
+        <link type="text/css" rel="stylesheet" href="/static/css/main.css" media="screen" />
+    </head>
+    <body>
+        <h1>SampleSync: Contacts for '{{ username }}'</h1>
+        <table class="data" cellpadding="0" cellspacing="0">
+        <tr>
+            <th>&nbsp;</th>
+            <th>Id</th>
+            <th>Name</th>
+            <th>Email</th>
+            <th>Home</th>
+            <th>Office</th>
+            <th>Mobile</th>
+            <th>Status</th>
+        </tr>
+        {% for contact in contacts %}
+        <tr {% if contact.deleted %} class="deleted" {% endif %}>
+            <td class="center">
+            <a href="/edit_avatar?id={{ contact.key.id }}"><img src="/avatar?id={{ contact.key.id }}" height="25" width="25" /></a>
+            </td>
+            <td><a href="/edit_contact?id={{ contact.key.id }}">{{ contact.key.id }}</a></td>
+            <td><a href="/edit_contact?id={{ contact.key.id }}">{{ contact.firstname }} {{ contact.lastname }}</a></td>
+            <td>{{ contact.email }}</td>
+            <td>{{ contact.phone_home }}</td>
+            <td>{{ contact.phone_office }}</td>
+            <td>{{ contact.phone_mobile }}</td>
+            <td><span style="whitespace: no-wrap;">{{ contact.status }}</span></td>
+        </tr>
+        {% endfor %}
+        </table>
+
+        <a href = "/add_contact">Add Contact</a>
+    </body>
+</html>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/templates/edit_avatar.html b/samples/SampleSyncAdapter/samplesyncadapter_server/templates/edit_avatar.html
new file mode 100644
index 0000000..49cd3d3
--- /dev/null
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/templates/edit_avatar.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+<!--
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+-->
+    <head>
+        <title>SampleSync: Edit Picture</title>
+        <link type="text/css" rel="stylesheet" href="/static/css/main.css" media="screen" />
+    </head>
+    <body>
+        <h1>SampleSync: Edit Picture</h1>
+        <form method="POST" action="/edit_avatar" enctype="multipart/form-data">
+            <h3>Current Avatar:</h3>
+            <blockquote>
+                {% if avatar %}
+                <img src="/avatar?id={{ contactId }}" />
+                {% else %}
+                <i>You haven't added a picture for this friend...</i>
+                {% endif %}
+            </blockquote>
+            <h3>New Avatar:</h3>
+            <p>Please select a file containing the image you'd like to use for this friend</p>
+            <input type="file" name="avatar" />
+            <p>&nbsp;</p>
+            <input type="submit" name="Save" value="Save Changes" />
+            <input type="button" name="Cancel" value="Cancel" onclick="document.location='/';return false;" />
+            <input type="hidden" name="id" value="{{ contactId }}" />
+        </form>
+    </body>
+</html>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/templates/simple_form.html b/samples/SampleSyncAdapter/samplesyncadapter_server/templates/simple_form.html
new file mode 100644
index 0000000..1d72819
--- /dev/null
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/templates/simple_form.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+<!--
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+-->
+    <head>
+        <title>SampleSync: {{ title }}</title>
+        <link type="text/css" rel="stylesheet" href="/static/css/main.css" media="screen" />
+    </head>
+    <body>
+        <h1>SampleSync: {{ header }}</h1>
+        <form method="POST" action="{{ action }}">
+            <table class="form" cellpadding="0" cellspacing="0">
+              {{ form_data_rows }}
+            </table>
+            <input type="submit" name="Save" value="Save Changes" />
+            <input type="button" name="Cancel" value="Cancel" onclick="document.location='/';return false;" />
+            {% if has_contactId %}
+            <input type="hidden" name="id" value="{{ contactId }}" />
+            {% endif %}
+            {% if has_handle %}
+            <input type="hidden" name="username" value="{{ handle }}" />
+            {% endif %}
+        </form>
+    </body>
+</html>
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/templates/users.html b/samples/SampleSyncAdapter/samplesyncadapter_server/templates/users.html
deleted file mode 100644
index 044c352..0000000
--- a/samples/SampleSyncAdapter/samplesyncadapter_server/templates/users.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html>
-<body>
-<h1> Sample Sync Adapter </h1>
-
-<p>
-<h3> List of Users </h3>
-<table>
-
-{% for user in users %}
-  <tr><td>
-  <a
-  href="/edit_user?user={{ user.key.id}}">{{ user.firstname }}&nbsp; {{ user.lastname }} </a>
-  </td><td>&nbsp;&nbsp;<a href="/user_friends?user={{ user.handle }}">Friends</a> </td>
-  </tr>
-{% endfor %}
-</table>
-</p>
-
-<a href = "/add_user"> Insert More </a>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/templates/view_friends.html b/samples/SampleSyncAdapter/samplesyncadapter_server/templates/view_friends.html
deleted file mode 100644
index d4ef892..0000000
--- a/samples/SampleSyncAdapter/samplesyncadapter_server/templates/view_friends.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<html>
-<body>
-<h1> Sample Sync Adapter </h1>
-
-<p>
-
-{{user}}'s friends 
-<table>
-{% for friend in friends %}
-  <tr><td>
-  {{ friend.friend_handle }} </td><td> <a href="/delete_friend?user={{ user }}&friend={{friend.friend_handle}}">Remove</a>  
-  </td></tr>
-{% endfor %}
-</table>
-</p>
-
-<a href = "/add_friend?user={{user}}"> Add More </a>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/samplesyncadapter_server/web_services.py b/samples/SampleSyncAdapter/samplesyncadapter_server/web_services.py
new file mode 100644
index 0000000..3028add
--- /dev/null
+++ b/samples/SampleSyncAdapter/samplesyncadapter_server/web_services.py
@@ -0,0 +1,400 @@
+#!/usr/bin/python2.5
+
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+"""
+Handlers for Sample SyncAdapter services.
+
+Contains several RequestHandler subclasses used to handle post operations.
+This script is designed to be run directly as a WSGI application.
+
+"""
+
+import cgi
+import logging
+import time as _time
+from datetime import datetime
+from django.utils import simplejson
+from google.appengine.api import users
+from google.appengine.ext import db
+from google.appengine.ext import webapp
+from model import datastore
+import wsgiref.handlers
+
+
+class BaseWebServiceHandler(webapp.RequestHandler):
+    """
+    Base class for our web services. We put some common helper
+    functions here.
+    """
+
+    """
+    Since we're only simulating a single user account, declare our
+    hard-coded credentials here, so that they're easy to see/find.
+    We actually accept any and all usernames that start with this
+    hard-coded values. So if ACCT_USER_NAME is 'user', then we'll
+    accept 'user', 'user75', 'userbuddy', etc, all as legal account
+    usernames.
+    """
+    ACCT_USER_NAME  = 'user'
+    ACCT_PASSWORD   = 'test'
+    ACCT_AUTH_TOKEN = 'xyzzy'
+
+    DATE_TIME_FORMAT = '%Y/%m/%d %H:%M'
+
+    """
+    Process a request to authenticate a client.  We assume that the username
+    and password will be included in the request. If successful, we'll return
+    an authtoken as the only content.  If auth fails, we'll send an "invalid
+    credentials" error.
+    We return a boolean indicating whether we were successful (true) or not (false).
+    In the event that this call fails, we will setup the response, so callers just
+    need to RETURN in the error case.
+    """
+    def authenticate(self):
+        self.username = self.request.get('username')
+        self.password = self.request.get('password')
+
+        logging.info('Authenticatng username: ' + self.username)
+
+        if ((self.username != None) and
+                (self.username.startswith(BaseWebServiceHandler.ACCT_USER_NAME)) and
+                (self.password == BaseWebServiceHandler.ACCT_PASSWORD)):
+            # Authentication was successful - return our hard-coded
+            # auth-token as the only response.
+            self.response.set_status(200, 'OK')
+            self.response.out.write(BaseWebServiceHandler.ACCT_AUTH_TOKEN)
+            return True
+        else:
+            # Authentication failed. Return the standard HTTP auth failure
+            # response to let the client know.
+            self.response.set_status(401, 'Invalid Credentials')
+            return False
+
+    """
+    Validate the credentials of the client for a web service request.
+    The request should include username/password parameters that correspond
+    to our hard-coded single account values.
+    We return a boolean indicating whether we were successful (true) or not (false).
+    In the event that this call fails, we will setup the response, so callers just
+    need to RETURN in the error case.
+    """
+    def validate(self):
+        self.username = self.request.get('username')
+        self.authtoken = self.request.get('authtoken')
+
+        logging.info('Validating username: ' + self.username)
+
+        if ((self.username != None) and
+                (self.username.startswith(BaseWebServiceHandler.ACCT_USER_NAME)) and
+                (self.authtoken == BaseWebServiceHandler.ACCT_AUTH_TOKEN)):
+            return True
+        else:
+            self.response.set_status(401, 'Invalid Credentials')
+            return False
+
+
+class Authenticate(BaseWebServiceHandler):
+    """
+    Handles requests for login and authentication.
+
+    UpdateHandler only accepts post events. It expects each
+    request to include username and password fields. It returns authtoken
+    after successful authentication and "invalid credentials" error otherwise.
+    """
+
+    def post(self):
+        self.authenticate()
+
+    def get(self):
+        """Used for debugging in a browser..."""
+        self.post()
+
+
+class SyncContacts(BaseWebServiceHandler):
+    """Handles requests for fetching user's contacts.
+
+    UpdateHandler only accepts post events. It expects each
+    request to include username and authtoken. If the authtoken is valid
+    it returns user's contact info in JSON format.
+    """
+
+    def get(self):
+        """Used for debugging in a browser..."""
+        self.post()
+
+    def post(self):
+        logging.info('*** Starting contact sync ***')
+        if (not self.validate()):
+            return
+
+        updated_contacts = []
+
+        # Process any client-side changes sent up in the request.
+        # Any new contacts that were added are included in the
+        # updated_contacts list, so that we return them to the
+        # client. That way, the client can see the serverId of
+        # the newly added contact.
+        client_buffer = self.request.get('contacts')
+        if ((client_buffer != None) and (client_buffer != '')):
+            self.process_client_changes(client_buffer, updated_contacts)
+
+        # Add any contacts that have been updated on the server-side
+        # since the last sync by this client.
+        client_state = self.request.get('syncstate')
+        self.get_updated_contacts(client_state, updated_contacts)
+
+        logging.info('Returning ' + str(len(updated_contacts)) + ' contact records')
+
+        # Return the list of updated contacts to the client
+        self.response.set_status(200)
+        self.response.out.write(toJSON(updated_contacts))
+
+    def get_updated_contacts(self, client_state, updated_contacts):
+        logging.info('* Processing server changes')
+        timestamp = None
+
+        base_url = self.request.host_url
+
+        # The client sends the last high-water-mark that they successfully
+        # sync'd to in the syncstate parameter.  It's opaque to them, but
+        # its actually a seconds-in-unix-epoch timestamp that we use
+        # as a baseline.
+        if client_state:
+            logging.info('Client sync state: ' + client_state)
+            timestamp = datetime.utcfromtimestamp(float(client_state))
+
+        # Keep track of the update/delete counts, so we can log it
+        # below.  Makes debugging easier...
+        update_count = 0
+        delete_count = 0
+
+        contacts = datastore.Contact.all()
+        if contacts:
+            # Find the high-water mark for the most recently updated friend.
+            # We'll return this as the syncstate (x) value for all the friends
+            # we return from this function.
+            high_water_date = datetime.min
+            for contact in contacts:
+                if (contact.updated > high_water_date):
+                    high_water_date = contact.updated
+            high_water_mark = str(long(_time.mktime(high_water_date.utctimetuple())) + 1)
+            logging.info('New sync state: ' + high_water_mark)
+
+            # Now build the updated_contacts containing all the friends that have been
+            # changed since the last sync
+            for contact in contacts:
+                # If our list of contacts we're returning already contains this
+                # contact (for example, it's a contact just uploaded from the client)
+                # then don't bother processing it any further...
+                if (self.list_contains_contact(updated_contacts, contact)):
+                    continue
+
+                handle = contact.handle
+
+                if timestamp is None or contact.updated > timestamp:
+                    if contact.deleted == True:
+                        delete_count = delete_count + 1
+                        DeletedContactData(updated_contacts, handle, high_water_mark)
+                    else:
+                        update_count = update_count + 1
+                        UpdatedContactData(updated_contacts, handle, None, base_url, high_water_mark)
+
+        logging.info('Server-side updates: ' + str(update_count))
+        logging.info('Server-side deletes: ' + str(delete_count))
+
+    def process_client_changes(self, contacts_buffer, updated_contacts):
+        logging.info('* Processing client changes: ' + self.username)
+
+        base_url = self.request.host_url
+
+        # Build an array of generic objects containing contact data,
+        # using the Django built-in JSON parser
+        logging.info('Uploaded contacts buffer: ' + contacts_buffer)
+        json_list = simplejson.loads(contacts_buffer)
+        logging.info('Client-side updates: ' + str(len(json_list)))
+
+        # Keep track of the number of new contacts the client sent to us,
+        # so that we can log it below.
+        new_contact_count = 0
+
+        for jcontact in json_list:
+            new_contact = False
+            id = self.safe_attr(jcontact, 'i')
+            if (id != None):
+                logging.info('Updating contact: ' + str(id))
+                contact = datastore.Contact.get(db.Key.from_path('Contact', id))
+            else:
+                logging.info('Creating new contact record')
+                new_contact = True
+                contact = datastore.Contact(handle='temp')
+
+            # If the 'change' for this contact is that they were deleted
+            # on the client-side, all we want to do is set the deleted
+            # flag here, and we're done.
+            if (self.safe_attr(jcontact, 'd') == True):
+                contact.deleted = True
+                contact.put()
+                logging.info('Deleted contact: ' + contact.handle)
+                continue
+
+            contact.firstname = self.safe_attr(jcontact, 'f')
+            contact.lastname = self.safe_attr(jcontact, 'l')
+            contact.phone_home = self.safe_attr(jcontact, 'h')
+            contact.phone_office = self.safe_attr(jcontact, 'o')
+            contact.phone_mobile = self.safe_attr(jcontact, 'm')
+            contact.email = self.safe_attr(jcontact, 'e')
+            contact.deleted = (self.safe_attr(jcontact, 'd') == 'true')
+            if (new_contact):
+                # New record - add them to db...
+                new_contact_count = new_contact_count + 1
+                contact.handle = contact.firstname + '_' + contact.lastname
+                logging.info('Created new contact handle: ' + contact.handle)
+            contact.put()
+            logging.info('Saved contact: ' + contact.handle)
+
+            # We don't save off the client_id value (thus we add it after
+            # the "put"), but we want it to be in the JSON object we
+            # serialize out, so that the client can match this contact
+            # up with the client version.
+            client_id = self.safe_attr(jcontact, 'c')
+
+            # Create a high-water-mark for sync-state from the 'updated' time
+            # for this contact, so we return the correct value to the client.
+            high_water = str(long(_time.mktime(contact.updated.utctimetuple())) + 1)
+
+            # Add new contacts to our updated_contacts, so that we return them
+            # to the client (so the client gets the serverId for the
+            # added contact)
+            if (new_contact):
+                UpdatedContactData(updated_contacts, contact.handle, client_id, base_url,
+                        high_water)
+
+        logging.info('Client-side adds: ' + str(new_contact_count))
+
+    def list_contains_contact(self, contact_list, contact):
+        if (contact is None):
+            return False
+        contact_id = str(contact.key().id())
+        for next in contact_list:
+            if ((next != None) and (next['i'] == contact_id)):
+                return True
+        return False
+
+    def safe_attr(self, obj, attr_name):
+        if attr_name in obj:
+            return obj[attr_name]
+        return None
+
+class ResetDatabase(BaseWebServiceHandler):
+    """
+    Handles cron request to reset the contact database.
+
+    We have a weekly cron task that resets the database back to a
+    few contacts, so that it doesn't grow to an absurd size.
+    """
+
+    def get(self):
+        # Delete all the existing contacts from the database
+        contacts = datastore.Contact.all()
+        for contact in contacts:
+            contact.delete()
+
+        # Now create three sample contacts
+        contact1 = datastore.Contact(handle = 'juliet',
+                firstname = 'Juliet',
+                lastname = 'Capulet',
+                phone_mobile = '(650) 555-1000',
+                phone_home = '(650) 555-1001',
+                status = 'Wherefore art thou Romeo?')
+        contact1.put()
+
+        contact2 = datastore.Contact(handle = 'romeo',
+                firstname = 'Romeo',
+                lastname = 'Montague',
+                phone_mobile = '(650) 555-2000',
+                phone_home = '(650) 555-2001',
+                status = 'I dream\'d a dream to-night')
+        contact2.put()
+
+        contact3 = datastore.Contact(handle = 'tybalt',
+                firstname = 'Tybalt',
+                lastname = 'Capulet',
+                phone_mobile = '(650) 555-3000',
+                phone_home = '(650) 555-3001',
+                status = 'Have at thee, coward')
+        contact3.put()
+
+
+
+
+def toJSON(object):
+    """Dumps the data represented by the object to JSON for wire transfer."""
+    return simplejson.dumps(object)
+
+class UpdatedContactData(object):
+    """Holds data for user's contacts.
+
+    This class knows how to serialize itself to JSON.
+    """
+    __FIELD_MAP = {
+        'handle': 'u',
+        'firstname': 'f',
+        'lastname': 'l',
+        'status': 's',
+        'phone_home': 'h',
+        'phone_office': 'o',
+        'phone_mobile': 'm',
+        'email': 'e',
+        'client_id': 'c'
+    }
+
+    def __init__(self, contact_list, username, client_id, host_url, high_water_mark):
+        obj = datastore.Contact.get_contact_info(username)
+        contact = {}
+        for obj_name, json_name in self.__FIELD_MAP.items():
+            if hasattr(obj, obj_name):
+              v = getattr(obj, obj_name)
+              if (v != None):
+                  contact[json_name] = str(v)
+              else:
+                  contact[json_name] = None
+        contact['i'] = str(obj.key().id())
+        contact['a'] = host_url + "/avatar?id=" + str(obj.key().id())
+        contact['x'] = high_water_mark
+        if (client_id != None):
+            contact['c'] = str(client_id)
+        contact_list.append(contact)
+
+class DeletedContactData(object):
+    def __init__(self, contact_list, username, high_water_mark):
+        obj = datastore.Contact.get_contact_info(username)
+        contact = {}
+        contact['d'] = 'true'
+        contact['i'] = str(obj.key().id())
+        contact['x'] = high_water_mark
+        contact_list.append(contact)
+
+def main():
+    application = webapp.WSGIApplication(
+            [('/auth', Authenticate),
+             ('/sync', SyncContacts),
+             ('/reset_database', ResetDatabase),
+            ],
+            debug=True)
+    wsgiref.handlers.CGIHandler().run(application)
+
+if __name__ == "__main__":
+    main()
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/Constants.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/Constants.java
index 49f92bf..bc09da2 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/Constants.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/Constants.java
@@ -1,12 +1,12 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticationService.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticationService.java
index 2c163be..9fc72eb 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticationService.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticationService.java
@@ -1,18 +1,19 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * 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.example.android.samplesync.authenticator;
 
 import android.app.Service;
@@ -49,7 +50,7 @@
     public IBinder onBind(Intent intent) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getBinder()...  returning the AccountAuthenticator binder for intent "
-                + intent);
+                    + intent);
         }
         return mAuthenticator.getIBinder();
     }
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/Authenticator.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/Authenticator.java
index 0c79c5e..2eb6ecd 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/Authenticator.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/Authenticator.java
@@ -1,38 +1,57 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * 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.example.android.samplesync.authenticator;
 
+import com.example.android.samplesync.Constants;
+import com.example.android.samplesync.client.NetworkUtilities;
+
 import android.accounts.AbstractAccountAuthenticator;
 import android.accounts.Account;
 import android.accounts.AccountAuthenticatorResponse;
 import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-
-import com.example.android.samplesync.Constants;
-import com.example.android.samplesync.R;
-import com.example.android.samplesync.client.NetworkUtilities;
+import android.text.TextUtils;
+import android.util.Log;
 
 /**
  * This class is an implementation of AbstractAccountAuthenticator for
- * authenticating accounts in the com.example.android.samplesync domain.
+ * authenticating accounts in the com.example.android.samplesync domain. The
+ * interesting thing that this class demonstrates is the use of authTokens as
+ * part of the authentication process. In the account setup UI, the user enters
+ * their username and password. But for our subsequent calls off to the service
+ * for syncing, we want to use an authtoken instead - so we're not continually
+ * sending the password over the wire. getAuthToken() will be called when
+ * SyncAdapter calls AccountManager.blockingGetAuthToken(). When we get called,
+ * we need to return the appropriate authToken for the specified account. If we
+ * already have an authToken stored in the account, we return that authToken. If
+ * we don't, but we do have a username and password, then we'll attempt to talk
+ * to the sample service to fetch an authToken. If that fails (or we didn't have
+ * a username/password), then we need to prompt the user - so we create an
+ * AuthenticatorActivity intent and return that. That will display the dialog
+ * that prompts the user for their login information.
  */
 class Authenticator extends AbstractAccountAuthenticator {
 
+    /** The tag used to log to adb console. **/
+    private static final String TAG = "Authenticator";
+
     // Authentication Service context
     private final Context mContext;
 
@@ -43,10 +62,9 @@
 
     @Override
     public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
-        String authTokenType, String[] requiredFeatures, Bundle options) {
-
+            String authTokenType, String[] requiredFeatures, Bundle options) {
+        Log.v(TAG, "addAccount()");
         final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
-        intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, authTokenType);
         intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
         final Bundle bundle = new Bundle();
         bundle.putParcelable(AccountManager.KEY_INTENT, intent);
@@ -54,54 +72,49 @@
     }
 
     @Override
-    public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,
-        Bundle options) {
-
-        if (options != null && options.containsKey(AccountManager.KEY_PASSWORD)) {
-            final String password = options.getString(AccountManager.KEY_PASSWORD);
-            final boolean verified = onlineConfirmPassword(account.name, password);
-            final Bundle result = new Bundle();
-            result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, verified);
-            return result;
-        }
-        // Launch AuthenticatorActivity to confirm credentials
-        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
-        intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);
-        intent.putExtra(AuthenticatorActivity.PARAM_CONFIRM_CREDENTIALS, true);
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
-        final Bundle bundle = new Bundle();
-        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
-        return bundle;
+    public Bundle confirmCredentials(
+            AccountAuthenticatorResponse response, Account account, Bundle options) {
+        Log.v(TAG, "confirmCredentials()");
+        return null;
     }
 
     @Override
     public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+        Log.v(TAG, "editProperties()");
         throw new UnsupportedOperationException();
     }
 
     @Override
     public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
-        String authTokenType, Bundle loginOptions) {
+            String authTokenType, Bundle loginOptions) throws NetworkErrorException {
+        Log.v(TAG, "getAuthToken()");
 
+        // If the caller requested an authToken type we don't support, then
+        // return an error
         if (!authTokenType.equals(Constants.AUTHTOKEN_TYPE)) {
             final Bundle result = new Bundle();
             result.putString(AccountManager.KEY_ERROR_MESSAGE, "invalid authTokenType");
             return result;
         }
+
+        // Extract the username and password from the Account Manager, and ask
+        // the server for an appropriate AuthToken.
         final AccountManager am = AccountManager.get(mContext);
         final String password = am.getPassword(account);
         if (password != null) {
-            final boolean verified = onlineConfirmPassword(account.name, password);
-            if (verified) {
+            final String authToken = NetworkUtilities.authenticate(account.name, password);
+            if (!TextUtils.isEmpty(authToken)) {
                 final Bundle result = new Bundle();
                 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
                 result.putString(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
-                result.putString(AccountManager.KEY_AUTHTOKEN, password);
+                result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
                 return result;
             }
         }
-        // the password was missing or incorrect, return an Intent to an
-        // Activity that will prompt the user for the password.
+
+        // If we get here, then we couldn't access the user's password - so we
+        // need to re-prompt them for their credentials. We do that by creating
+        // an intent to display our AuthenticatorActivity panel.
         final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
         intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);
         intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, authTokenType);
@@ -113,39 +126,27 @@
 
     @Override
     public String getAuthTokenLabel(String authTokenType) {
-        if (Constants.AUTHTOKEN_TYPE.equals(authTokenType)) {
-            return mContext.getString(R.string.label);
-        }
+        // null means we don't support multiple authToken types
+        Log.v(TAG, "getAuthTokenLabel()");
         return null;
     }
 
     @Override
-    public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,
-        String[] features) {
-
+    public Bundle hasFeatures(
+            AccountAuthenticatorResponse response, Account account, String[] features) {
+        // This call is used to query whether the Authenticator supports
+        // specific features. We don't expect to get called, so we always
+        // return false (no) for any queries.
+        Log.v(TAG, "hasFeatures()");
         final Bundle result = new Bundle();
         result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
         return result;
     }
 
-    /**
-     * Validates user's password on the server
-     */
-    private boolean onlineConfirmPassword(String username, String password) {
-        return NetworkUtilities
-            .authenticate(username, password, null/* Handler */, null/* Context */);
-    }
-
     @Override
     public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
-        String authTokenType, Bundle loginOptions) {
-
-        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
-        intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);
-        intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, authTokenType);
-        intent.putExtra(AuthenticatorActivity.PARAM_CONFIRM_CREDENTIALS, false);
-        final Bundle bundle = new Bundle();
-        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
-        return bundle;
+            String authTokenType, Bundle loginOptions) {
+        Log.v(TAG, "updateCredentials()");
+        return null;
     }
 }
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java
index 4e1ee2a..2a3c0fc 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java
@@ -1,20 +1,25 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * 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.example.android.samplesync.authenticator;
 
+import com.example.android.samplesync.Constants;
+import com.example.android.samplesync.R;
+import com.example.android.samplesync.client.NetworkUtilities;
+
 import android.accounts.Account;
 import android.accounts.AccountAuthenticatorActivity;
 import android.accounts.AccountManager;
@@ -23,6 +28,7 @@
 import android.content.ContentResolver;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.ContactsContract;
@@ -33,41 +39,36 @@
 import android.widget.EditText;
 import android.widget.TextView;
 
-import com.example.android.samplesync.Constants;
-import com.example.android.samplesync.R;
-import com.example.android.samplesync.client.NetworkUtilities;
-
 /**
  * Activity which displays login screen to the user.
  */
 public class AuthenticatorActivity extends AccountAuthenticatorActivity {
-
-    /** The Intent flag to confirm credentials. **/
+    /** The Intent flag to confirm credentials. */
     public static final String PARAM_CONFIRM_CREDENTIALS = "confirmCredentials";
 
-    /** The Intent extra to store password. **/
+    /** The Intent extra to store password. */
     public static final String PARAM_PASSWORD = "password";
 
-    /** The Intent extra to store username. **/
+    /** The Intent extra to store username. */
     public static final String PARAM_USERNAME = "username";
 
-    /** The Intent extra to store authtoken type. **/
+    /** The Intent extra to store username. */
     public static final String PARAM_AUTHTOKEN_TYPE = "authtokenType";
 
-    /** The tag used to log to adb console. **/
+    /** The tag used to log to adb console. */
     private static final String TAG = "AuthenticatorActivity";
-
     private AccountManager mAccountManager;
 
-    private Thread mAuthThread;
+    /** Keep track of the login task so can cancel it if requested */
+    private UserLoginTask mAuthTask = null;
 
-    private String mAuthtoken;
-
-    private String mAuthtokenType;
+    /** Keep track of the progress dialog so we can dismiss it */
+    private ProgressDialog mProgressDialog = null;
 
     /**
      * If set we are just checking that the user knows their credentials; this
-     * doesn't cause the user's password to be changed on the device.
+     * doesn't cause the user's password or authToken to be changed on the
+     * device.
      */
     private Boolean mConfirmCredentials = false;
 
@@ -99,14 +100,13 @@
         Log.i(TAG, "loading data from Intent");
         final Intent intent = getIntent();
         mUsername = intent.getStringExtra(PARAM_USERNAME);
-        mAuthtokenType = intent.getStringExtra(PARAM_AUTHTOKEN_TYPE);
         mRequestNewAccount = mUsername == null;
         mConfirmCredentials = intent.getBooleanExtra(PARAM_CONFIRM_CREDENTIALS, false);
         Log.i(TAG, "    request new: " + mRequestNewAccount);
         requestWindowFeature(Window.FEATURE_LEFT_ICON);
         setContentView(R.layout.login_activity);
-        getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
-            android.R.drawable.ic_dialog_alert);
+        getWindow().setFeatureDrawableResource(
+                Window.FEATURE_LEFT_ICON, android.R.drawable.ic_dialog_alert);
         mMessage = (TextView) findViewById(R.id.message);
         mUsernameEdit = (EditText) findViewById(R.id.username_edit);
         mPasswordEdit = (EditText) findViewById(R.id.password_edit);
@@ -118,27 +118,31 @@
      * {@inheritDoc}
      */
     @Override
-    protected Dialog onCreateDialog(int id) {
+    protected Dialog onCreateDialog(int id, Bundle args) {
         final ProgressDialog dialog = new ProgressDialog(this);
         dialog.setMessage(getText(R.string.ui_activity_authenticating));
         dialog.setIndeterminate(true);
         dialog.setCancelable(true);
         dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
             public void onCancel(DialogInterface dialog) {
-                Log.i(TAG, "dialog cancel has been invoked");
-                if (mAuthThread != null) {
-                    mAuthThread.interrupt();
-                    finish();
+                Log.i(TAG, "user cancelling authentication");
+                if (mAuthTask != null) {
+                    mAuthTask.cancel(true);
                 }
             }
         });
+        // We save off the progress dialog in a field so that we can dismiss
+        // it later. We can't just call dismissDialog(0) because the system
+        // can lose track of our dialog if there's an orientation change.
+        mProgressDialog = dialog;
         return dialog;
     }
 
     /**
      * Handles onClick event on the Submit button. Sends username/password to
-     * the server for authentication.
-     * 
+     * the server for authentication. The button is configured to call
+     * handleLogin() in the layout XML.
+     *
      * @param view The Submit button for which this method is invoked
      */
     public void handleLogin(View view) {
@@ -149,11 +153,11 @@
         if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword)) {
             mMessage.setText(getMessage());
         } else {
+            // Show a progress dialog, and kick off a background task to perform
+            // the user login attempt.
             showProgress();
-            // Start authenticating...
-            mAuthThread =
-                NetworkUtilities.attemptAuth(mUsername, mPassword, mHandler,
-                    AuthenticatorActivity.this);
+            mAuthTask = new UserLoginTask();
+            mAuthTask.execute();
         }
     }
 
@@ -161,8 +165,8 @@
      * Called when response is received from the server for confirm credentials
      * request. See onAuthenticationResult(). Sets the
      * AccountAuthenticatorResult which is sent back to the caller.
-     * 
-     * @param the confirmCredentials result.
+     *
+     * @param result the confirmCredentials result.
      */
     private void finishConfirmCredentials(boolean result) {
         Log.i(TAG, "finishConfirmCredentials()");
@@ -178,12 +182,13 @@
     /**
      * Called when response is received from the server for authentication
      * request. See onAuthenticationResult(). Sets the
-     * AccountAuthenticatorResult which is sent back to the caller. Also sets
-     * the authToken in AccountManager for this account.
-     * 
-     * @param the confirmCredentials result.
+     * AccountAuthenticatorResult which is sent back to the caller. We store the
+     * authToken that's returned from the server as the 'password' for this
+     * account - so we're never storing the user's actual password locally.
+     *
+     * @param result the confirmCredentials result.
      */
-    private void finishLogin() {
+    private void finishLogin(String authToken) {
 
         Log.i(TAG, "finishLogin()");
         final Account account = new Account(mUsername, Constants.ACCOUNT_TYPE);
@@ -195,37 +200,35 @@
             mAccountManager.setPassword(account, mPassword);
         }
         final Intent intent = new Intent();
-        mAuthtoken = mPassword;
         intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername);
         intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
-        if (mAuthtokenType != null && mAuthtokenType.equals(Constants.AUTHTOKEN_TYPE)) {
-            intent.putExtra(AccountManager.KEY_AUTHTOKEN, mAuthtoken);
-        }
         setAccountAuthenticatorResult(intent.getExtras());
         setResult(RESULT_OK, intent);
         finish();
     }
 
     /**
-     * Hides the progress UI for a lengthy operation.
-     */
-    private void hideProgress() {
-        dismissDialog(0);
-    }
-
-    /**
      * Called when the authentication process completes (see attemptLogin()).
+     *
+     * @param authToken the authentication token returned by the server, or NULL if
+     *            authentication failed.
      */
-    public void onAuthenticationResult(boolean result) {
+    public void onAuthenticationResult(String authToken) {
 
-        Log.i(TAG, "onAuthenticationResult(" + result + ")");
+        boolean success = ((authToken != null) && (authToken.length() > 0));
+        Log.i(TAG, "onAuthenticationResult(" + success + ")");
+
+        // Our task is complete, so clear it out
+        mAuthTask = null;
+
         // Hide the progress dialog
         hideProgress();
-        if (result) {
+
+        if (success) {
             if (!mConfirmCredentials) {
-                finishLogin();
+                finishLogin(authToken);
             } else {
-                finishConfirmCredentials(true);
+                finishConfirmCredentials(success);
             }
         } else {
             Log.e(TAG, "onAuthenticationResult: failed to authenticate");
@@ -241,6 +244,16 @@
         }
     }
 
+    public void onAuthenticationCancel() {
+        Log.i(TAG, "onAuthenticationCancel()");
+
+        // Our task is complete, so clear it out
+        mAuthTask = null;
+
+        // Hide the progress dialog
+        hideProgress();
+    }
+
     /**
      * Returns the message to be displayed at the top of the login dialog box.
      */
@@ -265,4 +278,49 @@
     private void showProgress() {
         showDialog(0);
     }
+
+    /**
+     * Hides the progress UI for a lengthy operation.
+     */
+    private void hideProgress() {
+        if (mProgressDialog != null) {
+            mProgressDialog.dismiss();
+            mProgressDialog = null;
+        }
+    }
+
+    /**
+     * Represents an asynchronous task used to authenticate a user against the
+     * SampleSync Service
+     */
+    public class UserLoginTask extends AsyncTask<Void, Void, String> {
+
+        @Override
+        protected String doInBackground(Void... params) {
+            // We do the actual work of authenticating the user
+            // in the NetworkUtilities class.
+            try {
+                return NetworkUtilities.authenticate(mUsername, mPassword);
+            } catch (Exception ex) {
+                Log.e(TAG, "UserLoginTask.doInBackground: failed to authenticate");
+                Log.i(TAG, ex.toString());
+                return null;
+            }
+        }
+
+        @Override
+        protected void onPostExecute(final String authToken) {
+            // On a successful authentication, call back into the Activity to
+            // communicate the authToken (or null for an error).
+            onAuthenticationResult(authToken);
+        }
+
+        @Override
+        protected void onCancelled() {
+            // If the action was canceled (by the user clicking the cancel
+            // button in the progress dialog), then call back into the
+            // activity to let it know.
+            onAuthenticationCancel();
+        }
+    }
 }
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java
index 7824a4d..bebcd72 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java
@@ -1,23 +1,27 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * 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.example.android.samplesync.client;
 
 import android.accounts.Account;
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.os.Handler;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.example.android.samplesync.authenticator.AuthenticatorActivity;
@@ -37,11 +41,19 @@
 import org.apache.http.params.HttpConnectionParams;
 import org.apache.http.params.HttpParams;
 import org.apache.http.util.EntityUtils;
+import org.json.JSONObject;
 import org.json.JSONArray;
 import org.json.JSONException;
 
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
@@ -52,31 +64,26 @@
  * Provides utility methods for communicating with the server.
  */
 final public class NetworkUtilities {
-
-    /** The tag used to log to adb console. **/
+    /** The tag used to log to adb console. */
     private static final String TAG = "NetworkUtilities";
-
-    /** The Intent extra to store password. **/
-    public static final String PARAM_PASSWORD = "password";
-
-    /** The Intent extra to store username. **/
+    /** POST parameter name for the user's account name */
     public static final String PARAM_USERNAME = "username";
-
-    public static final String PARAM_UPDATED = "timestamp";
-
-    public static final String USER_AGENT = "AuthenticationService/1.0";
-
-    public static final int REGISTRATION_TIMEOUT_MS = 30 * 1000; // ms
-
-    public static final String BASE_URL = "https://samplesyncadapter.appspot.com";
-
+    /** POST parameter name for the user's password */
+    public static final String PARAM_PASSWORD = "password";
+    /** POST parameter name for the user's authentication token */
+    public static final String PARAM_AUTH_TOKEN = "authtoken";
+    /** POST parameter name for the client's last-known sync state */
+    public static final String PARAM_SYNC_STATE = "syncstate";
+    /** POST parameter name for the sending client-edited contact info */
+    public static final String PARAM_CONTACTS_DATA = "contacts";
+    /** Timeout (in ms) we specify for each http request */
+    public static final int HTTP_REQUEST_TIMEOUT_MS = 30 * 1000;
+    /** Base URL for the v2 Sample Sync Service */
+    public static final String BASE_URL = "https://samplesyncadapter2.appspot.com";
+    /** URI for authentication service */
     public static final String AUTH_URI = BASE_URL + "/auth";
-
-    public static final String FETCH_FRIEND_UPDATES_URI = BASE_URL + "/fetch_friend_updates";
-
-    public static final String FETCH_STATUS_URI = BASE_URL + "/fetch_status";
-
-    private static HttpClient mHttpClient;
+    /** URI for sync service */
+    public static final String SYNC_CONTACTS_URI = BASE_URL + "/sync";
 
     private NetworkUtilities() {
     }
@@ -84,224 +91,188 @@
     /**
      * Configures the httpClient to connect to the URL provided.
      */
-    public static void maybeCreateHttpClient() {
-        if (mHttpClient == null) {
-            mHttpClient = new DefaultHttpClient();
-            final HttpParams params = mHttpClient.getParams();
-            HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT_MS);
-            HttpConnectionParams.setSoTimeout(params, REGISTRATION_TIMEOUT_MS);
-            ConnManagerParams.setTimeout(params, REGISTRATION_TIMEOUT_MS);
-        }
+    public static HttpClient getHttpClient() {
+        HttpClient httpClient = new DefaultHttpClient();
+        final HttpParams params = httpClient.getParams();
+        HttpConnectionParams.setConnectionTimeout(params, HTTP_REQUEST_TIMEOUT_MS);
+        HttpConnectionParams.setSoTimeout(params, HTTP_REQUEST_TIMEOUT_MS);
+        ConnManagerParams.setTimeout(params, HTTP_REQUEST_TIMEOUT_MS);
+        return httpClient;
     }
 
     /**
-     * Executes the network requests on a separate thread.
-     * 
-     * @param runnable The runnable instance containing network mOperations to
-     *        be executed.
+     * Connects to the SampleSync test server, authenticates the provided
+     * username and password.
+     *
+     * @param username The server account username
+     * @param password The server account password
+     * @return String The authentication token returned by the server (or null)
      */
-    public static Thread performOnBackgroundThread(final Runnable runnable) {
-        final Thread t = new Thread() {
-            @Override
-            public void run() {
-                try {
-                    runnable.run();
-                } finally {
-                }
-            }
-        };
-        t.start();
-        return t;
-    }
-
-    /**
-     * Connects to the Voiper server, authenticates the provided username and
-     * password.
-     * 
-     * @param username The user's username
-     * @param password The user's password
-     * @param handler The hander instance from the calling UI thread.
-     * @param context The context of the calling Activity.
-     * @return boolean The boolean result indicating whether the user was
-     *         successfully authenticated.
-     */
-    public static boolean authenticate(String username, String password, Handler handler,
-        final Context context) {
+    public static String authenticate(String username, String password) {
 
         final HttpResponse resp;
         final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
         params.add(new BasicNameValuePair(PARAM_USERNAME, username));
         params.add(new BasicNameValuePair(PARAM_PASSWORD, password));
-        HttpEntity entity = null;
+        final HttpEntity entity;
         try {
             entity = new UrlEncodedFormEntity(params);
         } catch (final UnsupportedEncodingException e) {
             // this should never happen.
-            throw new AssertionError(e);
+            throw new IllegalStateException(e);
         }
+        Log.i(TAG, "Authenticating to: " + AUTH_URI);
         final HttpPost post = new HttpPost(AUTH_URI);
         post.addHeader(entity.getContentType());
         post.setEntity(entity);
-        maybeCreateHttpClient();
         try {
-            resp = mHttpClient.execute(post);
+            resp = getHttpClient().execute(post);
+            String authToken = null;
             if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "Successful authentication");
+                InputStream istream = (resp.getEntity() != null) ? resp.getEntity().getContent()
+                        : null;
+                if (istream != null) {
+                    BufferedReader ireader = new BufferedReader(new InputStreamReader(istream));
+                    authToken = ireader.readLine().trim();
                 }
-                sendResult(true, handler, context);
-                return true;
+            }
+            if ((authToken != null) && (authToken.length() > 0)) {
+                Log.v(TAG, "Successful authentication");
+                return authToken;
             } else {
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "Error authenticating" + resp.getStatusLine());
-                }
-                sendResult(false, handler, context);
-                return false;
+                Log.e(TAG, "Error authenticating" + resp.getStatusLine());
+                return null;
             }
         } catch (final IOException e) {
-            if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.v(TAG, "IOException when getting authtoken", e);
-            }
-            sendResult(false, handler, context);
-            return false;
+            Log.e(TAG, "IOException when getting authtoken", e);
+            return null;
         } finally {
-            if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.v(TAG, "getAuthtoken completing");
-            }
+            Log.v(TAG, "getAuthtoken completing");
         }
     }
 
     /**
-     * Sends the authentication response from server back to the caller main UI
-     * thread through its handler.
-     * 
-     * @param result The boolean holding authentication result
-     * @param handler The main UI thread's handler instance.
-     * @param context The caller Activity's context.
+     * Perform 2-way sync with the server-side contacts. We send a request that
+     * includes all the locally-dirty contacts so that the server can process
+     * those changes, and we receive (and return) a list of contacts that were
+     * updated on the server-side that need to be updated locally.
+     *
+     * @param account The account being synced
+     * @param authtoken The authtoken stored in the AccountManager for this
+     *            account
+     * @param serverSyncState A token returned from the server on the last sync
+     * @param dirtyContacts A list of the contacts to send to the server
+     * @return A list of contacts that we need to update locally
      */
-    private static void sendResult(final Boolean result, final Handler handler,
-        final Context context) {
-        if (handler == null || context == null) {
-            return;
+    public static List<RawContact> syncContacts(
+            Account account, String authtoken, long serverSyncState, List<RawContact> dirtyContacts)
+            throws JSONException, ParseException, IOException, AuthenticationException {
+        // Convert our list of User objects into a list of JSONObject
+        List<JSONObject> jsonContacts = new ArrayList<JSONObject>();
+        for (RawContact rawContact : dirtyContacts) {
+            jsonContacts.add(rawContact.toJSONObject());
         }
-        handler.post(new Runnable() {
-            public void run() {
-                ((AuthenticatorActivity) context).onAuthenticationResult(result);
-            }
-        });
-    }
 
-    /**
-     * Attempts to authenticate the user credentials on the server.
-     * 
-     * @param username The user's username
-     * @param password The user's password to be authenticated
-     * @param handler The main UI thread's handler instance.
-     * @param context The caller Activity's context
-     * @return Thread The thread on which the network mOperations are executed.
-     */
-    public static Thread attemptAuth(final String username, final String password,
-        final Handler handler, final Context context) {
+        // Create a special JSONArray of our JSON contacts
+        JSONArray buffer = new JSONArray(jsonContacts);
 
-        final Runnable runnable = new Runnable() {
-            public void run() {
-                authenticate(username, password, handler, context);
-            }
-        };
-        // run on background thread.
-        return NetworkUtilities.performOnBackgroundThread(runnable);
-    }
+        // Create an array that will hold the server-side contacts
+        // that have been changed (returned by the server).
+        final ArrayList<RawContact> serverDirtyList = new ArrayList<RawContact>();
 
-    /**
-     * Fetches the list of friend data updates from the server
-     * 
-     * @param account The account being synced.
-     * @param authtoken The authtoken stored in AccountManager for this account
-     * @param lastUpdated The last time that sync was performed
-     * @return list The list of updates received from the server.
-     */
-    public static List<User> fetchFriendUpdates(Account account, String authtoken, Date lastUpdated)
-        throws JSONException, ParseException, IOException, AuthenticationException {
-
-        final ArrayList<User> friendList = new ArrayList<User>();
+        // Prepare our POST data
         final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
         params.add(new BasicNameValuePair(PARAM_USERNAME, account.name));
-        params.add(new BasicNameValuePair(PARAM_PASSWORD, authtoken));
-        if (lastUpdated != null) {
-            final SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm");
-            formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
-            params.add(new BasicNameValuePair(PARAM_UPDATED, formatter.format(lastUpdated)));
+        params.add(new BasicNameValuePair(PARAM_AUTH_TOKEN, authtoken));
+        params.add(new BasicNameValuePair(PARAM_CONTACTS_DATA, buffer.toString()));
+        if (serverSyncState > 0) {
+            params.add(new BasicNameValuePair(PARAM_SYNC_STATE, Long.toString(serverSyncState)));
         }
         Log.i(TAG, params.toString());
-        HttpEntity entity = null;
-        entity = new UrlEncodedFormEntity(params);
-        final HttpPost post = new HttpPost(FETCH_FRIEND_UPDATES_URI);
+        HttpEntity entity = new UrlEncodedFormEntity(params);
+
+        // Send the updated friends data to the server
+        Log.i(TAG, "Syncing to: " + SYNC_CONTACTS_URI);
+        final HttpPost post = new HttpPost(SYNC_CONTACTS_URI);
         post.addHeader(entity.getContentType());
         post.setEntity(entity);
-        maybeCreateHttpClient();
-        final HttpResponse resp = mHttpClient.execute(post);
+        final HttpResponse resp = getHttpClient().execute(post);
         final String response = EntityUtils.toString(resp.getEntity());
         if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
-            // Succesfully connected to the samplesyncadapter server and
-            // authenticated.
-            // Extract friends data in json format.
-            final JSONArray friends = new JSONArray(response);
+            // Our request to the server was successful - so we assume
+            // that they accepted all the changes we sent up, and
+            // that the response includes the contacts that we need
+            // to update on our side...
+            final JSONArray serverContacts = new JSONArray(response);
             Log.d(TAG, response);
-            for (int i = 0; i < friends.length(); i++) {
-                friendList.add(User.valueOf(friends.getJSONObject(i)));
+            for (int i = 0; i < serverContacts.length(); i++) {
+                RawContact rawContact = RawContact.valueOf(serverContacts.getJSONObject(i));
+                if (rawContact != null) {
+                    serverDirtyList.add(rawContact);
+                }
             }
         } else {
             if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
-                Log.e(TAG, "Authentication exception in fetching remote contacts");
+                Log.e(TAG, "Authentication exception in sending dirty contacts");
                 throw new AuthenticationException();
             } else {
-                Log.e(TAG, "Server error in fetching remote contacts: " + resp.getStatusLine());
+                Log.e(TAG, "Server error in sending dirty contacts: " + resp.getStatusLine());
                 throw new IOException();
             }
         }
-        return friendList;
+
+        return serverDirtyList;
     }
 
     /**
-     * Fetches status messages for the user's friends from the server
-     * 
-     * @param account The account being synced.
-     * @param authtoken The authtoken stored in the AccountManager for the
-     *        account
-     * @return list The list of status messages received from the server.
+     * Download the avatar image from the server.
+     *
+     * @param avatarUrl the URL pointing to the avatar image
+     * @return a byte array with the raw JPEG avatar image
      */
-    public static List<User.Status> fetchFriendStatuses(Account account, String authtoken)
-        throws JSONException, ParseException, IOException, AuthenticationException {
-
-        final ArrayList<User.Status> statusList = new ArrayList<User.Status>();
-        final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
-        params.add(new BasicNameValuePair(PARAM_USERNAME, account.name));
-        params.add(new BasicNameValuePair(PARAM_PASSWORD, authtoken));
-        HttpEntity entity = null;
-        entity = new UrlEncodedFormEntity(params);
-        final HttpPost post = new HttpPost(FETCH_STATUS_URI);
-        post.addHeader(entity.getContentType());
-        post.setEntity(entity);
-        maybeCreateHttpClient();
-        final HttpResponse resp = mHttpClient.execute(post);
-        final String response = EntityUtils.toString(resp.getEntity());
-        if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
-            // Succesfully connected to the samplesyncadapter server and
-            // authenticated.
-            // Extract friends data in json format.
-            final JSONArray statuses = new JSONArray(response);
-            for (int i = 0; i < statuses.length(); i++) {
-                statusList.add(User.Status.valueOf(statuses.getJSONObject(i)));
-            }
-        } else {
-            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
-                Log.e(TAG, "Authentication exception in fetching friend status list");
-                throw new AuthenticationException();
-            } else {
-                Log.e(TAG, "Server error in fetching friend status list");
-                throw new IOException();
-            }
+    public static byte[] downloadAvatar(final String avatarUrl) {
+        // If there is no avatar, we're done
+        if (TextUtils.isEmpty(avatarUrl)) {
+            return null;
         }
-        return statusList;
+
+        try {
+            Log.i(TAG, "Downloading avatar: " + avatarUrl);
+            // Request the avatar image from the server, and create a bitmap
+            // object from the stream we get back.
+            URL url = new URL(avatarUrl);
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+            connection.connect();
+            try {
+                final BitmapFactory.Options options = new BitmapFactory.Options();
+                final Bitmap avatar = BitmapFactory.decodeStream(connection.getInputStream(),
+                        null, options);
+
+                // Take the image we received from the server, whatever format it
+                // happens to be in, and convert it to a JPEG image. Note: we're
+                // not resizing the avatar - we assume that the image we get from
+                // the server is a reasonable size...
+                Log.i(TAG, "Converting avatar to JPEG");
+                ByteArrayOutputStream convertStream = new ByteArrayOutputStream(
+                        avatar.getWidth() * avatar.getHeight() * 4);
+                avatar.compress(Bitmap.CompressFormat.JPEG, 95, convertStream);
+                convertStream.flush();
+                convertStream.close();
+                // On pre-Honeycomb systems, it's important to call recycle on bitmaps
+                avatar.recycle();
+                return convertStream.toByteArray();
+            } finally {
+                connection.disconnect();
+            }
+        } catch (MalformedURLException muex) {
+            // A bad URL - nothing we can really do about it here...
+            Log.e(TAG, "Malformed avatar URL: " + avatarUrl);
+        } catch (IOException ioex) {
+            // If we're unable to download the avatar, it's a bummer but not the
+            // end of the world. We'll try to get it next time we sync.
+            Log.e(TAG, "Failed to download user avatar: " + avatarUrl);
+        }
+        return null;
     }
+
 }
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/RawContact.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/RawContact.java
new file mode 100644
index 0000000..6aa73d9
--- /dev/null
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/RawContact.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * 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.example.android.samplesync.client;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.json.JSONObject;
+import org.json.JSONException;
+
+import java.lang.StringBuilder;
+
+/**
+ * Represents a low-level contacts RawContact - or at least
+ * the fields of the RawContact that we care about.
+ */
+final public class RawContact {
+
+    /** The tag used to log to adb console. **/
+    private static final String TAG = "RawContact";
+
+    private final String mUserName;
+
+    private final String mFullName;
+
+    private final String mFirstName;
+
+    private final String mLastName;
+
+    private final String mCellPhone;
+
+    private final String mOfficePhone;
+
+    private final String mHomePhone;
+
+    private final String mEmail;
+
+    private final String mStatus;
+
+    private final String mAvatarUrl;
+
+    private final boolean mDeleted;
+
+    private final boolean mDirty;
+
+    private final long mServerContactId;
+
+    private final long mRawContactId;
+
+    private final long mSyncState;
+
+    public long getServerContactId() {
+        return mServerContactId;
+    }
+
+    public long getRawContactId() {
+        return mRawContactId;
+    }
+
+    public String getUserName() {
+        return mUserName;
+    }
+
+    public String getFirstName() {
+        return mFirstName;
+    }
+
+    public String getLastName() {
+        return mLastName;
+    }
+
+    public String getFullName() {
+        return mFullName;
+    }
+
+    public String getCellPhone() {
+        return mCellPhone;
+    }
+
+    public String getOfficePhone() {
+        return mOfficePhone;
+    }
+
+    public String getHomePhone() {
+        return mHomePhone;
+    }
+
+    public String getEmail() {
+        return mEmail;
+    }
+
+    public String getStatus() {
+        return mStatus;
+    }
+
+    public String getAvatarUrl() {
+        return mAvatarUrl;
+    }
+
+    public boolean isDeleted() {
+        return mDeleted;
+    }
+
+    public boolean isDirty() {
+        return mDirty;
+    }
+
+    public long getSyncState() {
+        return mSyncState;
+    }
+
+    public String getBestName() {
+        if (!TextUtils.isEmpty(mFullName)) {
+            return mFullName;
+        } else if (TextUtils.isEmpty(mFirstName)) {
+            return mLastName;
+        } else {
+            return mFirstName;
+        }
+    }
+
+    /**
+     * Convert the RawContact object into a JSON string.  From the
+     * JSONString interface.
+     * @return a JSON string representation of the object
+     */
+    public JSONObject toJSONObject() {
+        JSONObject json = new JSONObject();
+
+        try {
+            if (!TextUtils.isEmpty(mFirstName)) {
+                json.put("f", mFirstName);
+            }
+            if (!TextUtils.isEmpty(mLastName)) {
+                json.put("l", mLastName);
+            }
+            if (!TextUtils.isEmpty(mCellPhone)) {
+                json.put("m", mCellPhone);
+            }
+            if (!TextUtils.isEmpty(mOfficePhone)) {
+                json.put("o", mOfficePhone);
+            }
+            if (!TextUtils.isEmpty(mHomePhone)) {
+                json.put("h", mHomePhone);
+            }
+            if (!TextUtils.isEmpty(mEmail)) {
+                json.put("e", mEmail);
+            }
+            if (mServerContactId > 0) {
+                json.put("i", mServerContactId);
+            }
+            if (mRawContactId > 0) {
+                json.put("c", mRawContactId);
+            }
+            if (mDeleted) {
+                json.put("d", mDeleted);
+            }
+        } catch (final Exception ex) {
+            Log.i(TAG, "Error converting RawContact to JSONObject" + ex.toString());
+        }
+
+        return json;
+    }
+
+    public RawContact(String name, String fullName, String firstName, String lastName,
+            String cellPhone, String officePhone, String homePhone, String email,
+            String status, String avatarUrl, boolean deleted, long serverContactId,
+            long rawContactId, long syncState, boolean dirty) {
+        mUserName = name;
+        mFullName = fullName;
+        mFirstName = firstName;
+        mLastName = lastName;
+        mCellPhone = cellPhone;
+        mOfficePhone = officePhone;
+        mHomePhone = homePhone;
+        mEmail = email;
+        mStatus = status;
+        mAvatarUrl = avatarUrl;
+        mDeleted = deleted;
+        mServerContactId = serverContactId;
+        mRawContactId = rawContactId;
+        mSyncState = syncState;
+        mDirty = dirty;
+    }
+
+    /**
+     * Creates and returns an instance of the RawContact from the provided JSON data.
+     *
+     * @param user The JSONObject containing user data
+     * @return user The new instance of Sample RawContact created from the JSON data.
+     */
+    public static RawContact valueOf(JSONObject contact) {
+
+        try {
+            final String userName = !contact.isNull("u") ? contact.getString("u") : null;
+            final int serverContactId = !contact.isNull("i") ? contact.getInt("i") : -1;
+            // If we didn't get either a username or serverId for the contact, then
+            // we can't do anything with it locally...
+            if ((userName == null) && (serverContactId <= 0)) {
+                throw new JSONException("JSON contact missing required 'u' or 'i' fields");
+            }
+
+            final int rawContactId = !contact.isNull("c") ? contact.getInt("c") : -1;
+            final String firstName = !contact.isNull("f")  ? contact.getString("f") : null;
+            final String lastName = !contact.isNull("l") ? contact.getString("l") : null;
+            final String cellPhone = !contact.isNull("m") ? contact.getString("m") : null;
+            final String officePhone = !contact.isNull("o") ? contact.getString("o") : null;
+            final String homePhone = !contact.isNull("h") ? contact.getString("h") : null;
+            final String email = !contact.isNull("e") ? contact.getString("e") : null;
+            final String status = !contact.isNull("s") ? contact.getString("s") : null;
+            final String avatarUrl = !contact.isNull("a") ? contact.getString("a") : null;
+            final boolean deleted = !contact.isNull("d") ? contact.getBoolean("d") : false;
+            final long syncState = !contact.isNull("x") ? contact.getLong("x") : 0;
+            return new RawContact(userName, null, firstName, lastName, cellPhone,
+                    officePhone, homePhone, email, status, avatarUrl, deleted,
+                    serverContactId, rawContactId, syncState, false);
+        } catch (final Exception ex) {
+            Log.i(TAG, "Error parsing JSON contact object" + ex.toString());
+        }
+        return null;
+    }
+
+    /**
+     * Creates and returns RawContact instance from all the supplied parameters.
+     */
+    public static RawContact create(String fullName, String firstName, String lastName,
+            String cellPhone, String officePhone, String homePhone,
+            String email, String status, boolean deleted, long rawContactId,
+            long serverContactId) {
+        return new RawContact(null, fullName, firstName, lastName, cellPhone, officePhone,
+                homePhone, email, status, null, deleted, serverContactId, rawContactId,
+                -1, true);
+    }
+
+    /**
+     * Creates and returns a User instance that represents a deleted user.
+     * Since the user is deleted, all we need are the client/server IDs.
+     * @param clientUserId The client-side ID for the contact
+     * @param serverUserId The server-side ID for the contact
+     * @return a minimal User object representing the deleted contact.
+     */
+    public static RawContact createDeletedContact(long rawContactId, long serverContactId)
+    {
+        return new RawContact(null, null, null, null, null, null, null,
+                null, null, null, true, serverContactId, rawContactId, -1, true);
+    }
+}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/User.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/User.java
deleted file mode 100644
index 217a383..0000000
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/User.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * 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.example.android.samplesync.client;
-
-import android.util.Log;
-
-import org.json.JSONObject;
-
-/**
- * Represents a sample SyncAdapter user
- */
-final public class User {
-
-    private final String mUserName;
-
-    private final String mFirstName;
-
-    private final String mLastName;
-
-    private final String mCellPhone;
-
-    private final String mOfficePhone;
-
-    private final String mHomePhone;
-
-    private final String mEmail;
-
-    private final boolean mDeleted;
-
-    private final int mUserId;
-
-    public int getUserId() {
-        return mUserId;
-    }
-
-    public String getUserName() {
-        return mUserName;
-    }
-
-    public String getFirstName() {
-        return mFirstName;
-    }
-
-    public String getLastName() {
-        return mLastName;
-    }
-
-    public String getCellPhone() {
-        return mCellPhone;
-    }
-
-    public String getOfficePhone() {
-        return mOfficePhone;
-    }
-
-    public String getHomePhone() {
-        return mHomePhone;
-    }
-
-    public String getEmail() {
-        return mEmail;
-    }
-
-    public boolean isDeleted() {
-        return mDeleted;
-    }
-
-    private User(String name, String firstName, String lastName, String cellPhone,
-        String officePhone, String homePhone, String email, Boolean deleted, Integer userId) {
-
-        mUserName = name;
-        mFirstName = firstName;
-        mLastName = lastName;
-        mCellPhone = cellPhone;
-        mOfficePhone = officePhone;
-        mHomePhone = homePhone;
-        mEmail = email;
-        mDeleted = deleted;
-        mUserId = userId;
-    }
-
-    /**
-     * Creates and returns an instance of the user from the provided JSON data.
-     * 
-     * @param user The JSONObject containing user data
-     * @return user The new instance of Voiper user created from the JSON data.
-     */
-    public static User valueOf(JSONObject user) {
-
-        try {
-            final String userName = user.getString("u");
-            final String firstName = user.has("f") ? user.getString("f") : null;
-            final String lastName = user.has("l") ? user.getString("l") : null;
-            final String cellPhone = user.has("m") ? user.getString("m") : null;
-            final String officePhone = user.has("o") ? user.getString("o") : null;
-            final String homePhone = user.has("h") ? user.getString("h") : null;
-            final String email = user.has("e") ? user.getString("e") : null;
-            final boolean deleted = user.has("d") ? user.getBoolean("d") : false;
-            final int userId = user.getInt("i");
-            return new User(userName, firstName, lastName, cellPhone, officePhone, homePhone,
-                email, deleted, userId);
-        } catch (final Exception ex) {
-            Log.i("User", "Error parsing JSON user object" + ex.toString());
-        }
-        return null;
-    }
-
-    /**
-     * Represents the User's status messages
-     * 
-     */
-    final public static class Status {
-
-        private final Integer mUserId;
-
-        private final String mStatus;
-
-        public int getUserId() {
-            return mUserId;
-        }
-
-        public String getStatus() {
-            return mStatus;
-        }
-
-        public Status(Integer userId, String status) {
-            mUserId = userId;
-            mStatus = status;
-        }
-
-        public static User.Status valueOf(JSONObject userStatus) {
-            try {
-                final int userId = userStatus.getInt("i");
-                final String status = userStatus.getString("s");
-                return new User.Status(userId, status);
-            } catch (final Exception ex) {
-                Log.i("User.Status", "Error parsing JSON user object");
-            }
-            return null;
-        }
-    }
-}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/editor/ContactEditorActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/editor/ContactEditorActivity.java
new file mode 100644
index 0000000..2e30be7
--- /dev/null
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/editor/ContactEditorActivity.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * 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.example.android.samplesync.editor;
+
+import com.example.android.samplesync.R;
+import com.example.android.samplesync.client.RawContact;
+import com.example.android.samplesync.platform.BatchOperation;
+import com.example.android.samplesync.platform.ContactManager;
+import com.example.android.samplesync.platform.ContactManager.EditorQuery;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.RawContacts;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.EditText;
+import android.widget.TextView;
+
+/**
+ * Implements a sample editor for a contact that belongs to a remote contact service.
+ * The editor can be invoked for an existing SampleSyncAdapter contact, or it can
+ * be used to create a brand new SampleSyncAdapter contact. We look at the Intent
+ * object to figure out whether this is a "new" or "edit" operation.
+ */
+public class ContactEditorActivity extends Activity {
+    private static final String TAG = "SampleSyncAdapter";
+
+    // Keep track of whether we're inserting a new contact or editing an
+    // existing contact.
+    private boolean mIsInsert;
+
+    // The name of the external account we're syncing this contact to.
+    private String mAccountName;
+
+    // For existing contacts, this is the URI to the contact data.
+    private Uri mRawContactUri;
+
+    // The raw clientId for this contact
+    private long mRawContactId;
+
+    // Make sure we only attempt to save the contact once if the
+    // user presses the "done" button multiple times...
+    private boolean mSaveInProgress = false;
+
+    // Keep track of the controls used to edit contact values, so we can get/set
+    // those values easily.
+    private EditText mNameEditText;
+    private EditText mHomePhoneEditText;
+    private EditText mMobilePhoneEditText;
+    private EditText mWorkPhoneEditText;
+    private EditText mEmailEditText;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.editor);
+
+        mNameEditText = (EditText)findViewById(R.id.editor_name);
+        mHomePhoneEditText = (EditText)findViewById(R.id.editor_phone_home);
+        mMobilePhoneEditText = (EditText)findViewById(R.id.editor_phone_mobile);
+        mWorkPhoneEditText = (EditText)findViewById(R.id.editor_phone_work);
+        mEmailEditText = (EditText)findViewById(R.id.editor_email);
+
+        // Figure out whether we're creating a new contact (ACTION_INSERT) or editing
+        // an existing contact.
+        Intent intent = getIntent();
+        String action = intent.getAction();
+        if (Intent.ACTION_INSERT.equals(action)) {
+            // We're inserting a new contact, so save off the external account name
+            // which should have been added to the intent we were passed.
+            mIsInsert = true;
+            String accountName = intent.getStringExtra(RawContacts.ACCOUNT_NAME);
+            if (accountName == null) {
+                Log.e(TAG, "Account name is required");
+                finish();
+            }
+            setAccountName(accountName);
+        } else {
+            // We're editing an existing contact. Load in the data from the contact
+            // so that the user can edit it.
+            mIsInsert = false;
+            mRawContactUri = intent.getData();
+            if (mRawContactUri == null) {
+                Log.e(TAG, "Raw contact URI is required");
+                finish();
+            }
+            startLoadRawContactEntity();
+        }
+    }
+
+    @Override
+    public void onBackPressed() {
+        // This method will have been called if the user presses the "Back" button
+        // in the ActionBar.  We treat that the same way as the "Done" button in
+        // the ActionBar.
+        save();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // This method gets called so that we can place items in the main Options menu -
+        // for example, the ActionBar items.  We add our menus from the res/menu/edit.xml
+        // file.
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.edit, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+            case R.id.menu_done:
+                // The user pressed the "Home" button or our "Done" button - both
+                // in the ActionBar.  In both cases, we want to save the contact
+                // and exit.
+                save();
+                return true;
+            case R.id.menu_cancel:
+                // The user pressed the Cancel menu item in the ActionBar.
+                // Close the editor without saving any changes.
+                finish();
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Create an AsyncTask to load the contact from the Contacts data provider
+     */
+    private void startLoadRawContactEntity() {
+        Uri uri = Uri.withAppendedPath(mRawContactUri, RawContacts.Entity.CONTENT_DIRECTORY);
+        new LoadRawContactTask().execute(uri);
+    }
+
+    /**
+     * Called by the LoadRawContactTask when the contact information has been
+     * successfully loaded from the Contacts data provider.
+     */
+    public void onRawContactEntityLoaded(Cursor cursor) {
+        while (cursor.moveToNext()) {
+            String mimetype = cursor.getString(EditorQuery.COLUMN_MIMETYPE);
+            if (StructuredName.CONTENT_ITEM_TYPE.equals(mimetype)) {
+                setAccountName(cursor.getString(EditorQuery.COLUMN_ACCOUNT_NAME));
+                mRawContactId = cursor.getLong(EditorQuery.COLUMN_RAW_CONTACT_ID);
+                mNameEditText.setText(cursor.getString(EditorQuery.COLUMN_FULL_NAME));
+            } else if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
+                final int type = cursor.getInt(EditorQuery.COLUMN_PHONE_TYPE);
+                if (type == Phone.TYPE_HOME) {
+                    mHomePhoneEditText.setText(cursor.getString(EditorQuery.COLUMN_PHONE_NUMBER));
+                } else if (type == Phone.TYPE_MOBILE) {
+                    mMobilePhoneEditText.setText(cursor.getString(EditorQuery.COLUMN_PHONE_NUMBER));
+                } else if (type == Phone.TYPE_WORK) {
+                    mWorkPhoneEditText.setText(cursor.getString(EditorQuery.COLUMN_PHONE_NUMBER));
+                }
+            } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
+                mEmailEditText.setText(cursor.getString(EditorQuery.COLUMN_DATA1));
+            }
+        }
+    }
+
+    /**
+     * Save the updated contact data. We actually take two different actions
+     * depending on whether we are creating a new contact or editing an
+     * existing contact.
+     */
+    public void save() {
+        // If we're already saving this contact, don't kick-off yet
+        // another save - the user probably just pressed the "Done"
+        // button multiple times...
+        if (mSaveInProgress) {
+            return;
+        }
+
+        mSaveInProgress = true;
+        if (mIsInsert) {
+            saveNewContact();
+        } else {
+            saveChanges();
+        }
+    }
+
+    /**
+     * Save off the external contacts provider account name. We show the account name
+     * in the header section of the edit panel, and we also need it later when we
+     * save off a brand new contact.
+     */
+    private void setAccountName(String accountName) {
+        mAccountName = accountName;
+        if (accountName != null) {
+            TextView accountNameLabel = (TextView)findViewById(R.id.header_account_name);
+            if (accountNameLabel != null) {
+                accountNameLabel.setText(accountName);
+            }
+        }
+    }
+
+    /**
+     * Save a new contact using the Contacts content provider. The actual insertion
+     * is performed in an AsyncTask.
+     */
+    @SuppressWarnings("unchecked")
+    private void saveNewContact() {
+        new InsertContactTask().execute(buildRawContact());
+    }
+
+    /**
+     * Save changes to an existing contact.  The actual update is performed in
+     * an AsyncTask.
+     */
+    @SuppressWarnings("unchecked")
+    private void saveChanges() {
+        new UpdateContactTask().execute(buildRawContact());
+    }
+
+    /**
+     * Build a RawContact object from the data in the user-editable form
+     * @return a new RawContact object representing the edited user
+     */
+    private RawContact buildRawContact() {
+        return RawContact.create(mNameEditText.getText().toString(),
+                null,
+                null,
+                mMobilePhoneEditText.getText().toString(),
+                mWorkPhoneEditText.getText().toString(),
+                mHomePhoneEditText.getText().toString(),
+                mEmailEditText.getText().toString(),
+                null,
+                false,
+                mRawContactId,
+                -1);
+    }
+
+    /**
+     * Called after a contact is saved - both for edited contacts and new contacts.
+     * We set the final result of the activity to be "ok", and then close the activity
+     * by calling finish().
+     */
+    public void onContactSaved(Uri result) {
+        if (result != null) {
+            Intent intent = new Intent();
+            intent.setData(result);
+            setResult(RESULT_OK, intent);
+            finish();
+        }
+        mSaveInProgress = false;
+    }
+
+    /**
+     * Represents an asynchronous task used to load a contact from
+     * the Contacts content provider.
+     *
+     */
+    public class LoadRawContactTask extends AsyncTask<Uri, Void, Cursor> {
+
+        @Override
+        protected Cursor doInBackground(Uri... params) {
+            // Our background task is to load the contact from the Contacts provider
+            return getContentResolver().query(params[0], EditorQuery.PROJECTION, null, null, null);
+        }
+
+        @Override
+        protected void onPostExecute(Cursor cursor) {
+            // After we've successfully loaded the contact, call back into
+            // the ContactEditorActivity so we can update the UI
+            try {
+                if (cursor != null) {
+                    onRawContactEntityLoaded(cursor);
+                }
+            } finally {
+                cursor.close();
+            }
+        }
+    }
+
+    /**
+     * Represents an asynchronous task used to save a new contact
+     * into the contacts database.
+     */
+    public class InsertContactTask extends AsyncTask<RawContact, Void, Uri> {
+
+        @Override
+        protected Uri doInBackground(RawContact... params) {
+            try {
+                final RawContact rawContact = params[0];
+                final Context context = getApplicationContext();
+                final ContentResolver resolver = getContentResolver();
+                final BatchOperation batchOperation = new BatchOperation(context, resolver);
+                ContactManager.addContact(context, mAccountName, rawContact, false, batchOperation);
+                Uri rawContactUri = batchOperation.execute();
+
+                // Convert the raw contact URI to a contact URI
+                if (rawContactUri != null) {
+                    return RawContacts.getContactLookupUri(resolver, rawContactUri);
+                } else {
+                    Log.e(TAG, "Could not save new contact");
+                    return null;
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "An error occurred while saving new contact", e);
+            }
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(Uri result) {
+            // Tell the UI that the contact has been successfully saved
+            onContactSaved(result);
+        }
+    }
+
+
+    /**
+     * Represents an asynchronous task used to save an updated contact
+     * into the contacts database.
+     */
+    public class UpdateContactTask extends AsyncTask<RawContact, Void, Uri> {
+
+        @Override
+        protected Uri doInBackground(RawContact... params) {
+            try {
+                final RawContact rawContact = params[0];
+                final Context context = getApplicationContext();
+                final ContentResolver resolver = getContentResolver();
+                final BatchOperation batchOperation = new BatchOperation(context, resolver);
+                ContactManager.updateContact(context, resolver, rawContact, false, false, false,
+                        false, rawContact.getRawContactId(), batchOperation);
+                batchOperation.execute();
+
+                // Convert the raw contact URI to a contact URI
+                return RawContacts.getContactLookupUri(resolver, mRawContactUri);
+            } catch (Exception e) {
+                Log.e(TAG, "Could not save changes", e);
+            }
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(Uri result) {
+            // Tell the UI that the contact has been successfully saved
+            onContactSaved(result);
+        }
+    }
+}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java
index 0be3daa..3a9c879 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java
@@ -1,12 +1,12 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -16,9 +16,11 @@
 package com.example.android.samplesync.platform;
 
 import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.OperationApplicationException;
+import android.net.Uri;
 import android.os.RemoteException;
 import android.provider.ContactsContract;
 import android.util.Log;
@@ -50,19 +52,24 @@
         mOperations.add(cpo);
     }
 
-    public void execute() {
+    public Uri execute() {
+        Uri result = null;
 
         if (mOperations.size() == 0) {
-            return;
+            return result;
         }
         // Apply the mOperations to the content provider
         try {
-            mResolver.applyBatch(ContactsContract.AUTHORITY, mOperations);
+            ContentProviderResult[] results = mResolver.applyBatch(ContactsContract.AUTHORITY,
+                    mOperations);
+            if ((results != null) && (results.length > 0))
+                result = results[0].uri;
         } catch (final OperationApplicationException e1) {
             Log.e(TAG, "storing contact data failed", e1);
         } catch (final RemoteException e2) {
             Log.e(TAG, "storing contact data failed", e2);
         }
         mOperations.clear();
+        return result;
     }
 }
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
index 218b165..2335d38 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
@@ -1,12 +1,12 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -15,25 +15,30 @@
  */
 package com.example.android.samplesync.platform;
 
+import com.example.android.samplesync.Constants;
+import com.example.android.samplesync.R;
+import com.example.android.samplesync.client.RawContact;
+
+import android.accounts.Account;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.StatusUpdates;
+import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Im;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.Settings;
+import android.provider.ContactsContract.StatusUpdates;
 import android.util.Log;
 
-import com.example.android.samplesync.Constants;
-import com.example.android.samplesync.R;
-import com.example.android.samplesync.client.User;
-
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -49,81 +54,172 @@
     private static final String TAG = "ContactManager";
 
     /**
-     * Synchronize raw contacts
-     * 
+     * Take a list of updated contacts and apply those changes to the
+     * contacts database. Typically this list of contacts would have been
+     * returned from the server, and we want to apply those changes locally.
+     *
      * @param context The context of Authenticator Activity
      * @param account The username for the account
-     * @param users The list of users
+     * @param rawContacts The list of contacts to update
+     * @param lastSyncMarker The previous server sync-state
+     * @return the server syncState that should be used in our next
+     * sync request.
      */
-    public static synchronized void syncContacts(Context context, String account, List<User> users) {
+    public static synchronized long updateContacts(Context context, String account,
+            List<RawContact> rawContacts, long lastSyncMarker) {
 
-        long userId;
-        long rawContactId = 0;
+        long currentSyncMarker = lastSyncMarker;
         final ContentResolver resolver = context.getContentResolver();
         final BatchOperation batchOperation = new BatchOperation(context, resolver);
+        final List<RawContact> newUsers = new ArrayList<RawContact>();
+
         Log.d(TAG, "In SyncContacts");
-        for (final User user : users) {
-            userId = user.getUserId();
-            // Check to see if the contact needs to be inserted or updated
-            rawContactId = lookupRawContact(resolver, userId);
+        for (final RawContact rawContact : rawContacts) {
+            // The server returns a syncState (x) value with each contact record.
+            // The syncState is sequential, so higher values represent more recent
+            // changes than lower values. We keep track of the highest value we
+            // see, and consider that a "high water mark" for the changes we've
+            // received from the server.  That way, on our next sync, we can just
+            // ask for changes that have occurred since that most-recent change.
+            if (rawContact.getSyncState() > currentSyncMarker) {
+                currentSyncMarker = rawContact.getSyncState();
+            }
+
+            // If the server returned a clientId for this user, then it's likely
+            // that the user was added here, and was just pushed to the server
+            // for the first time. In that case, we need to update the main
+            // row for this contact so that the RawContacts.SOURCE_ID value
+            // contains the correct serverId.
+            final long rawContactId;
+            final boolean updateServerId;
+            if (rawContact.getRawContactId() > 0) {
+                rawContactId = rawContact.getRawContactId();
+                updateServerId = true;
+            } else {
+                long serverContactId = rawContact.getServerContactId();
+                rawContactId = lookupRawContact(resolver, serverContactId);
+                updateServerId = false;
+            }
             if (rawContactId != 0) {
-                if (!user.isDeleted()) {
-                    // update contact
-                    updateContact(context, resolver, account, user, rawContactId, batchOperation);
+                if (!rawContact.isDeleted()) {
+                    updateContact(context, resolver, rawContact, updateServerId,
+                            true, true, true, rawContactId, batchOperation);
                 } else {
-                    // delete contact
                     deleteContact(context, rawContactId, batchOperation);
                 }
             } else {
-                // add new contact
                 Log.d(TAG, "In addContact");
-                if (!user.isDeleted()) {
-                    addContact(context, account, user, batchOperation);
+                if (!rawContact.isDeleted()) {
+                    newUsers.add(rawContact);
+                    addContact(context, account, rawContact, true, batchOperation);
                 }
             }
             // A sync adapter should batch operations on multiple contacts,
             // because it will make a dramatic performance difference.
+            // (UI updates, etc)
             if (batchOperation.size() >= 50) {
                 batchOperation.execute();
             }
         }
         batchOperation.execute();
+
+        return currentSyncMarker;
     }
 
     /**
-     * Add a list of status messages to the contacts provider.
-     * 
-     * @param context the context to use
-     * @param accountName the username of the logged in user
-     * @param statuses the list of statuses to store
+     * Return a list of the local contacts that have been marked as
+     * "dirty", and need syncing to the SampleSync server.
+     *
+     * @param context The context of Authenticator Activity
+     * @param account The account that we're interested in syncing
+     * @return a list of Users that are considered "dirty"
      */
-    public static void insertStatuses(Context context, String username, List<User.Status> list) {
+    public static List<RawContact> getDirtyContacts(Context context, Account account) {
+        Log.i(TAG, "*** Looking for local dirty contacts");
+        List<RawContact> dirtyContacts = new ArrayList<RawContact>();
 
-        final ContentValues values = new ContentValues();
+        final ContentResolver resolver = context.getContentResolver();
+        final Cursor c = resolver.query(DirtyQuery.CONTENT_URI,
+                DirtyQuery.PROJECTION,
+                DirtyQuery.SELECTION,
+                new String[] {account.name},
+                null);
+        try {
+            while (c.moveToNext()) {
+                final long rawContactId = c.getLong(DirtyQuery.COLUMN_RAW_CONTACT_ID);
+                final long serverContactId = c.getLong(DirtyQuery.COLUMN_SERVER_ID);
+                final boolean isDirty = "1".equals(c.getString(DirtyQuery.COLUMN_DIRTY));
+                final boolean isDeleted = "1".equals(c.getString(DirtyQuery.COLUMN_DELETED));
+
+                // The system actually keeps track of a change version number for
+                // each contact. It may be something you're interested in for your
+                // client-server sync protocol. We're not using it in this example,
+                // other than to log it.
+                final long version = c.getLong(DirtyQuery.COLUMN_VERSION);
+
+                Log.i(TAG, "Dirty Contact: " + Long.toString(rawContactId));
+                Log.i(TAG, "Contact Version: " + Long.toString(version));
+
+                if (isDeleted) {
+                    Log.i(TAG, "Contact is marked for deletion");
+                    RawContact rawContact = RawContact.createDeletedContact(rawContactId,
+                            serverContactId);
+                    dirtyContacts.add(rawContact);
+                } else if (isDirty) {
+                    RawContact rawContact = getRawContact(context, rawContactId);
+                    Log.i(TAG, "Contact Name: " + rawContact.getBestName());
+                    dirtyContacts.add(rawContact);
+                }
+            }
+
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        return dirtyContacts;
+    }
+
+    /**
+     * Update the status messages for a list of users.  This is typically called
+     * for contacts we've just added to the system, since we can't monkey with
+     * the contact's status until they have a profileId.
+     *
+     * @param context The context of Authenticator Activity
+     * @param rawContacts The list of users we want to update
+     */
+    public static void updateStatusMessages(Context context, List<RawContact> rawContacts) {
         final ContentResolver resolver = context.getContentResolver();
         final BatchOperation batchOperation = new BatchOperation(context, resolver);
-        for (final User.Status status : list) {
-            // Look up the user's sample SyncAdapter data row
-            final long userId = status.getUserId();
-            final long profileId = lookupProfile(resolver, userId);
-            // Insert the activity into the stream
-            if (profileId > 0) {
-                values.put(StatusUpdates.DATA_ID, profileId);
-                values.put(StatusUpdates.STATUS, status.getStatus());
-                values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_CUSTOM);
-                values.put(StatusUpdates.CUSTOM_PROTOCOL, CUSTOM_IM_PROTOCOL);
-                values.put(StatusUpdates.IM_ACCOUNT, username);
-                values.put(StatusUpdates.IM_HANDLE, status.getUserId());
-                values.put(StatusUpdates.STATUS_RES_PACKAGE, context.getPackageName());
-                values.put(StatusUpdates.STATUS_ICON, R.drawable.icon);
-                values.put(StatusUpdates.STATUS_LABEL, R.string.label);
-                batchOperation.add(ContactOperations.newInsertCpo(StatusUpdates.CONTENT_URI, true)
-                    .withValues(values).build());
-                // A sync adapter should batch operations on multiple contacts,
-                // because it will make a dramatic performance difference.
-                if (batchOperation.size() >= 50) {
-                    batchOperation.execute();
-                }
+        for (RawContact rawContact : rawContacts) {
+            updateContactStatus(context, rawContact, batchOperation);
+        }
+        batchOperation.execute();
+    }
+
+    /**
+     * After we've finished up a sync operation, we want to clean up the sync-state
+     * so that we're ready for the next time.  This involves clearing out the 'dirty'
+     * flag on the synced contacts - but we also have to finish the DELETE operation
+     * on deleted contacts.  When the user initially deletes them on the client, they're
+     * marked for deletion - but they're not actually deleted until we delete them
+     * again, and include the ContactsContract.CALLER_IS_SYNCADAPTER parameter to
+     * tell the contacts provider that we're really ready to let go of this contact.
+     *
+     * @param context The context of Authenticator Activity
+     * @param dirtyContacts The list of contacts that we're cleaning up
+     */
+    public static void clearSyncFlags(Context context, List<RawContact> dirtyContacts) {
+        Log.i(TAG, "*** Clearing Sync-related Flags");
+        final ContentResolver resolver = context.getContentResolver();
+        final BatchOperation batchOperation = new BatchOperation(context, resolver);
+        for (RawContact rawContact : dirtyContacts) {
+            if (rawContact.isDeleted()) {
+                Log.i(TAG, "Deleting contact: " + Long.toString(rawContact.getRawContactId()));
+                deleteContact(context, rawContact.getRawContactId(), batchOperation);
+            } else if (rawContact.isDirty()) {
+                Log.i(TAG, "Clearing dirty flag for: " + rawContact.getBestName());
+                clearDirtyFlag(context, rawContact.getRawContactId(), batchOperation);
             }
         }
         batchOperation.execute();
@@ -131,89 +227,312 @@
 
     /**
      * Adds a single contact to the platform contacts provider.
-     * 
+     * This can be used to respond to a new contact found as part
+     * of sync information returned from the server, or because a
+     * user added a new contact.
+     *
      * @param context the Authenticator Activity context
      * @param accountName the account the contact belongs to
-     * @param user the sample SyncAdapter User object
+     * @param rawContact the sample SyncAdapter User object
+     * @param inSync is the add part of a client-server sync?
+     * @param batchOperation allow us to batch together multiple operations
+     *        into a single provider call
      */
-    private static void addContact(Context context, String accountName, User user,
-        BatchOperation batchOperation) {
+    public static void addContact(Context context, String accountName, RawContact rawContact,
+        boolean inSync, BatchOperation batchOperation) {
 
         // Put the data in the contacts provider
-        final ContactOperations contactOp =
-            ContactOperations.createNewContact(context, user.getUserId(), accountName,
-                batchOperation);
-        contactOp.addName(user.getFirstName(), user.getLastName()).addEmail(user.getEmail())
-            .addPhone(user.getCellPhone(), Phone.TYPE_MOBILE).addPhone(user.getHomePhone(),
-                Phone.TYPE_OTHER).addProfileAction(user.getUserId());
+        final ContactOperations contactOp = ContactOperations.createNewContact(
+                context, rawContact.getServerContactId(), accountName, inSync, batchOperation);
+
+        contactOp.addName(rawContact.getFullName(), rawContact.getFirstName(),
+                rawContact.getLastName())
+                .addEmail(rawContact.getEmail())
+                .addPhone(rawContact.getCellPhone(), Phone.TYPE_MOBILE)
+                .addPhone(rawContact.getHomePhone(), Phone.TYPE_HOME)
+                .addPhone(rawContact.getOfficePhone(), Phone.TYPE_WORK)
+                .addAvatar(rawContact.getAvatarUrl());
+
+        // If we have a serverId, then go ahead and create our status profile.
+        // Otherwise skip it - and we'll create it after we sync-up to the
+        // server later on.
+        if (rawContact.getServerContactId() > 0) {
+            contactOp.addProfileAction(rawContact.getServerContactId());
+        }
     }
 
     /**
      * Updates a single contact to the platform contacts provider.
-     * 
+     * This method can be used to update a contact from a sync
+     * operation or as a result of a user editing a contact
+     * record.
+     *
+     * This operation is actually relatively complex.  We query
+     * the database to find all the rows of info that already
+     * exist for this Contact. For rows that exist (and thus we're
+     * modifying existing fields), we create an update operation
+     * to change that field.  But for fields we're adding, we create
+     * "add" operations to create new rows for those fields.
+     *
      * @param context the Authenticator Activity context
      * @param resolver the ContentResolver to use
-     * @param accountName the account the contact belongs to
-     * @param user the sample SyncAdapter contact object.
+     * @param rawContact the sample SyncAdapter contact object
+     * @param updateStatus should we update this user's status
+     * @param updateAvatar should we update this user's avatar image
+     * @param inSync is the update part of a client-server sync?
      * @param rawContactId the unique Id for this rawContact in contacts
      *        provider
+     * @param batchOperation allow us to batch together multiple operations
+     *        into a single provider call
      */
-    private static void updateContact(Context context, ContentResolver resolver,
-        String accountName, User user, long rawContactId, BatchOperation batchOperation) {
+    public static void updateContact(Context context, ContentResolver resolver,
+        RawContact rawContact, boolean updateServerId, boolean updateStatus, boolean updateAvatar,
+        boolean inSync, long rawContactId, BatchOperation batchOperation) {
 
-        Uri uri;
-        String cellPhone = null;
-        String otherPhone = null;
-        String email = null;
+        boolean existingCellPhone = false;
+        boolean existingHomePhone = false;
+        boolean existingWorkPhone = false;
+        boolean existingEmail = false;
+        boolean existingAvatar = false;
+
         final Cursor c =
-            resolver.query(Data.CONTENT_URI, DataQuery.PROJECTION, DataQuery.SELECTION,
+                resolver.query(DataQuery.CONTENT_URI, DataQuery.PROJECTION, DataQuery.SELECTION,
                 new String[] {String.valueOf(rawContactId)}, null);
         final ContactOperations contactOp =
-            ContactOperations.updateExistingContact(context, rawContactId, batchOperation);
+                ContactOperations.updateExistingContact(context, rawContactId,
+                inSync, batchOperation);
         try {
+            // Iterate over the existing rows of data, and update each one
+            // with the information we received from the server.
             while (c.moveToNext()) {
                 final long id = c.getLong(DataQuery.COLUMN_ID);
                 final String mimeType = c.getString(DataQuery.COLUMN_MIMETYPE);
-                uri = ContentUris.withAppendedId(Data.CONTENT_URI, id);
+                final Uri uri = ContentUris.withAppendedId(Data.CONTENT_URI, id);
                 if (mimeType.equals(StructuredName.CONTENT_ITEM_TYPE)) {
-                    final String lastName = c.getString(DataQuery.COLUMN_FAMILY_NAME);
-                    final String firstName = c.getString(DataQuery.COLUMN_GIVEN_NAME);
-                    contactOp.updateName(uri, firstName, lastName, user.getFirstName(), user
-                        .getLastName());
+                    contactOp.updateName(uri,
+                            c.getString(DataQuery.COLUMN_GIVEN_NAME),
+                            c.getString(DataQuery.COLUMN_FAMILY_NAME),
+                            c.getString(DataQuery.COLUMN_FULL_NAME),
+                            rawContact.getFirstName(),
+                            rawContact.getLastName(),
+                            rawContact.getFullName());
                 } else if (mimeType.equals(Phone.CONTENT_ITEM_TYPE)) {
                     final int type = c.getInt(DataQuery.COLUMN_PHONE_TYPE);
                     if (type == Phone.TYPE_MOBILE) {
-                        cellPhone = c.getString(DataQuery.COLUMN_PHONE_NUMBER);
-                        contactOp.updatePhone(cellPhone, user.getCellPhone(), uri);
-                    } else if (type == Phone.TYPE_OTHER) {
-                        otherPhone = c.getString(DataQuery.COLUMN_PHONE_NUMBER);
-                        contactOp.updatePhone(otherPhone, user.getHomePhone(), uri);
+                        existingCellPhone = true;
+                        contactOp.updatePhone(c.getString(DataQuery.COLUMN_PHONE_NUMBER),
+                                rawContact.getCellPhone(), uri);
+                    } else if (type == Phone.TYPE_HOME) {
+                        existingHomePhone = true;
+                        contactOp.updatePhone(c.getString(DataQuery.COLUMN_PHONE_NUMBER),
+                                rawContact.getHomePhone(), uri);
+                    } else if (type == Phone.TYPE_WORK) {
+                        existingWorkPhone = true;
+                        contactOp.updatePhone(c.getString(DataQuery.COLUMN_PHONE_NUMBER),
+                                rawContact.getOfficePhone(), uri);
                     }
-                } else if (Data.MIMETYPE.equals(Email.CONTENT_ITEM_TYPE)) {
-                    email = c.getString(DataQuery.COLUMN_EMAIL_ADDRESS);
-                    contactOp.updateEmail(user.getEmail(), email, uri);
+                } else if (mimeType.equals(Email.CONTENT_ITEM_TYPE)) {
+                    existingEmail = true;
+                    contactOp.updateEmail(rawContact.getEmail(),
+                            c.getString(DataQuery.COLUMN_EMAIL_ADDRESS), uri);
+                } else if (mimeType.equals(Photo.CONTENT_ITEM_TYPE)) {
+                    existingAvatar = true;
+                    contactOp.updateAvatar(rawContact.getAvatarUrl(), uri);
                 }
             } // while
         } finally {
             c.close();
         }
+
         // Add the cell phone, if present and not updated above
-        if (cellPhone == null) {
-            contactOp.addPhone(user.getCellPhone(), Phone.TYPE_MOBILE);
+        if (!existingCellPhone) {
+            contactOp.addPhone(rawContact.getCellPhone(), Phone.TYPE_MOBILE);
         }
-        // Add the other phone, if present and not updated above
-        if (otherPhone == null) {
-            contactOp.addPhone(user.getHomePhone(), Phone.TYPE_OTHER);
+        // Add the home phone, if present and not updated above
+        if (!existingHomePhone) {
+            contactOp.addPhone(rawContact.getHomePhone(), Phone.TYPE_HOME);
+        }
+
+        // Add the work phone, if present and not updated above
+        if (!existingWorkPhone) {
+            contactOp.addPhone(rawContact.getOfficePhone(), Phone.TYPE_WORK);
         }
         // Add the email address, if present and not updated above
-        if (email == null) {
-            contactOp.addEmail(user.getEmail());
+        if (!existingEmail) {
+            contactOp.addEmail(rawContact.getEmail());
+        }
+        // Add the avatar if we didn't update the existing avatar
+        if (!existingAvatar) {
+            contactOp.addAvatar(rawContact.getAvatarUrl());
+        }
+
+        // If we need to update the serverId of the contact record, take
+        // care of that.  This will happen if the contact is created on the
+        // client, and then synced to the server. When we get the updated
+        // record back from the server, we can set the SOURCE_ID property
+        // on the contact, so we can (in the future) lookup contacts by
+        // the serverId.
+        if (updateServerId) {
+            Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
+            contactOp.updateServerId(rawContact.getServerContactId(), uri);
+        }
+
+        // If we don't have a status profile, then create one.  This could
+        // happen for contacts that were created on the client - we don't
+        // create the status profile until after the first sync...
+        final long serverId = rawContact.getServerContactId();
+        final long profileId = lookupProfile(resolver, serverId);
+        if (profileId <= 0) {
+            contactOp.addProfileAction(serverId);
         }
     }
 
     /**
-     * Deletes a contact from the platform contacts provider.
-     * 
+     * When we first add a sync adapter to the system, the contacts from that
+     * sync adapter will be hidden unless they're merged/grouped with an existing
+     * contact.  But typically we want to actually show those contacts, so we
+     * need to mess with the Settings table to get them to show up.
+     *
+     * @param context the Authenticator Activity context
+     * @param account the Account who's visibility we're changing
+     * @param visible true if we want the contacts visible, false for hidden
+     */
+    public static void setAccountContactsVisibility(Context context, Account account,
+            boolean visible) {
+        ContentValues values = new ContentValues();
+        values.put(RawContacts.ACCOUNT_NAME, account.name);
+        values.put(RawContacts.ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
+        values.put(Settings.UNGROUPED_VISIBLE, visible ? 1 : 0);
+
+        context.getContentResolver().insert(Settings.CONTENT_URI, values);
+    }
+
+    /**
+     * Return a User object with data extracted from a contact stored
+     * in the local contacts database.
+     *
+     * Because a contact is actually stored over several rows in the
+     * database, our query will return those multiple rows of information.
+     * We then iterate over the rows and build the User structure from
+     * what we find.
+     *
+     * @param context the Authenticator Activity context
+     * @param rawContactId the unique ID for the local contact
+     * @return a User object containing info on that contact
+     */
+    private static RawContact getRawContact(Context context, long rawContactId) {
+        String firstName = null;
+        String lastName = null;
+        String fullName = null;
+        String cellPhone = null;
+        String homePhone = null;
+        String workPhone = null;
+        String email = null;
+        long serverId = -1;
+
+        final ContentResolver resolver = context.getContentResolver();
+        final Cursor c =
+            resolver.query(DataQuery.CONTENT_URI, DataQuery.PROJECTION, DataQuery.SELECTION,
+                new String[] {String.valueOf(rawContactId)}, null);
+        try {
+            while (c.moveToNext()) {
+                final long id = c.getLong(DataQuery.COLUMN_ID);
+                final String mimeType = c.getString(DataQuery.COLUMN_MIMETYPE);
+                final long tempServerId = c.getLong(DataQuery.COLUMN_SERVER_ID);
+                if (tempServerId > 0) {
+                    serverId = tempServerId;
+                }
+                final Uri uri = ContentUris.withAppendedId(Data.CONTENT_URI, id);
+                if (mimeType.equals(StructuredName.CONTENT_ITEM_TYPE)) {
+                    lastName = c.getString(DataQuery.COLUMN_FAMILY_NAME);
+                    firstName = c.getString(DataQuery.COLUMN_GIVEN_NAME);
+                    fullName = c.getString(DataQuery.COLUMN_FULL_NAME);
+                } else if (mimeType.equals(Phone.CONTENT_ITEM_TYPE)) {
+                    final int type = c.getInt(DataQuery.COLUMN_PHONE_TYPE);
+                    if (type == Phone.TYPE_MOBILE) {
+                        cellPhone = c.getString(DataQuery.COLUMN_PHONE_NUMBER);
+                    } else if (type == Phone.TYPE_HOME) {
+                        homePhone = c.getString(DataQuery.COLUMN_PHONE_NUMBER);
+                    } else if (type == Phone.TYPE_WORK) {
+                        workPhone = c.getString(DataQuery.COLUMN_PHONE_NUMBER);
+                    }
+                } else if (mimeType.equals(Email.CONTENT_ITEM_TYPE)) {
+                    email = c.getString(DataQuery.COLUMN_EMAIL_ADDRESS);
+                }
+            } // while
+        } finally {
+            c.close();
+        }
+
+        // Now that we've extracted all the information we care about,
+        // create the actual User object.
+        RawContact rawContact = RawContact.create(fullName, firstName, lastName, cellPhone,
+                workPhone, homePhone, email, null, false, rawContactId, serverId);
+
+        return rawContact;
+    }
+
+    /**
+     * Update the status message associated with the specified user.  The status
+     * message would be something that is likely to be used by IM or social
+     * networking sync providers, and less by a straightforward contact provider.
+     * But it's a useful demo to see how it's done.
+     *
+     * @param context the Authenticator Activity context
+     * @param rawContact the contact who's status we should update
+     * @param batchOperation allow us to batch together multiple operations
+     */
+    private static void updateContactStatus(Context context, RawContact rawContact,
+            BatchOperation batchOperation) {
+        final ContentValues values = new ContentValues();
+        final ContentResolver resolver = context.getContentResolver();
+
+        final long userId = rawContact.getServerContactId();
+        final String username = rawContact.getUserName();
+        final String status = rawContact.getStatus();
+
+        // Look up the user's sample SyncAdapter data row
+        final long profileId = lookupProfile(resolver, userId);
+
+        // Insert the activity into the stream
+        if (profileId > 0) {
+            values.put(StatusUpdates.DATA_ID, profileId);
+            values.put(StatusUpdates.STATUS, status);
+            values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_CUSTOM);
+            values.put(StatusUpdates.CUSTOM_PROTOCOL, CUSTOM_IM_PROTOCOL);
+            values.put(StatusUpdates.IM_ACCOUNT, username);
+            values.put(StatusUpdates.IM_HANDLE, userId);
+            values.put(StatusUpdates.STATUS_RES_PACKAGE, context.getPackageName());
+            values.put(StatusUpdates.STATUS_ICON, R.drawable.icon);
+            values.put(StatusUpdates.STATUS_LABEL, R.string.label);
+            batchOperation.add(ContactOperations.newInsertCpo(StatusUpdates.CONTENT_URI,
+                    false, true).withValues(values).build());
+        }
+    }
+
+    /**
+     * Clear the local system 'dirty' flag for a contact.
+     *
+     * @param context the Authenticator Activity context
+     * @param rawContactId the id of the contact update
+     * @param batchOperation allow us to batch together multiple operations
+     */
+    private static void clearDirtyFlag(Context context, long rawContactId,
+        BatchOperation batchOperation) {
+        final ContactOperations contactOp =
+                ContactOperations.updateExistingContact(context, rawContactId, true,
+                batchOperation);
+
+        final Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
+        contactOp.updateDirtyFlag(false, uri);
+    }
+
+     /**
+     * Deletes a contact from the platform contacts provider. This method is used
+     * both for contacts that were deleted locally and then that deletion was synced
+     * to the server, and for contacts that were deleted on the server and the
+     * deletion was synced to the client.
+     *
      * @param context the Authenticator Activity context
      * @param rawContactId the unique Id for this rawContact in contacts
      *        provider
@@ -222,39 +541,43 @@
         BatchOperation batchOperation) {
 
         batchOperation.add(ContactOperations.newDeleteCpo(
-            ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), true).build());
+                ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
+                true, true).build());
     }
 
     /**
      * Returns the RawContact id for a sample SyncAdapter contact, or 0 if the
      * sample SyncAdapter user isn't found.
-     * 
-     * @param context the Authenticator Activity context
-     * @param userId the sample SyncAdapter user ID to lookup
+     *
+     * @param resolver the content resolver to use
+     * @param serverContactId the sample SyncAdapter user ID to lookup
      * @return the RawContact id, or 0 if not found
      */
-    private static long lookupRawContact(ContentResolver resolver, long userId) {
+    private static long lookupRawContact(ContentResolver resolver, long serverContactId) {
 
-        long authorId = 0;
-        final Cursor c =
-            resolver.query(RawContacts.CONTENT_URI, UserIdQuery.PROJECTION, UserIdQuery.SELECTION,
-                new String[] {String.valueOf(userId)}, null);
+        long rawContactId = 0;
+        final Cursor c = resolver.query(
+                UserIdQuery.CONTENT_URI,
+                UserIdQuery.PROJECTION,
+                UserIdQuery.SELECTION,
+                new String[] {String.valueOf(serverContactId)},
+                null);
         try {
-            if (c.moveToFirst()) {
-                authorId = c.getLong(UserIdQuery.COLUMN_ID);
+            if ((c != null) && c.moveToFirst()) {
+                rawContactId = c.getLong(UserIdQuery.COLUMN_RAW_CONTACT_ID);
             }
         } finally {
             if (c != null) {
                 c.close();
             }
         }
-        return authorId;
+        return rawContactId;
     }
 
     /**
      * Returns the Data id for a sample SyncAdapter contact's profile row, or 0
      * if the sample SyncAdapter user isn't found.
-     * 
+     *
      * @param resolver a content resolver
      * @param userId the sample SyncAdapter user ID to lookup
      * @return the profile Data row id, or 0 if not found
@@ -266,7 +589,7 @@
             resolver.query(Data.CONTENT_URI, ProfileQuery.PROJECTION, ProfileQuery.SELECTION,
                 new String[] {String.valueOf(userId)}, null);
         try {
-            if (c != null && c.moveToFirst()) {
+            if ((c != null) && c.moveToFirst()) {
                 profileId = c.getLong(ProfileQuery.COLUMN_ID);
             }
         } finally {
@@ -277,6 +600,46 @@
         return profileId;
     }
 
+    final public static class EditorQuery {
+
+        private EditorQuery() {
+        }
+
+        public static final String[] PROJECTION = new String[] {
+            RawContacts.ACCOUNT_NAME,
+            Data._ID,
+            RawContacts.Entity.DATA_ID,
+            Data.MIMETYPE,
+            Data.DATA1,
+            Data.DATA2,
+            Data.DATA3,
+            Data.DATA15,
+            Data.SYNC1
+            };
+
+        public static final int COLUMN_ACCOUNT_NAME = 0;
+        public static final int COLUMN_RAW_CONTACT_ID = 1;
+        public static final int COLUMN_DATA_ID = 2;
+        public static final int COLUMN_MIMETYPE = 3;
+        public static final int COLUMN_DATA1 = 4;
+        public static final int COLUMN_DATA2 = 5;
+        public static final int COLUMN_DATA3 = 6;
+        public static final int COLUMN_DATA15 = 7;
+        public static final int COLUMN_SYNC1 = 8;
+
+        public static final int COLUMN_PHONE_NUMBER = COLUMN_DATA1;
+        public static final int COLUMN_PHONE_TYPE = COLUMN_DATA2;
+        public static final int COLUMN_EMAIL_ADDRESS = COLUMN_DATA1;
+        public static final int COLUMN_EMAIL_TYPE = COLUMN_DATA2;
+        public static final int COLUMN_FULL_NAME = COLUMN_DATA1;
+        public static final int COLUMN_GIVEN_NAME = COLUMN_DATA2;
+        public static final int COLUMN_FAMILY_NAME = COLUMN_DATA3;
+        public static final int COLUMN_AVATAR_IMAGE = COLUMN_DATA15;
+        public static final int COLUMN_SYNC_DIRTY = COLUMN_SYNC1;
+
+        public static final String SELECTION = Data.RAW_CONTACT_ID + "=?";
+    }
+
     /**
      * Constants for a query to find a contact given a sample SyncAdapter user
      * ID.
@@ -304,9 +667,15 @@
         private UserIdQuery() {
         }
 
-        public final static String[] PROJECTION = new String[] {RawContacts._ID};
+        public final static String[] PROJECTION = new String[] {
+            RawContacts._ID,
+            RawContacts.CONTACT_ID
+            };
 
-        public final static int COLUMN_ID = 0;
+        public final static int COLUMN_RAW_CONTACT_ID = 0;
+        public final static int COLUMN_LINKED_CONTACT_ID = 1;
+
+        public final static Uri CONTENT_URI = RawContacts.CONTENT_URI;
 
         public static final String SELECTION =
             RawContacts.ACCOUNT_TYPE + "='" + Constants.ACCOUNT_TYPE + "' AND "
@@ -314,6 +683,40 @@
     }
 
     /**
+     * Constants for a query to find SampleSyncAdapter contacts that are
+     * in need of syncing to the server. This should cover new, edited,
+     * and deleted contacts.
+     */
+    final private static class DirtyQuery {
+
+        private DirtyQuery() {
+        }
+
+        public final static String[] PROJECTION = new String[] {
+            RawContacts._ID,
+            RawContacts.SOURCE_ID,
+            RawContacts.DIRTY,
+            RawContacts.DELETED,
+            RawContacts.VERSION
+            };
+
+        public final static int COLUMN_RAW_CONTACT_ID = 0;
+        public final static int COLUMN_SERVER_ID = 1;
+        public final static int COLUMN_DIRTY = 2;
+        public final static int COLUMN_DELETED = 3;
+        public final static int COLUMN_VERSION = 4;
+
+        public static final Uri CONTENT_URI = RawContacts.CONTENT_URI.buildUpon()
+            .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
+            .build();
+
+        public static final String SELECTION =
+            RawContacts.DIRTY + "=1 AND "
+                + RawContacts.ACCOUNT_TYPE + "='" + Constants.ACCOUNT_TYPE + "' AND "
+                + RawContacts.ACCOUNT_NAME + "=?";
+    }
+
+    /**
      * Constants for a query to get contact data for a given rawContactId
      */
     final private static class DataQuery {
@@ -322,29 +725,29 @@
         }
 
         public static final String[] PROJECTION =
-            new String[] {Data._ID, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3,};
+            new String[] {Data._ID, RawContacts.SOURCE_ID, Data.MIMETYPE, Data.DATA1,
+            Data.DATA2, Data.DATA3, Data.DATA15, Data.SYNC1};
 
         public static final int COLUMN_ID = 0;
+        public static final int COLUMN_SERVER_ID = 1;
+        public static final int COLUMN_MIMETYPE = 2;
+        public static final int COLUMN_DATA1 = 3;
+        public static final int COLUMN_DATA2 = 4;
+        public static final int COLUMN_DATA3 = 5;
+        public static final int COLUMN_DATA15 = 6;
+        public static final int COLUMN_SYNC1 = 7;
 
-        public static final int COLUMN_MIMETYPE = 1;
-
-        public static final int COLUMN_DATA1 = 2;
-
-        public static final int COLUMN_DATA2 = 3;
-
-        public static final int COLUMN_DATA3 = 4;
+        public static final Uri CONTENT_URI = Data.CONTENT_URI;
 
         public static final int COLUMN_PHONE_NUMBER = COLUMN_DATA1;
-
         public static final int COLUMN_PHONE_TYPE = COLUMN_DATA2;
-
         public static final int COLUMN_EMAIL_ADDRESS = COLUMN_DATA1;
-
         public static final int COLUMN_EMAIL_TYPE = COLUMN_DATA2;
-
+        public static final int COLUMN_FULL_NAME = COLUMN_DATA1;
         public static final int COLUMN_GIVEN_NAME = COLUMN_DATA2;
-
         public static final int COLUMN_FAMILY_NAME = COLUMN_DATA3;
+        public static final int COLUMN_AVATAR_IMAGE = COLUMN_DATA15;
+        public static final int COLUMN_SYNC_DIRTY = COLUMN_SYNC1;
 
         public static final String SELECTION = Data.RAW_CONTACT_ID + "=?";
     }
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java
index db01f48..cb8e97b 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java
@@ -1,12 +1,12 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -15,115 +15,134 @@
  */
 package com.example.android.samplesync.platform;
 
+import com.example.android.samplesync.Constants;
+import com.example.android.samplesync.R;
+import com.example.android.samplesync.client.NetworkUtilities;
+
 import android.content.ContentProviderOperation;
 import android.content.ContentValues;
 import android.content.Context;
 import android.net.Uri;
 import android.provider.ContactsContract;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
 import android.text.TextUtils;
-import android.util.Log;
-
-import com.example.android.samplesync.Constants;
-import com.example.android.samplesync.R;
 
 /**
  * Helper class for storing data in the platform content providers.
  */
 public class ContactOperations {
-
     private final ContentValues mValues;
-
-    private ContentProviderOperation.Builder mBuilder;
-
     private final BatchOperation mBatchOperation;
-
     private final Context mContext;
-
-    private boolean mYield;
-
+    private boolean mIsSyncOperation;
     private long mRawContactId;
-
     private int mBackReference;
-
     private boolean mIsNewContact;
 
     /**
+     * Since we're sending a lot of contact provider operations in a single
+     * batched operation, we want to make sure that we "yield" periodically
+     * so that the Contact Provider can write changes to the DB, and can
+     * open a new transaction.  This prevents ANR (application not responding)
+     * errors.  The recommended time to specify that a yield is permitted is
+     * with the first operation on a particular contact.  So if we're updating
+     * multiple fields for a single contact, we make sure that we call
+     * withYieldAllowed(true) on the first field that we update. We use
+     * mIsYieldAllowed to keep track of what value we should pass to
+     * withYieldAllowed().
+     */
+    private boolean mIsYieldAllowed;
+
+    /**
      * Returns an instance of ContactOperations instance for adding new contact
      * to the platform contacts provider.
-     * 
+     *
      * @param context the Authenticator Activity context
      * @param userId the userId of the sample SyncAdapter user object
-     * @param accountName the username of the current login
+     * @param accountName the username for the SyncAdapter account
+     * @param isSyncOperation are we executing this as part of a sync operation?
      * @return instance of ContactOperations
      */
-    public static ContactOperations createNewContact(Context context, int userId,
-        String accountName, BatchOperation batchOperation) {
-
-        return new ContactOperations(context, userId, accountName, batchOperation);
+    public static ContactOperations createNewContact(Context context, long userId,
+            String accountName, boolean isSyncOperation, BatchOperation batchOperation) {
+        return new ContactOperations(context, userId, accountName, isSyncOperation, batchOperation);
     }
 
     /**
      * Returns an instance of ContactOperations for updating existing contact in
      * the platform contacts provider.
-     * 
+     *
      * @param context the Authenticator Activity context
      * @param rawContactId the unique Id of the existing rawContact
+     * @param isSyncOperation are we executing this as part of a sync operation?
      * @return instance of ContactOperations
      */
     public static ContactOperations updateExistingContact(Context context, long rawContactId,
-        BatchOperation batchOperation) {
-
-        return new ContactOperations(context, rawContactId, batchOperation);
+            boolean isSyncOperation, BatchOperation batchOperation) {
+        return new ContactOperations(context, rawContactId, isSyncOperation, batchOperation);
     }
 
-    public ContactOperations(Context context, BatchOperation batchOperation) {
+    public ContactOperations(Context context, boolean isSyncOperation,
+            BatchOperation batchOperation) {
         mValues = new ContentValues();
-        mYield = true;
+        mIsYieldAllowed = true;
+        mIsSyncOperation = isSyncOperation;
         mContext = context;
         mBatchOperation = batchOperation;
     }
 
-    public ContactOperations(Context context, int userId, String accountName,
-        BatchOperation batchOperation) {
-
-        this(context, batchOperation);
+    public ContactOperations(Context context, long userId, String accountName,
+            boolean isSyncOperation, BatchOperation batchOperation) {
+        this(context, isSyncOperation, batchOperation);
         mBackReference = mBatchOperation.size();
         mIsNewContact = true;
         mValues.put(RawContacts.SOURCE_ID, userId);
         mValues.put(RawContacts.ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
         mValues.put(RawContacts.ACCOUNT_NAME, accountName);
-        mBuilder = newInsertCpo(RawContacts.CONTENT_URI, true).withValues(mValues);
-        mBatchOperation.add(mBuilder.build());
+        ContentProviderOperation.Builder builder =
+                newInsertCpo(RawContacts.CONTENT_URI, mIsSyncOperation, true).withValues(mValues);
+        mBatchOperation.add(builder.build());
     }
 
-    public ContactOperations(Context context, long rawContactId, BatchOperation batchOperation) {
-        this(context, batchOperation);
+    public ContactOperations(Context context, long rawContactId, boolean isSyncOperation,
+            BatchOperation batchOperation) {
+        this(context, isSyncOperation, batchOperation);
         mIsNewContact = false;
         mRawContactId = rawContactId;
     }
 
     /**
-     * Adds a contact name
-     * 
-     * @param name Name of contact
-     * @param nameType type of name: family name, given name, etc.
+     * Adds a contact name. We can take either a full name ("Bob Smith") or separated
+     * first-name and last-name ("Bob" and "Smith").
+     *
+     * @param fullName The full name of the contact - typically from an edit form
+     *      Can be null if firstName/lastName are specified.
+     * @param firstName The first name of the contact - can be null if fullName
+     *      is specified.
+     * @param lastName The last name of the contact - can be null if fullName
+     *      is specified.
      * @return instance of ContactOperations
      */
-    public ContactOperations addName(String firstName, String lastName) {
-
+    public ContactOperations addName(String fullName, String firstName, String lastName) {
         mValues.clear();
-        if (!TextUtils.isEmpty(firstName)) {
-            mValues.put(StructuredName.GIVEN_NAME, firstName);
+
+        if (!TextUtils.isEmpty(fullName)) {
+            mValues.put(StructuredName.DISPLAY_NAME, fullName);
             mValues.put(StructuredName.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
-        }
-        if (!TextUtils.isEmpty(lastName)) {
-            mValues.put(StructuredName.FAMILY_NAME, lastName);
-            mValues.put(StructuredName.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+        } else {
+            if (!TextUtils.isEmpty(firstName)) {
+                mValues.put(StructuredName.GIVEN_NAME, firstName);
+                mValues.put(StructuredName.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+            }
+            if (!TextUtils.isEmpty(lastName)) {
+                mValues.put(StructuredName.FAMILY_NAME, lastName);
+                mValues.put(StructuredName.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+            }
         }
         if (mValues.size() > 0) {
             addInsertOp();
@@ -133,8 +152,8 @@
 
     /**
      * Adds an email
-     * 
-     * @param new email for user
+     *
+     * @param the email address we're adding
      * @return instance of ContactOperations
      */
     public ContactOperations addEmail(String email) {
@@ -150,7 +169,7 @@
 
     /**
      * Adds a phone number
-     * 
+     *
      * @param phone new phone number for the contact
      * @param phoneType the type: cell, home, etc.
      * @return instance of ContactOperations
@@ -166,9 +185,22 @@
         return this;
     }
 
+    public ContactOperations addAvatar(String avatarUrl) {
+        if (avatarUrl != null) {
+            byte[] avatarBuffer = NetworkUtilities.downloadAvatar(avatarUrl);
+            if (avatarBuffer != null) {
+                mValues.clear();
+                mValues.put(Photo.PHOTO, avatarBuffer);
+                mValues.put(Photo.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
+                addInsertOp();
+            }
+        }
+        return this;
+    }
+
     /**
      * Adds a profile action
-     * 
+     *
      * @param userId the userId of the sample SyncAdapter user object
      * @return instance of ContactOperations
      */
@@ -187,8 +219,22 @@
     }
 
     /**
+     * Updates contact's serverId
+     *
+     * @param serverId the serverId for this contact
+     * @param uri Uri for the existing raw contact to be updated
+     * @return instance of ContactOperations
+     */
+    public ContactOperations updateServerId(long serverId, Uri uri) {
+        mValues.clear();
+        mValues.put(RawContacts.SOURCE_ID, serverId);
+        addUpdateOp(uri);
+        return this;
+    }
+
+    /**
      * Updates contact's email
-     * 
+     *
      * @param email email id of the sample SyncAdapter user
      * @param uri Uri for the existing raw contact to be updated
      * @return instance of ContactOperations
@@ -203,25 +249,38 @@
     }
 
     /**
-     * Updates contact's name
-     * 
-     * @param name Name of contact
-     * @param existingName Name of contact stored in provider
-     * @param nameType type of name: family name, given name, etc.
+     * Updates contact's name. The caller can either provide first-name
+     * and last-name fields or a full-name field.
+     *
      * @param uri Uri for the existing raw contact to be updated
+     * @param existingFirstName the first name stored in provider
+     * @param existingLastName the last name stored in provider
+     * @param existingFullName the full name stored in provider
+     * @param firstName the new first name to store
+     * @param lastName the new last name to store
+     * @param fullName the new full name to store
      * @return instance of ContactOperations
      */
-    public ContactOperations updateName(Uri uri, String existingFirstName, String existingLastName,
-        String firstName, String lastName) {
+    public ContactOperations updateName(Uri uri,
+        String existingFirstName,
+        String existingLastName,
+        String existingFullName,
+        String firstName,
+        String lastName,
+        String fullName) {
 
-        Log.i("ContactOperations", "ef=" + existingFirstName + "el=" + existingLastName + "f="
-            + firstName + "l=" + lastName);
         mValues.clear();
-        if (!TextUtils.equals(existingFirstName, firstName)) {
-            mValues.put(StructuredName.GIVEN_NAME, firstName);
-        }
-        if (!TextUtils.equals(existingLastName, lastName)) {
-            mValues.put(StructuredName.FAMILY_NAME, lastName);
+        if (TextUtils.isEmpty(fullName)) {
+            if (!TextUtils.equals(existingFirstName, firstName)) {
+                mValues.put(StructuredName.GIVEN_NAME, firstName);
+            }
+            if (!TextUtils.equals(existingLastName, lastName)) {
+                mValues.put(StructuredName.FAMILY_NAME, lastName);
+            }
+        } else {
+            if (!TextUtils.equals(existingFullName, fullName)) {
+                mValues.put(StructuredName.DISPLAY_NAME, fullName);
+            }
         }
         if (mValues.size() > 0) {
             addUpdateOp(uri);
@@ -229,9 +288,17 @@
         return this;
     }
 
+    public ContactOperations updateDirtyFlag(boolean isDirty, Uri uri) {
+        int isDirtyValue = isDirty ? 1 : 0;
+        mValues.clear();
+        mValues.put(RawContacts.DIRTY, isDirtyValue);
+        addUpdateOp(uri);
+        return this;
+    }
+
     /**
      * Updates contact's phone
-     * 
+     *
      * @param existingNumber phone number stored in contacts provider
      * @param phone new phone number for the contact
      * @param uri Uri for the existing raw contact to be updated
@@ -246,9 +313,22 @@
         return this;
     }
 
+    public ContactOperations updateAvatar(String avatarUrl, Uri uri) {
+        if (avatarUrl != null) {
+            byte[] avatarBuffer = NetworkUtilities.downloadAvatar(avatarUrl);
+            if (avatarBuffer != null) {
+                mValues.clear();
+                mValues.put(Photo.PHOTO, avatarBuffer);
+                mValues.put(Photo.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
+                addUpdateOp(uri);
+            }
+        }
+        return this;
+    }
+
     /**
      * Updates contact's profile action
-     * 
+     *
      * @param userId sample SyncAdapter user id
      * @param uri Uri for the existing raw contact to be updated
      * @return instance of ContactOperations
@@ -268,41 +348,62 @@
         if (!mIsNewContact) {
             mValues.put(Phone.RAW_CONTACT_ID, mRawContactId);
         }
-        mBuilder = newInsertCpo(addCallerIsSyncAdapterParameter(Data.CONTENT_URI), mYield);
-        mBuilder.withValues(mValues);
+        ContentProviderOperation.Builder builder =
+                newInsertCpo(Data.CONTENT_URI, mIsSyncOperation, mIsYieldAllowed);
+        builder.withValues(mValues);
         if (mIsNewContact) {
-            mBuilder.withValueBackReference(Data.RAW_CONTACT_ID, mBackReference);
+            builder.withValueBackReference(Data.RAW_CONTACT_ID, mBackReference);
         }
-        mYield = false;
-        mBatchOperation.add(mBuilder.build());
+        mIsYieldAllowed = false;
+        mBatchOperation.add(builder.build());
     }
 
     /**
      * Adds an update operation into the batch
      */
     private void addUpdateOp(Uri uri) {
-        mBuilder = newUpdateCpo(uri, mYield).withValues(mValues);
-        mYield = false;
-        mBatchOperation.add(mBuilder.build());
+        ContentProviderOperation.Builder builder =
+                newUpdateCpo(uri, mIsSyncOperation, mIsYieldAllowed).withValues(mValues);
+        mIsYieldAllowed = false;
+        mBatchOperation.add(builder.build());
     }
 
-    public static ContentProviderOperation.Builder newInsertCpo(Uri uri, boolean yield) {
-        return ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(uri))
-            .withYieldAllowed(yield);
+    public static ContentProviderOperation.Builder newInsertCpo(Uri uri,
+            boolean isSyncOperation, boolean isYieldAllowed) {
+        return ContentProviderOperation
+                .newInsert(addCallerIsSyncAdapterParameter(uri, isSyncOperation))
+                .withYieldAllowed(isYieldAllowed);
     }
 
-    public static ContentProviderOperation.Builder newUpdateCpo(Uri uri, boolean yield) {
-        return ContentProviderOperation.newUpdate(addCallerIsSyncAdapterParameter(uri))
-            .withYieldAllowed(yield);
+    public static ContentProviderOperation.Builder newUpdateCpo(Uri uri,
+            boolean isSyncOperation, boolean isYieldAllowed) {
+        return ContentProviderOperation
+                .newUpdate(addCallerIsSyncAdapterParameter(uri, isSyncOperation))
+                .withYieldAllowed(isYieldAllowed);
     }
 
-    public static ContentProviderOperation.Builder newDeleteCpo(Uri uri, boolean yield) {
-        return ContentProviderOperation.newDelete(addCallerIsSyncAdapterParameter(uri))
-            .withYieldAllowed(yield);
+    public static ContentProviderOperation.Builder newDeleteCpo(Uri uri,
+            boolean isSyncOperation, boolean isYieldAllowed) {
+        return ContentProviderOperation
+                .newDelete(addCallerIsSyncAdapterParameter(uri, isSyncOperation))
+                .withYieldAllowed(isYieldAllowed);
     }
 
-    private static Uri addCallerIsSyncAdapterParameter(Uri uri) {
-        return uri.buildUpon().appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
-            .build();
+    private static Uri addCallerIsSyncAdapterParameter(Uri uri, boolean isSyncOperation) {
+        if (isSyncOperation) {
+            // If we're in the middle of a real sync-adapter operation, then go ahead
+            // and tell the Contacts provider that we're the sync adapter.  That
+            // gives us some special permissions - like the ability to really
+            // delete a contact, and the ability to clear the dirty flag.
+            //
+            // If we're not in the middle of a sync operation (for example, we just
+            // locally created/edited a new contact), then we don't want to use
+            // the special permissions, and the system will automagically mark
+            // the contact as 'dirty' for us!
+            return uri.buildUpon()
+                    .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
+                    .build();
+        }
+        return uri;
     }
 }
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/SampleSyncAdapterColumns.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/SampleSyncAdapterColumns.java
index 7b60d5b..e8a99a4 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/SampleSyncAdapterColumns.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/SampleSyncAdapterColumns.java
@@ -1,12 +1,12 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
index 206189a..0ca8dee 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
@@ -1,12 +1,12 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -24,12 +24,12 @@
 import android.content.Context;
 import android.content.SyncResult;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.example.android.samplesync.Constants;
 import com.example.android.samplesync.client.NetworkUtilities;
-import com.example.android.samplesync.client.User;
-import com.example.android.samplesync.client.User.Status;
+import com.example.android.samplesync.client.RawContact;
 import com.example.android.samplesync.platform.ContactManager;
 
 import org.apache.http.ParseException;
@@ -37,23 +37,27 @@
 import org.json.JSONException;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
 /**
  * SyncAdapter implementation for syncing sample SyncAdapter contacts to the
- * platform ContactOperations provider.
+ * platform ContactOperations provider.  This sample shows a basic 2-way
+ * sync between the client and a sample server.  It also contains an
+ * example of how to update the contacts' status messages, which
+ * would be useful for a messaging or social networking client.
  */
 public class SyncAdapter extends AbstractThreadedSyncAdapter {
 
     private static final String TAG = "SyncAdapter";
+    private static final String SYNC_MARKER_KEY = "com.example.android.samplesync.marker";
+    private static final boolean NOTIFY_AUTH_FAILURE = true;
 
     private final AccountManager mAccountManager;
 
     private final Context mContext;
 
-    private Date mLastUpdated;
-
     public SyncAdapter(Context context, boolean autoInitialize) {
         super(context, autoInitialize);
         mContext = context;
@@ -64,42 +68,101 @@
     public void onPerformSync(Account account, Bundle extras, String authority,
         ContentProviderClient provider, SyncResult syncResult) {
 
-        List<User> users;
-        List<Status> statuses;
-        String authtoken = null;
         try {
-            // use the account manager to request the credentials
-            authtoken =
-                mAccountManager
-                    .blockingGetAuthToken(account, Constants.AUTHTOKEN_TYPE, true /* notifyAuthFailure */);
-            // fetch updates from the sample service over the cloud
-            users = NetworkUtilities.fetchFriendUpdates(account, authtoken, mLastUpdated);
-            // update the last synced date.
-            mLastUpdated = new Date();
-            // update platform contacts.
+            // see if we already have a sync-state attached to this account. By handing
+            // This value to the server, we can just get the contacts that have
+            // been updated on the server-side since our last sync-up
+            long lastSyncMarker = getServerSyncMarker(account);
+
+            // By default, contacts from a 3rd party provider are hidden in the contacts
+            // list. So let's set the flag that causes them to be visible, so that users
+            // can actually see these contacts.
+            if (lastSyncMarker == 0) {
+                ContactManager.setAccountContactsVisibility(getContext(), account, true);
+            }
+
+            List<RawContact> dirtyContacts;
+            List<RawContact> updatedContacts;
+
+            // Use the account manager to request the AuthToken we'll need
+            // to talk to our sample server.  If we don't have an AuthToken
+            // yet, this could involve a round-trip to the server to request
+            // and AuthToken.
+            final String authtoken = mAccountManager.blockingGetAuthToken(account,
+                    Constants.AUTHTOKEN_TYPE, NOTIFY_AUTH_FAILURE);
+
+            // Find the local 'dirty' contacts that we need to tell the server about...
+            // Find the local users that need to be sync'd to the server...
+            dirtyContacts = ContactManager.getDirtyContacts(mContext, account);
+
+            // Send the dirty contacts to the server, and retrieve the server-side changes
+            updatedContacts = NetworkUtilities.syncContacts(account, authtoken,
+                    lastSyncMarker, dirtyContacts);
+
+            // Update the local contacts database with the changes. updateContacts()
+            // returns a syncState value that indicates the high-water-mark for
+            // the changes we received.
             Log.d(TAG, "Calling contactManager's sync contacts");
-            ContactManager.syncContacts(mContext, account.name, users);
-            // fetch and update status messages for all the synced users.
-            statuses = NetworkUtilities.fetchFriendStatuses(account, authtoken);
-            ContactManager.insertStatuses(mContext, account.name, statuses);
+            long newSyncState = ContactManager.updateContacts(mContext,
+                    account.name,
+                    updatedContacts,
+                    lastSyncMarker);
+
+            // This is a demo of how you can update IM-style status messages
+            // for contacts on the client. This probably won't apply to
+            // 2-way contact sync providers - it's more likely that one-way
+            // sync providers (IM clients, social networking apps, etc) would
+            // use this feature.
+            ContactManager.updateStatusMessages(mContext, updatedContacts);
+
+            // Save off the new sync marker. On our next sync, we only want to receive
+            // contacts that have changed since this sync...
+            setServerSyncMarker(account, newSyncState);
+
+            if (dirtyContacts.size() > 0) {
+                ContactManager.clearSyncFlags(mContext, dirtyContacts);
+            }
+
         } catch (final AuthenticatorException e) {
-            syncResult.stats.numParseExceptions++;
             Log.e(TAG, "AuthenticatorException", e);
+            syncResult.stats.numParseExceptions++;
         } catch (final OperationCanceledException e) {
             Log.e(TAG, "OperationCanceledExcetpion", e);
         } catch (final IOException e) {
             Log.e(TAG, "IOException", e);
             syncResult.stats.numIoExceptions++;
         } catch (final AuthenticationException e) {
-            mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE, authtoken);
-            syncResult.stats.numAuthExceptions++;
             Log.e(TAG, "AuthenticationException", e);
+            syncResult.stats.numAuthExceptions++;
         } catch (final ParseException e) {
-            syncResult.stats.numParseExceptions++;
             Log.e(TAG, "ParseException", e);
-        } catch (final JSONException e) {
             syncResult.stats.numParseExceptions++;
+        } catch (final JSONException e) {
             Log.e(TAG, "JSONException", e);
+            syncResult.stats.numParseExceptions++;
         }
     }
+
+    /**
+     * This helper function fetches the last known high-water-mark
+     * we received from the server - or 0 if we've never synced.
+     * @param account the account we're syncing
+     * @return the change high-water-mark
+     */
+    private long getServerSyncMarker(Account account) {
+        String markerString = mAccountManager.getUserData(account, SYNC_MARKER_KEY);
+        if (!TextUtils.isEmpty(markerString)) {
+            return Long.parseLong(markerString);
+        }
+        return 0;
+    }
+
+    /**
+     * Save off the high-water-mark we receive back from the server.
+     * @param account The account we're syncing
+     * @param marker The high-water-mark we want to save.
+     */
+    private void setServerSyncMarker(Account account, long marker) {
+        mAccountManager.setUserData(account, SYNC_MARKER_KEY, Long.toString(marker));
+    }
 }
diff --git a/samples/SimpleJNI/jni/Android.mk b/samples/SimpleJNI/jni/Android.mk
index 528196b..a704fcf 100644
--- a/samples/SimpleJNI/jni/Android.mk
+++ b/samples/SimpleJNI/jni/Android.mk
@@ -44,11 +44,4 @@
 # No special compiler flags.
 LOCAL_CFLAGS +=
 
-# Don't prelink this library.  For more efficient code, you may want
-# to add this library to the prelink map and set this to true. However,
-# it's difficult to do this for applications that are not supplied as
-# part of a system image.
-
-LOCAL_PRELINK_MODULE := false
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/samples/Support4Demos/AndroidManifest.xml b/samples/Support4Demos/AndroidManifest.xml
index 5c74954..4719268 100644
--- a/samples/Support4Demos/AndroidManifest.xml
+++ b/samples/Support4Demos/AndroidManifest.xml
@@ -208,5 +208,15 @@
         <provider android:name=".app.LoaderThrottleSupport$SimpleProvider"
                   android:authorities="com.example.android.apis.supportv4.app.LoaderThrottle" />
 
+        <activity android:name=".content.LocalServiceBroadcaster"
+                android:label="@string/local_service_broadcaster">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+        <service android:name=".content.LocalServiceBroadcaster$LocalService"
+                android:stopWithTask="true" />
+
     </application>
 </manifest>
diff --git a/samples/Support4Demos/res/layout/local_service_broadcaster.xml b/samples/Support4Demos/res/layout/local_service_broadcaster.xml
new file mode 100644
index 0000000..f01120d
--- /dev/null
+++ b/samples/Support4Demos/res/layout/local_service_broadcaster.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Demonstrates starting and stopping a local service.
+     See corresponding Java code com.android.sdk.app.LocalSerice.java. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="4dip"
+    android:gravity="center_horizontal"
+    android:layout_width="match_parent" android:layout_height="match_parent">
+
+    <TextView
+        android:layout_width="match_parent" android:layout_height="wrap_content"
+        android:layout_weight="0"
+        android:paddingBottom="4dip"
+        android:text="@string/local_service_broadcaster_msg"/>
+
+    <Button android:id="@+id/start"
+        android:layout_width="wrap_content" android:layout_height="wrap_content"
+        android:text="@string/start_service">
+        <requestFocus />
+    </Button>
+
+    <Button android:id="@+id/stop"
+        android:layout_width="wrap_content" android:layout_height="wrap_content"
+        android:text="@string/stop_service">
+    </Button>
+
+    <TextView android:id="@+id/callback"
+        android:layout_width="match_parent" android:layout_height="wrap_content"
+        android:layout_weight="0"
+        android:gravity="center_horizontal" android:paddingTop="4dip"/>
+
+</LinearLayout>
diff --git a/samples/Support4Demos/res/values/strings.xml b/samples/Support4Demos/res/values/strings.xml
index fa437db..5fa5af7 100644
--- a/samples/Support4Demos/res/values/strings.xml
+++ b/samples/Support4Demos/res/values/strings.xml
@@ -93,4 +93,11 @@
 
     <string name="loader_throttle_support">Loader/Throttle</string>
 
+    <string name="local_service_broadcaster">Content/Local Service Broadcaster</string>
+
+    <string name="local_service_broadcaster_msg">Demonstrates use of LocalBroadcastManager
+        to communicate from a Service to an Activity.</string>
+    <string name="start_service">Start Service</string>
+    <string name="stop_service">Stop Service</string>
+
 </resources>
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.java b/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.java
new file mode 100644
index 0000000..d4dc8e1
--- /dev/null
+++ b/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.supportv4.content;
+
+import com.example.android.supportv4.R;
+
+import android.app.Activity;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.support.v4.content.LocalBroadcastManager;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Demonstrates the use of a LocalBroadcastManager to easily communicate
+ * data from a service to any other interested code.
+ */
+public class LocalServiceBroadcaster extends Activity {
+    static final String ACTION_STARTED = "com.example.android.supportv4.STARTED";
+    static final String ACTION_UPDATE = "com.example.android.supportv4.UPDATE";
+    static final String ACTION_STOPPED = "com.example.android.supportv4.STOPPED";
+
+    LocalBroadcastManager mLocalBroadcastManager;
+    BroadcastReceiver mReceiver;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.local_service_broadcaster);
+
+        // This is where we print the data we get back.
+        final TextView callbackData = (TextView)findViewById(R.id.callback);
+
+        // Put in some initial text.
+        callbackData.setText("No broadcast received yet");
+
+        // We use this to send broadcasts within our local process.
+        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
+
+        // We are going to watch for interesting local broadcasts.
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_STARTED);
+        filter.addAction(ACTION_UPDATE);
+        filter.addAction(ACTION_STOPPED);
+        mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getAction().equals(ACTION_STARTED)) {
+                    callbackData.setText("STARTED");
+                } else if (intent.getAction().equals(ACTION_UPDATE)) {
+                    callbackData.setText("Got update: " + intent.getIntExtra("value", 0));
+                } else if (intent.getAction().equals(ACTION_STOPPED)) {
+                    callbackData.setText("STOPPED");
+                }
+            }
+        };
+        mLocalBroadcastManager.registerReceiver(mReceiver, filter);
+
+        // Watch for button clicks.
+        Button button = (Button)findViewById(R.id.start);
+        button.setOnClickListener(mStartListener);
+        button = (Button)findViewById(R.id.stop);
+        button.setOnClickListener(mStopListener);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mLocalBroadcastManager.unregisterReceiver(mReceiver);
+    }
+
+    private OnClickListener mStartListener = new OnClickListener() {
+        public void onClick(View v) {
+            startService(new Intent(LocalServiceBroadcaster.this, LocalService.class));
+        }
+    };
+
+    private OnClickListener mStopListener = new OnClickListener() {
+        public void onClick(View v) {
+            stopService(new Intent(LocalServiceBroadcaster.this, LocalService.class));
+        }
+    };
+
+    public static class LocalService extends Service {
+        LocalBroadcastManager mLocalBroadcastManager;
+        int mCurUpdate;
+
+        static final int MSG_UPDATE = 1;
+
+        Handler mHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case MSG_UPDATE: {
+                        mCurUpdate++;
+                        Intent intent = new Intent(ACTION_UPDATE);
+                        intent.putExtra("value", mCurUpdate);
+                        mLocalBroadcastManager.sendBroadcast(intent);
+                        Message nmsg = mHandler.obtainMessage(MSG_UPDATE);
+                        mHandler.sendMessageDelayed(nmsg, 1000);
+                    } break;
+                    default:
+                        super.handleMessage(msg);
+                }
+            }
+        };
+
+        @Override
+        public void onCreate() {
+            super.onCreate();
+            mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
+        }
+
+        @Override
+        public int onStartCommand(Intent intent, int flags, int startId) {
+            // Tell any local interested parties about the start.
+            mLocalBroadcastManager.sendBroadcast(new Intent(ACTION_STARTED));
+
+            // Prepare to do update reports.
+            mHandler.removeMessages(MSG_UPDATE);
+            Message msg = mHandler.obtainMessage(MSG_UPDATE);
+            mHandler.sendMessageDelayed(msg, 1000);
+            return Service.START_STICKY;
+        }
+
+        @Override
+        public void onDestroy() {
+            super.onDestroy();
+
+            // Tell any local interested parties about the stop.
+            mLocalBroadcastManager.sendBroadcast(new Intent(ACTION_STOPPED));
+
+            // Stop doing updates.
+            mHandler.removeMessages(MSG_UPDATE);
+        }
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            return null;
+        }
+    }
+}
diff --git a/samples/TtsEngine/Android.mk b/samples/TtsEngine/Android.mk
new file mode 100644
index 0000000..30569ac
--- /dev/null
+++ b/samples/TtsEngine/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := samples
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := TtsEngine
+
+include $(BUILD_PACKAGE)
+
diff --git a/samples/TtsEngine/AndroidManifest.xml b/samples/TtsEngine/AndroidManifest.xml
new file mode 100644
index 0000000..268ac43
--- /dev/null
+++ b/samples/TtsEngine/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.ttsengine">
+
+    <!-- TODO: Fix this when the API level for ICS is finalized. -->
+    <uses-sdk android:minSdkVersion="IceCreamSandwich"
+        android:targetSdkVersion="IceCreamSandwich" />
+
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application android:label="@string/app_name">
+        <service android:name=".RobotSpeakTtsService"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.TTS_SERVICE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <!-- Note that this meta data element must be inside the service
+                 definition of the service that handles the TTS_SERVICE intent
+                 -->
+            <meta-data android:name="android.speech.tts" android:resource="@xml/tts_engine" />
+        </service>
+
+        <activity android:name=".CheckVoiceData"
+                android:theme="@android:style/Theme.NoDisplay">
+            <intent-filter>
+                <action android:name="android.speech.tts.engine.CHECK_TTS_DATA" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".RobotSpeakSettings"
+                android:label="@string/general_settings"  />
+
+    </application>
+
+</manifest>
+
diff --git a/samples/TtsEngine/_index.html b/samples/TtsEngine/_index.html
new file mode 100644
index 0000000..07a54a9
--- /dev/null
+++ b/samples/TtsEngine/_index.html
@@ -0,0 +1,30 @@
+<p>This sample demonstrates how to create a text to speech engine
+that users can install on their devices.</p>
+
+<p>The application includes a service and two activities:</p>
+<ul>
+  <li><a
+    href="src/com/example/android/ttsengine/RobotSpeakEngine.html"><code>RobotSpeakEngine</code></a>,
+    a simple text to speech engine that converts sentences into audio by
+    generating a square wave of a given frequency for each alphabet of a
+    given language. Though this doesn't qualify as speech (except for robots)
+    it exercises all aspects of the new text to speech API
+    by subclassing the
+    <a href="../../../reference/android/speech/tts/TextToSpeechService.html"><code>TextToSpeechService</code></a>
+    framework class.
+  </li>
+  <li><a
+    href="src/com/example/android/ttsengine/CheckVoiceData.html"><code>CheckVoiceData</code></a>,
+  an activity that checks that all voice related data is installed and
+  available.</li>
+  <li><a
+    href="src/com/example/android/ttsengine/RobotSpeakSettings.html"><code>RobotSpeakSettings</code></a>,
+    a settings screen for users to set various engine parameters. This is
+    usually accessed by users from the system wide settings app. This must be
+    declared in the <code>AndroidManifest.xml</code> file as a
+    <code>meta-data</code> element.</li>
+
+<!-- TODO: Fix this when the API level for ICS is finalized -->
+<p>Note that this API is supported only on Android 4.0 (API level 13)
+and higher versions of the platform.</p>
+
diff --git a/samples/TtsEngine/assets/eng-GBR.freq b/samples/TtsEngine/assets/eng-GBR.freq
new file mode 100644
index 0000000..61382ac
--- /dev/null
+++ b/samples/TtsEngine/assets/eng-GBR.freq
@@ -0,0 +1,26 @@
+z:2
+y:4
+x:8
+w:16
+v:32
+u:64
+t:128
+s:160
+r:320
+q:400
+p:640
+o:800
+n:1600
+m:3200
+l:4000
+k:8000
+j:20
+i:40
+h:80
+g:125
+f:250
+e:500
+d:1000
+c:2000
+b:5
+a:10
diff --git a/samples/TtsEngine/assets/eng-USA.freq b/samples/TtsEngine/assets/eng-USA.freq
new file mode 100644
index 0000000..9dfc147
--- /dev/null
+++ b/samples/TtsEngine/assets/eng-USA.freq
@@ -0,0 +1,26 @@
+a:2
+b:4
+c:8
+d:16
+e:32
+f:64
+g:128
+h:160
+i:320
+j:400
+k:640
+l:800
+m:1600
+n:3200
+o:4000
+p:8000
+q:20
+r:40
+s:80
+t:125
+u:250
+v:500
+w:1000
+x:2000
+y:5
+z:10
diff --git a/samples/TtsEngine/res/values/strings.xml b/samples/TtsEngine/res/values/strings.xml
new file mode 100644
index 0000000..70ad3fb
--- /dev/null
+++ b/samples/TtsEngine/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+
+    <!-- The name of the application. -->
+    <string name="app_name">Example TTS Engine</string>
+    <!-- The heading of the first (and only) preference fragment -->
+    <string name="general_settings">General settings</string>
+
+    <string name="whisper_title">Whisper utterances</string>
+    <string name="whisper_summary">Say stuff really softly, only the keenest
+      eared robots can understand.</string>
+
+</resources>
diff --git a/samples/TtsEngine/res/xml/general_settings.xml b/samples/TtsEngine/res/xml/general_settings.xml
new file mode 100644
index 0000000..1cd6fd9
--- /dev/null
+++ b/samples/TtsEngine/res/xml/general_settings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <CheckboxPreference
+        android:key="robot_speak_whisper"
+        android:title="@string/whisper_title"
+        android:summary="@string/whisper_summary"
+        android:defaultValue="true"
+        android:persistent="true"
+        />
+
+</PreferenceScreen>
diff --git a/samples/TtsEngine/res/xml/preferences_headers.xml b/samples/TtsEngine/res/xml/preferences_headers.xml
new file mode 100644
index 0000000..53d0047
--- /dev/null
+++ b/samples/TtsEngine/res/xml/preferences_headers.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
+    <header android:fragment="com.example.android.ttsengine.GeneralSettingsFragment"
+        android:title="@string/general_settings"
+    />
+</preference-headers>
diff --git a/samples/TtsEngine/res/xml/tts_engine.xml b/samples/TtsEngine/res/xml/tts_engine.xml
new file mode 100644
index 0000000..fb6a823
--- /dev/null
+++ b/samples/TtsEngine/res/xml/tts_engine.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<tts-engine xmlns:android="http://schemas.android.com/apk/res/android"
+  android:settingsActivity="com.example.android.ttsengine.RobotSpeakSettings" />
diff --git a/samples/TtsEngine/src/com/example/android/ttsengine/CheckVoiceData.java b/samples/TtsEngine/src/com/example/android/ttsengine/CheckVoiceData.java
new file mode 100755
index 0000000..954dc80
--- /dev/null
+++ b/samples/TtsEngine/src/com/example/android/ttsengine/CheckVoiceData.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.ttsengine;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.speech.tts.TextToSpeech;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/*
+ * Checks if the voice data is present.
+ */
+public class CheckVoiceData extends Activity {
+    private static final String TAG = "CheckVoiceData";
+
+    private static final String[] SUPPORTED_LANGUAGES = { "eng-GBR", "eng-USA" };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Intent intent = getIntent();
+        List<String> checkLanguages = getCheckVoiceDataFor(intent);
+
+        // If the call didn't specify which languages to check, check
+        // for all the supported ones.
+        if (checkLanguages.isEmpty()) {
+            checkLanguages = Arrays.asList(SUPPORTED_LANGUAGES);
+        }
+
+        ArrayList<String> available = new ArrayList<String>();
+        ArrayList<String> unavailable = new ArrayList<String>();
+
+        for (String lang : checkLanguages) {
+            // This check is required because checkLanguages might contain
+            // an arbitrary list of languages if the intent specified them
+            // {@link #getCheckVoiceDataFor}.
+            if (isLanguageSupported(lang)) {
+                if (isDataInstalled(lang)) {
+                    available.add(lang);
+                } else {
+                    unavailable.add(lang);
+                }
+            }
+        }
+
+        int result;
+        if (!checkLanguages.isEmpty() && available.isEmpty()) {
+            // No voices available at all.
+            result = TextToSpeech.Engine.CHECK_VOICE_DATA_FAIL;
+        } else if (!unavailable.isEmpty()) {
+            // Some voices are available, but some have missing
+            // data.
+            result = TextToSpeech.Engine.CHECK_VOICE_DATA_MISSING_DATA;
+        } else {
+            // All voices are available.
+            result = TextToSpeech.Engine.CHECK_VOICE_DATA_PASS;
+        }
+
+        // We now return the list of available and unavailable voices
+        // as well as the return code.
+        Intent returnData = new Intent();
+        returnData.putStringArrayListExtra(
+                TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES, available);
+        returnData.putStringArrayListExtra(
+                TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES, unavailable);
+        setResult(result, returnData);
+        finish();
+    }
+
+    /**
+     * The intent that launches this activity can contain an intent extra
+     * {@link TextToSpeech.Engine.EXTRA_CHECK_VOICE_DATA_FOR} that might specify
+     * a given language to check voice data for. If the intent does not contain
+     * this extra, we assume that a voice check for all supported languages
+     * was requested.
+     */
+    private List<String> getCheckVoiceDataFor(Intent intent) {
+        ArrayList<String> list = intent.getStringArrayListExtra(
+                TextToSpeech.Engine.EXTRA_CHECK_VOICE_DATA_FOR);
+        ArrayList<String> ret = new ArrayList<String>();
+        if (list != null) {
+            for (String lang : list) {
+                if (!TextUtils.isEmpty(lang)) {
+                    ret.add(lang);
+                }
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Checks whether a given language is in the list of supported languages.
+     */
+    private boolean isLanguageSupported(String input) {
+        for (String lang : SUPPORTED_LANGUAGES) {
+            if (lang.equals(input)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /*
+     * Note that in our example, all data is packaged in our APK as
+     * assets (it could be a raw resource as well). This check is unnecessary
+     * because it will always succeed.
+     *
+     * If for example, engine data was downloaded or installed on external storage,
+     * this check would make much more sense.
+     */
+    private boolean isDataInstalled(String lang) {
+        try {
+            InputStream is = getAssets().open(lang + ".freq");
+
+            if (is != null) {
+                is.close();
+            } else {
+                return false;
+            }
+        } catch (IOException e) {
+            Log.w(TAG, "Unable to find data for: " + lang + ", exception: " + e);
+            return false;
+        }
+
+        // The asset InputStream was non null, and therefore this
+        // data file is available.
+        return true;
+    }
+}
diff --git a/samples/TtsEngine/src/com/example/android/ttsengine/GeneralSettingsFragment.java b/samples/TtsEngine/src/com/example/android/ttsengine/GeneralSettingsFragment.java
new file mode 100644
index 0000000..ca7353b
--- /dev/null
+++ b/samples/TtsEngine/src/com/example/android/ttsengine/GeneralSettingsFragment.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.ttsengine;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+
+public class GeneralSettingsFragment extends PreferenceFragment {
+    static final String SHARED_PREFS_NAME = "RobotSpeakSettings";
+    static final String WHISPER_KEY = "robot_speak_whisper";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getPreferenceManager().setSharedPreferencesName(SHARED_PREFS_NAME);
+        addPreferencesFromResource(R.xml.general_settings);
+    }
+}
diff --git a/samples/TtsEngine/src/com/example/android/ttsengine/RobotSpeakSettings.java b/samples/TtsEngine/src/com/example/android/ttsengine/RobotSpeakSettings.java
new file mode 100644
index 0000000..d4713d2
--- /dev/null
+++ b/samples/TtsEngine/src/com/example/android/ttsengine/RobotSpeakSettings.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.ttsengine;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+import java.util.List;
+
+/*
+ * This class is referenced via a meta data section in the manifest.
+ * A settings screen is optional, and if a given engine has no settings,
+ * there is no need to implement such a class.
+ */
+public class RobotSpeakSettings extends PreferenceActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public void onBuildHeaders(List<Header> target) {
+        loadHeadersFromResource(R.xml.preferences_headers, target);
+    }
+}
diff --git a/samples/TtsEngine/src/com/example/android/ttsengine/RobotSpeakTtsService.java b/samples/TtsEngine/src/com/example/android/ttsengine/RobotSpeakTtsService.java
new file mode 100644
index 0000000..81f9f2b
--- /dev/null
+++ b/samples/TtsEngine/src/com/example/android/ttsengine/RobotSpeakTtsService.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * 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.example.android.ttsengine;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.media.AudioFormat;
+import android.speech.tts.SynthesisCallback;
+import android.speech.tts.SynthesisRequest;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeechService;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A text to speech engine that generates "speech" that a robot might understand.
+ * The engine supports two different "languages", each with their own frequency
+ * mappings.
+ *
+ * It exercises all aspects of the Text to speech engine API
+ * {@link android.speech.tts.TextToSpeechService}.
+ */
+public class RobotSpeakTtsService extends TextToSpeechService {
+    private static final String TAG = "ExampleTtsService";
+
+    /*
+     * This is the sampling rate of our output audio. This engine outputs
+     * audio at 16khz 16bits per sample PCM audio.
+     */
+    private static final int SAMPLING_RATE_HZ = 16000;
+
+    /*
+     * We multiply by a factor of two since each sample contains 16 bits (2 bytes).
+     */
+    private final byte[] mAudioBuffer = new byte[SAMPLING_RATE_HZ * 2];
+
+    private Map<Character, Integer> mFrequenciesMap;
+    private volatile String[] mCurrentLanguage = null;
+    private volatile boolean mStopRequested = false;
+    private SharedPreferences mSharedPrefs = null;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mSharedPrefs = getSharedPreferences(GeneralSettingsFragment.SHARED_PREFS_NAME,
+                Context.MODE_PRIVATE);
+        // We load the default language when we start up. This isn't strictly
+        // required though, it can always be loaded lazily on the first call to
+        // onLoadLanguage or onSynthesizeText. This a tradeoff between memory usage
+        // and the latency of the first call.
+        onLoadLanguage("eng", "usa", "");
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+
+    @Override
+    protected String[] onGetLanguage() {
+        // Note that mCurrentLanguage is volatile because this can be called from
+        // multiple threads.
+        return mCurrentLanguage;
+    }
+
+    @Override
+    protected int onIsLanguageAvailable(String lang, String country, String variant) {
+        // The robot speak synthesizer supports only english.
+        if ("eng".equals(lang)) {
+            // We support two specific robot languages, the british robot language
+            // and the american robot language.
+            if ("USA".equals(country) || "GBR".equals(country)) {
+                // If the engine supported a specific variant, we would have
+                // something like.
+                //
+                // if ("android".equals(variant)) {
+                //     return TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE;
+                // }
+                return TextToSpeech.LANG_COUNTRY_AVAILABLE;
+            }
+
+            // We support the language, but not the country.
+            return TextToSpeech.LANG_AVAILABLE;
+        }
+
+        return TextToSpeech.LANG_NOT_SUPPORTED;
+    }
+
+    /*
+     * Note that this method is synchronized, as is onSynthesizeText because
+     * onLoadLanguage can be called from multiple threads (while onSynthesizeText
+     * is always called from a single thread only).
+     */
+    @Override
+    protected synchronized int onLoadLanguage(String lang, String country, String variant) {
+        final int isLanguageAvailable = onIsLanguageAvailable(lang, country, variant);
+
+        if (isLanguageAvailable == TextToSpeech.LANG_NOT_SUPPORTED) {
+            return isLanguageAvailable;
+        }
+
+        String loadCountry = country;
+        if (isLanguageAvailable == TextToSpeech.LANG_AVAILABLE) {
+            loadCountry = "USA";
+        }
+
+        // If we've already loaded the requested language, we can return early.
+        if (mCurrentLanguage != null) {
+            if (mCurrentLanguage[0].equals(lang) && mCurrentLanguage[1].equals(country)) {
+                return isLanguageAvailable;
+            }
+        }
+
+        Map<Character, Integer> newFrequenciesMap = null;
+        try {
+            InputStream file = getAssets().open(lang + "-" + loadCountry + ".freq");
+            newFrequenciesMap = buildFrequencyMap(file);
+            file.close();
+        } catch (IOException e) {
+            Log.e(TAG, "Error loading data for : " + lang + "-" + country);
+        }
+
+        mFrequenciesMap = newFrequenciesMap;
+        mCurrentLanguage = new String[] { lang, loadCountry, ""};
+
+        return isLanguageAvailable;
+    }
+
+    @Override
+    protected void onStop() {
+        mStopRequested = true;
+    }
+
+    @Override
+    protected synchronized void onSynthesizeText(SynthesisRequest request,
+            SynthesisCallback callback) {
+        // Note that we call onLoadLanguage here since there is no guarantee
+        // that there would have been a prior call to this function.
+        int load = onLoadLanguage(request.getLanguage(), request.getCountry(),
+                request.getVariant());
+
+        // We might get requests for a language we don't support - in which case
+        // we error out early before wasting too much time.
+        if (load == TextToSpeech.LANG_NOT_SUPPORTED) {
+            callback.error();
+            return;
+        }
+
+        // At this point, we have loaded the language we need for synthesis and
+        // it is guaranteed that we support it so we proceed with synthesis.
+
+        // We denote that we are ready to start sending audio across to the
+        // framework. We use a fixed sampling rate (16khz), and send data across
+        // in 16bit PCM mono.
+        callback.start(SAMPLING_RATE_HZ,
+                AudioFormat.ENCODING_PCM_16BIT, 1 /* Number of channels. */);
+
+        // We then scan through each character of the request string and
+        // generate audio for it.
+        final String text = request.getText().toLowerCase();
+        for (int i = 0; i < text.length(); ++i) {
+            char value = normalize(text.charAt(i));
+            // It is crucial to call either of callback.error() or callback.done() to ensure
+            // that audio / other resources are released as soon as possible.
+            if (!generateOneSecondOfAudio(value, callback)) {
+                callback.error();
+                return;
+            }
+        }
+
+        // Alright, we're done with our synthesis - yay!
+        callback.done();
+    }
+
+    /*
+     * Normalizes a given character to the range 'a' - 'z' (inclusive). Our
+     * frequency mappings contain frequencies for each of these characters.
+     */
+    private static char normalize(char input) {
+        if (input == ' ') {
+            return input;
+        }
+
+        if (input < 'a') {
+            return 'a';
+        }
+        if (input > 'z') {
+            return 'z';
+        }
+
+        return input;
+    }
+
+    private Map<Character, Integer> buildFrequencyMap(InputStream is) throws IOException {
+        BufferedReader br = new BufferedReader(new InputStreamReader(is));
+        String line = null;
+        Map<Character, Integer> map = new HashMap<Character, Integer>();
+        try {
+            while ((line = br.readLine()) != null) {
+                String[] parts = line.split(":");
+                if (parts.length != 2) {
+                    throw new IOException("Invalid line encountered: " + line);
+                }
+                map.put(parts[0].charAt(0), Integer.parseInt(parts[1]));
+            }
+            map.put(' ', 0);
+            return map;
+        } finally {
+            is.close();
+        }
+    }
+
+    private boolean generateOneSecondOfAudio(char alphabet, SynthesisCallback cb) {
+        ByteBuffer buffer = ByteBuffer.wrap(mAudioBuffer).order(ByteOrder.LITTLE_ENDIAN);
+
+        // Someone called onStop, end the current synthesis and return.
+        // The mStopRequested variable will be reset at the beginning of the
+        // next synthesis.
+        //
+        // In general, a call to onStop( ) should make a best effort attempt
+        // to stop all processing for the *current* onSynthesizeText request (if
+        // one is active).
+        if (mStopRequested) {
+            return false;
+        }
+
+
+        if (mFrequenciesMap == null || !mFrequenciesMap.containsKey(alphabet)) {
+            return false;
+        }
+
+        final int frequency = mFrequenciesMap.get(alphabet);
+
+        if (frequency > 0) {
+            // This is the wavelength in samples. The frequency is chosen so that the
+            // waveLength is always a multiple of two and frequency divides the
+            // SAMPLING_RATE exactly.
+            final int waveLength = SAMPLING_RATE_HZ / frequency;
+            final int times = SAMPLING_RATE_HZ / waveLength;
+
+            for (int j = 0; j < times; ++j) {
+                // For a square curve, half of the values will be at Short.MIN_VALUE
+                // and the other half will be Short.MAX_VALUE.
+                for (int i = 0; i < waveLength / 2; ++i) {
+                    buffer.putShort((short)(getAmplitude() * -1));
+                }
+                for (int i = 0; i < waveLength / 2; ++i) {
+                    buffer.putShort(getAmplitude());
+                }
+            }
+        } else {
+            // Play a second of silence.
+            for (int i = 0; i < mAudioBuffer.length / 2; ++i) {
+                buffer.putShort((short) 0);
+            }
+        }
+
+        // Get the maximum allowed size of data we can send across in audioAvailable.
+        final int maxBufferSize = cb.getMaxBufferSize();
+        int offset = 0;
+        while (offset < mAudioBuffer.length) {
+            int bytesToWrite = Math.min(maxBufferSize, mAudioBuffer.length - offset);
+            cb.audioAvailable(mAudioBuffer, offset, bytesToWrite);
+            offset += bytesToWrite;
+        }
+        return true;
+    }
+
+    private short getAmplitude() {
+        boolean whisper = mSharedPrefs.getBoolean(GeneralSettingsFragment.WHISPER_KEY, false);
+        return (short) (whisper ? 2048 : 8192);
+    }
+}
diff --git a/samples/VoicemailProviderDemo/Android.mk b/samples/VoicemailProviderDemo/Android.mk
new file mode 100644
index 0000000..60bf14d
--- /dev/null
+++ b/samples/VoicemailProviderDemo/Android.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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_MODULE_TAGS := samples
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := VoicemailProviderDemo
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/samples/VoicemailProviderDemo/AndroidManifest.xml b/samples/VoicemailProviderDemo/AndroidManifest.xml
new file mode 100644
index 0000000..e1a3404
--- /dev/null
+++ b/samples/VoicemailProviderDemo/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2011 The Android Open Source Project.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<!-- Declare the contents of this Android application.  The namespace
+     attribute brings in the Android platform namespace, and the package
+     supplies a unique name for the application.  When writing your
+     own application, the package name must be changed from "com.example.*"
+     to come from a domain that you own or have control over. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    android:versionCode="1" android:versionName="1.0" package="com.example.android.voicemail">
+
+    <uses-sdk android:minSdkVersion="13"
+              android:targetSdkVersion="13" />
+
+    <uses-permission android:name="com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+    <application android:icon="@drawable/icon" android:label="@string/app_name">
+        <activity android:name=".AddVoicemailActivity" android:label="@string/app_name">
+            <intent-filter>
+            <action android:name="android.intent.action.MAIN" />
+            <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/VoicemailProviderDemo/MODULE_LICENSE_APACHE2 b/samples/VoicemailProviderDemo/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/samples/VoicemailProviderDemo/MODULE_LICENSE_APACHE2
diff --git a/apps/SpareParts/NOTICE b/samples/VoicemailProviderDemo/NOTICE
similarity index 98%
rename from apps/SpareParts/NOTICE
rename to samples/VoicemailProviderDemo/NOTICE
index c5b1efa..becc120 100644
--- a/apps/SpareParts/NOTICE
+++ b/samples/VoicemailProviderDemo/NOTICE
@@ -1,5 +1,5 @@
 
-   Copyright (c) 2005-2008, The Android Open Source Project
+   Copyright (c) 2011, The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
diff --git a/samples/VoicemailProviderDemo/_index.html b/samples/VoicemailProviderDemo/_index.html
new file mode 100644
index 0000000..27a9e49
--- /dev/null
+++ b/samples/VoicemailProviderDemo/_index.html
@@ -0,0 +1,47 @@
+<p>
+This is a simple sample application that demonstrates how to use voicemail
+content provider APIs to insert new voicemail records.
+</p>
+<p>
+The application includes
+ <a href="src/com/example/android/voicemail/AddVoicemailActivity.html">
+    <code>AddVoicemailActivity</code>
+ </a>,
+an activity that lets the user enter voicemail details and record voicemail audio,
+which can then be stored with the voicemail content provider by tapping the "Send"
+button.
+<p>
+<img alt="Add voicemail" src="../images/VoicemailProviderDemo.png"
+ width=250px/>
+</p>
+
+<p>
+In the real world, a similar application could download voicemails from a
+remote voicemail server and store them locally with the voicemail content
+provider. The platform would then take care of notification and rendering of the
+voicemails.
+</p>
+<p>
+Following interfaces are of particular interest:
+<ul>
+   <li>
+     <a href="src/com/example/android/voicemail/common/core/VoicemailProviderHelper.html">
+      <code>VoicemailProviderHelper</code>
+     </a> and its implementation in
+     <a href="src/com/example/android/voicemail/common/core/VoicemailProviderHelpers.html">
+      <code>VoicemailProviderHelpers</code>
+     </a>.
+     This interface provides a good demonstration of various fields exposed by voicemail
+     content provider and their usage.
+   </li>
+   <li>
+     <a href="src/com/example/android/voicemail/common/core/Voicemail.html">
+       <code>Voicemail</code>
+     </a> and its implementation in
+    <a href="src/com/example/android/voicemail/common/core/VoicemailImpl.html">
+      <code>VoicemailImpl</code> </a>.
+      This interface provides a structured view of most the important fields in
+      voicemail content provider.
+   </li>
+ </ul>
+</p>
diff --git a/samples/VoicemailProviderDemo/res/drawable-hdpi/icon.png b/samples/VoicemailProviderDemo/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/samples/VoicemailProviderDemo/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/samples/VoicemailProviderDemo/res/drawable-ldpi/icon.png b/samples/VoicemailProviderDemo/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/samples/VoicemailProviderDemo/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/samples/VoicemailProviderDemo/res/drawable-mdpi/icon.png b/samples/VoicemailProviderDemo/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/samples/VoicemailProviderDemo/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/samples/VoicemailProviderDemo/res/layout/add_voicemail.xml b/samples/VoicemailProviderDemo/res/layout/add_voicemail.xml
new file mode 100644
index 0000000..8b2f52d
--- /dev/null
+++ b/samples/VoicemailProviderDemo/res/layout/add_voicemail.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2011 The Android Open Source Project.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/add_voicemail"/>
+
+    <EditText android:id = "@+id/sender_number"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/sender_number"
+        android:inputType="phone"/>
+    <EditText android:id = "@+id/time"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/time"/>
+    <EditText android:id = "@+id/duration"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/duration"
+        android:inputType="number"/>
+    <EditText android:id = "@+id/mime_type"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/mime_type"/>
+    <EditText android:id = "@+id/provider_package"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"/>
+
+    <!-- Recording button -->
+    <Button android:id = "@+id/start_recording_btn"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/record_voice"/>
+
+    <!-- Save button -->
+    <Button android:id = "@+id/save_btn"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/send"/>
+</LinearLayout>
diff --git a/samples/VoicemailProviderDemo/res/values/strings.xml b/samples/VoicemailProviderDemo/res/values/strings.xml
new file mode 100644
index 0000000..250a6b7
--- /dev/null
+++ b/samples/VoicemailProviderDemo/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2011 The Android Open Source Project.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<resources>
+    <string name="app_name">VoicemaiProviderDemo</string>
+    <!-- AddVoicemailActivity -->
+    <string name="add_voicemail">Add voicemail</string>
+    <string name="sender_number">Sender phone number</string>
+    <string name="time">Time in DD/MM/YYYY hh:mm</string>
+    <string name="duration">Duration in seconds</string>
+    <string name="mime_type">MIME type</string>
+    <string name="voicemail_store_error">Error in storing voicemail!</string>
+    <string name="send">Send</string>
+    <string name="record_voice">Record voice</string>
+</resources>
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/provider/VoicemailContract.java b/samples/VoicemailProviderDemo/src/com/example/android/provider/VoicemailContract.java
new file mode 100644
index 0000000..3fe6cc8
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/provider/VoicemailContract.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.provider;
+
+// This is a COPY of the voicemail provider contract file checked in at
+// framework/base/core/java/android/provider. The API is currently hidden so
+// it is not available through the SDK and hence is not available to the sample
+// code.
+// TODO: get rid of this copy once the voicemail provider API is opened ups.
+
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.provider.CallLog.Calls;
+
+/**
+ * The contract between the voicemail provider and applications. Contains
+ * definitions for the supported URIs and columns.
+ *
+ * <P>Voicemails are inserted by what is called as a "voicemail source"
+ * application, which is responsible for syncing voicemail data between a remote
+ * server and the local voicemail content provider. "voicemail source"
+ * application should use the source specific {@link #CONTENT_URI_SOURCE} URI
+ * to insert and retrieve voicemails.
+ *
+ * <P>In addition to the {@link ContentObserver} notifications the voicemail
+ * provider also generates broadcast intents to notify change for applications
+ * that are not active and therefore cannot listen to ContentObserver
+ * notifications. Broadcast intents with following actions are generated:
+ * <ul>
+ *   <li> {@link #ACTION_NEW_VOICEMAIL} is generated for each new voicemail
+ *   inserted.
+ *   </li>
+ *   <li> {@link Intent#ACTION_PROVIDER_CHANGED} is generated for any change
+ *    made into the database, including new voicemail.
+ *   </li>
+ * </ul>
+ * @hide
+ */
+// TODO: unhide when the API is approved by android-api-council
+public class VoicemailContract {
+    /** Not instantiable. */
+    private VoicemailContract() {
+    }
+
+    /** The authority used by the voicemail provider. */
+    public static final String AUTHORITY = "com.android.voicemail";
+    /**
+     * URI to insert/retrieve all voicemails.
+     * @deprecated
+     */
+    public static final Uri CONTENT_URI =
+            Uri.parse("content://" + AUTHORITY + "/voicemail");
+    /**
+     * URI to insert/retrieve voicemails by a given voicemail source.
+     * @deprecated
+     */
+    public static final Uri CONTENT_URI_SOURCE =
+            Uri.parse("content://" + AUTHORITY + "/voicemail/source/");
+    /**
+     * Parameter key used in the URI to specify the voicemail source package name.
+     * <p> This field must be set in all requests that originate from a voicemail source.
+     */
+    public static final String PARAM_KEY_SOURCE_PACKAGE = "source_package";
+
+    // TODO: Move ACTION_NEW_VOICEMAIL to the Intent class.
+    /** Broadcast intent when a new voicemail record is inserted. */
+    public static final String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
+    /**
+     * Extra included in {@value Intent#ACTION_PROVIDER_CHANGED} and
+     * {@value #ACTION_NEW_VOICEMAIL} broadcast intents to indicate if the receiving
+     * package made this change.
+     */
+    public static final String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
+
+    /**
+     * The mime type for a collection of voicemails.
+     * @deprecated */
+    public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
+
+    /** Defines fields exposed through the /voicemail path of this content provider. */
+    public static final class Voicemails implements BaseColumns {
+        /** Not instantiable. */
+        private Voicemails() {
+        }
+
+        /** URI to insert/retrieve voicemails by a given voicemail source. */
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://" + AUTHORITY + "/voicemail");
+        /** URI to insert/retrieve voicemails by a given voicemail source. */
+        public static final Uri CONTENT_URI_SOURCE =
+                Uri.parse("content://" + AUTHORITY + "/voicemail/source/");
+
+        /** The mime type for a collection of voicemails. */
+        public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
+
+        /**
+         * Phone number of the voicemail sender.
+         * <P>Type: TEXT</P>
+         */
+        public static final String NUMBER = Calls.NUMBER;
+        /**
+         * The date the voicemail was sent, in milliseconds since the epoch
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String DATE = Calls.DATE;
+        /**
+         * The duration of the voicemail in seconds.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String DURATION = Calls.DURATION;
+        /**
+         * Whether this is a new voicemail (i.e. has not been heard).
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String NEW = Calls.NEW;
+        /**
+         * The mail box state of the voicemail.
+         * <P> Possible values: {@link #STATE_INBOX}, {@link #STATE_DELETED},
+         * {@link #STATE_UNDELETED}.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String STATE = "state";
+        /** Value of {@link #STATE} when the voicemail is in inbox. */
+        public static int STATE_INBOX = 0;
+        /** Value of {@link #STATE} when the voicemail has been marked as deleted. */
+        public static int STATE_DELETED = 1;
+        /** Value of {@link #STATE} when the voicemail has marked as undeleted. */
+        public static int STATE_UNDELETED = 2;
+        /**
+         * Package name of the source application that inserted the voicemail.
+         * <P>Type: TEXT</P>
+         */
+        public static final String SOURCE_PACKAGE = "source_package";
+        /**
+         * Application-specific data available to the source application that
+         * inserted the voicemail. This is typically used to store the source
+         * specific message id to identify this voicemail on the remote
+         * voicemail server.
+         * <P>Type: TEXT</P>
+         * <P> Note that this is NOT the voicemail media content data.
+         */
+        public static final String SOURCE_DATA = "source_data";
+        /**
+         * Whether the media content for this voicemail is available for
+         * consumption.
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String HAS_CONTENT = "has_content";
+        /**
+         * MIME type of the media content for the voicemail.
+         * <P>Type: TEXT</P>
+         */
+        public static final String MIME_TYPE = "mime_type";
+        /**
+         * Path to the media content file. Internal only field.
+         * @hide
+         */
+        public static final String _DATA = "_data";
+
+        /**
+         * A convenience method to build voicemail URI specific to a source package by appending
+         * {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
+         */
+        public static Uri buildSourceUri(String packageName) {
+            return Voicemails.CONTENT_URI.buildUpon()
+                    .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
+        }
+    }
+
+    /** Defines fields exposed through the /status path of this content provider. */
+    public static final class Status implements BaseColumns {
+        /** URI to insert/retrieve status of voicemail source. */
+        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/status");
+        /** The mime type for a collection of voicemail source statuses. */
+        public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status";
+        /** The mime type for a collection of voicemails. */
+        public static final String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status";
+
+        /** Not instantiable. */
+        private Status() {
+        }
+        /**
+         * The package name of the voicemail source. There can only be a one entry per source.
+         * <P>Type: TEXT</P>
+         */
+        public static final String SOURCE_PACKAGE = "source_package";
+        /**
+         * The URI to call to invoke source specific voicemail settings screen. On a user request
+         * to setup voicemail an intent with action VIEW with this URI will be fired by the system.
+         * <P>Type: TEXT</P>
+         */
+        public static final String SETTINGS_URI = "settings_uri";
+        /**
+         * The URI to call when the user requests to directly access the voicemail from the remote
+         * server. In case of an IVR voicemail system this is typically set to the the voicemail
+         * number specified using a tel:/ URI.
+         * <P>Type: TEXT</P>
+         */
+        public static final String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
+        /**
+         * The configuration state of the voicemail source.
+         * <P> Possible values:
+         * {@link #CONFIGURATION_STATE_OK},
+         * {@link #CONFIGURATION_STATE_NOT_CONFIGURED},
+         * {@link #CONFIGURATION_STATE_CAN_BE_CONFIGURED}
+         * <P>Type: INTEGER</P>
+         */
+        public static final String CONFIGURATION_STATE = "configuration_state";
+        public static final int CONFIGURATION_STATE_OK = 0;
+        public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1;
+        /**
+         * This state must be used when the source has verified that the current user can be
+         * upgraded to visual voicemail and would like to show a set up invitation message.
+         */
+        public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2;
+        /**
+         * The data channel state of the voicemail source. This the channel through which the source
+         * pulls voicemail data from a remote server.
+         * <P> Possible values:
+         * {@link #DATA_CHANNEL_STATE_OK},
+         * {@link #DATA_CHANNEL_STATE_NO_CONNECTION}
+         * </P>
+         * <P>Type: INTEGER</P>
+         */
+        public static final String DATA_CHANNEL_STATE = "data_channel_state";
+        public static final int DATA_CHANNEL_STATE_OK = 0;
+        public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1;
+        /**
+         * The notification channel state of the voicemail source. This is the channel through which
+         * the source gets notified of new voicemails on the remote server.
+         * <P> Possible values:
+         * {@link #NOTIFICATION_CHANNEL_STATE_OK},
+         * {@link #NOTIFICATION_CHANNEL_STATE_NO_CONNECTION},
+         * {@link #NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING}
+         * </P>
+         * <P>Type: INTEGER</P>
+         */
+        public static final String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
+        public static final int NOTIFICATION_CHANNEL_STATE_OK = 0;
+        public static final int NOTIFICATION_CHANNEL_STATE_NO_CONNECTION = 1;
+        /**
+         * Use this state when the notification can only tell that there are pending messages on
+         * the server but no details of the sender/time etc are known.
+         */
+        public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2;
+
+        /**
+         * A convenience method to build status URI specific to a source package by appending
+         * {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
+         */
+        public static Uri buildSourceUri(String packageName) {
+            return Status.CONTENT_URI.buildUpon()
+                    .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
+        }
+    }
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/AddVoicemailActivity.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/AddVoicemailActivity.java
new file mode 100644
index 0000000..c2a34ae
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/AddVoicemailActivity.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.MediaStore;
+import android.util.Pair;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.example.android.voicemail.common.core.Voicemail;
+import com.example.android.voicemail.common.core.VoicemailImpl;
+import com.example.android.voicemail.common.core.VoicemailProviderHelper;
+import com.example.android.voicemail.common.core.VoicemailProviderHelpers;
+import com.example.android.voicemail.common.inject.InjectView;
+import com.example.android.voicemail.common.inject.Injector;
+import com.example.android.voicemail.common.logging.Logger;
+import com.example.android.voicemail.common.ui.DialogHelperImpl;
+import com.example.android.voicemail.common.utils.CloseUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * A simple activity that stores user entered voicemail data into voicemail content provider. To be
+ * used as a test voicemail source.
+ */
+public class AddVoicemailActivity extends Activity {
+    private static final Logger logger = Logger.getLogger(AddVoicemailActivity.class);
+
+    private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("dd/MM/yyyy h:mm");
+
+    private static final int REQUEST_CODE_RECORDING = 100;
+
+    private final DialogHelperImpl mDialogHelper = new DialogHelperImpl(this);
+    /**
+     * This is created in {@link #onCreate(Bundle)}, and needs to be released in
+     * {@link #onDestroy()}.
+     */
+    private VoicemailProviderHelper mVoicemailProviderHelper;
+    private Uri mRecordingUri;
+
+    // Mark the views as injectable. These objects are instantiated automatically during
+    // onCreate() by finding the appropriate view that matches the specified resource_id.
+    @InjectView(R.id.start_recording_btn)
+    private Button mStartRec;
+    @InjectView(R.id.save_btn)
+    private Button mSaveButton;
+    @InjectView(R.id.time)
+    private TextView mTime;
+    @InjectView(R.id.provider_package)
+    private TextView mProviderPackage;
+    @InjectView(R.id.mime_type)
+    private TextView mMimeType;
+    @InjectView(R.id.sender_number)
+    private TextView mSenderNumber;
+    @InjectView(R.id.duration)
+    private TextView mDuration;
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.add_voicemail);
+        // Inject all objects that are marked by @InjectView annotation.
+        Injector.get(this).inject();
+        mVoicemailProviderHelper = VoicemailProviderHelpers.createPackageScopedVoicemailProvider(this);
+
+        setDefaultValues();
+
+        // Record voice button.
+        mStartRec.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                startRecording();
+            }
+        });
+
+        // Save voicemail button.
+        mSaveButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                storeVoicemail();
+            }
+
+        });
+    }
+
+    private void storeVoicemail() {
+        try {
+            Pair<Voicemail, Uri> newVoicemail = new Pair<Voicemail, Uri>(
+                    buildVoicemailObjectFromUiElements(), mRecordingUri);
+            new InsertVoicemailTask().execute(newVoicemail);
+        } catch (ParseException e) {
+            handleError(e);
+        }
+    }
+
+    private Voicemail buildVoicemailObjectFromUiElements() throws ParseException {
+        String sender = mSenderNumber.getText().toString();
+        String dateStr = mTime.getText().toString();
+        String durationStr = mDuration.getText().toString();
+        String mimeType = mMimeType.getText().toString();
+        String sourcePackageName = mProviderPackage.getText().toString();
+        long time = DATE_FORMATTER.parse(dateStr.trim()).getTime();
+        long duration = durationStr.length() != 0 ? Long.parseLong(durationStr) : 0;
+        return VoicemailImpl.createForInsertion(time, sender)
+                .setDuration(duration)
+                .setSourcePackage(sourcePackageName)
+                .setMailbox(Voicemail.Mailbox.INBOX)
+                .build();
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        switch (requestCode) {
+            case REQUEST_CODE_RECORDING:
+                handleRecordingResult(resultCode, data);
+                break;
+            default:
+                logger.e("onActivityResult: Unexpected requestCode: " + requestCode);
+        }
+    }
+
+    @Override
+    protected Dialog onCreateDialog(int id, Bundle bundle) {
+        return mDialogHelper.handleOnCreateDialog(id, bundle);
+    }
+
+    /** Set default values in the display */
+    private void setDefaultValues() {
+        // Set time to current time.
+        mTime.setText(DATE_FORMATTER.format(new Date()));
+
+        // Set provider package to this app's package.
+        mProviderPackage.setText(getPackageName());
+    }
+
+    private void startRecording() {
+        Intent recordingIntent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
+        startActivityForResult(recordingIntent, REQUEST_CODE_RECORDING);
+    }
+
+    private void handleRecordingResult(int resultCode, Intent data) {
+        if (resultCode != RESULT_OK) {
+            handleError(new Exception("Failed to do recording. Error Code: " + resultCode));
+        }
+
+        Uri uri = data.getData();
+        logger.d("Received recording URI: " + uri);
+        if (uri != null) {
+            mRecordingUri = uri;
+            mMimeType.setText(getContentResolver().getType(uri));
+        }
+    }
+
+    private void handleError(Exception e) {
+        mDialogHelper.showErrorMessageDialog(R.string.voicemail_store_error, e);
+    }
+
+    /**
+     * An async task that inserts a new voicemail record using a background thread.
+     * The tasks accepts a pair of voicemail object and the recording Uri as the param.
+     * The result returned is the error exception, if any, encountered during the operation.
+     */
+    private class InsertVoicemailTask extends AsyncTask<Pair<Voicemail, Uri>, Void, Exception> {
+        @Override
+        protected Exception doInBackground(Pair<Voicemail, Uri>... params) {
+            if (params.length > 0) {
+                try {
+                    insertVoicemail(params[0].first, params[0].second);
+                } catch (IOException e) {
+                    return e;
+                }
+            }
+            return null;
+        }
+
+        private void insertVoicemail(Voicemail voicemail, Uri recordingUri) throws IOException {
+            InputStream inputAudioStream = recordingUri == null ? null :
+                  getContentResolver().openInputStream(recordingUri);
+            Uri newVoicemailUri = mVoicemailProviderHelper.insert(voicemail);
+            logger.i("Inserted new voicemail URI: " + newVoicemailUri);
+            if (inputAudioStream != null) {
+                OutputStream outputStream = null;
+                try {
+                    outputStream = mVoicemailProviderHelper.setVoicemailContent(
+                            newVoicemailUri, getContentResolver().getType(recordingUri));
+                    copyStreamData(inputAudioStream, outputStream);
+                } finally {
+                    CloseUtils.closeQuietly(outputStream);
+                    CloseUtils.closeQuietly(inputAudioStream);
+                }
+            }
+        }
+
+        @Override
+        protected void onPostExecute(Exception error) {
+            if (error == null) {
+                // No error - done.
+                finish();
+            } else {
+                handleError(error);
+            }
+        }
+
+        private void copyStreamData(InputStream in, OutputStream out) throws IOException {
+            // Copy 8K chunk at a time.
+            byte[] data = new byte[8 * 1024];
+            int numBytes;
+            while ((numBytes = in.read(data)) > 0) {
+                out.write(data, 0, numBytes);
+            }
+        }
+    }
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/Voicemail.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/Voicemail.java
new file mode 100644
index 0000000..17f03c7
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/Voicemail.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.core;
+
+import com.example.android.provider.VoicemailContract;
+
+import android.net.Uri;
+
+/**
+ * Represents a single voicemail stored in the voicemail content provider.
+ * <p>
+ * The presence of a field is indicated by a corresponding 'has' method.
+ */
+public interface Voicemail {
+    /**
+     * Which mailbox the message is sitting in.
+     * <p>
+     * Note that inbox and deleted are alone insufficient, because we may have a provider that is
+     * not able to undelete (re-upload) a message. Thus we need a state to represent the (common)
+     * case where the user has deleted a message (which results in the message being removed from
+     * the server) and then restored the message (where we are unable to re-upload the message to
+     * the server). That's what the undeleted state is for.
+     * <p>
+     * The presence of an undeleted mailbox prevents the voicemail source from having to keep a list
+     * of all such deleted-then-restored message ids, without which it would be unable to tell the
+     * difference between a message that has been deleted-then-restored by the user and a message
+     * which has been deleted on the server and should now be removed (for example one removed via
+     * an IVR).
+     */
+    public enum Mailbox {
+        /** After being fetched from the server, a message usually starts in the inbox. */
+        INBOX(VoicemailContract.Voicemails.STATE_INBOX),
+        /** Indicates that a message has been deleted. */
+        DELETED(VoicemailContract.Voicemails.STATE_DELETED),
+        /** Restored from having been deleted, distinct from being in the inbox. */
+        UNDELETED(VoicemailContract.Voicemails.STATE_UNDELETED);
+
+        private final int mValue;
+
+        private Mailbox(int value) {
+            mValue = value;
+        }
+
+        /** Returns the DB value of this mailbox state. */
+        public int getValue() {
+            return mValue;
+        }
+    }
+
+    /**
+     * The identifier of the voicemail in the content provider.
+     * <p>
+     * This may be missing in the case of a new {@link Voicemail} that we plan to insert into the
+     * content provider, since until it has been inserted we don't know what id it should have. If
+     * none is specified, we return -1.
+     */
+    public long getId();
+
+    public boolean hasId();
+
+    /** The number of the person leaving the voicemail, empty string if unknown, null if not set. */
+    public String getNumber();
+
+    public boolean hasNumber();
+
+    /** The timestamp the voicemail was received, in millis since the epoch, zero if not set. */
+    public long getTimestampMillis();
+
+    public boolean hasTimestampMillis();
+
+    /** Gets the duration of the voicemail in millis, or zero if the field is not set. */
+    public long getDuration();
+
+    public boolean hasDuration();
+
+    /**
+     * Returns the package name of the source that added this voicemail, or null if this field is
+     * not set.
+     */
+    public String getSourcePackage();
+
+    public boolean hasSourcePackage();
+
+    /**
+     * Returns the application-specific data type stored with the voicemail, or null if this field
+     * is not set.
+     * <p>
+     * Source data is typically used as an identifier to uniquely identify the voicemail against
+     * the voicemail server. This is likely to be something like the IMAP UID, or some other
+     * server-generated identifying string.
+     */
+    public String getSourceData();
+
+    public boolean hasSourceData();
+
+    /**
+     * Gets the Uri that can be used to refer to this voicemail, and to make it play.
+     * <p>
+     * Returns null if we don't know the Uri.
+     */
+    public Uri getUri();
+
+    public boolean hasUri();
+
+    /** Tells us which mailbox the message is sitting in, returns null if this is not set. */
+    public Voicemail.Mailbox getMailbox();
+
+    public boolean hasMailbox();
+
+    /**
+     * Tells us if the voicemail message has been marked as read.
+     * <p>
+     * Always returns false if this field has not been set, i.e. if hasRead() returns false.
+     */
+    public boolean isRead();
+
+    public boolean hasRead();
+
+    /**
+     * Tells us if there is content stored at the Uri.
+     */
+    public boolean hasContent();
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailFilter.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailFilter.java
new file mode 100644
index 0000000..20abe33
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailFilter.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.core;
+
+/**
+ * An object that can be used to apply filter on voicemail queries made through the voicemail helper
+ * interface.
+ */
+public interface VoicemailFilter {
+    /** Returns the where clause for this filter. Returns null if the filter is empty. */
+    public String getWhereClause();
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailFilterFactory.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailFilterFactory.java
new file mode 100644
index 0000000..b3eab91
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailFilterFactory.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.core;
+
+import static com.example.android.voicemail.common.utils.DbQueryUtils.concatenateClausesWithAnd;
+import static com.example.android.voicemail.common.utils.DbQueryUtils.concatenateClausesWithOr;
+import static com.example.android.voicemail.common.utils.DbQueryUtils.getEqualityClause;
+
+import com.example.android.voicemail.common.core.Voicemail.Mailbox;
+import com.example.android.provider.VoicemailContract.Voicemails;
+
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Factory class to create {@link VoicemailFilter} objects for various filtering needs.
+ * <p>
+ * Factory methods like {@link #createWithMailbox(Mailbox)}, {@link #createWithReadStatus(boolean)}
+ * and {@link #createWithMatchingFields(Voicemail)} can be used to create a voicemail filter that
+ * matches the value of the specific field.
+ * <p>
+ * It is possible to combine multiple filters with OR or AND operation using the methods
+ * {@link #createWithOrOf(VoicemailFilter...)} and {@link #createWithAndOf(VoicemailFilter...)}
+ * respectively.
+ * <p>
+ * {@link #createWithWhereClause(String)} can be used to create an arbitrary filter for a specific
+ * where clause. Using this method requires the knowledge of the name of columns used in voicemail
+ * content provider database and is therefore less recommended.
+ */
+public class VoicemailFilterFactory {
+    /** Predefined filter for inbox only messages. */
+    public static final VoicemailFilter INBOX_MESSAGES_FILTER = createWithOrOf(
+            createWithMailbox(Mailbox.INBOX), createWithMailbox(Mailbox.UNDELETED));
+    /** Predefined filter for trashed messages. */
+    public static final VoicemailFilter TRASHED_MESSAGES_FILTER =
+            createWithMailbox(Mailbox.DELETED);
+
+    /**
+     * Creates a voicemail filter with the specified where clause. Use this method only if you know
+     * and want to directly use the column names of the content provider. For most of the usages
+     * one of the other factory methods should be good enough.
+     */
+    public static VoicemailFilter createWithWhereClause(final String whereClause) {
+        return new VoicemailFilter() {
+          @Override
+          public String getWhereClause() {
+            return TextUtils.isEmpty(whereClause) ? null : whereClause;
+          }
+          @Override
+          public String toString() {
+              return getWhereClause();
+          }
+        };
+    }
+
+    /** Creates a filter with fields matching the ones set in the supplied voicemail object. */
+    public static VoicemailFilter createWithMatchingFields(Voicemail fieldMatch) {
+        if (fieldMatch == null) {
+            throw new IllegalArgumentException("Cannot create filter null fieldMatch");
+        }
+        return VoicemailFilterFactory.createWithWhereClause(
+                getWhereClauseForMatchingFields(fieldMatch));
+    }
+
+    /** Creates a voicemail filter with the specified mailbox state. */
+    public static VoicemailFilter createWithMailbox(Mailbox mailbox) {
+        return createWithMatchingFields(
+                VoicemailImpl.createEmptyBuilder().setMailbox(mailbox).build());
+    }
+
+    /** Creates a voicemail filter with the specified read status. */
+    public static VoicemailFilter createWithReadStatus(boolean isRead) {
+        return createWithMatchingFields(
+                VoicemailImpl.createEmptyBuilder().setIsRead(isRead).build());
+    }
+
+    /** Combine multiple filters with OR clause. */
+    public static VoicemailFilter createWithAndOf(VoicemailFilter... filters) {
+        return createWithWhereClause(concatenateClausesWithAnd(getClauses(filters)));
+    }
+
+    /** Combine multiple filters with AND clause. */
+    public static VoicemailFilter createWithOrOf(VoicemailFilter... filters) {
+        return createWithWhereClause(concatenateClausesWithOr(getClauses(filters)));
+    }
+
+    private static String[] getClauses(VoicemailFilter[] filters) {
+        String[] clauses = new String[filters.length];
+        for (int i = 0; i < filters.length; ++i) {
+            clauses[i] = filters[i].getWhereClause();
+        }
+        return clauses;
+    }
+
+    private static String getWhereClauseForMatchingFields(Voicemail fieldMatch) {
+        List<String> clauses = new ArrayList<String>();
+        if (fieldMatch.hasRead()) {
+            clauses.add(getEqualityClause(Voicemails.NEW, fieldMatch.isRead() ? "1" : "0"));
+        }
+        if (fieldMatch.hasMailbox()) {
+            clauses.add(getEqualityClause(Voicemails.STATE,
+                    Integer.toString(fieldMatch.getMailbox().getValue())));
+        }
+        if (fieldMatch.hasNumber()) {
+            clauses.add(getEqualityClause(Voicemails.NUMBER, fieldMatch.getNumber()));
+        }
+        if (fieldMatch.hasSourcePackage()) {
+            clauses.add(getEqualityClause(Voicemails.SOURCE_PACKAGE,
+                    fieldMatch.getSourcePackage()));
+        }
+        if (fieldMatch.hasSourceData()) {
+            clauses.add(getEqualityClause(Voicemails.SOURCE_DATA, fieldMatch.getSourceData()));
+        }
+        if (fieldMatch.hasDuration()) {
+            clauses.add(getEqualityClause(Voicemails.DURATION,
+                    Long.toString(fieldMatch.getDuration())));
+        }
+        if (fieldMatch.hasTimestampMillis()) {
+            clauses.add(getEqualityClause(Voicemails.DATE,
+                    Long.toString(fieldMatch.getTimestampMillis())));
+        }
+        // Empty filter.
+        if (clauses.size() == 0) {
+            return null;
+        }
+        return concatenateClausesWithAnd(clauses.toArray(new String[0]));
+    }
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailImpl.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailImpl.java
new file mode 100644
index 0000000..9e08b68
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailImpl.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.core;
+
+import android.net.Uri;
+
+/**
+ * A simple immutable data object to represent a voicemail.
+ */
+public final class VoicemailImpl implements Voicemail {
+    private final Long mTimestamp;
+    private final String mNumber;
+    private final Long mId;
+    private final Long mDuration;
+    private final String mSource;
+    private final String mProviderData;
+    private final Uri mUri;
+    private final Voicemail.Mailbox mMailbox;
+    private final Boolean mIsRead;
+    private final boolean mHasContent;
+
+    // TODO: 5. We should probably consider changing "number" everywhere to "contact", given that
+    // it's not clear that these will be restricted to telephone numbers.
+
+    private VoicemailImpl(
+            Long timestamp,
+            String number,
+            Long id,
+            Long duration,
+            String source,
+            String providerData,
+            Uri uri,
+            Voicemail.Mailbox mailbox,
+            Boolean isRead,
+            boolean hasContent) {
+        mId = id;
+        mNumber = number;
+        mDuration = duration;
+        mTimestamp = timestamp;
+        mSource = source;
+        mProviderData = providerData;
+        mUri = uri;
+        mMailbox = mailbox;
+        mIsRead = isRead;
+        mHasContent = hasContent;
+    }
+
+    /**
+     * Create a {@link Builder} for a new {@link Voicemail} to be inserted.
+     * <p>
+     * The number and the timestamp are mandatory for insertion.
+     */
+    public static Builder createForInsertion(long timestamp, String number) {
+        return new Builder().setNumber(number).setTimestamp(timestamp);
+    }
+
+    /**
+     * Create a {@link Builder} for updating a {@link Voicemail}.
+     * <p>
+     * Only the id of the voicemail to be updated is mandatory.
+     */
+    public static Builder createForUpdate(long id) {
+        return new Builder().setId(id);
+    }
+
+    /**
+     * Create a {@link Builder} for a new {@link Voicemail}, such as one suitable for returning from
+     * a list of results or creating from scratch.
+     */
+    public static Builder createEmptyBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder pattern for creating a {@link VoicemailImpl}.
+     * <p>
+     * All fields are optional, and can be set with the various {@code setXXX} methods.
+     * <p>
+     * This class is <b>not thread safe</b>
+     */
+    public static class Builder {
+        private Long mBuilderTimestamp;
+        private String mBuilderNumber;
+        private Long mBuilderId;
+        private Long mBuilderDuration;
+        private String mBuilderSourcePackage;
+        private String mBuilderSourceData;
+        private Uri mBuilderUri;
+        private Voicemail.Mailbox mBuilderMailbox;
+        private Boolean mBuilderIsRead;
+        private boolean mBuilderHasContent;
+
+        /** You should use the correct factory method to construct a builder. */
+        private Builder() {
+        }
+
+        public Builder setNumber(String number) {
+            mBuilderNumber = number;
+            return this;
+        }
+
+        public Builder setTimestamp(long timestamp) {
+            mBuilderTimestamp = timestamp;
+            return this;
+        }
+
+        public Builder setId(long id) {
+            mBuilderId = id;
+            return this;
+        }
+
+        public Builder setDuration(long duration) {
+            mBuilderDuration = duration;
+            return this;
+        }
+
+        public Builder setSourcePackage(String sourcePackage) {
+            mBuilderSourcePackage = sourcePackage;
+            return this;
+        }
+
+        public Builder setSourceData(String sourceData) {
+            mBuilderSourceData = sourceData;
+            return this;
+        }
+
+        public Builder setUri(Uri uri) {
+            mBuilderUri = uri;
+            return this;
+        }
+
+        public Builder setMailbox(Voicemail.Mailbox mailbox) {
+            mBuilderMailbox = mailbox;
+            return this;
+        }
+
+        public Builder setIsRead(boolean isRead) {
+            mBuilderIsRead = isRead;
+            return this;
+        }
+
+        public Builder setHasContent(boolean hasContent) {
+            mBuilderHasContent = hasContent;
+            return this;
+        }
+
+        public VoicemailImpl build() {
+            return new VoicemailImpl(mBuilderTimestamp, mBuilderNumber, mBuilderId,
+                    mBuilderDuration,
+                    mBuilderSourcePackage, mBuilderSourceData, mBuilderUri, mBuilderMailbox,
+                    mBuilderIsRead,
+                    mBuilderHasContent);
+        }
+    }
+
+    @Override
+    public long getId() {
+        return hasId() ? mId : -1;
+    }
+
+    @Override
+    public boolean hasId() {
+        return mId != null;
+    }
+
+    @Override
+    public String getNumber() {
+        return mNumber;
+    }
+
+    @Override
+    public boolean hasNumber() {
+        return mNumber != null;
+    }
+
+    @Override
+    public long getTimestampMillis() {
+        return hasTimestampMillis() ? mTimestamp : 0;
+    }
+
+    @Override
+    public boolean hasTimestampMillis() {
+        return mTimestamp != null;
+    }
+
+    @Override
+    public long getDuration() {
+        return hasDuration() ? mDuration : 0;
+    }
+
+    @Override
+    public boolean hasDuration() {
+        return mDuration != null;
+    }
+
+    @Override
+    public String getSourcePackage() {
+        return mSource;
+    }
+
+    @Override
+    public boolean hasSourcePackage() {
+        return mSource != null;
+    }
+
+    @Override
+    public String getSourceData() {
+        return mProviderData;
+    }
+
+    @Override
+    public boolean hasSourceData() {
+        return mProviderData != null;
+    }
+
+    @Override
+    public Uri getUri() {
+        return mUri;
+    }
+
+    @Override
+    public boolean hasUri() {
+        return mUri != null;
+    }
+
+    @Override
+    public Mailbox getMailbox() {
+        return mMailbox;
+    }
+
+    @Override
+    public boolean hasMailbox() {
+        return mMailbox != null;
+    }
+
+    @Override
+    public boolean isRead() {
+        return hasRead() ? mIsRead : false;
+    }
+
+    @Override
+    public boolean hasRead() {
+        return mIsRead != null;
+    }
+
+    @Override
+    public boolean hasContent() {
+        return mHasContent;
+    }
+
+    @Override
+    public String toString() {
+        return "VoicemailImpl [mTimestamp=" + mTimestamp + ", mNumber=" + mNumber + ", mId=" + mId
+                + ", mDuration=" + mDuration + ", mSource=" + mSource + ", mProviderData="
+                + mProviderData + ", mUri=" + mUri + ", mMailbox=" + mMailbox + ", mIsRead="
+                + mIsRead + ", mHasContent=" + mHasContent + "]";
+    }
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelper.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelper.java
new file mode 100644
index 0000000..d3ff514
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelper.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.core;
+
+import com.example.android.provider.VoicemailContract;
+
+import android.net.Uri;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+/**
+ * Provides a simple interface to manipulate voicemails within the voicemail content provider.
+ * <p>
+ * Methods on this interface throw checked exceptions only where the corresponding underlying
+ * methods perform an operation that itself requires a checked exception. In all other cases a
+ * {@link RuntimeException} will be thrown here.
+ * <p>
+ * These methods are blocking, and will return control to the caller only when the operation
+ * completes. You should not call any of these methods from your main ui thread, as this may result
+ * in your application becoming unresponsive.
+ */
+public interface VoicemailProviderHelper {
+
+    /** Sort order to return results by. */
+    public enum SortOrder {
+        ASCENDING,
+        DESCENDING,
+        /** Default sort order returned by DB. (Typically Ascending, but no guarantees made). */
+        DEFAULT
+    }
+
+    /**
+     * Clears all voicemails accessible to this voicemail content provider.
+     *
+     * @return the number of voicemails deleted
+     */
+    public int deleteAll();
+
+    /**
+     * Inserts a new voicemail into the voicemail content provider.
+     *
+     * @param voicemail data to be inserted
+     * @return {@link Uri} of the newly inserted {@link Voicemail}
+     * @throws IllegalArgumentException if any of the following are true:
+     *         <ul>
+     *         <li>your voicemail is missing a timestamp</li>
+     *         <li>your voiceamil is missing a number</li>
+     *         <li>your voicemail is missing the provider id field</li>
+     *         <li>voicemail has an id (which would indicate that it has already been inserted)
+     *         </li>
+     *         </ul>
+     */
+    public Uri insert(Voicemail voicemail);
+
+    /**
+     * Returns the {@link Voicemail} whose provider data matches the given value.
+     * <p>
+     * It is expected that there be one such voicemail. Returns null if no such voicemail exists,
+     * and returns one chosen arbitrarily if more than one exists.
+     */
+    public Voicemail findVoicemailBySourceData(String providerData);
+
+    /**
+     * Returns the {@link Voicemail} corresponding to a given Uri. The uri must correspond to a
+     * unique voicemail record.
+     * <p>
+     * Returns null if no voicemail was found that exactly matched the given uri.
+     */
+    public Voicemail findVoicemailByUri(Uri uri);
+
+    /**
+     * Updates an existing voicemail in the content provider.
+     * <p>
+     * Note that <b>only the fields that are set</b> on the {@link Voicemail} that you provide will
+     * be used to perform the update. The remaining fields will be left unmodified. To mark a
+     * voicemail as read, create a new {@link Voicemail} that is marked as read, and call update.
+     *
+     * @throws IllegalArgumentException if you provide a {@link Voicemail} that already has a Uri
+     *             set, because we don't support altering the Uri of a voicemail, and this most
+     *             likely implies that you're using this api incorrectly
+     * @return the number of rows that were updated
+     */
+    public int update(Uri uri, Voicemail voicemail);
+
+    /**
+     * Get the OutputStream to write the voicemail content with the given mime type.
+     * <p>
+     * <b>Remember to close the OutputStream after you're done writing.</b>
+     *
+     * @throws IOException if there is a problem creating the file or no voicemail is found matching
+     *             the given Uri
+     */
+    public OutputStream setVoicemailContent(Uri voicemailUri, String mimeType) throws IOException;
+
+    /**
+     * Fetch all the voicemails accessible to this voicemail content provider.
+     *
+     * @return the list of voicemails, no guarantee is made about the ordering
+     */
+    public List<Voicemail> getAllVoicemails();
+
+    /**
+     * Same as {@link #getAllVoicemails()} but also sorts them by the requested column and allows to
+     * set a filter.
+     *
+     * @param filter The filter to apply while retrieving voicemails.
+     * @param sortColumn The column to sort by. Must be one of the values defined in
+     *            {@link VoicemailContract.Voicemails}.
+     * @param sortOrder Order to sort by
+     * @return the list of voicemails, sorted by the requested DB column in specified sort order.
+     */
+    public List<Voicemail> getAllVoicemails(VoicemailFilter filter,
+            String sortColumn, SortOrder sortOrder);
+
+    /**
+     * Returns the Uri for the voicemail with the specified message Id.
+     */
+    public Uri getUriForVoicemailWithId(long id);
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelpers.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelpers.java
new file mode 100644
index 0000000..2d8d9bc
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelpers.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.core;
+
+import com.example.android.provider.VoicemailContract.Voicemails;
+import com.example.android.voicemail.common.logging.Logger;
+import com.example.android.voicemail.common.utils.CloseUtils;
+import com.example.android.voicemail.common.utils.DbQueryUtils;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of the {@link VoicemailProviderHelper} interface.
+ */
+public final class VoicemailProviderHelpers implements VoicemailProviderHelper {
+    private static final Logger logger = Logger.getLogger(VoicemailProviderHelpers.class);
+
+    /** Full projection on the voicemail table, giving us all the columns. */
+    private static final String[] FULL_PROJECTION = new String[] {
+            Voicemails._ID,
+            Voicemails.HAS_CONTENT,
+            Voicemails.NUMBER,
+            Voicemails.DURATION,
+            Voicemails.DATE,
+            Voicemails.SOURCE_PACKAGE,
+            Voicemails.SOURCE_DATA,
+            Voicemails.NEW,
+            Voicemails.STATE
+    };
+
+    private final ContentResolver mContentResolver;
+    private final Uri mBaseUri;
+
+    /**
+     * Creates an instance of {@link VoicemailProviderHelpers} that wraps the supplied content
+     * provider.
+     *
+     * @param contentResolver the ContentResolver used for opening the output stream to read and
+     *            write to the file
+     */
+    private VoicemailProviderHelpers(Uri baseUri, ContentResolver contentResolver) {
+        mContentResolver = contentResolver;
+        mBaseUri = baseUri;
+    }
+
+    /**
+     * Constructs a VoicemailProviderHelper with full access to all voicemails.
+     * <p>
+     * Requires the manifest permissions
+     * <code>com.android.providers.voicemail.permission.READ_WRITE_ALL_VOICEMAIL</code> and
+     * <code>com.android.providers.voicemail.permission.READ_WRITE_OWN_VOICEMAIL</code>.
+     */
+    public static VoicemailProviderHelper createFullVoicemailProvider(Context context) {
+        return new VoicemailProviderHelpers(Voicemails.CONTENT_URI, context.getContentResolver());
+    }
+
+    /**
+     * Constructs a VoicemailProviderHelper with limited access to voicemails created by this
+     * source.
+     * <p>
+     * Requires the manifest permission
+     * <code>com.android.providers.voicemail.permission.READ_WRITE_OWN_VOICEMAIL</code>.
+     */
+    public static VoicemailProviderHelper createPackageScopedVoicemailProvider(Context context) {
+        return new VoicemailProviderHelpers(Voicemails.buildSourceUri(context.getPackageName()),
+                context.getContentResolver());
+    }
+
+    @Override
+    public Uri insert(Voicemail voicemail) {
+        check(!voicemail.hasId(), "Inserted voicemails must not have an id", voicemail);
+        check(voicemail.hasTimestampMillis(), "Inserted voicemails must have a timestamp",
+                voicemail);
+        check(voicemail.hasNumber(), "Inserted voicemails must have a number", voicemail);
+        logger.d(String.format("Inserting new voicemail: %s", voicemail));
+        ContentValues contentValues = getContentValues(voicemail);
+        return mContentResolver.insert(mBaseUri, contentValues);
+    }
+
+    @Override
+    public int update(Uri uri, Voicemail voicemail) {
+        check(!voicemail.hasUri(), "Can't update the Uri of a voicemail", voicemail);
+        logger.d("Updating voicemail: " + voicemail + " for uri: " + uri);
+        ContentValues values = getContentValues(voicemail);
+        return mContentResolver.update(uri, values, null, null);
+    }
+
+    @Override
+    public OutputStream setVoicemailContent(Uri voicemailUri, String mimeType) throws IOException {
+        ContentValues values = new ContentValues();
+        values.put(Voicemails.MIME_TYPE, mimeType);
+        int updatedCount = mContentResolver.update(voicemailUri, values, null, null);
+        if (updatedCount != 1) {
+            throw new IOException("Updating voicemail should have updated 1 row, was: "
+                    + updatedCount);
+        }
+        logger.d(String.format("Writing new voicemail content: %s", voicemailUri));
+        return mContentResolver.openOutputStream(voicemailUri);
+    }
+
+    @Override
+    public Voicemail findVoicemailBySourceData(String sourceData) {
+        Cursor cursor = null;
+        try {
+            cursor = mContentResolver.query(mBaseUri, FULL_PROJECTION,
+                    DbQueryUtils.getEqualityClause(Voicemails.SOURCE_DATA, sourceData),
+                    null, null);
+            if (cursor.getCount() != 1) {
+                logger.w("Expected 1 voicemail matching sourceData " + sourceData + ", got " +
+                        cursor.getCount());
+                return null;
+            }
+            cursor.moveToFirst();
+            return getVoicemailFromCursor(cursor);
+        } finally {
+            CloseUtils.closeQuietly(cursor);
+        }
+    }
+
+    @Override
+    public Voicemail findVoicemailByUri(Uri uri) {
+        Cursor cursor = null;
+        try {
+            cursor = mContentResolver.query(uri, FULL_PROJECTION, null, null, null);
+            if (cursor.getCount() != 1) {
+                logger.w("Expected 1 voicemail matching uri " + uri + ", got " + cursor.getCount());
+                return null;
+            }
+            cursor.moveToFirst();
+            Voicemail voicemail = getVoicemailFromCursor(cursor);
+            // Make sure this is an exact match.
+            if (voicemail.getUri().equals(uri)) {
+                return voicemail;
+            } else {
+                logger.w("Queried uri: " + uri + " do not represent a unique voicemail record.");
+                return null;
+            }
+        } finally {
+            CloseUtils.closeQuietly(cursor);
+        }
+    }
+
+    @Override
+    public Uri getUriForVoicemailWithId(long id) {
+        return ContentUris.withAppendedId(mBaseUri, id);
+    }
+
+    /**
+     * Checks that an assertion is true.
+     *
+     * @throws IllegalArgumentException if the assertion is false, along with a suitable message
+     *             including a toString() representation of the voicemail
+     */
+    private void check(boolean assertion, String message, Voicemail voicemail) {
+        if (!assertion) {
+            throw new IllegalArgumentException(message + ": " + voicemail);
+        }
+    }
+
+    @Override
+    public int deleteAll() {
+        logger.i(String.format("Deleting all voicemails"));
+        return mContentResolver.delete(mBaseUri, "", new String[0]);
+    }
+
+    @Override
+    public List<Voicemail> getAllVoicemails() {
+        return getAllVoicemails(null, null, SortOrder.DEFAULT);
+    }
+
+    @Override
+    public List<Voicemail> getAllVoicemails(VoicemailFilter filter,
+            String sortColumn, SortOrder sortOrder) {
+        logger.i(String.format("Fetching all voicemails"));
+        Cursor cursor = null;
+        try {
+            cursor = mContentResolver.query(mBaseUri, FULL_PROJECTION,
+                    filter != null ? filter.getWhereClause() : null,
+                    null, getSortBy(sortColumn, sortOrder));
+            List<Voicemail> results = new ArrayList<Voicemail>(cursor.getCount());
+            while (cursor.moveToNext()) {
+                // A performance optimisation is possible here.
+                // The helper method extracts the column indices once every time it is called,
+                // whilst
+                // we could extract them all up front (without the benefit of the re-use of the
+                // helper
+                // method code).
+                // At the moment I'm pretty sure the benefits outweigh the costs, so leaving as-is.
+                results.add(getVoicemailFromCursor(cursor));
+            }
+            return results;
+        } finally {
+            CloseUtils.closeQuietly(cursor);
+        }
+    }
+
+    private String getSortBy(String column, SortOrder sortOrder) {
+        if (column == null) {
+            return null;
+        }
+        switch (sortOrder) {
+            case ASCENDING:
+                return column + " ASC";
+            case DESCENDING:
+                return column + " DESC";
+            case DEFAULT:
+                return column;
+        }
+        // Should never reach here.
+        return null;
+    }
+
+    private VoicemailImpl getVoicemailFromCursor(Cursor cursor) {
+        long id = cursor.getLong(cursor.getColumnIndexOrThrow(Voicemails._ID));
+        String sourcePackage = cursor.getString(
+                cursor.getColumnIndexOrThrow(Voicemails.SOURCE_PACKAGE));
+        VoicemailImpl voicemail = VoicemailImpl
+                .createEmptyBuilder()
+                .setTimestamp(cursor.getLong(cursor.getColumnIndexOrThrow(Voicemails.DATE)))
+                .setNumber(cursor.getString(cursor.getColumnIndexOrThrow(Voicemails.NUMBER)))
+                .setId(id)
+                .setDuration(cursor.getLong(cursor.getColumnIndexOrThrow(Voicemails.DURATION)))
+                .setSourcePackage(sourcePackage)
+                .setSourceData(cursor.getString(
+                        cursor.getColumnIndexOrThrow(Voicemails.SOURCE_DATA)))
+                .setUri(buildUriWithSourcePackage(id, sourcePackage))
+                .setHasContent(cursor.getInt(
+                        cursor.getColumnIndexOrThrow(Voicemails.HAS_CONTENT)) == 1)
+                .setIsRead(cursor.getInt(cursor.getColumnIndexOrThrow(Voicemails.NEW)) == 1)
+                .setMailbox(mapValueToMailBoxEnum(cursor.getInt(
+                        cursor.getColumnIndexOrThrow(Voicemails.STATE))))
+                .build();
+        return voicemail;
+    }
+
+    private Uri buildUriWithSourcePackage(long id, String sourcePackage) {
+        return ContentUris.withAppendedId(Voicemails.buildSourceUri(sourcePackage), id);
+    }
+
+    private Voicemail.Mailbox mapValueToMailBoxEnum(int value) {
+        for (Voicemail.Mailbox mailbox : Voicemail.Mailbox.values()) {
+            if (mailbox.getValue() == value) {
+                return mailbox;
+            }
+        }
+        throw new IllegalArgumentException("Value: " + value + " not valid for Voicemail.Mailbox.");
+    }
+
+    /**
+     * Maps structured {@link Voicemail} to {@link ContentValues} understood by content provider.
+     */
+    private ContentValues getContentValues(Voicemail voicemail) {
+        ContentValues contentValues = new ContentValues();
+        if (voicemail.hasTimestampMillis()) {
+            contentValues.put(Voicemails.DATE, String.valueOf(voicemail.getTimestampMillis()));
+        }
+        if (voicemail.hasNumber()) {
+            contentValues.put(Voicemails.NUMBER, voicemail.getNumber());
+        }
+        if (voicemail.hasDuration()) {
+            contentValues.put(Voicemails.DURATION, String.valueOf(voicemail.getDuration()));
+        }
+        if (voicemail.hasSourcePackage()) {
+            contentValues.put(Voicemails.SOURCE_PACKAGE, voicemail.getSourcePackage());
+        }
+        if (voicemail.hasSourceData()) {
+            contentValues.put(Voicemails.SOURCE_DATA, voicemail.getSourceData());
+        }
+        if (voicemail.hasRead()) {
+            contentValues.put(Voicemails.NEW, voicemail.isRead() ? 1 : 0);
+        }
+        if (voicemail.hasMailbox()) {
+            contentValues.put(Voicemails.STATE, voicemail.getMailbox().getValue());
+        }
+        return contentValues;
+    }
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/inject/InjectView.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/inject/InjectView.java
new file mode 100644
index 0000000..59e6213
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/inject/InjectView.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.inject;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Use this annotation to mark the fields of your Activity as being injectable.
+ * <p>
+ * See the {@link Injector} class for more details of how this operates.
+ */
+@Target({ ElementType.FIELD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface InjectView {
+    /**
+     * The resource id of the View to find and inject.
+     */
+    public int value();
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/inject/Injector.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/inject/Injector.java
new file mode 100644
index 0000000..d9a1078
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/inject/Injector.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.inject;
+
+import android.app.Activity;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+
+/**
+ * Very lightweight form of injection, inspired by RoboGuice, for injecting common ui elements.
+ * <p>
+ * Usage is very simple. In your Activity, define some fields as follows:
+ *
+ * <pre class="code">
+ * &#064;InjectView(R.id.fetch_button)
+ * private Button mFetchButton;
+ * &#064;InjectView(R.id.submit_button)
+ * private Button mSubmitButton;
+ * &#064;InjectView(R.id.main_view)
+ * private TextView mTextView;
+ * </pre>
+ * <p>
+ * Then, inside your Activity's onCreate() method, perform the injection like this:
+ *
+ * <pre class="code">
+ * setContentView(R.layout.main_layout);
+ * Injector.get(this).inject();
+ * </pre>
+ * <p>
+ * See the {@link #inject()} method for full details of how it works. Note that the fields are
+ * fetched and assigned at the time you call {@link #inject()}, consequently you should not do this
+ * until after you've called the setContentView() method.
+ */
+public final class Injector {
+    private final Activity mActivity;
+
+    private Injector(Activity activity) {
+        mActivity = activity;
+    }
+
+    /**
+     * Gets an {@link Injector} capable of injecting fields for the given Activity.
+     */
+    public static Injector get(Activity activity) {
+        return new Injector(activity);
+    }
+
+    /**
+     * Injects all fields that are marked with the {@link InjectView} annotation.
+     * <p>
+     * For each field marked with the InjectView annotation, a call to
+     * {@link Activity#findViewById(int)} will be made, passing in the resource id stored in the
+     * value() method of the InjectView annotation as the int parameter, and the result of this call
+     * will be assigned to the field.
+     *
+     * @throws IllegalStateException if injection fails, common causes being that you have used an
+     *             invalid id value, or you haven't called setContentView() on your Activity.
+     */
+    public void inject() {
+        for (Field field : mActivity.getClass().getDeclaredFields()) {
+            for (Annotation annotation : field.getAnnotations()) {
+                if (annotation.annotationType().equals(InjectView.class)) {
+                    try {
+                        Class<?> fieldType = field.getType();
+                        int idValue = InjectView.class.cast(annotation).value();
+                        field.setAccessible(true);
+                        Object injectedValue = fieldType.cast(mActivity.findViewById(idValue));
+                        if (injectedValue == null) {
+                            throw new IllegalStateException("findViewById(" + idValue
+                                    + ") gave null for " +
+                                    field + ", can't inject");
+                        }
+                        field.set(mActivity, injectedValue);
+                        field.setAccessible(false);
+                    } catch (IllegalAccessException e) {
+                        throw new IllegalStateException(e);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/logging/Logger.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/logging/Logger.java
new file mode 100644
index 0000000..2683fa1
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/logging/Logger.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.logging;
+
+import android.util.Log;
+
+/**
+ * Simplifies usage of Android logging class {@link Log} by abstracting the TAG field that is
+ * required to be passed to every logging method. Also, allows automatic insertion of the owner
+ * class name prefix to log outputs for better debugging.
+ * <p>
+ * Use {@link #getLogger(Class)} to create an instance of Logger that automatically inserts the
+ * class name as a prefix to each log output. If you do not want the class name to be prefixed to
+ * log output then use {@link #getLogger()} to create the instance of Logger.
+ */
+public class Logger {
+    private static final String APP_TAG = "VoicemailSample";
+
+    /**
+     * Use this method if you want your class name to be prefixed to each log output.
+     */
+    public static Logger getLogger(Class<?> classZ) {
+        return new Logger(classZ.getSimpleName() + ": ");
+    }
+
+    /**
+     * Use this factory method if you DO NOT want your class name to be prefixed into the log
+     * output.
+     */
+    public static Logger getLogger() {
+        return new Logger();
+    }
+
+    private final String mLogPrefix;
+
+    /** No custom log prefix used. */
+    private Logger() {
+        mLogPrefix = null;
+    }
+
+    /** Use the supplied custom prefix in log output. */
+    private Logger(String logPrefix) {
+        mLogPrefix = logPrefix;
+    }
+
+    private String getMsg(String msg) {
+        if (mLogPrefix != null) {
+            return mLogPrefix + msg;
+        } else {
+            return msg;
+        }
+    }
+
+    public void i(String msg) {
+        Log.i(APP_TAG, getMsg(msg));
+    }
+
+    public void i(String msg, Throwable t) {
+        Log.i(APP_TAG, getMsg(msg), t);
+    }
+
+    public void d(String msg) {
+        Log.d(APP_TAG, getMsg(msg));
+    }
+
+    public void d(String msg, Throwable t) {
+        Log.d(APP_TAG, getMsg(msg), t);
+    }
+
+    public void w(String msg) {
+        Log.w(APP_TAG, getMsg(msg));
+    }
+
+    public void w(String msg, Throwable t) {
+        Log.w(APP_TAG, getMsg(msg), t);
+    }
+
+    public void e(String msg) {
+        Log.e(APP_TAG, getMsg(msg));
+    }
+
+    public void e(String msg, Throwable t) {
+        Log.e(APP_TAG, getMsg(msg), t);
+    }
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/ui/DialogHelper.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/ui/DialogHelper.java
new file mode 100644
index 0000000..95df4b3
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/ui/DialogHelper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.ui;
+
+/**
+ * Show common Dialogs.
+ * <p>
+ * Contains methods to show common types of Dialog. This is done both for ease of code re-use and to
+ * improve testability. See the implementation {@link DialogHelperImpl} for details.
+ */
+public interface DialogHelper {
+    public void showErrorMessageDialog(int titleId, Exception exception);
+
+    public void showErrorMessageDialog(String title, Exception exception);
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/ui/DialogHelperImpl.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/ui/DialogHelperImpl.java
new file mode 100644
index 0000000..cf067ed
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/ui/DialogHelperImpl.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.ui;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+
+/**
+ * Uses an {@link Activity} to show Dialogs.
+ * <p>
+ * Instantiate this class inside your Activity.
+ *
+ * <pre class="code">
+ * private final DialogHelperImpl mDialogHelper = new DialogHelperImpl(this);
+ * </pre>
+ * <p>
+ * Override your Activity's onCreateDialog(int, Bundle) method, as follows:
+ *
+ * <pre class="code">
+ * &#064;Override
+ * protected Dialog onCreateDialog(int id, Bundle bundle) {
+ *     return mDialogHelper.handleOnCreateDialog(id, bundle);
+ * }
+ * </pre>
+ * <p>
+ * Now you can pass mDialogHelper around as a {@link DialogHelper} interface, and code that wants to
+ * show a Dialog can call a method like this:
+ *
+ * <pre class="code">
+ * mDialogHelper.showErrorMessageDialog(&quot;An exception occurred!&quot;, e);
+ * </pre>
+ * <p>
+ * If you want more flexibility, and want to mix this implementation with your own dialogs, then you
+ * should do something like this in your Activity:
+ *
+ * <pre class="code">
+ * &#064;Override
+ * protected Dialog onCreateDialog(int id, Bundle bundle) {
+ *     switch (id) {
+ *         case ID_MY_OTHER_DIALOG:
+ *             return new AlertDialog.Builder(this)
+ *                     .setTitle(&quot;something&quot;)
+ *                     .create();
+ *         default:
+ *             return mDialogHelper.handleOnCreateDialog(id, bundle);
+ *     }
+ * }
+ * </pre>
+ *
+ * Just be careful that you don't pick any IDs that conflict with those used by this class (which
+ * are documented in the public static final fields).
+ */
+public class DialogHelperImpl implements DialogHelper {
+    public static final int DIALOG_ID_EXCEPTION = 88953588;
+
+    private static final String KEY_EXCEPTION = "exception";
+    private static final String KEY_TITLE = "title";
+
+    private final Activity mActivity;
+
+    public DialogHelperImpl(Activity activity) {
+        mActivity = activity;
+    }
+
+    @Override
+    public void showErrorMessageDialog(int titleId, Exception exception) {
+        showErrorMessageDialog(mActivity.getString(titleId), exception);
+    }
+
+    @Override
+    public void showErrorMessageDialog(String title, Exception exception) {
+        Bundle bundle = new Bundle();
+        bundle.putString(KEY_TITLE, title);
+        bundle.putSerializable(KEY_EXCEPTION, exception);
+        mActivity.showDialog(DIALOG_ID_EXCEPTION, bundle);
+    }
+
+    /**
+     * You should call this method from your Activity's onCreateDialog(int, Bundle) method.
+     */
+    public Dialog handleOnCreateDialog(int id, Bundle args) {
+        if (id == DIALOG_ID_EXCEPTION) {
+            Exception exception = (Exception) args.getSerializable(KEY_EXCEPTION);
+            String title = args.getString(KEY_TITLE);
+            return new AlertDialog.Builder(mActivity)
+                    .setTitle(title)
+                    .setMessage(convertExceptionToErrorMessage(exception))
+                    .setCancelable(true)
+                    .create();
+        }
+        return null;
+    }
+
+    private String convertExceptionToErrorMessage(Exception exception) {
+        StringBuilder sb = new StringBuilder().append(exception.getClass().getSimpleName());
+        if (exception.getMessage() != null) {
+            sb.append("\n");
+            sb.append(exception.getMessage());
+        }
+        return sb.toString();
+    }
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/utils/CloseUtils.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/utils/CloseUtils.java
new file mode 100644
index 0000000..56d8e93
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/utils/CloseUtils.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.utils;
+
+import android.database.Cursor;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Utility methods for closing io streams and database cursors.
+ */
+public class CloseUtils {
+    private CloseUtils() {
+    }
+
+    /**
+     * If the argument is non-null, close the Closeable ignoring any {@link IOException}.
+     */
+    public static void closeQuietly(Closeable closeable) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (IOException e) {
+                // Ignore.
+            }
+        }
+    }
+
+    /** If the argument is non-null, close the cursor. */
+    public static void closeQuietly(Cursor cursor) {
+        if (cursor != null) {
+            cursor.close();
+        }
+    }
+}
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/utils/DbQueryUtils.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/utils/DbQueryUtils.java
new file mode 100644
index 0000000..a809770
--- /dev/null
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/utils/DbQueryUtils.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.voicemail.common.utils;
+
+import android.database.DatabaseUtils;
+import android.text.TextUtils;
+
+/**
+ * Static methods for helping us build database query selection strings.
+ */
+public class DbQueryUtils {
+    // Static class with helper methods, so private constructor.
+    private DbQueryUtils() {
+    }
+
+    /** Returns a WHERE clause assert equality of a field to a value for the specified table . */
+    public static String getEqualityClause(String table, String field, String value) {
+        return getEqualityClause(table + "." + field, value);
+    }
+
+    /** Returns a WHERE clause assert equality of a field to a value. */
+    public static String getEqualityClause(String field, String value) {
+        StringBuilder clause = new StringBuilder();
+        clause.append(field);
+        clause.append(" = ");
+        DatabaseUtils.appendEscapedSQLString(clause, value);
+        return clause.toString();
+    }
+
+    /** Concatenates any number of clauses using "AND". */
+    // TODO: 0. It worries me that I can change the following "AND" to "OR" and the provider tests
+    // all pass. I can also remove the braces, and the tests all pass.
+    public static String concatenateClausesWithAnd(String... clauses) {
+        return concatenateClausesWithOperation("AND", clauses);
+    }
+
+    /** Concatenates any number of clauses using "OR". */
+    public static String concatenateClausesWithOr(String... clauses) {
+        return concatenateClausesWithOperation("OR", clauses);
+    }
+
+    /** Concatenates any number of clauses using the specified operation. */
+    public static String concatenateClausesWithOperation(String operation, String... clauses) {
+        // Nothing to concatenate.
+        if (clauses.length == 1) {
+            return clauses[0];
+        }
+
+        StringBuilder builder = new StringBuilder();
+
+        for (String clause : clauses) {
+            if (!TextUtils.isEmpty(clause)) {
+                if (builder.length() > 0) {
+                    builder.append(" ").append(operation).append(" ");
+                }
+                builder.append("(");
+                builder.append(clause);
+                builder.append(")");
+            }
+        }
+        return builder.toString();
+    }
+}
diff --git a/samples/XmlAdapters/src/com/example/android/xmladapters/Adapters.java b/samples/XmlAdapters/src/com/example/android/xmladapters/Adapters.java
index 9d4794c..2fbfb34 100644
--- a/samples/XmlAdapters/src/com/example/android/xmladapters/Adapters.java
+++ b/samples/XmlAdapters/src/com/example/android/xmladapters/Adapters.java
@@ -16,9 +16,6 @@
 
 package com.example.android.xmladapters;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.Resources;
@@ -37,6 +34,9 @@
 import android.widget.SimpleCursorAdapter;
 import android.widget.TextView;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
@@ -257,7 +257,6 @@
  * attr ref android.R.styleable#CursorAdapter_TransformItem_withClass
  * attr ref android.R.styleable#CursorAdapter_TransformItem_withExpression
  */
-@SuppressWarnings({"JavadocReference"})
 public class Adapters {
     private static final String ADAPTER_CURSOR = "cursor-adapter";
 
@@ -898,10 +897,13 @@
      * of a SimpleCursorAdapter. The main difference is the ability to handle CursorBinders.
      */
     private static class XmlCursorAdapter extends SimpleCursorAdapter implements ManagedAdapter {
+        private Context mContext;
         private String mUri;
         private final String mSelection;
         private final String[] mSelectionArgs;
         private final String mSortOrder;
+        private final int[] mTo;
+        private final String[] mFrom;
         private final String[] mColumns;
         private final CursorBinder[] mBinders;
         private AsyncTask<Void,Void,Cursor> mLoadTask;
@@ -913,6 +915,8 @@
             super(context, layout, null, from, to);
             mContext = context;
             mUri = uri;
+            mFrom = from;
+            mTo = to;
             mSelection = selection;
             mSelectionArgs = selectionArgs;
             mSortOrder = sortOrder;
@@ -935,14 +939,14 @@
         @Override
         public void bindView(View view, Context context, Cursor cursor) {
             final int count = mTo.length;
-            final int[] from = mFrom;
             final int[] to = mTo;
             final CursorBinder[] binders = mBinders;
 
             for (int i = 0; i < count; i++) {
                 final View v = view.findViewById(to[i]);
                 if (v != null) {
-                    binders[i].bind(v, cursor, from[i]);
+                    // Not optimal, the column index could be cached
+                    binders[i].bind(v, cursor, cursor.getColumnIndex(mFrom[i]));
                 }
             }
         }
diff --git a/samples/XmlAdapters/src/com/example/android/xmladapters/ImageDownloader.java b/samples/XmlAdapters/src/com/example/android/xmladapters/ImageDownloader.java
index c84f9d5..eb91fcb 100644
--- a/samples/XmlAdapters/src/com/example/android/xmladapters/ImageDownloader.java
+++ b/samples/XmlAdapters/src/com/example/android/xmladapters/ImageDownloader.java
@@ -12,7 +12,9 @@
  * WITHOUT 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.example.android.xmladapters;
+ */
+
+package com.example.android.xmladapters;
 
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
@@ -58,14 +60,16 @@
     // Hard cache, with a fixed maximum capacity and a life duration
     private final HashMap<String, Bitmap> sHardBitmapCache =
         new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY / 2, 0.75f, true) {
+        private static final long serialVersionUID = -7190622541619388252L;
         @Override
         protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {
             if (size() > HARD_CACHE_CAPACITY) {
                 // Entries push-out of hard reference cache are transferred to soft reference cache
                 sSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
                 return true;
-            } else
+            } else {
                 return false;
+            }
         }
     };
 
diff --git a/samples/XmlAdapters/src/com/example/android/xmladapters/RssReaderActivity.java b/samples/XmlAdapters/src/com/example/android/xmladapters/RssReaderActivity.java
index 16df246..defdc19 100644
--- a/samples/XmlAdapters/src/com/example/android/xmladapters/RssReaderActivity.java
+++ b/samples/XmlAdapters/src/com/example/android/xmladapters/RssReaderActivity.java
@@ -17,7 +17,6 @@
 package com.example.android.xmladapters;
 
 import android.app.ListActivity;
-import android.content.XmlDocumentProvider;
 import android.net.Uri;
 import android.os.Bundle;
 import android.widget.AdapterView.OnItemClickListener;
diff --git a/samples/XmlAdapters/src/com/example/android/xmladapters/XmlDocumentProvider.java b/samples/XmlAdapters/src/com/example/android/xmladapters/XmlDocumentProvider.java
new file mode 100644
index 0000000..d0ab0cf
--- /dev/null
+++ b/samples/XmlAdapters/src/com/example/android/xmladapters/XmlDocumentProvider.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.example.android.xmladapters;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpGet;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.net.http.AndroidHttpClient;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.CursorAdapter;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Stack;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * A read-only content provider which extracts data out of an XML document.
+ *
+ * <p>A XPath-like selection pattern is used to select some nodes in the XML document. Each such
+ * node will create a row in the {@link Cursor} result.</p>
+ *
+ * Each row is then populated with columns that are also defined as XPath-like projections. These
+ * projections fetch attributes values or text in the matching row node or its children.
+ *
+ * <p>To add this provider in your application, you should add its declaration to your application
+ * manifest:
+ * <pre class="prettyprint">
+ * &lt;provider android:name="android.content.XmlDocumentProvider" android:authorities="xmldocument" /&gt;
+ * </pre>
+ * </p>
+ *
+ * <h2>Node selection syntax</h2>
+ * The node selection syntax is made of the concatenation of an arbitrary number (at least one) of
+ * <code>/node_name</code> node selection patterns.
+ *
+ * <p>The <code>/root/child1/child2</code> pattern will for instance match all nodes named
+ * <code>child2</code> which are children of a node named <code>child1</code> which are themselves
+ * children of a root node named <code>root</code>.</p>
+ *
+ * Any <code>/</code> separator in the previous expression can be replaced by a <code>//</code>
+ * separator instead, which indicated a <i>descendant</i> instead of a child.
+ *
+ * <p>The <code>//node1//node2</code> pattern will for instance match all nodes named
+ * <code>node2</code> which are descendant of a node named <code>node1</code> located anywhere in
+ * the document hierarchy.</p>
+ *
+ * Node names can contain namespaces in the form <code>namespace:node</code>.
+ *
+ * <h2>Projection syntax</h2>
+ * For every selected node, the projection will then extract actual data from this node and its
+ * descendant.
+ *
+ * <p>Use a syntax similar to the selection syntax described above to select the text associated
+ * with a child of the selected node. The implicit root of this projection pattern is the selected
+ * node. <code>/</code> will hence refer to the text of the selected node, while
+ * <code>/child1</code> will fetch the text of its child named <code>child1</code> and
+ * <code>//child1</code> will match any <i>descendant</i> named <code>child1</code>. If several
+ * nodes match the projection pattern, their texts are appended as a result.</p>
+ *
+ * A projection can also fetch any node attribute by appending a <code>@attribute_name</code>
+ * pattern to the previously described syntax. <code>//child1@price</code> will for instance match
+ * the attribute <code>price</code> of any <code>child1</code> descendant.
+ *
+ * <p>If a projection does not match any node/attribute, its associated value will be an empty
+ * string.</p>
+ *
+ * <h2>Example</h2>
+ * Using the following XML document:
+ * <pre class="prettyprint">
+ * &lt;library&gt;
+ *   &lt;book id="EH94"&gt;
+ *     &lt;title&gt;The Old Man and the Sea&lt;/title&gt;
+ *     &lt;author&gt;Ernest Hemingway&lt;/author&gt;
+ *   &lt;/book&gt;
+ *   &lt;book id="XX10"&gt;
+ *     &lt;title&gt;The Arabian Nights: Tales of 1,001 Nights&lt;/title&gt;
+ *   &lt;/book&gt;
+ *   &lt;no-id&gt;
+ *     &lt;book&gt;
+ *       &lt;title&gt;Animal Farm&lt;/title&gt;
+ *       &lt;author&gt;George Orwell&lt;/author&gt;
+ *     &lt;/book&gt;
+ *   &lt;/no-id&gt;
+ * &lt;/library&gt;
+ * </pre>
+ * A selection pattern of <code>/library//book</code> will match the three book entries (while
+ * <code>/library/book</code> will only match the first two ones).
+ *
+ * <p>Defining the projections as <code>/title</code>, <code>/author</code> and <code>@id</code>
+ * will retrieve the associated data. Note that the author of the second book as well as the id of
+ * the third are empty strings.
+ */
+public class XmlDocumentProvider extends ContentProvider {
+    /*
+     * Ideas for improvement:
+     * - Expand XPath-like syntax to allow for [nb] child number selector
+     * - Address the starting . bug in AbstractCursor which prevents a true XPath syntax.
+     * - Provide an alternative to concatenation when several node match (list-like).
+     * - Support namespaces in attribute names.
+     * - Incremental Cursor creation, pagination
+     */
+    private static final String LOG_TAG = "XmlDocumentProvider";
+    private AndroidHttpClient mHttpClient;
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    /**
+     * Query data from the XML document referenced in the URI.
+     *
+     * <p>The XML document can be a local resource or a file that will be downloaded from the
+     * Internet. In the latter case, your application needs to request the INTERNET permission in
+     * its manifest.</p>
+     *
+     * The URI will be of the form <code>content://xmldocument/?resource=R.xml.myFile</code> for a
+     * local resource. <code>xmldocument</code> should match the authority declared for this
+     * provider in your manifest. Internet documents are referenced using
+     * <code>content://xmldocument/?url=</code> followed by an encoded version of the URL of your
+     * document (see {@link Uri#encode(String)}).
+     *
+     * <p>The number of columns of the resulting Cursor is equal to the size of the projection
+     * array plus one, named <code>_id</code> which will contain a unique row id (allowing the
+     * Cursor to be used with a {@link CursorAdapter}). The other columns' names are the projection
+     * patterns.</p>
+     *
+     * @param uri The URI of your local resource or Internet document.
+     * @param projection A set of patterns that will be used to extract data from each selected
+     * node. See class documentation for pattern syntax.
+     * @param selection A selection pattern which will select the nodes that will create the
+     * Cursor's rows. See class documentation for pattern syntax.
+     * @param selectionArgs This parameter is ignored.
+     * @param sortOrder The row order in the resulting cursor is determined from the node order in
+     * the XML document. This parameter is ignored.
+     * @return A Cursor or null in case of error.
+     */
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+
+        XmlPullParser parser = null;
+        mHttpClient = null;
+
+        final String url = uri.getQueryParameter("url");
+        if (url != null) {
+            parser = getUriXmlPullParser(url);
+        } else {
+            final String resource = uri.getQueryParameter("resource");
+            if (resource != null) {
+                Uri resourceUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+                        getContext().getPackageName() + "/" + resource);
+                parser = getResourceXmlPullParser(resourceUri);
+            }
+        }
+
+        if (parser != null) {
+            XMLCursor xmlCursor = new XMLCursor(selection, projection);
+            try {
+                xmlCursor.parseWith(parser);
+                return xmlCursor;
+            } catch (IOException e) {
+                Log.w(LOG_TAG, "I/O error while parsing XML " + uri, e);
+            } catch (XmlPullParserException e) {
+                Log.w(LOG_TAG, "Error while parsing XML " + uri, e);
+            } finally {
+                if (mHttpClient != null) {
+                    mHttpClient.close();
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates an XmlPullParser for the provided URL. Can be overloaded to provide your own parser.
+     * @param url The URL of the XML document that is to be parsed.
+     * @return An XmlPullParser on this document.
+     */
+    protected XmlPullParser getUriXmlPullParser(String url) {
+        XmlPullParser parser = null;
+        try {
+            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+            factory.setNamespaceAware(true);
+            parser = factory.newPullParser();
+        } catch (XmlPullParserException e) {
+            Log.e(LOG_TAG, "Unable to create XmlPullParser", e);
+            return null;
+        }
+
+        InputStream inputStream = null;
+        try {
+            final HttpGet get = new HttpGet(url);
+            mHttpClient = AndroidHttpClient.newInstance("Android");
+            HttpResponse response = mHttpClient.execute(get);
+            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+                final HttpEntity entity = response.getEntity();
+                if (entity != null) {
+                    inputStream = entity.getContent();
+                }
+            }
+        } catch (IOException e) {
+            Log.w(LOG_TAG, "Error while retrieving XML file " + url, e);
+            return null;
+        }
+
+        try {
+            parser.setInput(inputStream, null);
+        } catch (XmlPullParserException e) {
+            Log.w(LOG_TAG, "Error while reading XML file from " + url, e);
+            return null;
+        }
+
+        return parser;
+    }
+
+    /**
+     * Creates an XmlPullParser for the provided local resource. Can be overloaded to provide your
+     * own parser.
+     * @param resourceUri A fully qualified resource name referencing a local XML resource.
+     * @return An XmlPullParser on this resource.
+     */
+    protected XmlPullParser getResourceXmlPullParser(Uri resourceUri) {
+        //OpenResourceIdResult resourceId;
+        try {
+            String authority = resourceUri.getAuthority();
+            Resources r;
+            if (TextUtils.isEmpty(authority)) {
+                throw new FileNotFoundException("No authority: " + resourceUri);
+            } else {
+                try {
+                    r = getContext().getPackageManager().getResourcesForApplication(authority);
+                } catch (NameNotFoundException ex) {
+                    throw new FileNotFoundException("No package found for authority: " + resourceUri);
+                }
+            }
+            List<String> path = resourceUri.getPathSegments();
+            if (path == null) {
+                throw new FileNotFoundException("No path: " + resourceUri);
+            }
+            int len = path.size();
+            int id;
+            if (len == 1) {
+                try {
+                    id = Integer.parseInt(path.get(0));
+                } catch (NumberFormatException e) {
+                    throw new FileNotFoundException("Single path segment is not a resource ID: " + resourceUri);
+                }
+            } else if (len == 2) {
+                id = r.getIdentifier(path.get(1), path.get(0), authority);
+            } else {
+                throw new FileNotFoundException("More than two path segments: " + resourceUri);
+            }
+            if (id == 0) {
+                throw new FileNotFoundException("No resource found for: " + resourceUri);
+            }
+
+            return r.getXml(id);
+        } catch (FileNotFoundException e) {
+            Log.w(LOG_TAG, "XML resource not found: " + resourceUri.toString(), e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns "vnd.android.cursor.dir/xmldoc".
+     */
+    @Override
+    public String getType(Uri uri) {
+        return "vnd.android.cursor.dir/xmldoc";
+    }
+
+    /**
+     * This ContentProvider is read-only. This method throws an UnsupportedOperationException.
+     **/
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * This ContentProvider is read-only. This method throws an UnsupportedOperationException.
+     **/
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * This ContentProvider is read-only. This method throws an UnsupportedOperationException.
+     **/
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+
+    private static class XMLCursor extends MatrixCursor {
+        private final Pattern mSelectionPattern;
+        private Pattern[] mProjectionPatterns;
+        private String[] mAttributeNames;
+        private String[] mCurrentValues;
+        private BitSet[] mActiveTextDepthMask;
+        private final int mNumberOfProjections;
+
+        public XMLCursor(String selection, String[] projections) {
+            super(projections);
+            // The first column in projections is used for the _ID
+            mNumberOfProjections = projections.length - 1;
+            mSelectionPattern = createPattern(selection);
+            createProjectionPattern(projections);
+        }
+
+        private Pattern createPattern(String input) {
+            String pattern = input.replaceAll("//", "/(.*/|)").replaceAll("^/", "^/") + "$";
+            return Pattern.compile(pattern);
+        }
+
+        private void createProjectionPattern(String[] projections) {
+            mProjectionPatterns = new Pattern[mNumberOfProjections];
+            mAttributeNames = new String[mNumberOfProjections];
+            mActiveTextDepthMask = new BitSet[mNumberOfProjections];
+            // Add a column to store _ID
+            mCurrentValues = new String[mNumberOfProjections + 1];
+
+            for (int i=0; i<mNumberOfProjections; i++) {
+                mActiveTextDepthMask[i] = new BitSet();
+                String projection = projections[i + 1]; // +1 to skip the _ID column
+                int atIndex = projection.lastIndexOf('@', projection.length());
+                if (atIndex >= 0) {
+                    mAttributeNames[i] = projection.substring(atIndex+1);
+                    projection = projection.substring(0, atIndex);
+                } else {
+                    mAttributeNames[i] = null;
+                }
+
+                // Conforms to XPath standard: reference to local context starts with a .
+                if (projection.charAt(0) == '.') {
+                    projection = projection.substring(1);
+                }
+                mProjectionPatterns[i] = createPattern(projection);
+            }
+        }
+
+        public void parseWith(XmlPullParser parser) throws IOException, XmlPullParserException {
+            StringBuilder path = new StringBuilder();
+            Stack<Integer> pathLengthStack = new Stack<Integer>();
+
+            // There are two parsing mode: in root mode, rootPath is updated and nodes matching
+            // selectionPattern are searched for and currentNodeDepth is negative.
+            // When a node matching selectionPattern is found, currentNodeDepth is set to 0 and
+            // updated as children are parsed and projectionPatterns are searched in nodePath.
+            int currentNodeDepth = -1;
+
+            // Index where local selected node path starts from in path
+            int currentNodePathStartIndex = 0;
+
+            int eventType = parser.getEventType();
+            while (eventType != XmlPullParser.END_DOCUMENT) {
+
+                if (eventType == XmlPullParser.START_TAG) {
+                    // Update path
+                    pathLengthStack.push(path.length());
+                    path.append('/');
+                    String prefix = null;
+                    try {
+                        // getPrefix is not supported by local Xml resource parser
+                        prefix = parser.getPrefix();
+                    } catch (RuntimeException e) {
+                        prefix = null;
+                    }
+                    if (prefix != null) {
+                        path.append(prefix);
+                        path.append(':');
+                    }
+                    path.append(parser.getName());
+
+                    if (currentNodeDepth >= 0) {
+                        currentNodeDepth++;
+                    } else {
+                        // A node matching selection is found: initialize child parsing mode
+                        if (mSelectionPattern.matcher(path.toString()).matches()) {
+                            currentNodeDepth = 0;
+                            currentNodePathStartIndex = path.length();
+                            mCurrentValues[0] = Integer.toString(getCount()); // _ID
+                            for (int i = 0; i < mNumberOfProjections; i++) {
+                                // Reset values to default (empty string)
+                                mCurrentValues[i + 1] = "";
+                                mActiveTextDepthMask[i].clear();
+                            }
+                        }
+                    }
+
+                    // This test has to be separated from the previous one as currentNodeDepth can
+                    // be modified above (when a node matching selection is found).
+                    if (currentNodeDepth >= 0) {
+                        final String localNodePath = path.substring(currentNodePathStartIndex);
+                        for (int i = 0; i < mNumberOfProjections; i++) {
+                            if (mProjectionPatterns[i].matcher(localNodePath).matches()) {
+                                String attribute = mAttributeNames[i];
+                                if (attribute != null) {
+                                    mCurrentValues[i + 1] =
+                                        parser.getAttributeValue(null, attribute);
+                                } else {
+                                    mActiveTextDepthMask[i].set(currentNodeDepth, true);
+                                }
+                            }
+                        }
+                    }
+
+                } else if (eventType == XmlPullParser.END_TAG) {
+                    // Pop last node from path
+                    final int length = pathLengthStack.pop();
+                    path.setLength(length);
+
+                    if (currentNodeDepth >= 0) {
+                        if (currentNodeDepth == 0) {
+                            // Leaving a selection matching node: add a new row with results
+                            addRow(mCurrentValues);
+                        } else {
+                            for (int i = 0; i < mNumberOfProjections; i++) {
+                                mActiveTextDepthMask[i].set(currentNodeDepth, false);
+                            }
+                        }
+                        currentNodeDepth--;
+                    }
+
+                } else if ((eventType == XmlPullParser.TEXT) && (!parser.isWhitespace())) {
+                    for (int i = 0; i < mNumberOfProjections; i++) {
+                        if ((currentNodeDepth >= 0) &&
+                            (mActiveTextDepthMask[i].get(currentNodeDepth))) {
+                            mCurrentValues[i + 1] += parser.getText();
+                        }
+                    }
+                }
+
+                eventType = parser.next();
+            }
+        }
+    }
+}
diff --git a/simulator/app/Android.mk b/simulator/app/Android.mk
deleted file mode 100644
index 5a2d3b5..0000000
--- a/simulator/app/Android.mk
+++ /dev/null
@@ -1,133 +0,0 @@
-# Copyright 2005 The Android Open Source Project
-#
-
-ifeq ($(TARGET_SIMULATOR),true)
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	DeviceManager.cpp \
-	DeviceWindow.cpp \
-	ExternalRuntime.cpp \
-	LoadableImage.cpp \
-	LocalBiChannel.cpp \
-	LogMessage.cpp \
-	LogPool.cpp \
-	LogPrefsDialog.cpp \
-	LogWindow.cpp \
-	MainFrame.cpp \
-	MessageStream.cpp \
-	MyApp.cpp \
-	PhoneButton.cpp \
-	PhoneCollection.cpp \
-	PhoneData.cpp \
-	PhoneWindow.cpp \
-	Pipe.cpp \
-	Preferences.cpp \
-	PrefsDialog.cpp \
-	PropertyServer.cpp \
-	Semaphore.cpp \
-	Shmem.cpp \
-	UserEvent.cpp \
-	executablepath_linux.cpp \
-	ported.cpp
-
-LOCAL_STATIC_LIBRARIES := \
-	libtinyxml
-LOCAL_WHOLE_STATIC_LIBRARIES := \
-	libutils\
-	libcutils
-LOCAL_MODULE := simulator
-
-LOCAL_LDLIBS += -lpthread
-
-LOCAL_CFLAGS := -UNDEBUG
-#LOCAL_LDFLAGS :=
-
-LOCAL_C_INCLUDES += \
-	external/tinyxml \
-	commands/runtime
-
-# wxWidgets defines
-LOCAL_C_INCLUDES += \
-	/usr/include/wx-2.6 \
-	/usr/lib/wx/include/gtk2-unicode-release-2.6
-
-ifeq ($(HOST_OS),linux)
-	# You can install wxWidgets with "sudo apt-get libwxgtk2.6-dev"
-	LOCAL_LDFLAGS += -lwx_baseu-2.6 \
-		-lwx_baseu_net-2.6 \
-		-lwx_baseu_xml-2.6 \
-		-lwx_gtk2u_adv-2.6 \
-		-lwx_gtk2u_core-2.6 \
-		-lwx_gtk2u_html-2.6 \
-		-lwx_gtk2u_qa-2.6 \
-		-lwx_gtk2u_xrc-2.6
-
-	# this next line makes the simulator able to find its shared libraries
-	# without us explicitly setting the LD_LIBRARY_PATH environment variable
-	LOCAL_LDLIBS += -Wl,-z,origin
-	LOCAL_CFLAGS += -DGTK_NO_CHECK_CASTS -D__WXGTK__ -D_FILE_OFFSET_BITS=64 \
-   					-D_LARGE_FILES -D_LARGEFILE_SOURCE=1 -DNO_GCC_PRAGMA
-	LOCAL_LDLIBS += -lrt
-endif
-ifeq ($(HOST_OS),darwin)
-	# NOTE: OS X is no longer supported
-	LOCAL_C_INCLUDES += prebuilt/$(HOST_PREBUILT_TAG)/wxwidgets 
-	LOCAL_LDLIBS += \
-				-framework QuickTime \
-				-framework IOKit \
-				-framework Carbon \
-				-framework Cocoa \
-				-framework System \
-				-lwx_mac_xrc-2.6 \
-				-lwx_mac_qa-2.6 \
-				-lwx_mac_html-2.6 \
-				-lwx_mac_adv-2.6 \
-				-lwx_mac_core-2.6 \
-				-lwx_base_carbon_xml-2.6 \
-				-lwx_base_carbon_net-2.6 \
-				-lwx_base_carbon-2.6 \
-				-lwxexpat-2.6 \
-				-lwxtiff-2.6 \
-				-lwxjpeg-2.6 \
-				-lwxpng-2.6 \
-				-lz \
-				-lpthread \
-				-liconv
-	LOCAL_CFLAGS += \
-				-D__WXMAC__ \
-				-D_FILE_OFFSET_BITS=64 \
-				-D_LARGE_FILES \
-				-DNO_GCC_PRAGMA
-endif
-
-
-include $(BUILD_HOST_EXECUTABLE)
-
-ifeq ($(HOST_OS),darwin)
-# Add the carbon resources to the executable.
-$(LOCAL_BUILT_MODULE): PRIVATE_POST_PROCESS_COMMAND := \
-        /Developer/Tools/Rez -d __DARWIN__ -t APPL \
-        -d __WXMAC__ -o $(LOCAL_BUILT_MODULE) Carbon.r
-endif
-
-# also, we need to copy our assets.  We place these by hand now, because
-# I'd like to clean this up as part of some pdk cleanup I want to do.
-
-asset_files := $(addprefix $(LOCAL_PATH)/assets/,$(call find-subdir-assets,$(LOCAL_PATH)/assets))
-asset_target := $(HOST_COMMON_OUT_ROOT)/sim-assets/simulator$(COMMON_PACKAGE_SUFFIX)
-$(asset_target): PRIVATE_ASSET_ROOT := $(LOCAL_PATH)/assets
-
-$(asset_target) : $(asset_files) $(AAPT)
-	@echo host Package $@
-	$(hide) mkdir -p $(dir $@)
-	$(hide) $(AAPT) package -u -A $(PRIVATE_ASSET_ROOT) -F $@
-
-$(LOCAL_INSTALLED_MODULE): | $(asset_target)
-
-ALL_DEFAULT_INSTALLED_MODULES += $(asset_target)
-
-endif # $(TARGET_SIMULATOR) == true
diff --git a/simulator/app/AssetStream.h b/simulator/app/AssetStream.h
deleted file mode 100644
index 0ab2d12..0000000
--- a/simulator/app/AssetStream.h
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Provide a wxInputStream subclass based on the Android Asset class.
-// This is necessary because some wxWidgets functions require either a
-// filename or a wxInputStream (e.g. wxImage).
-//
-#ifndef _SIM_ASSETSTREAM_H
-#define _SIM_ASSETSTREAM_H
-
-#include "wx/stream.h"
-#include <utils/Asset.h>
-
-/*
- * There is no sample code or concrete documentation about providing
- * input streams, but it seems straightforward.  The PNG loading code
- * uses the following:
- *  OnSysTell()
- *  OnSysSeek()
- *  Read()
- *
- * The AssetStream takes ownership of the Asset.
- */
-class AssetStream : public wxInputStream {
-public:
-    AssetStream(android::Asset* pAsset)
-        : mpAsset(pAsset)
-        {}
-    virtual ~AssetStream(void) {
-        delete mpAsset;
-    }
-
-    virtual wxFileOffset GetLength() const {
-        //printf("## GetLength --> %ld\n", (long) mpAsset->getLength());
-        return mpAsset->getLength();
-    }
-    virtual size_t GetSize() const {
-        //printf("## GetSize --> %ld\n", (long) mpAsset->getLength());
-        return mpAsset->getLength();
-    }
-    virtual bool IsSeekable() const { return true; }
-
-    virtual bool Eof() const {
-        //printf("## Eof\n");
-        return (mpAsset->seek(0, SEEK_CUR) == mpAsset->getLength());
-    }
-
-    virtual bool CanRead() const {
-        //printf("## CanRead\n");
-        return !Eof();
-    }
-
-    virtual wxInputStream& Read(void* buffer, size_t size) {
-        OnSysRead(buffer, size);
-
-        return *this;
-    }
-
-protected:
-    /* read data, return number of bytes or 0 if EOF reached */
-    virtual size_t OnSysRead(void* buffer, size_t size) {
-        ssize_t actual = mpAsset->read(buffer, size);
-        if (actual < 0) {
-            // TODO: flag error
-            actual = 0;
-        }
-        //printf("## OnSysRead(%p %u) --> %d\n", buffer, size, actual);
-        return actual;
-    }
-
-    /* seek, using wxWidgets-defined values for "whence" */
-    virtual wxFileOffset OnSysSeek(wxFileOffset seek, wxSeekMode mode) {
-        int whence;
-        off_t newPosn;
-
-        if (mode == wxFromStart)
-            whence = SEEK_SET;
-        else if (mode == wxFromEnd)
-            whence = SEEK_END;
-        else
-            whence = SEEK_CUR;
-        newPosn = mpAsset->seek(seek, whence);
-        //printf("## OnSysSeek(%ld %d) --> %ld\n",
-        //    (long) seek, mode, (long) newPosn);
-        if (newPosn == (off_t) -1)
-            return wxInvalidOffset;
-        else
-            return newPosn;
-    }
-
-    virtual wxFileOffset OnSysTell() const {
-        //printf("## OnSysTell() --> %ld\n", (long) mpAsset->seek(0, SEEK_CUR));
-        return mpAsset->seek(0, SEEK_CUR);
-    }
-
-private:
-    android::Asset*     mpAsset;
-
-    DECLARE_NO_COPY_CLASS(AssetStream);     // private copy-ctor and op=
-};
-
-#endif // _SIM_ASSETSTREAM_H
diff --git a/simulator/app/DeviceManager.cpp b/simulator/app/DeviceManager.cpp
deleted file mode 100644
index c387d3a..0000000
--- a/simulator/app/DeviceManager.cpp
+++ /dev/null
@@ -1,1220 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Management of the simulated device.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h"
-
-#include "DeviceManager.h"
-#include "MyApp.h"
-#include "DeviceWindow.h"
-#include "LogWindow.h"
-#include "UserEvent.h"
-#include "UserEventMessage.h"
-
-#include "SimRuntime.h"
-#include "utils.h"
-
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-
-#if !defined(SIGKILL)      // doesn't exist in MinGW
-# if defined(SIGBREAK)
-#  define SIGKILL   SIGBREAK        // intended for Ctrl-Break
-# else
-#  define SIGKILL   SIGABRT
-# endif
-#endif
-
-
-/*
- * Constructor.
- */
-DeviceManager::DeviceManager(void)
-    : mThread(NULL), mDisplay(NULL), mNumDisplays(0), mKeyMap(NULL),
-      mpStatusWindow(NULL)
-{
-    //printf("--- DeviceManager constructor\n");
-}
-
-/*
- * Destructor.  Snuff the thread if it's still kicking.
- */
-DeviceManager::~DeviceManager(void)
-{
-    //printf("--- DeviceManager destructor\n");
-
-    if (mThread != NULL && mThread->IsRunning()) {
-        mThread->KillChildProcesses();
-    }
-    if (mThread != NULL) {
-        wxThread::ExitCode code;
-
-        printf("Sim: Waiting for old runtime thread..."); fflush(stdout);
-        code = mThread->Wait();        // join the old thread
-        printf("done (code=%ld)\n", (long) code);
-    }
-    delete mThread;
-    mThread = NULL;
-
-    delete[] mDisplay;
-    free((void*)mKeyMap);
-}
-
-/*
- * Initialize the device configuration.
- *
- * "statusWindow" is where message boxes with failure messages go, usually
- * the main frame.
- */
-bool DeviceManager::Init(int numDisplays, wxWindow* statusWindow)
-{
-    //if (IsRunning()) {
-    //    fprintf(stderr, "ERROR: tried to Configure device while running\n");
-    //    return false;
-    //}
-    assert(mDisplay == NULL);
-    assert(numDisplays > 0);
-
-    //if (mDisplay != NULL)
-    //     delete[] mDisplay;
-
-    mDisplay = new Display[numDisplays];
-    mNumDisplays = numDisplays;
-
-    mpStatusWindow = statusWindow;
-
-    return true;
-}
-
-/*
- * Have we been initialized already?
- */
-bool DeviceManager::IsInitialized(void) const
-{
-    return (mDisplay != NULL);
-}
-
-#if 0
-/*
- * Return the Nth display.
- */
-int DeviceManager::GetShmemKey(int displayIndex)
-{
-    assert(displayIndex >= 0 && displayIndex < mNumDisplays);
-    return mDisplay[displayIndex].GetShmemKey();
-}
-#endif
-
-/*
- * Define mapping between the device's display and a wxWidgets window.
- */
-bool DeviceManager::SetDisplayConfig(int displayIndex, wxWindow* window,
-    int width, int height, android::PixelFormat format, int refresh)
-{
-    assert(displayIndex >= 0 && displayIndex < mNumDisplays);
-
-    if (!mDisplay[displayIndex].Create(displayIndex, window, width, height,
-        format, refresh))
-    {
-        fprintf(stderr, "Sim: ERROR: unable to configure display %d\n",
-            displayIndex);
-        return false;
-    } else {
-        printf("Sim: configured display %d (w=%d h=%d f=%d re=%d)\n",
-            displayIndex, width, height, format, refresh);
-        return true;
-    }
-}
-
-/*
- * Define the keyboard
- */
-bool DeviceManager::SetKeyboardConfig(const char *keymap) {
-    free((void*)mKeyMap);
-    mKeyMap = strdup(keymap);
-    return true;
-}
-
-/*
- * Called before the phone window dialog destroys itself.  The goal here
- * is to prevent the runtime thread from trying to draw after the phone
- * window has closed for business but before the device manager destructor
- * gets called.
- */
-void DeviceManager::WindowsClosing(void)
-{
-    int i;
-
-    for (i = 0; i < mNumDisplays; i++)
-        mDisplay[i].Uncreate();
-}
-
-/*
- * Launch a new runtime process.  If there is an existing device manager
- * thread, we assume that it is in the process of shutting down.
- */
-bool DeviceManager::StartRuntime(void)
-{
-    return DeviceManager::DeviceThread::LaunchProcess(mpStatusWindow);
-}
-
-/*
- * Start the runtime management thread when a runtime connects to us.  If
- * there is an existing thread, we assume that it is in the process of
- * shutting down.
- */
-bool DeviceManager::StartRuntime(android::Pipe* reader, android::Pipe* writer)
-{
-    if (mThread != NULL) {
-        wxThread::ExitCode code;
-
-        if (mThread->IsRunning()) {
-            fprintf(stderr,
-                "Sim: ERROR: start requested, but thread running\n");
-            return false;
-        }
-
-        // clean up old thread
-        printf("Sim: Waiting for old runtime thread..."); fflush(stdout);
-        code = mThread->Wait();        // join the old thread
-        printf("done (code=%ld)\n", (long) code);
-
-        delete mThread;
-        mThread = NULL;
-    }
-
-    assert(mpStatusWindow != NULL);
-    mThread = new DeviceThread(this, mpStatusWindow, reader, writer);
-    if (mThread->Create() != wxTHREAD_NO_ERROR) {
-        fprintf(stderr, "Sim: ERROR: can't create thread\n");
-        return false;
-    }
-    mThread->Run();
-
-    return true;
-}
-
-/*
- * Get the message stream.  Returns NULL if it doesn't exist.
- */
-android::MessageStream* DeviceManager::GetStream(void)
-{
-    if (!IsRunning()) {
-        fprintf(stderr, "Sim: ERROR: runtime thread not active\n");
-        return NULL;
-    }
-
-    assert(mThread != NULL);
-    android::MessageStream* pStream = mThread->GetStream();
-    assert(pStream != NULL);
-
-    if (!pStream->isReady()) {
-        fprintf(stderr, "Sim: NOTE: connection to runtime not ready\n");
-        return NULL;
-    }
-
-    return pStream;
-}
-
-/*
- * Stop the runtime, politely.
- *
- * We don't clean up the thread here, because it might not exit immediately.
- */
-bool DeviceManager::StopRuntime(void)
-{
-    android::MessageStream* pStream = GetStream();
-    if (pStream == NULL)
-        return false;
-
-    printf("Sim: Sending quit command\n");
-
-    android::Message msg;
-    msg.setCommand(android::Simulator::kCommandQuit, 0);
-    pStream->send(&msg);
-    return true;
-}
-
-/*
- * Kill the runtime as efficiently as possible.
- */
-void DeviceManager::KillRuntime(void)
-{
-    if (mThread != NULL && mThread->IsRunning())
-        mThread->KillChildProcesses();
-}
-
-#if 0
-/*
- * Check if the modified time is newer than mLastModified
- */
-bool DeviceManager::RefreshRuntime(void)
-{
-    return (IsRunning() && mThread->IsRuntimeNew());
-}
-
-/*
- * Tells the device manager that the user does not want to update
- * the runtime
- */
-void DeviceManager::UserCancelledRefresh(void)
-{
-    mThread->UpdateLastModified();
-}
-#endif
-
-/*
- * Send an event to the runtime.
- *
- * The events are defined in display_device.h.
- */
-void DeviceManager::SendKeyEvent(int32_t keyCode, bool down)
-{
-    android::MessageStream* pStream = GetStream();
-    if (pStream == NULL)
-        return;
-
-    int event = down ? android::Simulator::kCommandKeyDown :
-                       android::Simulator::kCommandKeyUp;
-
-    //printf("Sim: sending key-%s %d\n", down ? "down" : "up", keyCode);
-
-    android::Message msg;
-    msg.setCommand(event, keyCode);
-    pStream->send(&msg);
-}
-
-/*
- * Send a "touch screen" event to the runtime.
- *
- * "mode" can be "down" (we're pressing), "up" (we're lifting our finger
- * off) or "drag".
- */
-void DeviceManager::SendTouchEvent(android::Simulator::TouchMode mode,
-    int x, int y)
-{
-    android::MessageStream* pStream = GetStream();
-    if (pStream == NULL)
-        return;
-
-    //printf("Sim: sending touch-%d x=%d y=%d\n", (int) mode, x, y);
-
-    android::Message msg;
-    msg.setCommandExt(android::Simulator::kCommandTouch, mode, x, y);
-    pStream->send(&msg);
-}
-
-/*
- * The runtime has sent us a new frame of stuff to display.
- *
- * NOTE: we're still in the runtime management thread.  We have to pass the
- * bitmap through AddPendingEvent to get it over to the main thread.
- *
- * We have to make a copy of the data from the runtime; the easiest
- * way to do that is to convert it to a bitmap here.  However, X11 gets
- * all worked up about calls being made from multiple threads, so we're
- * better off just copying it into a buffer.
- *
- * Because we're decoupled from the runtime, there is a chance that we
- * could drop frames.  Buffering them up is probably worse, since it
- * creates the possibility that we could stall and run out of memory.
- * We could save a copy by handing the runtime a pointer to our buffer,
- * but then we'd have to mutex the runtime against the simulator window
- * Paint function.
- */
-void DeviceManager::ShowFrame(int displayIndex)
-{
-    assert(displayIndex >= 0 && displayIndex < mNumDisplays);
-
-    // copy the data to local storage and convert
-    mDisplay[displayIndex].CopyFromShared();
-
-    // create a user event and send it to the window
-    UserEvent uev(0, (void*) displayIndex);
-
-    wxWindow* pEventWindow = mDisplay[displayIndex].GetWindow();
-    if (pEventWindow != NULL) {
-        //printf("runtime has image, passing up\n");
-        pEventWindow->AddPendingEvent(uev);
-    } else {
-        fprintf(stderr, "NOTE: runtime has image, display not available\n");
-    }
-}
-
-void DeviceManager::Vibrate(int vibrateOn)
-{
-	((MyApp*)wxTheApp)->Vibrate(vibrateOn);
-}
-
-/*
- * Get the display data from the specified display.
- */
-wxBitmap* DeviceManager::GetImageData(int displayIndex)
-{
-    assert(displayIndex >= 0 && displayIndex < mNumDisplays);
-    return mDisplay[displayIndex].GetImageData();
-}
-
-/*
- * Send an event to all device windows
- */
-void DeviceManager::BroadcastEvent(UserEvent& userEvent) {
-    int numDisplays = GetNumDisplays();
-    for (int i = 0; i < numDisplays; i++) {
-        wxWindow* pEventWindow = mDisplay[i].GetWindow();
-        if (pEventWindow != NULL) {
-            pEventWindow->AddPendingEvent(userEvent);
-        }
-    }
-}
-
-
-/*
- * ===========================================================================
- *      DeviceManager::Display
- * ===========================================================================
- */
-
-/*
- * Fill out the various interesting fields based on the parameters.
- */
-bool DeviceManager::Display::Create(int displayNum, wxWindow* window,
-    int width, int height, android::PixelFormat format, int refresh)
-{
-    //printf("DeviceManager::Display constructor\n");
-
-    assert(window != NULL);
-    if (mImageData != NULL) {
-        assert(false);              // no re-init
-        return false;
-    }
-
-    mDisplayNum = displayNum;
-    mDisplayWindow = window;
-    mWidth = width;
-    mHeight = height;
-    mFormat = format;
-    mRefresh = refresh;
-
-    // use a fixed key for now
-    mShmemKey = GenerateKey(displayNum);
-    // allocate 24bpp for now
-    mpShmem = new android::Shmem;
-    if (!mpShmem->create(mShmemKey, width * height * 3, true))
-        return false;
-    //printf("--- CREATED shmem, key=0x%08x addr=%p\n",
-    //    mShmemKey, mpShmem->getAddr());
-
-    mImageData = new unsigned char[width * height * 3];
-    if (mImageData == NULL)
-        return false;
-
-    return true;
-}
-
-/*
- * The UI components are starting to shut down.  We need to do away with
- * our wxWindow pointer so that the runtime management thread doesn't try
- * to send it display update events.
- *
- * We also need to let go of our side of the shared memory, because a
- * new DeviceManager may get started up before our destructor gets called,
- * and we may be re-using the key.
- */
-void DeviceManager::Display::Uncreate(void)
-{
-    wxMutexLocker locker(mImageDataLock);
-
-    //printf("--- Uncreate\n");
-
-    mDisplayWindow = NULL;
-
-    // the "locker" mutex keeps this from hosing CopyFromShared()
-    if (mpShmem != NULL) {
-        //printf("--- DELETING shmem, addr=%p\n", mpShmem->getAddr());
-        delete mpShmem;
-        mpShmem = NULL;
-    }
-}
-
-/*
- * Make a local copy of the image data.  The UI grabs this data from a
- * different thread, so we have to mutex it.
- */
-void DeviceManager::Display::CopyFromShared(void)
-{
-    wxMutexLocker locker(mImageDataLock);
-
-    if (mpShmem == NULL) {
-        //printf("Sim: SKIP CopyFromShared\n");
-        return;
-    }
-
-    //printf("Display %d: copying data from %p to %p\n",
-    //    mDisplayNum, mpShmem->getAddr(), mImageData);
-
-    /* data is always 24bpp RGB */
-    mpShmem->lock();        // avoid tearing
-    memcpy(mImageData, mpShmem->getAddr(), mWidth * mHeight * 3);
-    mpShmem->unlock();
-}
-
-/*
- * Get the image data in the form of a newly-allocated bitmap.
- *
- * This MUST be called from the UI thread.  Creating wxBitmaps in the
- * runtime management thread will cause X11 failures (e.g.
- * "Xlib: unexpected async reply").
- */
-wxBitmap* DeviceManager::Display::GetImageData(void)
-{
-    wxMutexLocker locker(mImageDataLock);
-
-    assert(mImageData != NULL);
-
-    //printf("HEY: creating tmpImage, w=%d h=%d data=%p\n",
-    //    mWidth, mHeight, mImageData);
-
-    /* create a temporary wxImage; it does not own the data */
-    wxImage tmpImage(mWidth, mHeight, (unsigned char*) mImageData, true);
-
-    /* return a new bitmap with the converted-for-display data */
-    return new wxBitmap(tmpImage);
-}
-
-
-/*
- * ===========================================================================
- *      DeviceManager::DeviceThread
- * ===========================================================================
- */
-
-/*
- * Some notes on process management under Linux/Mac OS X:
- *
- * We want to put the runtime into its own process group.  That way we
- * can send SIGKILL to the entire group to guarantee that we kill it and
- * all of its children.  Simply killing the sim's direct descendant doesn't
- * do what we want.  If it's a debugger, we will just orphan the runtime
- * without killing it.  Even if the runtime is our child, the children of
- * the runtime might outlive it.
- *
- * We want to be able to run the child under GDB or Valgrind, both
- * of which take input from the tty.  They need to be in the "foreground"
- * process group.  We might be debugging or valgrinding the simulator,
- * or operating in a command-line-only "headless" mode, so in that case
- * the sim front-end should actually be in the foreground group.
- *
- * Putting the runtime in the background group means it can't read input
- * from the tty (not an issue) and will generate SIGTTOU signals when it
- * writes output to the tty (easy to ignore).  The trick, then, is to
- * have the simulator and gdb/valgrind in the foreground pgrp while the
- * runtime itself is in a different group.  This group needs to be known
- * to the simulator so that it can send signals to the appropriate place.
- *
- * The solution is to have the runtime process change its process group
- * after it starts but before it creates any new processes, and then send
- * the process group ID back to the simulator.  The sim can then send
- * signals to the pgrp to ensure that we don't end up with zombies.  Any
- * "pre-launch" processes, like GDB, stay in the sim's pgrp.  This also
- * allows a consistent API for platforms that don't have fork/exec
- * (e.g. MinGW).
- *
- * This doesn't help us with interactive valgrind (e.g. --db-attach=yes),
- * because valgrind is an LD_PRELOAD shared library rather than a
- * separate process.  For that, we actually need to use termios(3) to
- * change the terminal's pgrp, or the interactive stuff just doesn't work.
- * We don't want to do that every time or attempting to debug the simulator
- * front-end will have difficulties.
- *
- * Making this even more entertaining is the fact that the simulator
- * front-end could itself be launched in the background.  It's essential
- * that we be careful about assigning a process group to the foreground,
- * and that we don't restore ourselves unless we were in the foreground to
- * begin with.
- *
- *
- * Some notes on process management under Windows (Cygwin, MinGW):
- *
- * Signals cannot be caught or ignored under MinGW.  All signals are fatal.
- *
- * Signals can be ignored under Cygwin, but not caught.
- *
- * Windows has some process group stuff (e.g. CREATE_NEW_PROCESS_GROUP flag
- * and GenerateConsoleCtrlEvent()).  Need to explore.
- *
- *
- * UPDATE: we've abandoned Mac OS and MinGW, so we now launch the runtime in
- * a separate xterm.  This avoids all tty work on our side.  We still need
- * to learn the pgrp from the child during the initial communication
- * handshake so we can do necessary cleanup.
- */
-
-
-/*
- * Convert a space-delimited string into an argument vector.
- *
- * "arg" is the current arg offset.
- */
-static int stringToArgv(char* mangle, const char** argv, int arg, int maxArgs)
-{
-    bool first = true;
-
-    while (*mangle != '\0') {
-        assert(arg < maxArgs);
-        if (first) {
-            argv[arg++] = mangle;
-            first = false;
-        }
-        if (*mangle == ' ') {
-            *mangle = '\0';
-            first = true;
-        }
-        mangle++;
-    }
-
-    return arg;
-}
-
-/*
- * Launch the runtime process in its own terminal window.  Start by setting
- * up the argument vector to the runtime process.
- *
- * The last entry in the vector will be a NULL pointer.
- *
- * This is awkward and annoying because the wxWidgets strings are current
- * configured for UNICODE.
- */
-/*static*/ bool DeviceManager::DeviceThread::LaunchProcess(wxWindow* statusWindow)
-{
-    static const char* kLaunchWrapper = "launch-wrapper";
-    const int kMaxArgs = 64;
-    Preferences* pPrefs;
-    wxString errMsg;
-    wxString runtimeExe;
-    wxString debuggerExe;
-	wxString debuggerScript;
-    wxString valgrinderExe;
-    wxString launchWrapperExe;
-    wxString launchWrapperArgs;
-    wxString javaAppName;
-    wxString termCmd;
-    wxString tmpStr;
-    char gammaVal[8];
-    //bool bval;
-    double dval;
-    bool result = false;
-    bool doDebug, doValgrind, doCheckJni, doEnableSound, doEnableFakeCamera;
-    const char** argv = NULL;
-    int arg;
-    wxCharBuffer runtimeExeTmp;
-    wxCharBuffer debuggerExeTmp;
-	wxCharBuffer debuggerScriptTmp;
-    wxCharBuffer javaAppNameTmp;
-    wxCharBuffer valgrinderExeTmp;
-    wxCharBuffer termCmdTmp;
-    wxCharBuffer launchWrapperExeTmp;
-    wxCharBuffer launchWrapperArgsTmp;
-    
-    pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    if (pPrefs == NULL) {
-        errMsg = wxT("Preferences were not loaded.");
-        goto bail;
-    }
-
-    /*
-     * Set environment variables.  This stuff should be passed through as
-     * arguments, but the runtime binary currently has a disconnect
-     * between main() and the VM initilization.
-     *
-     * TODO: remove this in favor of system properties
-     */
-#if 0
-    // TODO: restore this
-    doCheckJni = false;
-    pPrefs->GetBool("check-jni", &doCheckJni);
-#endif
-
-    tmpStr.Empty();
-    pPrefs->GetString("ld-assume-kernel", /*ref*/ tmpStr);
-    if (tmpStr.IsEmpty()) {
-        unsetenv("LD_ASSUME_KERNEL");
-    } else {
-        setenv("LD_ASSUME_KERNEL", tmpStr.ToAscii(), 1);
-    }
-
-    doEnableSound = false; 
-    pPrefs->GetBool("enable-sound", &doEnableSound);
-    if (doEnableSound)
-        setenv("ANDROIDSOUND", "1", 1);
-
-    doEnableFakeCamera = false; 
-    pPrefs->GetBool("enable-fake-camera", &doEnableFakeCamera);
-    if (doEnableFakeCamera)
-        setenv("ANDROIDFAKECAMERA", "1", 1);
-
-    /*
-     * Set the Dalvik bootstrap class path.  Normally this is set by "init".
-     */
-    setenv("BOOTCLASSPATH",
-        "/system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar",
-        1);
-
-    /*
-     * Figure out where the "runtime" binary lives.
-     */
-    runtimeExe = ((MyApp*)wxTheApp)->GetRuntimeExe();
-    assert(!runtimeExe.IsEmpty());
-
-    //UpdateLastModified();
-
-    /*
-     * Initialize argv.
-     */
-    argv = new const char*[kMaxArgs];
-    if (argv == NULL)
-        goto bail;
-    arg = 0;
-
-    /*
-     * We want to launch the runtime in its own terminal window so we don't
-     * have to fight over who gets access to the controlling tty.  We allow
-     * the user to specify the command they want to use to perform the
-     * launch.  Here we cut it into pieces for argv.
-     *
-     * To make life easier here, we require that the launch command be
-     * all one piece, i.e. it's not "xterm -e <stuff> -geom blah" with our
-     * stuff in the middle.
-     */
-    termCmd.Empty();
-    pPrefs->GetString("launch-command", /*ref*/ termCmd);
-    if (termCmd.IsEmpty()) {
-        fprintf(stderr, "Sim: WARNING: launch-command is empty\n");
-    } else {
-        termCmdTmp = termCmd.ToAscii();
-        char* mangle = strdup(termCmdTmp);
-        arg = stringToArgv(mangle, argv, arg, kMaxArgs);
-    }
-
-    /*
-     * The "launch-wrapper" binary lives in the same place as the runtime.
-     * This sets up LD_PRELOAD and some other environment variables.
-     */
-    int charIdx;
-
-    charIdx = runtimeExe.Find('/', true);
-    if (charIdx == -1) {
-        launchWrapperExe = wxString::FromAscii(kLaunchWrapper);
-    } else {
-        launchWrapperExe = runtimeExe.Mid(0, charIdx+1);
-        launchWrapperExe.Append(wxString::FromAscii(kLaunchWrapper));
-    }
-    printf("Sim launch wrapper: %s\n", (const char*)launchWrapperExe.ToAscii());
-
-    argv[arg++] = launchWrapperExeTmp = launchWrapperExe.ToAscii();
-
-    launchWrapperArgs.Empty();
-    pPrefs->GetString("launch-wrapper-args", /*ref*/ launchWrapperArgs);
-    if (!launchWrapperArgs.IsEmpty()) {
-        launchWrapperArgsTmp = launchWrapperArgs.ToAscii();
-        char* mangle = strdup(launchWrapperArgsTmp);
-        arg = stringToArgv(mangle, argv, arg, kMaxArgs);
-    }
-
-    /*
-     * If we're launching under GDB or valgrind, set that up.
-     */
-    doDebug = doValgrind = false;
-    pPrefs->GetBool("debug", &doDebug);
-    if (((MyApp*)wxTheApp)->GetDebuggerOption()) {
-        doDebug = true;
-    }
-	debuggerScript = ((MyApp*)wxTheApp)->GetDebuggerScript();
-
-    pPrefs->GetBool("valgrind", &doValgrind);
-    if (doDebug || doValgrind) {
-
-        pPrefs->GetString("debugger", /*ref*/ debuggerExe);
-        pPrefs->GetString("valgrinder", /*ref*/ valgrinderExe);
-
-        // check for empty or undefined preferences
-        if (doDebug && debuggerExe.IsEmpty()) {
-            errMsg = wxT("Debugger not defined.");
-            goto bail;
-        }
-        if (doValgrind && valgrinderExe.IsEmpty()) {
-            errMsg = wxT("Valgrinder not defined.");
-            goto bail;
-        }
-
-        if (doValgrind) {
-            argv[arg++] = valgrinderExeTmp = valgrinderExe.ToAscii();
-            //argv[arg++] = "--tool=callgrind";
-            argv[arg++] = "--tool=memcheck";
-            argv[arg++] = "--leak-check=yes";       // check for leaks too
-            argv[arg++] = "--leak-resolution=med";  // increase from 2 to 4
-            argv[arg++] = "--num-callers=8";        // reduce from 12 to 8
-            //argv[arg++] = "--show-reachable=yes";   // show still-reachable
-            if (doDebug) {
-                //mTerminalFollowsChild = true;   // interactive
-                argv[arg++] = "--db-attach=yes";
-            }
-            //mSlowExit = true;
-        } else /*doDebug*/ {
-            argv[arg++] = debuggerExeTmp = debuggerExe.ToAscii();
-			if (!debuggerScript.IsEmpty()) {
-				argv[arg++] = "-x";
-				argv[arg++] = debuggerScriptTmp = debuggerScript.ToAscii();
-			}
-            argv[arg++] = runtimeExeTmp = runtimeExe.ToAscii();
-            argv[arg++] = "--args";
-        }
-    }
-
-    /*
-     * Get runtime args.
-     */
-
-    argv[arg++] = runtimeExeTmp = (const char*) runtimeExe.ToAscii();
-
-    javaAppName = ((MyApp*)wxTheApp)->GetAutoRunApp();
-    if (javaAppName.IsEmpty()) {
-        if (!pPrefs->GetString("java-app-name", /*ref*/ javaAppName)) {
-            javaAppName = wxT("");
-        }
-    }
-
-    if (!javaAppName.IsEmpty())
-    {
-        argv[arg++] = "-j";
-        argv[arg++] = javaAppNameTmp = (const char*) javaAppName.ToAscii();
-    }
-
-    if (pPrefs->GetDouble("gamma", &dval) && dval != 1.0) {
-        snprintf(gammaVal, sizeof(gammaVal), "%.3f", dval);
-        argv[arg++] = "-g";
-        argv[arg++] = gammaVal;
-    }
-
-    /* finish arg set */
-    argv[arg++] = NULL;
-
-    assert(arg <= kMaxArgs);
-
-#if 1
-    printf("ARGS:\n");
-    for (int i = 0; i < arg; i++)
-        printf(" %d: '%s'\n", i, argv[i]);
-#endif
-
-    if (fork() == 0) {
-        execvp(argv[0], (char* const*) argv);
-        fprintf(stderr, "execvp '%s' failed: %s\n", argv[0], strerror(errno));
-        exit(1);
-    }
-
-    /*
-     * We assume success; if it didn't succeed we'll just sort of hang
-     * out waiting for a connection.  There are ways to fix this (create
-     * a non-close-on-exec pipe and watch to see if the other side closes),
-     * but at this stage it's not worthwhile.
-     */
-    result = true;
-
-    tmpStr = wxT("=== launched ");
-    tmpStr += runtimeExe;
-    LogWindow::PostLogMsg(tmpStr);
-
-    assert(errMsg.IsEmpty());
-
-bail:
-    if (!errMsg.IsEmpty()) {
-        assert(result == false);
-
-        UserEventMessage* pUem = new UserEventMessage;
-        pUem->CreateErrorMessage(errMsg);
-
-        UserEvent uev(0, (void*) pUem);
-
-        assert(statusWindow != NULL);
-        statusWindow->AddPendingEvent(uev);
-    }
-    delete[] argv;
-    return result;
-}
-
-/*
- * This is the entry point for the device thread.  The thread launches the
- * runtime process and monitors it.  When the runtime exits, the thread
- * exits.
- *
- * Because this isn't running in the UI thread, any user interaction has
- * to be channeled through "user events" to the appropriate window.
- */
-void* DeviceManager::DeviceThread::Entry(void)
-{
-    //android::MessageStream stream;
-    android::Message msg;
-    wxString errMsg;
-    char statusBuf[64] = "(no status)";
-    int result = 1;
-
-    /* print this so we can make sense of log messages */
-    LOG(LOG_DEBUG, "", "Sim: device management thread starting (pid=%d)\n",
-        getpid());
-
-    assert(mReader != NULL && mWriter != NULL);
-
-    /*
-     * Tell the main thread that we're running.  If something fails here,
-     * we'll send them a "stopped running" immediately afterward.
-     */
-    {
-        UserEventMessage* pUem = new UserEventMessage;
-        pUem->CreateRuntimeStarted();
-
-        UserEvent uev(0, (void*) pUem);
-
-        assert(mpStatusWindow != NULL);
-        mpStatusWindow->AddPendingEvent(uev);
-    }
-    LogWindow::PostLogMsg(
-            "==============================================================");
-    LogWindow::PostLogMsg("=== runtime starting");
-
-    /*
-     * Establish contact with runtime.
-     */
-    if (!mStream.init(mReader, mWriter, true)) {
-        errMsg = wxT("ERROR: Unable to establish communication with runtime.\n");
-        goto bail;
-    }
-
-    /*
-     * Tell the runtime to put itself into a new process group and set
-     * itself up as the foreground process.  The latter is only really
-     * necessary to make valgrind+gdb work.
-     */
-    msg.setCommand(android::Simulator::kCommandNewPGroup, true);
-    mStream.send(&msg);
-
-    printf("Sim: Sending hardware configuration\n");
-
-    /*
-     * Send display config.
-     *
-     * Right now we're just shipping a big binary blob over.
-     */
-    assert(android::Simulator::kValuesPerDisplay >= 5);
-    int buf[1 + 1 + mpDeviceManager->GetNumDisplays() *
-                    android::Simulator::kValuesPerDisplay];
-    buf[0] = android::Simulator::kDisplayConfigMagic;
-    buf[1] = mpDeviceManager->GetNumDisplays();
-    for (int i = 0; i < mpDeviceManager->GetNumDisplays(); i++) {
-        DeviceManager::Display* pDisplay = mpDeviceManager->GetDisplay(i);
-        int* pBuf = &buf[2 + android::Simulator::kValuesPerDisplay * i];
-
-        pBuf[0] = pDisplay->GetWidth();
-        pBuf[1] = pDisplay->GetHeight();
-        pBuf[2] = pDisplay->GetFormat();
-        pBuf[3] = pDisplay->GetRefresh();
-        pBuf[4] = pDisplay->GetShmemKey();
-    }
-    msg.setRaw((const unsigned char*)buf, sizeof(buf),
-        android::Message::kCleanupNoDelete);
-    mStream.send(&msg);
-
-    /*
-     * Send other hardware config.
-     *
-     * Examples:
-     * - Available input devices.
-     * - Set of buttons on device.
-     * - External devices (Bluetooth, etc).
-     * - Initial mode (e.g. "flipped open" vs. "flipped closed").
-     */
-
-    msg.setConfig("keycharmap", mpDeviceManager->GetKeyMap());
-    mStream.send(&msg);
-
-    /*
-     * Done with config.
-     */
-    msg.setCommand(android::Simulator::kCommandConfigDone, 0);
-    mStream.send(&msg);
-
-    /*
-     * Sit forever, waiting for messages from the runtime process.
-     */
-    while (1) {
-        if (!mStream.recv(&msg, true)) {
-            /*
-             * The read failed.  This usually means the child has died.
-             */
-            printf("Sim: runtime process has probably died\n");
-            break;
-        }
-
-        if (msg.getType() == android::Message::kTypeCommand) {
-            int cmd, arg;
-
-            if (!msg.getCommand(&cmd, &arg)) {
-                fprintf(stderr, "Sim: Warning: failed unpacking command\n");
-                /* keep going? */
-            } else {
-                switch (cmd) {
-                case android::Simulator::kCommandNewPGroupCreated:
-                    // runtime has moved into a separate process group
-                    // (not expected for external)
-                    printf("Sim: child says it's now in pgrp %d\n", arg);
-                    mRuntimeProcessGroup = arg;
-                    break;
-                case android::Simulator::kCommandRuntimeReady:
-                    // sim is up and running, do late init
-                    break;
-                case android::Simulator::kCommandUpdateDisplay:
-                    // new frame of graphics is ready
-                    //printf("RCVD display update %d\n", arg);
-                    mpDeviceManager->ShowFrame(arg);
-                    break;
-                case android::Simulator::kCommandVibrate:
-                    // vibrator on or off
-                    //printf("RCVD vibrator update %d\n", arg);
-                    mpDeviceManager->Vibrate(arg);
-                    break;
-                default:
-                    printf("Sim: got unknown command %d/%d\n", cmd, arg);
-                    break;
-                }
-            }
-        } else if (msg.getType() == android::Message::kTypeLogBundle) {
-            android_LogBundle bundle;
-
-            if (!msg.getLogBundle(&bundle)) {
-                fprintf(stderr, "Sim: Warning: failed unpacking logBundle\n");
-                /* keep going? */
-            } else {
-                LogWindow::PostLogMsg(&bundle);
-            }
-        } else {
-            printf("Sim: got unknown message type=%d\n", msg.getType());
-        }
-    }
-
-    result = 0;
-
-bail:
-    printf("Sim: DeviceManager thread preparing to exit\n");
-
-    /* kill the comm channel; should encourage runtime to die */
-    mStream.close();
-    delete mReader;
-    delete mWriter;
-    mReader = mWriter = NULL;
-
-    /*
-     * We never really did get a "friendly death" working, so just slam
-     * the thing if we have the process group.
-     */
-    if (mRuntimeProcessGroup != 0) {
-        /* kill the group, not our immediate child */
-        printf("Sim: killing pgrp %d\n", (int) mRuntimeProcessGroup);
-        kill(-mRuntimeProcessGroup, 9);
-    }
-
-    if (!errMsg.IsEmpty()) {
-        UserEventMessage* pUem = new UserEventMessage;
-        pUem->CreateErrorMessage(errMsg);
-
-        UserEvent uev(0, (void*) pUem);
-        mpStatusWindow->AddPendingEvent(uev);
-    }
-
-    /* notify the main window that the runtime has stopped */
-    {
-        UserEventMessage* pUem = new UserEventMessage;
-        pUem->CreateRuntimeStopped();
-
-        UserEvent uev(0, (void*) pUem);
-        mpStatusWindow->AddPendingEvent(uev);
-    }
-
-    /* show exit status in log file */
-    wxString exitMsg;
-    exitMsg.Printf(wxT("=== runtime exiting - %s"), statusBuf);
-    LogWindow::PostLogMsg(exitMsg);
-    LogWindow::PostLogMsg(
-        "==============================================================\n");
-
-    /*
-     * Reset system properties for future runs.
-     */
-    ResetProperties();
-
-    return (void*) result;
-}
-
-
-/*
- * Wait for a little bit to see if the thread will exit.
- *
- * "delay" is in 0.1s increments.
- */
-void DeviceManager::DeviceThread::WaitForDeath(int delay)
-{
-    const int kDelayUnit = 100000;
-    int i;
-
-    for (i = 0; i < delay; i++) {
-        if (!IsRunning())
-            return;
-        usleep(kDelayUnit);
-    }
-}
-
-
-/*
- * Kill the runtime process.  The goal is to cause our local runtime
- * management thread to exit.  If it doesn't, this will kill the thread
- * before it returns.
- */
-void DeviceManager::DeviceThread::KillChildProcesses(void)
-{
-    if (!this->IsRunning())
-        return;
-
-    /* clear "slow exit" flag -- we're forcefully killing this thing */
-    //this->mSlowExit = false;
-
-    /*
-     * Use the ChildProcess object in the thread to send signals.  There's
-     * a risk that the DeviceThread will exit and destroy the object while
-     * we're using it.  Using a mutex here gets a little awkward because
-     * we can't put it in DeviceThread.  It's easier to make a copy of
-     * ChildProcess and operate on the copy, but we have to do that very
-     * carefully to avoid interfering with the communcation pipes.
-     *
-     * For now, we just hope for the best.  FIX this someday.
-     *
-     * We broadcast to the process group, which will ordinarily kill
-     * everything.  If we're running with valgrind+GDB everything is in our
-     * pgrp and we can't do the broadcast; if GDB alone, then only GDB is
-     * in our pgrp, so the broadcast will hit everything except it.  We
-     * hit the group and then hit our child for good measure.
-     */
-    if (mRuntimeProcessGroup != 0) {
-        /* kill the group, not our immediate child */
-        printf("Sim: killing pgrp %d\n", (int) mRuntimeProcessGroup);
-        kill(-mRuntimeProcessGroup, 9);
-        WaitForDeath(15);
-    }
-
-    /*
-     * Close the communication channel.  This should cause our thread
-     * to snap out of its blocking read and the runtime thread to bail
-     * out the next time it tries to interact with us.  We should only
-     * get here if somebody other than our direct descendant has the
-     * comm channel open and our broadcast didn't work, which should
-     * no longer be possible.
-     */
-    if (this->IsRunning()) {
-        printf("Sim: killing comm channel\n");
-        mStream.close();
-        delete mReader;
-        delete mWriter;
-        mReader = mWriter = NULL;
-        WaitForDeath(15);
-    }
-
-    /*
-     * At this point it's possible that our DeviceThread is just wedged.
-     * Kill it.
-     *
-     * Using the thread Kill() function can orphan resources, including
-     * locks and semaphores.  There is some risk that the simulator will
-     * be hosed after this.
-     */
-    if (this->IsRunning()) {
-        fprintf(stderr, "Sim: WARNING: killing runtime thread (%ld)\n",
-            (long) GetId());
-        this->Kill();
-        WaitForDeath(15);
-    }
-
-    /*
-     * Now I'm scared.
-     */
-    if (this->IsRunning()) {
-        fprintf(stderr, "Sim: thread won't die!\n");
-    }
-}
-
-
-/*
- * Configure system properties for the simulated device.
- *
- * Property requests can arrive *before* the full connection to the
- * simulator is established, so we want to reset these during cleanup.
- */
-void DeviceManager::DeviceThread::ResetProperties(void)
-{
-	wxWindow* mainFrame = ((MyApp*)wxTheApp)->GetMainFrame();
-    PropertyServer* props = ((MainFrame*)mainFrame)->GetPropertyServer();
-
-    props->ClearProperties();
-    props->SetDefaultProperties();
-}
-
-
-#if 0
-/*
- * Return true if the executable found is newer than
- * what is currently running
- */
-bool DeviceManager::DeviceThread::IsRuntimeNew(void)
-{
-    if (mLastModified == 0) {
-        /*
-         * Haven't called UpdateLastModified yet, or called it but
-         * couldn't stat() the executable.
-         */
-        return false;
-    }
-
-    struct stat status;
-    if (stat(mRuntimeExe.ToAscii(), &status) == 0) {
-        return (status.st_mtime > mLastModified);
-    } else {
-        // doesn't exist, so it can't be newer
-        fprintf(stderr, "Sim: unable to stat '%s': %s\n",
-            (const char*) mRuntimeExe.ToAscii(), strerror(errno));
-        return false;
-    }
-}
-
-/*
- * Updates mLastModified to reflect the current executables mtime
- */
-void DeviceManager::DeviceThread::UpdateLastModified(void)
-{
-    struct stat status;
-    if (stat(mRuntimeExe.ToAscii(), &status) == 0) {
-        mLastModified = status.st_mtime;
-    } else {
-        fprintf(stderr, "Sim: unable to stat '%s': %s\n",
-            (const char*) mRuntimeExe.ToAscii(), strerror(errno));
-        mLastModified = 0;
-    }
-}
-#endif
-
diff --git a/simulator/app/DeviceManager.h b/simulator/app/DeviceManager.h
deleted file mode 100644
index e3d8af3..0000000
--- a/simulator/app/DeviceManager.h
+++ /dev/null
@@ -1,284 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Class that manages the simulated device.
-//
-#ifndef _SIM_DEVICE_MANAGER_H
-#define _SIM_DEVICE_MANAGER_H
-
-#include "UserEvent.h"
-
-#include "Shmem.h"
-#include "MessageStream.h"
-#include "SimRuntime.h"
-
-#include "ui/PixelFormat.h"
-#include "ui/KeycodeLabels.h"
-
-#include <sys/stat.h>
-
-/*
- * Manage the simulated device.  This includes starting/stopping as well
- * as sending messages to it and receiving events from it.
- *
- * The object may span multiple invocations of a specific device.  If
- * the simulator is reconfigured to use a device with different
- * characteristics, the object should be destroyed and recreated (which
- * guarantees that the runtime is restarted).
- */
-class DeviceManager {
-public:
-    DeviceManager(void);
-    virtual ~DeviceManager(void);
-
-    /*
-     * Initialize the object.  Call this once.
-     *
-     * "numDisplays" is the number of displays that the simulated hardware
-     * supports.  The displays themselves are configured with separate calls.
-     *
-     * "statusWindow" should be the main frame.  Messages indicating runtime
-     * startup/shutdown are sent, as well as error messages that should be
-     * displayed in message boxes.
-     */
-    bool Init(int numDisplays, wxWindow* statusWindow);
-    bool IsInitialized(void) const;
-
-    /*
-     * Tell the device manager that the windows used to display its output
-     * are closing down.
-     */
-    void WindowsClosing(void);
-
-    /*
-     * "displayWindow" is the window to notify when a new frame of graphics
-     * data is available.  This can be set independently for each display.
-     */
-    bool SetDisplayConfig(int displayIndex, wxWindow* window,
-        int width, int height, android::PixelFormat format, int refresh);
-
-    /*
-     * set the key map
-     */
-    bool SetKeyboardConfig(const char *keymap);
-
-    /*
-     * Return the number of displays we're configured for.
-     */
-    int GetNumDisplays(void) const { return mNumDisplays; }
-
-    /*
-     * Return the shmem key for the Nth display.
-     */
-    //int GetShmemKey(int displayIndex);
-
-    /*
-     * Is the runtime process still running?
-     */
-    bool IsRunning(void) const {
-        if (mThread != NULL)
-            return mThread->IsRunning();
-        return false;
-    }
-    bool IsKillable(void) const {
-        return true;
-    }
-
-    // (Re-)configure the device, e.g. when #of displays changes because
-    // a different phone model has been selected.  Call this before doing
-    // any display-specific setup.  DO NOT call this if the runtime is active.
-//    void Configure(int numDisplays);
-
-    // start the runtime, acting as parent
-    bool StartRuntime(void);
-    // start the runtime, acting as peer
-    bool StartRuntime(android::Pipe* reader, android::Pipe* writer);
-    // politely ask the runtime to stop
-    bool StopRuntime(void);
-    // kill the runtime with extreme prejudice
-    void KillRuntime(void);
-
-#if 0
-    // Returns if the executable is new
-    bool RefreshRuntime(void);
-    // Update the time of the current runtime because the user cancelled a
-    // refresh
-    void UserCancelledRefresh(void);
-#endif
-
-    // send a key-up or key-down event to the runtime
-    void SendKeyEvent(int32_t keyCode, bool down);
-    // send touch-screen events
-    void SendTouchEvent(android::Simulator::TouchMode mode, int x, int y);
-
-    wxBitmap* GetImageData(int displayIndex);
-    
-    void BroadcastEvent(UserEvent &userEvent);
-
-private:
-    /*
-     * Threads in wxWidgets use sub-classing to define interfaces and
-     * entry points.  We use this to create the thread that interacts
-     * with the runtime.
-     *
-     * The "reader" and "writer" arguments may be NULL.  If they are,
-     * we will launch the runtime ourselves.  If not, we will use them
-     * to speak with an externally-launched runtime process.  The thread
-     * will own the pipes, shutting them down when it exits.
-     */
-    class DeviceThread : public wxThread {
-    public:
-        DeviceThread(DeviceManager* pDM, wxWindow* pStatusWindow,
-            android::Pipe* reader, android::Pipe* writer)
-            : wxThread(wxTHREAD_JOINABLE), mpStatusWindow(pStatusWindow),
-              mReader(reader), mWriter(writer),
-              mpDeviceManager(pDM), /*mTerminalFollowsChild(false),
-              mSlowExit(false), mIsExternal(false), mLastModified(0),*/
-              mRuntimeProcessGroup(0)
-            {}
-        virtual ~DeviceThread(void) {
-            delete mReader;
-            delete mWriter;
-        }
-
-        /* thread entry point */
-        virtual void* Entry(void);
-
-        // wxThread class supplies an IsRunning() method
-
-        /*
-         * This kills the runtime process to force this thread to exit.
-         * If the thread doesn't exit after a short period of time, it
-         * is forcibly terminated.
-         */
-        void KillChildProcesses(void);
-
-#if 0
-        /*
-         * Return if the runtime executable is new
-         */
-        bool IsRuntimeNew(void);
-
-        void UpdateLastModified(void);
-#endif
-
-        android::MessageStream* GetStream(void) { return &mStream; }
-
-        static bool LaunchProcess(wxWindow* statusWindow);
-
-    private:
-        void WaitForDeath(int delay);
-        void ResetProperties(void);
-
-        android::MessageStream  mStream;
-        wxWindow*       mpStatusWindow;
-        android::Pipe*  mReader;
-        android::Pipe*  mWriter;
-        DeviceManager*  mpDeviceManager;
-        pid_t           mRuntimeProcessGroup;
-        //time_t          mLastModified;
-        wxString        mRuntimeExe;
-    };
-
-    friend class DeviceThread;
-
-    /*
-     * We need one of these for each display on the device.  Most devices
-     * only have one, but some flip phones have two.
-     */
-    class Display {
-    public:
-        Display(void)
-            : mDisplayWindow(NULL), mpShmem(NULL), mShmemKey(0),
-              mImageData(NULL), mDisplayNum(-1), mWidth(-1), mHeight(-1),
-              mFormat(android::PIXEL_FORMAT_UNKNOWN), mRefresh(0)
-            {}
-        ~Display() {
-            delete mpShmem;
-            delete[] mImageData;
-        }
-
-        /* initialize goodies */
-        bool Create(int displayNum, wxWindow* window, int width, int height,
-            android::PixelFormat format, int refresh);
-
-        /* call this if we're shutting down soon */
-        void Uncreate(void);
-
-        /* copy & convert data from shared memory */
-        void CopyFromShared(void);
-
-        /* get image data in the form of a 24bpp bitmap */
-        wxBitmap* GetImageData(void);
-
-        /* get a pointer to our display window */
-        wxWindow* GetWindow(void) const { return mDisplayWindow; }
-
-        /* get our shared memory key */
-        int GetShmemKey(void) const { return mShmemKey; }
-
-        int GetWidth(void) const { return mWidth; }
-        int GetHeight(void) const { return mHeight; }
-        android::PixelFormat GetFormat(void) const { return mFormat; }
-        int GetRefresh(void) const { return mRefresh; }
-
-    private:
-        int GenerateKey(int displayNum) {
-            return 0x41544d00 | displayNum;
-        }
-
-        // control access to image data shared between runtime mgr and UI
-        wxMutex         mImageDataLock;
-        // we send an event here when we get stuff to display
-        wxWindow*       mDisplayWindow;
-
-        // shared memory segment
-        android::Shmem* mpShmem;
-        int             mShmemKey;
-
-        // local copy of data from shared mem, converted to 24bpp
-        unsigned char*  mImageData;
-
-        // mainly for debugging -- which display are we?
-        int             mDisplayNum;
-
-        // display characteristics
-        int             mWidth;
-        int             mHeight;
-        android::PixelFormat mFormat;
-        int             mRefresh;       // fps
-    };
-
-    Display* GetDisplay(int dispNum) { return &mDisplay[dispNum]; }
-
-    const char* GetKeyMap() { return mKeyMap ? mKeyMap : "qwerty"; }
-
-    void ShowFrame(int displayIndex);
-
-    void Vibrate(int vibrateOn);
-
-    // get the message stream from the device thread
-    android::MessageStream* GetStream(void);
-
-    // send a request to set the visible layers
-    void SendSetVisibleLayers(void);
-
-    // points at the runtime's thread (while it's running)
-    DeviceThread*   mThread;
-
-    // array of Displays, one per display on the device
-    Display*        mDisplay;
-    int             mNumDisplays;
-
-    // the key map
-    const char * mKeyMap;
-
-    // which graphics layers are visible?
-    int             mVisibleLayers;
-
-    // where to send status messages
-    wxWindow*       mpStatusWindow;
-
-};
-
-#endif // _SIM_DEVICE_MANAGER_H
diff --git a/simulator/app/DeviceWindow.cpp b/simulator/app/DeviceWindow.cpp
deleted file mode 100644
index a15b03b..0000000
--- a/simulator/app/DeviceWindow.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Displays output from the device.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h"   // needed for Windows build
-#include "wx/dcbuffer.h"
-
-#include "AssetStream.h"
-#include "DeviceWindow.h"
-#include "MyApp.h"
-#include "Preferences.h"
-
-BEGIN_EVENT_TABLE(DeviceWindow, wxWindow)
-    EVT_SIZE(DeviceWindow::OnSize)
-    EVT_ERASE_BACKGROUND(DeviceWindow::OnErase)
-    EVT_PAINT(DeviceWindow::OnPaint)
-    EVT_KEY_DOWN(DeviceWindow::OnKeyDown)
-    EVT_KEY_UP(DeviceWindow::OnKeyUp)
-
-    EVT_LEFT_DOWN(DeviceWindow::OnMouseLeftDown)
-    EVT_LEFT_DCLICK(DeviceWindow::OnMouseLeftDown)
-    EVT_LEFT_UP(DeviceWindow::OnMouseLeftUp)
-    EVT_RIGHT_DOWN(DeviceWindow::OnMouseRightDown)
-    EVT_RIGHT_DCLICK(DeviceWindow::OnMouseRightDown)
-    EVT_RIGHT_UP(DeviceWindow::OnMouseRightUp)
-    EVT_MOTION(DeviceWindow::OnMouseMotion)
-
-    EVT_USER_EVENT(DeviceWindow::OnUserEvent)
-END_EVENT_TABLE()
-
-
-/*
- * Create a new DeviceWindow.  This should be a child of PhoneWindow.
- *
- * Note the DeviceManager may not be fully initialized yet.
- */
-DeviceWindow::DeviceWindow(wxWindow* parent, DeviceManager* pDM)
-    : wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
-        wxNO_BORDER | wxWANTS_CHARS),
-      mpDeviceManager(pDM)
-{
-    //printf("DW: created (parent=%p DM=%p)\n", parent, pDM);
-
-    SetBackgroundStyle(wxBG_STYLE_CUSTOM);
-
-    // create a trivial bitmap so we have something allocated
-    mBitmap.Create(1, 1);
-
-}
-
-/*
- * Destructor.
- */
-DeviceWindow::~DeviceWindow(void)
-{
-}
-
-/*
- * We don't want to trap key or mouse events here.
- *
- * event.Skip() didn't seem to do the trick, so we call AddPendingEvent()
- * to add it to the parent's input queue.
- */
-void DeviceWindow::OnKeyDown(wxKeyEvent& event)
-{
-    //printf("DW: down: %d\n", event.GetKeyCode());
-    GetParent()->AddPendingEvent(event);
-}
-void DeviceWindow::OnKeyUp(wxKeyEvent& event)
-{
-    //printf("DW:   up: %d\n", event.GetKeyCode());
-    GetParent()->AddPendingEvent(event);
-}
-
-/*
- * Handle mouse events.  We want to pass these up to the PhoneWindow, since
- * that's where the "touch screen" code is.
- */
-void DeviceWindow::OnMouseLeftDown(wxMouseEvent& event)
-{
-    ClampMouse(&event);
-    GetParent()->AddPendingEvent(event);
-}
-void DeviceWindow::OnMouseLeftUp(wxMouseEvent& event)
-{
-    ClampMouse(&event);
-    GetParent()->AddPendingEvent(event);
-}
-void DeviceWindow::OnMouseRightDown(wxMouseEvent& event)
-{
-    ClampMouse(&event);
-    GetParent()->AddPendingEvent(event);
-}
-void DeviceWindow::OnMouseRightUp(wxMouseEvent& event)
-{
-    ClampMouse(&event);
-    GetParent()->AddPendingEvent(event);
-}
-void DeviceWindow::OnMouseMotion(wxMouseEvent& event)
-{
-    ClampMouse(&event);
-    GetParent()->AddPendingEvent(event);
-}
-
-/*
- * Clamp the mouse movement to the window bounds.
- */
-void DeviceWindow::ClampMouse(wxMouseEvent* pEvent)
-{
-    wxWindow* pEventWindow = (wxWindow*) pEvent->GetEventObject();
-    int width, height;
-
-    pEventWindow->GetSize(&width, &height);
-    if (pEvent->m_x < 0)
-        pEvent->m_x = 0;
-    else if (pEvent->m_x >= width)
-        pEvent->m_x = width-1;
-
-    if (pEvent->m_y < 0)
-        pEvent->m_y = 0;
-    else if (pEvent->m_y >= height)
-        pEvent->m_y = height-1;
-}
-
-
-/*
- * Handle a "user event".  We get these when the runtime wants us to
- * know that it has a new frame of graphics to display.
- * 
- */
-void DeviceWindow::OnUserEvent(UserEvent& event)
-{
-    wxBitmap* pBitmap;
-    long displayIndex;
-
-    displayIndex = (long) event.GetData();
-
-    //printf("GOT UAE %d\n", displayIndex);
-
-    // a displayIndex of -1 means just update the onion skin
-    if (displayIndex >= 0) {
-        /* get a newly-allocated bitmap with converted image data */
-        pBitmap = mpDeviceManager->GetImageData(displayIndex);
-    
-        /* do a ptr/refcount assignment to hold the data */
-        mBitmap = *pBitmap;
-        /* delete the temporary object; does not delete the bitmap storage */
-        delete pBitmap;
-    }
-    
-    if (displayIndex >= -1) {
-        mHasOnionSkinBitmap = false;
-        
-        Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-        assert(pPrefs != NULL);
-    
-        bool overlayOnionSkin;
-        char* onionSkinFileName = NULL;
-        
-        bool overlayOnionSkinExists = pPrefs->GetBool("overlay-onion-skin", &overlayOnionSkin);
-        if (overlayOnionSkinExists && overlayOnionSkin) {
-            bool fileNameExists = pPrefs->GetString("onion-skin-file-name", &onionSkinFileName);
-            if (fileNameExists && *onionSkinFileName) {
-                wxImage onionSkinImage(wxString::FromAscii(onionSkinFileName));
-                onionSkinImage.SetAlpha(NULL);
-                bool hasAlpha = onionSkinImage.HasAlpha();
-                int width = onionSkinImage.GetWidth();
-                int height = onionSkinImage.GetHeight();
-                if (hasAlpha) {
-                    unsigned char *alpha = onionSkinImage.GetAlpha();
-                    int alphaVal = 127;
-                    pPrefs->GetInt("onion-skin-alpha-value", &alphaVal);
-                    for (int i = (width * height) - 1; i >= 0; i--) {
-                        alpha[i] = alphaVal;
-                    } 
-                }
-                mOnionSkinBitmap = wxBitmap(onionSkinImage);
-                mHasOnionSkinBitmap = true;
-            }
-        }
-    }
-
-    /* induce an update */
-    Refresh();
-}
-
-/*
- * Window has been moved or resized.
- *
- * We get this when the model of phone is changed.
- *
- * FIX: in the future this only happens when the phone is rotated 90deg.
- */
-void DeviceWindow::OnSize(wxSizeEvent& WXUNUSED(event))
-{
-    int width, height;
-
-    GetClientSize(&width, &height);
-    printf("Sim: device window resize: %dx%d\n", width, height);
-
-    mBitmap.Create(width, height);
-
-    wxMemoryDC memDC;
-    memDC.SelectObject(mBitmap);
-
-    wxColour backColor(96, 122, 121);
-    memDC.SetBrush(wxBrush(backColor));
-    memDC.SetPen(wxPen(backColor, 1));
-    wxRect windowRect(wxPoint(0, 0), GetClientSize());
-    memDC.DrawRectangle(windowRect);
-}
-
-/*
- * No need to erase the background.
- */
-void DeviceWindow::OnErase(wxEraseEvent& WXUNUSED(event))
-{
-    //printf("erase device\n");
-}
-
-/*
- * Repaint the simulator output.
- */
-void DeviceWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
-{
-    wxPaintDC dc(this);
-
-    /* draw background image */
-    dc.DrawBitmap(mBitmap, 0, 0, TRUE);
-
-    /* If necessary, draw onion skin image on top */
-    if (mHasOnionSkinBitmap) {
-        dc.DrawBitmap(mOnionSkinBitmap, 0, 0, TRUE);
-    }
-    
-#if 0
-    // debug - draw the corners
-    int xoff = 0;
-    int yoff = 0;
-    int width;
-    int height;
-    GetClientSize(&width, &height);
-
-    dc.SetPen(*wxGREEN_PEN);
-    dc.DrawLine(xoff,           yoff+9,         xoff,           yoff);
-    dc.DrawLine(xoff,           yoff,           xoff+10,        yoff);
-    dc.DrawLine(xoff+width-10,  yoff,           xoff+width,     yoff);
-    dc.DrawLine(xoff+width-1,   yoff,           xoff+width-1,   yoff+10);
-    dc.DrawLine(xoff,           yoff+height-10, xoff,           yoff+height);
-    dc.DrawLine(xoff,           yoff+height-1,  xoff+10,        yoff+height-1);
-    dc.DrawLine(xoff+width-1,   yoff+height-10, xoff+width-1,   yoff+height);
-    dc.DrawLine(xoff+width-1,   yoff+height-1,  xoff+width-11,  yoff+height-1);
-#endif
-}
-
diff --git a/simulator/app/DeviceWindow.h b/simulator/app/DeviceWindow.h
deleted file mode 100644
index 4548fc3..0000000
--- a/simulator/app/DeviceWindow.h
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Window with simulated phone.
-//
-#ifndef _SIM_DEVICE_WINDOW_H
-#define _SIM_DEVICE_WINDOW_H
-
-#include "UserEvent.h"
-#include "DeviceManager.h"
-
-/*
- * This window displays the device output.
- */
-class DeviceWindow : public wxWindow {
-public:
-    DeviceWindow(wxWindow* parent, DeviceManager* pDM);
-    virtual ~DeviceWindow(void);
-
-#if 0       // can't work -- can't create bitmaps in other threads
-    /* this gets tucked into a user event */
-    class FrameData {
-    public:
-        FrameData(void)
-            : mDisplayIndex(-1), mpBitmap(NULL)
-            {}
-        ~FrameData(void) {
-            delete mpBitmap;
-        }
-
-        void Create(int displayIndex, wxBitmap* pBitmap) {
-            mDisplayIndex = displayIndex;
-            mpBitmap = pBitmap;
-        }
-
-        int GetDisplayIndex(void) const { return mDisplayIndex; }
-        wxBitmap* GetBitmap(void) const { return mpBitmap; }
-
-    private:
-        int         mDisplayIndex;
-        wxBitmap*   mpBitmap;
-    };
-#endif
-
-    void DeviceManagerClosing(void) { mpDeviceManager = NULL; }
-
-private:
-    void OnKeyDown(wxKeyEvent& event);
-    void OnKeyUp(wxKeyEvent& event);
-    void OnMouseLeftDown(wxMouseEvent& event);
-    void OnMouseLeftUp(wxMouseEvent& event);
-    void OnMouseRightDown(wxMouseEvent& event);
-    void OnMouseRightUp(wxMouseEvent& event);
-    void OnMouseMotion(wxMouseEvent& event);
-    void OnSize(wxSizeEvent& WXUNUSED(event));
-    void OnErase(wxEraseEvent& event);
-    void OnPaint(wxPaintEvent& WXUNUSED(event));
-    void OnUserEvent(UserEvent& event);
-
-    void ClampMouse(wxMouseEvent* pEvent);
-
-    DeviceManager*  mpDeviceManager;
-    wxBitmap    mBitmap;
-    wxBitmap	mOnionSkinBitmap;
-    bool        mHasOnionSkinBitmap;
-
-    DECLARE_EVENT_TABLE()
-};
-
-#endif // _SIM_DEVICE_WINDOW_H
diff --git a/simulator/app/ExternalRuntime.cpp b/simulator/app/ExternalRuntime.cpp
deleted file mode 100644
index 9f2cc5e..0000000
--- a/simulator/app/ExternalRuntime.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//  
-// Management of the simulated device.
-//  
-    
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-    
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h"
-    
-#include "ExternalRuntime.h"
-#include "MyApp.h"
-#include "UserEvent.h"
-#include "UserEventMessage.h"
-
-#include "SimRuntime.h"
-#include "LocalBiChannel.h"
-#include "utils.h"
-
-
-using namespace android;
-
-/*
- * Destructor.
- */
-ExternalRuntime::~ExternalRuntime(void)
-{
-    if (IsRunning()) {
-        // TODO: cause thread to stop, then Wait for it
-    }
-    printf("Sim: in ~ExternalRuntime()\n");
-}
-
-/*
- * Create and run the thread.
- */
-bool ExternalRuntime::StartThread(void)
-{
-    if (Create() != wxTHREAD_NO_ERROR) {
-        fprintf(stderr, "Sim: ERROR: can't create ExternalRuntime thread\n");
-        return false;
-    }
-
-    Run();
-    return true;
-}
-
-/*
- * Thread entry point.
- *
- * This just sits and waits for a new connection.  It hands it off to the
- * main thread and then goes back to waiting.
- *
- * There is currently no "polite" way to shut this down.
- */
-void* ExternalRuntime::Entry(void)
-{
-    LocalBiChannel lbic;
-    Pipe* reader;
-    Pipe* writer;
-
-    reader = writer = NULL;
-
-    if (!lbic.create(ANDROID_PIPE_NAME)) {
-        fprintf(stderr, "Sim: failed creating named pipe '%s'\n",
-            ANDROID_PIPE_NAME);
-        return NULL;
-    }
-
-    while (lbic.listen(&reader, &writer)) {
-        /*
-         * Throw it over the wall.
-         */
-        wxWindow* pMainFrame = ((MyApp*)wxTheApp)->GetMainFrame();
-
-        UserEventMessage* pUem = new UserEventMessage;
-        pUem->CreateExternalRuntime(reader, writer);
-
-        UserEvent uev(0, (void*) pUem);
-        pMainFrame->AddPendingEvent(uev);
-
-        reader = writer = NULL;
-    }
-
-    printf("Sim: ExternalRuntime thread wants to bail\n");
-
-    return NULL;
-}
-
diff --git a/simulator/app/ExternalRuntime.h b/simulator/app/ExternalRuntime.h
deleted file mode 100644
index 774a2cd..0000000
--- a/simulator/app/ExternalRuntime.h
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Class that manages the simulated device.
-//
-#ifndef _SIM_EXTERNAL_RUNTIME_H
-#define _SIM_EXTERNAL_RUNTIME_H
-
-/*
- * Define a thread that listens for the launch of an external runtime.
- * When we spot one we notify the main thread, which can choose to
- * accept or reject it.
- */
-class ExternalRuntime : public wxThread {
-public:
-    ExternalRuntime(void) {}
-    virtual ~ExternalRuntime(void);
-
-    /* start the thread running */
-    bool StartThread(void);
-
-    /* thread entry point */
-    virtual void* Entry(void);
-};
-
-#endif // _SIM_EXTERNAL_RUNTIME_H
diff --git a/simulator/app/LinuxKeys.h b/simulator/app/LinuxKeys.h
deleted file mode 100644
index 6382de9..0000000
--- a/simulator/app/LinuxKeys.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _SIM_LINUXKEYS_H
-#define _SIM_LINUXKEYS_H
-
-#include <linux/input.h>
-
-/* ubuntu has these, goobuntu doesn't */
-#ifndef KEY_SWITCHVIDEOMODE
-# define KEY_SWITCHVIDEOMODE 227
-#endif
-#ifndef KEY_KBDILLUMTOGGLE
-# define KEY_KBDILLUMTOGGLE 228
-#endif
-#ifndef KEY_KBDILLUMUP
-# define KEY_KBDILLUMUP     230
-#endif
-#ifndef KEY_REPLY
-# define KEY_REPLY          232
-#endif
-
-#endif /*_SIM_LINUXKEYS_H*/
diff --git a/simulator/app/LoadableImage.cpp b/simulator/app/LoadableImage.cpp
deleted file mode 100644
index 513165b..0000000
--- a/simulator/app/LoadableImage.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Simple class to hold an image that can be loaded and unloaded.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h"   // needed for Windows build
-
-#include "LoadableImage.h"
-#include "AssetStream.h"
-#include "MyApp.h"
-
-#include "utils.h"
-
-#include <stdio.h>
-
-
-/*
- * Load the image.
- */
-bool LoadableImage::Create(const char* fileName, int x, int y)
-{
-    if (fileName == NULL || x < 0 || y < 0) {
-        fprintf(stderr, "bad params to %s\n", __PRETTY_FUNCTION__);
-        return false;
-    }
-
-    delete[] mName;
-    mName = android::strdupNew(fileName);
-
-    mX = x;
-    mY = y;
-
-    return true;
-}
-
-/*
- * Load the bitmap.
- */
-bool LoadableImage::LoadResources(void)
-{
-    if (mName == NULL)
-        return false;
-
-    if (mpBitmap != NULL)       // already loaded?
-        return true;
-
-    //printf("LoadResources: '%s'\n", (const char*) mName);
-#ifdef BEFORE_ASSET
-    wxImage img(mName);
-#else
-    android::AssetManager* pAssetMgr = ((MyApp*)wxTheApp)->GetAssetManager();
-    android::Asset* pAsset;
-
-    pAsset = pAssetMgr->open(mName, android::Asset::ACCESS_RANDOM);
-    if (pAsset == NULL) {
-        fprintf(stderr, "ERROR: unable to load '%s'\n", mName);
-        return false;
-    } else {
-        //printf("--- opened asset '%s'\n",
-        //    (const char*) pAsset->getAssetSource());
-    }
-    AssetStream astr(pAsset);
-
-    wxImage img(astr);
-#endif
-
-    mWidth = img.GetWidth();
-    mHeight = img.GetHeight();
-    if (mWidth <= 0 || mHeight <= 0) {
-        /* image failed to load or decode */
-        fprintf(stderr, "ERROR: unable to load/decode '%s'\n", mName);
-        //delete img;
-        return false;
-    }
-
-    mpBitmap = new wxBitmap(img);
-
-    //delete img;
-
-    return true;
-}
-
-/*
- * Unload the bitmap.
- */
-bool LoadableImage::UnloadResources(void)
-{
-    delete mpBitmap;
-    mpBitmap = NULL;
-    return true;
-}
-
diff --git a/simulator/app/LoadableImage.h b/simulator/app/LoadableImage.h
deleted file mode 100644
index 368d520..0000000
--- a/simulator/app/LoadableImage.h
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Simulated device definition.
-//
-#ifndef _SIM_LOADABLE_IMAGE_H
-#define _SIM_LOADABLE_IMAGE_H
-
-#include "utils.h"
-
-/*
- * Holds an image that may or may not be loaded at present.  The image
- * has an (x,y) offset.
- */
-class LoadableImage {
-public:
-    LoadableImage(void)
-        : mName(NULL), mpBitmap(NULL), mX(-1), mY(-1), mWidth(-1), mHeight(-1)
-        {}
-    virtual ~LoadableImage(void) {
-        delete[] mName;
-        delete mpBitmap;
-    }
-    LoadableImage(const LoadableImage& src)
-        : mName(NULL), mpBitmap(NULL)
-    {
-        CopyMembers(src);
-    }
-    LoadableImage& operator=(const LoadableImage& src) {
-        if (this != &src)       // self-assignment
-            CopyMembers(src);
-        return *this;
-    }
-    void CopyMembers(const LoadableImage& src) {
-        // Need to delete resources in case we're using operator= and
-        // assigning into an object that already holds some.
-        delete mName;
-        delete mpBitmap;
-        mName = android::strdupNew(src.mName);
-        if (src.mpBitmap == NULL)
-            mpBitmap = NULL;
-        else
-            mpBitmap = new wxBitmap(*(src.mpBitmap));
-        mX = src.mX;
-        mY = src.mY;
-        mWidth = src.mWidth;
-        mHeight = src.mHeight;
-    }
-
-    virtual bool Create(const char* fileName, int x, int y);
-
-    // load or unload the bitmap
-    bool LoadResources(void);
-    bool UnloadResources(void);
-
-    // accessors
-    int GetX(void) const { return mX; }
-    int GetY(void) const { return mY; }
-    int GetWidth(void) const { return mWidth; }
-    int GetHeight(void) const { return mHeight; }
-    wxBitmap* GetBitmap(void) const { return mpBitmap; }
-
-private:
-    char*       mName;
-    wxBitmap*   mpBitmap;
-
-    int         mX;         // position relative to phone image
-    int         mY;
-    int         mWidth;     // from image (cached values)
-    int         mHeight;
-};
-
-#endif // _SIM_LOADABLE_IMAGE_H
diff --git a/simulator/app/LocalBiChannel.cpp b/simulator/app/LocalBiChannel.cpp
deleted file mode 100644
index 93a997d..0000000
--- a/simulator/app/LocalBiChannel.cpp
+++ /dev/null
@@ -1,444 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Local named bi-directional communication channel.
-//
-#include "LocalBiChannel.h"
-#include "utils/Log.h"
-
-#if defined(HAVE_WIN32_IPC)
-# define _WIN32_WINNT 0x0500
-# include <windows.h>
-#else
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <sys/stat.h>
-# include <sys/un.h>
-#endif
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-#ifndef SUN_LEN
-/*
- * Our current set of ARM header files don't define this.
- */
-# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path)        \
-                      + strlen ((ptr)->sun_path))
-#endif
-
-using namespace android;
-
-const unsigned long kInvalidHandle = (unsigned long) -1;
-
-/*
- * Initialize data fields.
- */
-LocalBiChannel::LocalBiChannel(void)
-    : mFileName(NULL), mIsListener(false), mHandle(kInvalidHandle)
-{
-}
-
-#if defined(HAVE_WIN32_IPC)
-/*
- * Implementation for Win32, using named pipes.
- *
- * Cygwin actually supports UNIX-domain sockets, but we want to stuff
- * the file handles into a Pipe, which uses HANDLE under Win32.
- */
-
-const int kPipeSize = 4096;
-
-/*
- * Destructor.  If we're the server side, we may need to clean up after
- * ourselves.
- */
-LocalBiChannel::~LocalBiChannel(void)
-{
-    if (mHandle != kInvalidHandle)
-        CloseHandle((HANDLE)mHandle);
-
-    delete[] mFileName;
-}
-
-/*
- * Construct the full path.  The caller must delete[] the return value.
- */
-static char* makeFilename(const char* name)
-{
-    static const char* kBasePath = "\\\\.\\pipe\\android-";
-    char* fileName;
-
-    assert(name != NULL && name[0] != '\0');
-
-    fileName = new char[strlen(kBasePath) + strlen(name) + 1];
-    strcpy(fileName, kBasePath);
-    strcat(fileName, name);
-
-    return fileName;
-}
-
-/*
- * Create a named pipe, so the client has something to connect to.
- */
-bool LocalBiChannel::create(const char* name)
-{
-    delete[] mFileName;
-    mFileName = makeFilename(name);
-
-#if 0
-    HANDLE hPipe;
-
-    hPipe = CreateNamedPipe(
-                    mFileName,              // unique pipe name
-                    PIPE_ACCESS_DUPLEX |    // open mode
-                        FILE_FLAG_FIRST_PIPE_INSTANCE,
-                    0,                      // pipe mode (byte, blocking)
-                    1,                      // max instances
-                    kPipeSize,              // output buffer
-                    kPipeSize,              // input buffer
-                    NMPWAIT_USE_DEFAULT_WAIT,   // client time-out
-                    NULL);                  // security
-
-    if (hPipe == 0) {
-        LOG(LOG_ERROR, "lbicomm",
-            "CreateNamedPipe failed (err=%ld)\n", GetLastError());
-        return false;
-    }
-
-    mHandle = (unsigned long) hPipe;
-#endif
-
-    return true;
-}
-
-/*
- * Attach to an existing named pipe.
- */
-bool LocalBiChannel::attach(const char* name, Pipe** ppReadPipe,
-    Pipe** ppWritePipe)
-{
-    HANDLE hPipe, dupHandle;
-
-    delete[] mFileName;
-    mFileName = makeFilename(name);
-
-    hPipe = CreateFile(
-                mFileName,                      // filename
-                GENERIC_READ | GENERIC_WRITE,   // access
-                0,                              // no sharing
-                NULL,                           // security
-                OPEN_EXISTING,                  // don't create
-                0,                              // attributes
-                NULL);                          // template
-    if (hPipe == INVALID_HANDLE_VALUE) {
-        LOG(LOG_ERROR, "lbicomm",
-            "CreateFile on pipe '%s' failed (err=%ld)\n", name, GetLastError());
-        return false;
-    }
-
-    assert(mHandle == kInvalidHandle);
-
-    /*
-     * Set up the pipes.  Use the new handle for one, and a duplicate
-     * of it for the other, in case we decide to only close one side.
-     */
-    *ppReadPipe = new Pipe();
-    (*ppReadPipe)->createReader((unsigned long) hPipe);
-
-    DuplicateHandle(
-            GetCurrentProcess(),
-            hPipe,
-            GetCurrentProcess(),
-            &dupHandle,
-            0,
-            FALSE,
-            DUPLICATE_SAME_ACCESS);
-    *ppWritePipe = new Pipe();
-    (*ppWritePipe)->createWriter((unsigned long) dupHandle);
-
-    return true;
-}
-
-/*
- * Listen for a new connection, discarding any existing connection.
- */
-bool LocalBiChannel::listen(Pipe** ppReadPipe, Pipe** ppWritePipe)
-{
-    BOOL connected;
-    HANDLE hPipe;
-
-    /*
-     * Create up to 3 instances of the named pipe:
-     * - currently active connection
-     * - connection currently being rejected because one is already active
-     * - a new listener to wait for the next round
-     */
-    hPipe = CreateNamedPipe(
-                    mFileName,              // unique pipe name
-                    PIPE_ACCESS_DUPLEX      // open mode
-                        /*| FILE_FLAG_FIRST_PIPE_INSTANCE*/,
-                    0,                      // pipe mode (byte, blocking)
-                    3,                      // max instances
-                    kPipeSize,              // output buffer
-                    kPipeSize,              // input buffer
-                    NMPWAIT_USE_DEFAULT_WAIT,   // client time-out
-                    NULL);                  // security
-
-    if (hPipe == 0) {
-        LOG(LOG_ERROR, "lbicomm",
-            "CreateNamedPipe failed (err=%ld)\n", GetLastError());
-        return false;
-    }
-
-    /*
-     * If a client is already connected to us, this fails with
-     * ERROR_PIPE_CONNECTED.  It returns success if we had to wait
-     * a little bit before the connection happens.
-     */
-    connected = ConnectNamedPipe(hPipe, NULL) ?
-        TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
-
-    if (connected) {
-        /*
-         * Create the pipes.  Give one a duplicated handle so that,
-         * when one closes, we don't lose both.
-         */
-        HANDLE dupHandle;
-
-        *ppReadPipe = new Pipe();
-        (*ppReadPipe)->createReader((unsigned long) hPipe);
-
-        DuplicateHandle(
-                GetCurrentProcess(),
-                hPipe,
-                GetCurrentProcess(),
-                &dupHandle,
-                0,
-                FALSE,
-                DUPLICATE_SAME_ACCESS);
-        *ppWritePipe = new Pipe();
-        (*ppWritePipe)->createWriter((unsigned long) dupHandle);
-
-        return true;
-    } else {
-        LOG(LOG_WARN, "lbicomm",
-            "ConnectNamedPipe failed (err=%ld)\n", GetLastError());
-#ifdef HAVE_WIN32_THREADS
-        Sleep(500); /* 500 ms */
-#else            
-        usleep(500000);     // DEBUG DEBUG
-#endif        
-        return false;
-    }
-}
-
-#else
-
-/*
- * Implementation for Linux and Darwin, using UNIX-domain sockets.
- */
-
-/*
- * Destructor.  If we're the server side, blow away the socket file.
- */
-LocalBiChannel::~LocalBiChannel(void)
-{
-    if (mHandle != kInvalidHandle)
-        close((int) mHandle);
-
-    if (mIsListener && mFileName != NULL) {
-        LOG(LOG_DEBUG, "lbicomm", "Removing '%s'\n", mFileName);
-        (void) unlink(mFileName);
-    }
-    delete[] mFileName;
-}
-
-/*
- * Construct the full path.  The caller must delete[] the return value.
- */
-static char* makeFilename(const char* name)
-{
-    static const char* kBasePath = "/tmp/android-";
-    char* fileName;
-
-    assert(name != NULL && name[0] != '\0');
-
-    fileName = new char[strlen(kBasePath) + strlen(name) + 1];
-    strcpy(fileName, kBasePath);
-    strcat(fileName, name);
-
-    return fileName;
-}
-
-/*
- * Create a UNIX domain socket, carefully removing it if it already
- * exists.
- */
-bool LocalBiChannel::create(const char* name)
-{
-    struct stat sb;
-    bool result = false;
-    int sock = -1;
-    int cc;
-
-    delete[] mFileName;
-    mFileName = makeFilename(name);
-
-    cc = stat(mFileName, &sb);
-    if (cc < 0) {
-        if (errno != ENOENT) {
-            LOG(LOG_ERROR, "lbicomm",
-                "Unable to stat '%s' (errno=%d)\n", mFileName, errno);
-            goto bail;
-        }
-    } else {
-        /* don't touch it if it's not a socket */
-        if (!(S_ISSOCK(sb.st_mode))) {
-            LOG(LOG_ERROR, "lbicomm",
-                "File '%s' exists and is not a socket\n", mFileName);
-            goto bail;
-        }
-
-        /* remove the cruft */
-        if (unlink(mFileName) < 0) {
-            LOG(LOG_ERROR, "lbicomm",
-                "Unable to remove '%s' (errno=%d)\n", mFileName, errno);
-            goto bail;
-        }
-    }
-
-    struct sockaddr_un addr;
-
-    sock = ::socket(AF_UNIX, SOCK_STREAM, 0);
-    if (sock < 0) {
-        LOG(LOG_ERROR, "lbicomm",
-            "UNIX domain socket create failed (errno=%d)\n", errno);
-        goto bail;
-    }
-
-    /* bind the socket; this creates the file on disk */
-    strcpy(addr.sun_path, mFileName);    // max 108 bytes
-    addr.sun_family = AF_UNIX;
-    cc = ::bind(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
-    if (cc < 0) {
-        LOG(LOG_ERROR, "lbicomm",
-            "AF_UNIX bind failed for '%s' (errno=%d)\n", mFileName, errno);
-        goto bail;
-    }
-
-    mHandle = (unsigned long) sock;
-    sock = -1;
-    mIsListener = true;
-    result = true;
-
-bail:
-    if (sock >= 0)
-        close(sock);
-    return result;
-}
-
-/*
- * Attach to an existing UNIX domain socket.
- */
-bool LocalBiChannel::attach(const char* name, Pipe** ppReadPipe,
-    Pipe** ppWritePipe)
-{
-    bool result = false;
-    int sock = -1;
-    int cc;
-
-    assert(ppReadPipe != NULL);
-    assert(ppWritePipe != NULL);
-
-    delete[] mFileName;
-    mFileName = makeFilename(name);
-
-    struct sockaddr_un addr;
-
-    sock = ::socket(AF_UNIX, SOCK_STREAM, 0);
-    if (sock < 0) {
-        LOG(LOG_ERROR, "lbicomm",
-            "UNIX domain socket create failed (errno=%d)\n", errno);
-        goto bail;
-    }
-
-    /* connect to socket; fails if file doesn't exist */
-    strcpy(addr.sun_path, mFileName);    // max 108 bytes
-    addr.sun_family = AF_UNIX;
-    cc = ::connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
-    if (cc < 0) {
-        // ENOENT means socket file doesn't exist
-        // ECONNREFUSED means socket exists but nobody is listening
-        LOG(LOG_ERROR, "lbicomm",
-            "AF_UNIX connect failed for '%s': %s\n", mFileName,strerror(errno));
-        goto bail;
-    }
-
-    /*
-     * Create the two halves.  We dup() the sock so that closing one side
-     * does not hose the other.
-     */
-    *ppReadPipe = new Pipe();
-    (*ppReadPipe)->createReader(sock);
-    *ppWritePipe = new Pipe();
-    (*ppWritePipe)->createWriter(dup(sock));
-
-    assert(mHandle == kInvalidHandle);
-    sock = -1;
-    mIsListener = false;
-
-    result = true;
-
-bail:
-    if (sock >= 0)
-        close(sock);
-    return result;
-}
-
-/*
- * Listen for a new connection.
- */
-bool LocalBiChannel::listen(Pipe** ppReadPipe, Pipe** ppWritePipe)
-{
-    bool result = false;
-    struct sockaddr_un from;
-    socklen_t fromlen;
-    int sock, lsock;
-    int cc;
-
-    assert(mHandle != kInvalidHandle);
-    lsock = (int) mHandle;
-
-    LOG(LOG_DEBUG, "lbicomm", "AF_UNIX listening\n");
-    cc = ::listen(lsock, 5);
-    if (cc < 0) {
-        LOG(LOG_ERROR, "lbicomm", "AF_UNIX listen failed (errno=%d)\n", errno);
-        goto bail;
-    }
-
-    fromlen = sizeof(from);     // not SUN_LEN()
-    sock = ::accept(lsock, (struct sockaddr*) &from, &fromlen);
-    if (sock < 0) {
-        LOG(LOG_WARN, "lbicomm", "AF_UNIX accept failed (errno=%d)\n", errno);
-        goto bail;
-    }
-
-    /*
-     * Create the two halves.  We dup() the sock so that closing one side
-     * does not hose the other.
-     */
-    *ppReadPipe = new Pipe();
-    (*ppReadPipe)->createReader(sock);
-    *ppWritePipe = new Pipe();
-    (*ppWritePipe)->createWriter(dup(sock));
-    result = true;
-
-bail:
-    return result;
-}
-
-#endif
diff --git a/simulator/app/LocalBiChannel.h b/simulator/app/LocalBiChannel.h
deleted file mode 100644
index a4f4d62..0000000
--- a/simulator/app/LocalBiChannel.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Create or attach to a named bi-directional channel on the local machine.
-//
-#ifndef __LIBS_LOCALBICHANNEL_H
-#define __LIBS_LOCALBICHANNEL_H
-
-#ifdef HAVE_ANDROID_OS
-#error DO NOT USE THIS FILE IN THE DEVICE BUILD
-#endif
-
-#include "Pipe.h"
-
-namespace android {
-
-/*
- * This is essentially a wrapper class for UNIX-domain sockets.  The
- * idea is to set one up with create() or attach to one with attach()
- * and then extract the unidirectional read/write Pipes.  These can
- * be used directly or stuffed into a MessageStream.
- *
- * The name for the pipe should be a short filename made up of alphanumeric
- * characters.  Depending on the implementation, we may create a file in
- * /tmp with the specified name, removing any existing copy.
- */
-class LocalBiChannel {
-public:
-    LocalBiChannel(void);
-    ~LocalBiChannel(void);
-
-    /* create the "listen" side */
-    bool create(const char* name);
-
-    /*
-     * Listen for a connection.  When we get one, we create unidirectional
-     * read/write pipes and return them.
-     */
-    bool listen(Pipe** ppReadPipe, Pipe** ppWritePipe);
-
-    /*
-     * Attach to a channel created by somebody else.  Returns pipes.
-     */
-    bool attach(const char* name, Pipe** ppReadPipe, Pipe** ppWritePipe);
-
-private:
-    char*       mFileName;
-    bool        mIsListener;
-    unsigned long mHandle;
-};
-
-}; // namespace android
-
-#endif // __LIBS_LOCALBICHANNEL_H
diff --git a/simulator/app/LogBundle.h b/simulator/app/LogBundle.h
deleted file mode 100644
index 2cba97b..0000000
--- a/simulator/app/LogBundle.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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 _SIM_LOG_BUNDLE_H
-#define _SIM_LOG_BUNDLE_H
-
-#ifdef HAVE_PTHREADS
-#include <pthread.h>
-#endif
-#include <cutils/logd.h> // for android_LogPriority.
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct android_LogBundle {
-    time_t              when;
-    android_LogPriority priority;
-    pid_t               pid;
-#ifndef HAVE_PTHREADS
-    unsigned            tid;
-#else    
-    pthread_t           tid;
-#endif    
-    const char*         tag;
-    const struct iovec* msgVec;
-    size_t              msgCount;
-    int                 fd;
-} android_LogBundle;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _SIM_LOG_BUNDLE_H
diff --git a/simulator/app/LogMessage.cpp b/simulator/app/LogMessage.cpp
deleted file mode 100644
index 63cb764..0000000
--- a/simulator/app/LogMessage.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Hold a single log message.
-//
-#include "LogMessage.h"
-#include <assert.h>
-
-/*
- * Constructor.
- *
- * Initializers here aren't necessary, since we can only create one of
- * these through Create(), which touches every field.
- */
-LogMessage::LogMessage(void)
-{
-}
-
-/*
- * Destructor.
- */
-LogMessage::~LogMessage(void)
-{
-    delete[] mTag;
-    delete[] mMsg;
-}
-
-/*
- * Create a new LogMessage object, and populate it with the contents of
- * "*pBundle".
- */
-/*static*/ LogMessage* LogMessage::Create(const android_LogBundle* pBundle)
-{
-    LogMessage* newMsg = new LogMessage;
-
-    if (newMsg == NULL)
-        return NULL;
-    assert(pBundle != NULL);
-
-    newMsg->mWhen = pBundle->when;
-    newMsg->mPriority = pBundle->priority;
-    newMsg->mPid = pBundle->pid;
-    newMsg->mTag = android::strdupNew(pBundle->tag);
-
-    size_t len = 0;
-    size_t i;
-    for (i=0; i<pBundle->msgCount; i++) len += pBundle->msgVec[i].iov_len;
-    newMsg->mMsg = new char[len+1];
-    char* p = newMsg->mMsg;
-    for (i=0; i<pBundle->msgCount; i++) {
-        memcpy(p, pBundle->msgVec[i].iov_base, pBundle->msgVec[i].iov_len);
-        p += pBundle->msgVec[i].iov_len;
-    }
-    *p = 0;
-
-    newMsg->mRefCnt = 1;
-    newMsg->mInternal = false;
-    newMsg->mFootprint = 8 * sizeof(int) + strlen(newMsg->mTag) +
-        strlen(newMsg->mMsg) + 4;
-    newMsg->mTextCtrlLen = 0;
-    newMsg->mpPrev = NULL;
-    newMsg->mpNext = NULL;
-
-    return newMsg;
-}
-
-/*
- * Create a new LogMessage object, with a simple message in it.
- *
- * Sets "mInternal" so we display it appropriately.
- */
-/*static*/ LogMessage* LogMessage::Create(const char* msg)
-{
-    LogMessage* newMsg;
-    android_LogBundle bundle;
-
-    assert(msg != NULL);
-
-    memset(&bundle, 0, sizeof(bundle));
-    bundle.when = time(NULL);
-    bundle.priority = ANDROID_LOG_ERROR;
-    bundle.pid = getpid();
-    bundle.tag = "-";
-    iovec iov;
-    iov.iov_base = (void*)msg;
-    iov.iov_len = strlen(msg);
-    bundle.msgVec = &iov;
-    bundle.msgCount = 1;
-
-    newMsg = Create(&bundle);
-
-    if (newMsg != NULL) {
-        newMsg->mInternal = true;
-    }
-
-    return newMsg;
-}
-
diff --git a/simulator/app/LogMessage.h b/simulator/app/LogMessage.h
deleted file mode 100644
index fe77dc0..0000000
--- a/simulator/app/LogMessage.h
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Class to hold a single log message.  Not thread safe.
-//
-#ifndef _SIM_LOG_MESSAGE_H
-#define _SIM_LOG_MESSAGE_H
-
-#include "utils.h"
-#include "LogBundle.h"
-
-/*
- * Hold a single log message.
- *
- * To reduce malloc strain we could over-allocate the object and tuck the
- * message text into the object storage.  On this off chance this becomes
- * important, the implementation keeps its constructor private.
- */
-class LogMessage {
-public:
-    ~LogMessage(void);
-
-    static LogMessage* Create(const android_LogBundle* pBundle);
-    static LogMessage* Create(const char* msg);
-
-    /* the total length of text added to the text ctrl */
-    int GetTextCtrlLen(void) const { return mTextCtrlLen; }
-    void SetTextCtrlLen(int len) { mTextCtrlLen = len; }
-
-    /* log pool */
-    LogMessage* GetPrev(void) const { return mpPrev; }
-    void SetPrev(LogMessage* pPrev) { mpPrev = pPrev; }
-    LogMessage* GetNext(void) const { return mpNext; }
-    void SetNext(LogMessage* pNext) { mpNext = pNext; }
-    int GetFootprint(void) const { return mFootprint; }
-
-    /* message contents */
-    time_t GetWhen(void) const { return mWhen; }
-    android_LogPriority GetPriority(void) const { return mPriority; }
-    pid_t GetPid(void) const { return mPid; }
-    const char* GetTag(void) const { return mTag; }
-    const char* GetMsg(void) const { return mMsg; }
-
-    bool GetInternal(void) const { return mInternal; }
-
-    void Acquire(void) { mRefCnt++; }
-    void Release(void) {
-        if (!--mRefCnt)
-            delete this;
-    }
-
-private:
-    LogMessage(void);
-    LogMessage(const LogMessage& src);              // not implemented
-    LogMessage& operator=(const LogMessage& src);   // not implemented
-
-    /* log message contents */
-    time_t          mWhen;
-    android_LogPriority mPriority;
-    pid_t           mPid;
-    char*           mTag;
-    char*           mMsg;
-
-    /* additional goodies */
-    int             mRefCnt;        // reference count
-    bool            mInternal;      // message generated internally by us?
-    int             mFootprint;     // approx. size of this object in memory
-    int             mTextCtrlLen;   // #of characters req'd in text ctrl
-    LogMessage*     mpPrev;         // link to previous item in log pool
-    LogMessage*     mpNext;         // link to next item in log pool
-};
-
-#endif // _SIM_LOG_MESSAGE_H
diff --git a/simulator/app/LogPool.cpp b/simulator/app/LogPool.cpp
deleted file mode 100644
index 43bf4be..0000000
--- a/simulator/app/LogPool.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Hold a collection of log messages, limiting ourselves to a certain
-// fixed maximum amount of memory.
-//
-#include "LogPool.h"
-#include <assert.h>
-
-
-/*
- * Add a message at the head of the pool.
- */
-void LogPool::Add(LogMessage* pLogMessage)
-{
-    pLogMessage->Acquire();     // bump up the ref count
-
-    assert(pLogMessage->GetPrev() == NULL);
-    assert(pLogMessage->GetNext() == NULL);
-
-    if (mpHead == NULL) {
-        assert(mpTail == NULL);
-        mpTail = mpHead = pLogMessage;
-    } else {
-        assert(mpHead->GetPrev() == NULL);
-        mpHead->SetPrev(pLogMessage);
-        pLogMessage->SetNext(mpHead);
-        mpHead = pLogMessage;
-    }
-
-    /* update the pool size, and remove old entries if necessary */
-    mCurrentSize += pLogMessage->GetFootprint();
-
-    while (mCurrentSize > mMaxSize)
-        RemoveOldest();
-}
-
-/*
- * Remove the oldest message (from the tail of the list).
- */
-void LogPool::RemoveOldest(void)
-{
-    LogMessage* pPrev;
-
-    if (mpTail == NULL) {
-        fprintf(stderr, "HEY: nothing left to remove (cur=%ld)\n",
-            mCurrentSize);
-        assert(false);
-        return;
-    }
-
-    if (mpTail == mpBookmark)
-        mpBookmark = NULL;
-
-    //printf("--- removing oldest, size %ld->%ld (%s)\n",
-    //    mCurrentSize, mCurrentSize - mpTail->GetFootprint(),mpTail->GetMsg());
-    mCurrentSize -= mpTail->GetFootprint();
-
-    pPrev = mpTail->GetPrev();
-    mpTail->Release();
-    mpTail = pPrev;
-    if (mpTail == NULL) {
-        //printf("--- pool is now empty (size=%ld)\n", mCurrentSize);
-        mpHead = NULL;
-    } else {
-        mpTail->SetNext(NULL);
-    }
-}
-
-/*
- * Resize the log pool.
- */
-void LogPool::Resize(long maxSize)
-{
-    assert(maxSize >= 0);
-
-    mMaxSize = maxSize;
-    while (mCurrentSize > mMaxSize)
-        RemoveOldest();
-}
-
-/*
- * Remove all entries.
- */
-void LogPool::Clear(void)
-{
-    while (mpTail != NULL)
-        RemoveOldest();
-}
-
diff --git a/simulator/app/LogPool.h b/simulator/app/LogPool.h
deleted file mode 100644
index b824fec..0000000
--- a/simulator/app/LogPool.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Pool of log messages.  Not thread safe -- operations on the log pool
-// should only happen in the main UI thread.
-//
-#ifndef _SIM_LOG_POOL_H
-#define _SIM_LOG_POOL_H
-
-#include "LogMessage.h"
-
-/*
- * This contains the pool of log messages.  The messages themselves are
- * allocated individually and reference counted.  We add new messages to
- * the head and, when the total "footprint" exceeds our stated max, we
- * delete one or more from the tail.
- *
- * To support pause/resume, we allow a "bookmark" to be set.  This is
- * just a pointer to a message in the pool.  If the bookmarked message
- * is deleted, we discard the bookmark.
- */
-class LogPool {
-public:
-    LogPool(void)
-        : mpHead(NULL), mpTail(NULL), mpBookmark(NULL),
-          mCurrentSize(0), mMaxSize(10240)
-        {}
-    ~LogPool(void) { Clear(); }
-
-    void Clear(void);
-
-    /* add a new message to the pool */
-    void Add(LogMessage* pLogMessage);
-
-    /* resize the pool, removing excess messages */
-    void Resize(long maxSize);
-
-    /* return the current limit, in bytes */
-    long GetMaxSize(void) const { return mMaxSize; }
-
-    LogMessage* GetHead(void) const { return mpHead; }
-
-    void SetBookmark(void) { mpBookmark = mpHead; }
-    LogMessage* GetBookmark(void) const { return mpBookmark; }
-
-private:
-    void RemoveOldest(void);
-
-    LogMessage*     mpHead;
-    LogMessage*     mpTail;
-    LogMessage*     mpBookmark;
-    long            mCurrentSize;       // current size, in bytes
-    long            mMaxSize;           // maximum size, in bytes
-};
-
-#endif // _SIM_LOG_POOL_H
diff --git a/simulator/app/LogPrefsDialog.cpp b/simulator/app/LogPrefsDialog.cpp
deleted file mode 100644
index dc3e07c..0000000
--- a/simulator/app/LogPrefsDialog.cpp
+++ /dev/null
@@ -1,404 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Log preferences modal dialog.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-
-#include "LogPrefsDialog.h"
-#include "Preferences.h"
-#include "Resource.h"
-#include "utils.h"
-
-BEGIN_EVENT_TABLE(LogPrefsDialog, wxDialog)
-    EVT_CHECKBOX(IDC_LOG_PREFS_WRITE_FILE, LogPrefsDialog::OnWriteFile)
-END_EVENT_TABLE()
-
-static const wxString gSpacerChoices[] = { 
-    wxT("0"), wxT("1"), wxT("2") 
-};
-static const wxString gPointSizes[] = { 
-    wxT("4"), wxT("6"), wxT("8"), wxT("10"), wxT("12"), wxT("14"), wxT("16") 
-};
-
-
-/*
- * Constructor.
- */
-LogPrefsDialog::LogPrefsDialog(wxWindow* parent)
-    : wxDialog(parent, IDD_LOG_PREFS, wxT("Log Preferences"), wxDefaultPosition,
-        wxDefaultSize, wxDEFAULT_DIALOG_STYLE),
-      mHeaderFormat(kHFFull), mSingleLine(false), mExtraSpacing(0),
-      mUseColor(false), mFontMonospace(false), mDisplayMax(0), mPoolSizeKB(0)
-{
-    CreateControls();
-}
-
-
-/*
- * Destructor.  Not much to do.
- */
-LogPrefsDialog::~LogPrefsDialog(void)
-{
-}
-
-/*
- * Create all of the pages and add them to the notebook.
- */
-void LogPrefsDialog::CreateControls(void)
-{
-    wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
-    wxBoxSizer* okCancelSizer = new wxBoxSizer(wxHORIZONTAL);
-    mNotebook.Create(this, wxID_ANY);
-    wxPanel* page;
-
-    page = CreateFormatPage(&mNotebook);
-    mNotebook.AddPage(page, wxT("Format"), true);
-    page = CreateLimitsPage(&mNotebook);
-    mNotebook.AddPage(page, wxT("Limits"), false);
-    page = CreateFilesPage(&mNotebook);
-    mNotebook.AddPage(page, wxT("Files"), false);
-
-    // note to self: could use CreateButtonSizer here?
-    wxButton* cancel = new wxButton(this, wxID_CANCEL, wxT("&Cancel"),
-        wxDefaultPosition, wxDefaultSize, 0);
-    okCancelSizer->Add(cancel, 0, wxALL, kInterSpacing);
-
-    wxButton* ok = new wxButton(this, wxID_OK, wxT("&OK"),
-        wxDefaultPosition, wxDefaultSize, 0);
-    okCancelSizer->Add(ok, 0, wxALL, kInterSpacing);
-
-    mainSizer->Add(&mNotebook);
-    mainSizer->Add(okCancelSizer, 0, wxALIGN_RIGHT);
-
-    SetSizer(mainSizer);
-
-    mainSizer->Fit(this);           // shrink-to-fit
-    mainSizer->SetSizeHints(this);  // define minimum size
-}
-
-/*
- * Transfer data from our members to the window controls.
- */
-bool LogPrefsDialog::TransferDataToWindow(void)
-{
-    /*
-     * Do standard dialog setup.
-     */
-    wxRadioButton* fmtFull = (wxRadioButton*) FindWindow(IDC_LOG_PREFS_FMT_FULL);
-    wxRadioButton* fmtBrief = (wxRadioButton*) FindWindow(IDC_LOG_PREFS_FMT_BRIEF);
-    wxRadioButton* fmtMinimal = (wxRadioButton*) FindWindow(IDC_LOG_PREFS_FMT_MINIMAL);
-    wxCheckBox* singleLine = (wxCheckBox*) FindWindow(IDC_LOG_PREFS_SINGLE_LINE);
-    wxComboBox* extraSpacing = (wxComboBox*) FindWindow(IDC_LOG_PREFS_EXTRA_SPACING);
-    wxComboBox* pointSize = (wxComboBox*) FindWindow(IDC_LOG_PREFS_POINT_SIZE);
-    wxCheckBox* useColor = (wxCheckBox*) FindWindow(IDC_LOG_PREFS_USE_COLOR);
-    wxCheckBox* fontMono = (wxCheckBox*) FindWindow(IDC_LOG_PREFS_FONT_MONO);
-    // -
-    wxTextCtrl* displayMax = (wxTextCtrl*) FindWindow(IDC_LOG_PREFS_DISPLAY_MAX);
-    wxTextCtrl* poolSize = (wxTextCtrl*) FindWindow(IDC_LOG_PREFS_POOL_SIZE);
-    // -
-    wxCheckBox* writeFile = (wxCheckBox*) FindWindow(IDC_LOG_PREFS_WRITE_FILE);
-    wxTextCtrl* fileName = (wxTextCtrl*) FindWindow(IDC_LOG_PREFS_FILENAME);
-    wxCheckBox* truncateOld = (wxCheckBox*) FindWindow(IDC_LOG_PREFS_TRUNCATE_OLD);
-    // -
-
-    fmtFull->SetValue(mHeaderFormat == kHFFull);
-    fmtBrief->SetValue(mHeaderFormat == kHFBrief);
-    fmtMinimal->SetValue(mHeaderFormat == kHFMinimal);
-    singleLine->SetValue(mSingleLine);
-    if (mExtraSpacing < 0 || mExtraSpacing > NELEM(gSpacerChoices))
-        mExtraSpacing = 0;
-    extraSpacing->SetSelection(mExtraSpacing);
-
-    pointSize->SetSelection(0);
-    for (int i = 0; i < NELEM(gPointSizes); i++) {
-        if (atoi(gPointSizes[i].ToAscii()) == mPointSize) {
-            pointSize->SetSelection(i);
-            break;
-        }
-    }
-    useColor->SetValue(mUseColor);
-    fontMono->SetValue(mFontMonospace);
-
-    wxString tmpStr;
-    tmpStr.Printf(wxT("%d"), mDisplayMax);
-    displayMax->SetValue(tmpStr);
-    tmpStr.Printf(wxT("%d"), mPoolSizeKB);
-    poolSize->SetValue(tmpStr);
-
-    writeFile->SetValue(mWriteFile);
-    fileName->SetValue(mFileName);
-    truncateOld->SetValue(mTruncateOld);
-
-    EnableFileControls(mWriteFile);
-
-    return true;
-}
-
-/*
- * Convert a string to a number.  The number is expected to be unsigned.
- * Returns < 0 on failure.
- */
-static long ConvertUnsigned(const wxString& str)
-{
-    long val;
-    if (!str.ToLong(&val))
-        return -1;
-    return val;
-}
-
-/*
- * Transfer and validate data from the window controls.
- *
- * This doesn't get called if the user cancels out of the dialog.
- */
-bool LogPrefsDialog::TransferDataFromWindow(void)
-{
-    /*
-     * Do standard dialog export.
-     */
-    //wxRadioButton* fmtFull = (wxRadioButton*) FindWindow(IDC_LOG_PREFS_FMT_FULL);
-    wxRadioButton* fmtBrief = (wxRadioButton*) FindWindow(IDC_LOG_PREFS_FMT_BRIEF);
-    wxRadioButton* fmtMinimal = (wxRadioButton*) FindWindow(IDC_LOG_PREFS_FMT_MINIMAL);
-    wxCheckBox* singleLine = (wxCheckBox*) FindWindow(IDC_LOG_PREFS_SINGLE_LINE);
-    wxComboBox* extraSpacing = (wxComboBox*) FindWindow(IDC_LOG_PREFS_EXTRA_SPACING);
-    wxComboBox* pointSize = (wxComboBox*) FindWindow(IDC_LOG_PREFS_POINT_SIZE);
-    wxCheckBox* useColor = (wxCheckBox*) FindWindow(IDC_LOG_PREFS_USE_COLOR);
-    wxCheckBox* fontMono = (wxCheckBox*) FindWindow(IDC_LOG_PREFS_FONT_MONO);
-    // -
-    wxTextCtrl* displayMax = (wxTextCtrl*) FindWindow(IDC_LOG_PREFS_DISPLAY_MAX);
-    wxTextCtrl* poolSize = (wxTextCtrl*) FindWindow(IDC_LOG_PREFS_POOL_SIZE);
-    // -
-    wxCheckBox* writeFile = (wxCheckBox*) FindWindow(IDC_LOG_PREFS_WRITE_FILE);
-    wxTextCtrl* fileName = (wxTextCtrl*) FindWindow(IDC_LOG_PREFS_FILENAME);
-    wxCheckBox* truncateOld = (wxCheckBox*) FindWindow(IDC_LOG_PREFS_TRUNCATE_OLD);
-    // -
-
-    mHeaderFormat = kHFFull;
-    if (fmtBrief->GetValue())
-        mHeaderFormat = kHFBrief;
-    else if (fmtMinimal->GetValue())
-        mHeaderFormat = kHFMinimal;
-
-    wxString tmpStr;
-
-    mSingleLine = (singleLine->GetValue() != 0);
-    mExtraSpacing = extraSpacing->GetSelection();
-    mPointSize = ConvertUnsigned(pointSize->GetValue());
-    mUseColor = useColor->GetValue();
-    mFontMonospace = fontMono->GetValue();
-
-    tmpStr = displayMax->GetValue();
-    mDisplayMax = ConvertUnsigned(tmpStr);
-    if (mDisplayMax <= 0 || mDisplayMax > 1000 * 1000) {
-        wxMessageBox(wxT("Bad value for display max -- must be > 0 and <= 1,000,000"),
-            wxT("Hoser"), wxOK, this);
-        return false;
-    }
-
-    tmpStr = poolSize->GetValue();
-    mPoolSizeKB = ConvertUnsigned(tmpStr);
-    if (mDisplayMax <= 0 || mDisplayMax > 1048576) {
-        wxMessageBox(wxT("Bad value for pool size -- must be > 0 and <= 1048576"),
-            wxT("Hoser"), wxOK, this);
-        return false;
-    }
-
-    mWriteFile = (writeFile->GetValue() != 0);
-    mFileName = fileName->GetValue();
-    mTruncateOld = (truncateOld->GetValue() != 0);
-    if (mWriteFile && mFileName.IsEmpty()) {
-        wxMessageBox(wxT("Log filename may not be blank"),
-            wxT("Hoser"), wxOK, this);
-        return false;
-    }
-
-    return true;
-}
-
-
-/*
- * Create the log Format page.
- */
-wxPanel* LogPrefsDialog::CreateFormatPage(wxBookCtrlBase* parent)
-{
-    wxPanel* panel = new wxPanel(parent);
-
-    wxStaticBoxSizer* headerOpts = new wxStaticBoxSizer(wxVERTICAL, panel,
-        wxT("Header"));
-    headerOpts->Add(new wxRadioButton(panel, IDC_LOG_PREFS_FMT_FULL,
-            wxT("Full header"), wxDefaultPosition, wxDefaultSize,
-            wxRB_GROUP));
-    headerOpts->Add(new wxRadioButton(panel, IDC_LOG_PREFS_FMT_BRIEF,
-            wxT("Brief header")));
-    headerOpts->Add(new wxRadioButton(panel, IDC_LOG_PREFS_FMT_MINIMAL,
-            wxT("Minimal, integrated header")));
-
-    wxCheckBox* singleLine = new wxCheckBox(panel, IDC_LOG_PREFS_SINGLE_LINE,
-        wxT("Put headers and message on same line"));
-
-    wxStaticText* extraSpacingDescr = new wxStaticText(panel, wxID_STATIC,
-        wxT("Extra line spacing:"));
-    wxComboBox* extraSpacing = new wxComboBox(panel,
-        IDC_LOG_PREFS_EXTRA_SPACING, wxT("blah"),
-        wxDefaultPosition, wxDefaultSize, NELEM(gSpacerChoices),
-        gSpacerChoices, wxCB_READONLY);
-    wxBoxSizer* extraSpacingSizer = new wxBoxSizer(wxHORIZONTAL);
-    extraSpacingSizer->Add(extraSpacingDescr, 0, wxALIGN_CENTER_VERTICAL);
-    extraSpacingSizer->AddSpacer(kInterSpacing);
-    extraSpacingSizer->Add(extraSpacing);
-
-    wxStaticBoxSizer* textOpts = new wxStaticBoxSizer(wxVERTICAL, panel,
-        wxT("Text"));
-    textOpts->Add(
-            new wxStaticText(panel, wxID_STATIC, wxT("Point size:")) );
-    textOpts->AddSpacer(kInterSpacing);
-    textOpts->Add(
-        new wxComboBox(panel,
-            IDC_LOG_PREFS_POINT_SIZE, wxT("blah"),
-            wxDefaultPosition, wxDefaultSize, NELEM(gPointSizes),
-            gPointSizes, wxCB_READONLY) );
-    textOpts->AddSpacer(kInterSpacing);
-    textOpts->Add(
-            new wxCheckBox(panel, IDC_LOG_PREFS_USE_COLOR,
-                wxT("Colorful messages")) );
-    textOpts->AddSpacer(kInterSpacing);
-    textOpts->Add(
-            new wxCheckBox(panel, IDC_LOG_PREFS_FONT_MONO,
-                wxT("Use monospace font")) );
-
-
-    wxBoxSizer* sizerPanel = new wxBoxSizer(wxVERTICAL);
-    sizerPanel->Add(kMinWidth, kEdgeSpacing);       // forces minimum width
-    sizerPanel->Add(headerOpts);
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->Add(singleLine);
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->Add(extraSpacingSizer);
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->Add(textOpts);
-    sizerPanel->AddSpacer(kInterSpacing);
-
-    wxBoxSizer* horizIndent = new wxBoxSizer(wxHORIZONTAL);
-    horizIndent->AddSpacer(kEdgeSpacing);
-    horizIndent->Add(sizerPanel);
-    horizIndent->AddSpacer(kEdgeSpacing);
-    panel->SetSizer(horizIndent);
-
-    return panel;
-}
-
-/*
- * Create the log Limits page.
- */
-wxPanel* LogPrefsDialog::CreateLimitsPage(wxBookCtrlBase* parent)
-{
-    wxPanel* panel = new wxPanel(parent);
-
-    wxBoxSizer* displayMaxSizer = new wxBoxSizer(wxHORIZONTAL);
-    displayMaxSizer->Add(
-            new wxStaticText(panel, wxID_ANY,
-                wxT("Maximum entries in log window:"),
-                wxDefaultPosition, wxDefaultSize,
-                wxALIGN_LEFT),
-            0, wxALIGN_CENTER_VERTICAL);
-    displayMaxSizer->AddSpacer(kInterSpacing);
-    displayMaxSizer->Add(
-            new wxTextCtrl(panel, IDC_LOG_PREFS_DISPLAY_MAX));
-
-    wxBoxSizer* poolSizeSizer = new wxBoxSizer(wxHORIZONTAL);
-    poolSizeSizer->Add(
-            new wxStaticText(panel, wxID_ANY,
-                wxT("Size of the log pool (KB):"),
-                wxDefaultPosition, wxDefaultSize,
-                wxALIGN_LEFT),
-            0, wxALIGN_CENTER_VERTICAL);
-    poolSizeSizer->AddSpacer(kInterSpacing);
-    poolSizeSizer->Add(
-            new wxTextCtrl(panel, IDC_LOG_PREFS_POOL_SIZE));
-
-
-    wxBoxSizer* sizerPanel = new wxBoxSizer(wxVERTICAL);
-    sizerPanel->Add(kMinWidth, kEdgeSpacing);       // forces minimum width
-    sizerPanel->Add(displayMaxSizer);
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->Add(poolSizeSizer);
-    sizerPanel->AddSpacer(kInterSpacing);
-
-    wxBoxSizer* horizIndent = new wxBoxSizer(wxHORIZONTAL);
-    horizIndent->AddSpacer(kEdgeSpacing);
-    horizIndent->Add(sizerPanel);
-    horizIndent->AddSpacer(kEdgeSpacing);
-    panel->SetSizer(horizIndent);
-
-    return panel;
-}
-
-/*
- * Create the log Files page.
- */
-wxPanel* LogPrefsDialog::CreateFilesPage(wxBookCtrlBase* parent)
-{
-    wxPanel* panel = new wxPanel(parent);
-    wxStaticBoxSizer* logOpts = new wxStaticBoxSizer(wxVERTICAL, panel,
-        wxT("Log File"));
-
-    wxCheckBox* writeCopy =
-            new wxCheckBox(panel, IDC_LOG_PREFS_WRITE_FILE,
-                wxT("Write a copy of log output to a file"));
-
-    logOpts->AddSpacer(kInterSpacing);
-    logOpts->Add(
-            new wxStaticText(panel, wxID_ANY,
-                wxT("Filename:"),
-                wxDefaultPosition, wxDefaultSize,
-                wxALIGN_LEFT));
-    logOpts->AddSpacer(kInterSpacing);
-    logOpts->Add(
-            new wxTextCtrl(panel, IDC_LOG_PREFS_FILENAME), 0, wxEXPAND);
-    logOpts->AddSpacer(kInterSpacing);
-    logOpts->Add(
-            new wxCheckBox(panel, IDC_LOG_PREFS_TRUNCATE_OLD,
-                wxT("Truncate the file if more than 8 hours old ")) );
-
-
-    wxBoxSizer* sizerPanel = new wxBoxSizer(wxVERTICAL);
-    sizerPanel->Add(kMinWidth, kEdgeSpacing);       // forces minimum width
-    sizerPanel->Add(writeCopy);
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->Add(logOpts);
-    sizerPanel->AddSpacer(kInterSpacing);
-
-    wxBoxSizer* horizIndent = new wxBoxSizer(wxHORIZONTAL);
-    horizIndent->AddSpacer(kEdgeSpacing);
-    horizIndent->Add(sizerPanel);
-    horizIndent->AddSpacer(kEdgeSpacing);
-    panel->SetSizer(horizIndent);
-
-    return panel;
-}
-
-
-/*
- * Handle clicks on the "write file" checkbox.
- */
-void LogPrefsDialog::OnWriteFile(wxCommandEvent& event)
-{
-    EnableFileControls(event.GetInt());
-}
-
-/*
- * Enable or disable some of the controls on the "file" page.
- */
-void LogPrefsDialog::EnableFileControls(bool enable)
-{
-    FindWindow(IDC_LOG_PREFS_FILENAME)->Enable(enable);
-    FindWindow(IDC_LOG_PREFS_TRUNCATE_OLD)->Enable(enable);
-}
-
diff --git a/simulator/app/LogPrefsDialog.h b/simulator/app/LogPrefsDialog.h
deleted file mode 100644
index 17a73a3..0000000
--- a/simulator/app/LogPrefsDialog.h
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Log preferences modal dialog.
-//
-#ifndef _SIM_LOG_PREFS_DIALOG_H
-#define _SIM_LOG_PREFS_DIALOG_H
-
-/*
- * Declaration of log preferences dialog.  This class defines the outer
- * wrapper as well as all of the pages.
- */
-class LogPrefsDialog : public wxDialog {
-    DECLARE_EVENT_TABLE()
-
-public:
-    LogPrefsDialog(wxWindow* parent);
-    virtual ~LogPrefsDialog(void);
-
-    void CreateControls(void);
-
-    /* these correspond to radio buttons */
-    typedef enum HeaderFormat {
-        kHFFull = 0,
-        kHFBrief,
-        kHFMinimal,
-        kHFInternal,        // special -- used for internally generated msgs
-    };
-
-    /*
-     * Values edited in the preference pages.  By Windows convention,
-     * these are public.
-     */
-    /* format options */
-    HeaderFormat mHeaderFormat;
-    bool        mSingleLine;        // put whole message on one line?
-    int         mExtraSpacing;      // double/triple-space messages?
-    int         mPointSize;         // text size
-    bool        mUseColor;          // colorful messages?
-    bool        mFontMonospace;     // use monospace font?
-
-    /* limit options */
-    int         mDisplayMax;
-    int         mPoolSizeKB;
-
-    /* file options */
-    bool        mWriteFile;
-    wxString    mFileName;
-    bool        mTruncateOld;
-
-private:
-    bool TransferDataToWindow(void);
-    bool TransferDataFromWindow(void);
-
-    wxPanel* CreateFormatPage(wxBookCtrlBase* parent);
-    wxPanel* CreateLimitsPage(wxBookCtrlBase* parent);
-    wxPanel* CreateFilesPage(wxBookCtrlBase* parent);
-
-    void OnWriteFile(wxCommandEvent& event);
-    void EnableFileControls(bool enable);
-
-    /* main notebook; for aesthetic reasons we may want a Choicebook */
-    wxNotebook    mNotebook;
-
-    enum {
-        kMinWidth = 300,        // minimum prefs dialog width, in pixels
-    };
-};
-
-#endif // _SIM_LOG_PREFS_DIALOG_H
diff --git a/simulator/app/LogWindow.cpp b/simulator/app/LogWindow.cpp
deleted file mode 100644
index b19debb..0000000
--- a/simulator/app/LogWindow.cpp
+++ /dev/null
@@ -1,1156 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Display runtime log output.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h"   // needed for Windows build
-#include "wx/dcbuffer.h"
-
-#include "LogWindow.h"
-#include "LogMessage.h"
-#include "LogPrefsDialog.h"
-#include "MyApp.h"
-#include "Preferences.h"
-#include "Resource.h"
-#include "UserEventMessage.h"
-
-#include <errno.h>
-
-static int android_snprintfBuffer(char** pBuf, int bufLen, const char* format, ...);
-static int android_vsnprintfBuffer(char** pBuf, int bufLen, const char* format, va_list args);
-
-
-using namespace android;
-
-#if 0   // experiment -- works on Win32, but not with GTK
-class MyTextCtrl : public wxTextCtrl {
-public:
-    MyTextCtrl(wxWindow* parent, wxWindowID id, const wxString& value,
-        const wxPoint& pos, const wxSize& size, int style = 0)
-        : wxTextCtrl(parent, id, value, pos, size, style)
-        {
-            printf("***************** MyTextCtrl!\n");
-        }
-
-    void OnScroll(wxScrollWinEvent& event);
-    void OnScrollBottom(wxScrollWinEvent& event);
-
-private:
-    DECLARE_EVENT_TABLE()
-};
-
-BEGIN_EVENT_TABLE(MyTextCtrl, wxTextCtrl)
-    EVT_SCROLLWIN(MyTextCtrl::OnScroll)
-    EVT_SCROLLWIN_BOTTOM(MyTextCtrl::OnScrollBottom)
-END_EVENT_TABLE()
-
-void MyTextCtrl::OnScroll(wxScrollWinEvent& event)
-{
-    printf("OnScroll!\n");
-}
-
-void MyTextCtrl::OnScrollBottom(wxScrollWinEvent& event)
-{
-    printf("OnScrollBottom!\n");
-}
-#endif
-
-
-BEGIN_EVENT_TABLE(LogWindow, wxDialog)
-    EVT_CLOSE(LogWindow::OnClose)
-    EVT_MOVE(LogWindow::OnMove)
-    EVT_COMBOBOX(IDC_LOG_LEVEL, LogWindow::OnLogLevel)
-    EVT_BUTTON(IDC_LOG_CLEAR, LogWindow::OnLogClear)
-    EVT_BUTTON(IDC_LOG_PAUSE, LogWindow::OnLogPause)
-    EVT_BUTTON(IDC_LOG_PREFS, LogWindow::OnLogPrefs)
-END_EVENT_TABLE()
-
-/*
- * Information about log levels.
- *
- * Each entry here corresponds to an entry in the combo box.  The first
- * letter of each name should be unique.
- */
-static const struct {
-    wxString    name;
-    android_LogPriority priority;
-} gLogLevels[] = {
-    { wxT("Verbose"),    ANDROID_LOG_VERBOSE },
-    { wxT("Debug"),      ANDROID_LOG_DEBUG },
-    { wxT("Info"),       ANDROID_LOG_INFO },
-    { wxT("Warn"),       ANDROID_LOG_WARN },
-    { wxT("Error"),      ANDROID_LOG_ERROR }
-};
-
-
-/*
- * Create a new LogWindow.  This should be a child of the main frame.
- */
-LogWindow::LogWindow(wxWindow* parent)
-    : wxDialog(parent, wxID_ANY, wxT("Log Output"), wxDefaultPosition,
-        wxDefaultSize,
-        wxCAPTION | wxSYSTEM_MENU | wxCLOSE_BOX | wxRESIZE_BORDER),
-      mDisplayArray(NULL), mMaxDisplayMsgs(0), mPaused(false),
-      mMinPriority(ANDROID_LOG_VERBOSE),
-      mHeaderFormat(LogPrefsDialog::kHFFull),
-      mSingleLine(false), mExtraSpacing(0), mPointSize(10), mUseColor(true),
-      mFontMonospace(true), mWriteFile(false), mTruncateOld(true), mLogFp(NULL),
-      mNewlyShown(false), mLastPosition(wxDefaultPosition), mVisible(false)
-{
-    ConstructControls();
-
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-
-    int poolSize = 10240;       // 10MB
-    pPrefs->GetInt("log-pool-size-kbytes", &poolSize);
-    assert(poolSize > 0);
-    mPool.Resize(poolSize * 1024);
-
-    mMaxDisplayMsgs = 1000;
-    pPrefs->GetInt("log-display-msg-count", &mMaxDisplayMsgs);
-    assert(mMaxDisplayMsgs > 0);
-    mDisplayArray = new LogMessage*[mMaxDisplayMsgs];
-    memset(mDisplayArray, 0, sizeof(LogMessage*) * mMaxDisplayMsgs);
-    mTopPtr = -1;
-    mNextPtr = 0;
-
-    int tmpInt = (int) mHeaderFormat;
-    pPrefs->GetInt("log-header-format", &tmpInt);
-    mHeaderFormat = (LogPrefsDialog::HeaderFormat) tmpInt;
-    pPrefs->GetBool("log-single-line", &mSingleLine);
-    pPrefs->GetInt("log-extra-spacing", &mExtraSpacing);
-    pPrefs->GetInt("log-point-size", &mPointSize);
-    pPrefs->GetBool("log-use-color", &mUseColor);
-    pPrefs->SetBool("log-font-monospace", &mFontMonospace);
-    SetTextStyle();
-
-    mFileName = wxT("/tmp/android-log.txt");
-    pPrefs->GetBool("log-write-file", &mWriteFile);
-    pPrefs->GetString("log-filename", /*ref*/mFileName);
-    pPrefs->GetBool("log-truncate-old", &mTruncateOld);
-
-    PrepareLogFile();
-}
-
-/*
- * Destroy everything we own.
- */
-LogWindow::~LogWindow(void)
-{
-    ClearDisplay();
-    delete[] mDisplayArray;
-
-    if (mLogFp != NULL)
-        fclose(mLogFp);
-}
-
-/*
- * Set the text style, based on our preferences.
- */
-void LogWindow::SetTextStyle(void)
-{
-    wxTextCtrl* pTextCtrl;
-    pTextCtrl = (wxTextCtrl*) FindWindow(IDC_LOG_TEXT);
-    wxTextAttr style;
-    style = pTextCtrl->GetDefaultStyle();
-
-    if (mFontMonospace) {
-        wxFont font(mPointSize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,
-            wxFONTWEIGHT_NORMAL);
-        style.SetFont(font);
-    } else {
-        wxFont font(mPointSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
-            wxFONTWEIGHT_NORMAL);
-        style.SetFont(font);
-    }
-
-    pTextCtrl->SetDefaultStyle(style);
-}
-
-/*
- * Set up the goodies in the window.
- *
- * Also initializes mMinPriority.
- */
-void LogWindow::ConstructControls(void)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    wxPanel* base = new wxPanel(this, wxID_ANY);
-    wxBoxSizer* masterSizer = new wxBoxSizer(wxVERTICAL);
-    wxBoxSizer* indentSizer = new wxBoxSizer(wxHORIZONTAL);
-    wxBoxSizer* configPrioritySizer = new wxBoxSizer(wxHORIZONTAL);
-    wxGridSizer* configSizer = new wxGridSizer(4, 1);
-
-    /*
-     * Configure log level combo box.
-     */
-    wxComboBox* logLevel;
-    int defaultLogLevel = 1;
-    pPrefs->GetInt("log-display-level", &defaultLogLevel);
-    logLevel = new wxComboBox(base, IDC_LOG_LEVEL, wxT(""),
-        wxDefaultPosition, wxDefaultSize, 0, NULL,
-        wxCB_READONLY /*| wxSUNKEN_BORDER*/);
-    for (int i = 0; i < NELEM(gLogLevels); i++) {
-        logLevel->Append(gLogLevels[i].name);
-        logLevel->SetClientData(i, (void*) gLogLevels[i].priority);
-    }
-    logLevel->SetSelection(defaultLogLevel);
-    mMinPriority = gLogLevels[defaultLogLevel].priority;
-
-    /*
-     * Set up stuff at the bottom, starting with the options
-     * at the bottom left.
-     */
-    configPrioritySizer->Add(new wxStaticText(base, wxID_ANY, wxT("Log level:"),
-            wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT),
-        0, wxALIGN_CENTER_VERTICAL);
-    configPrioritySizer->AddSpacer(kInterSpacing);
-    configPrioritySizer->Add(logLevel);
-
-    wxButton* clear = new wxButton(base, IDC_LOG_CLEAR, wxT("&Clear"),
-        wxDefaultPosition, wxDefaultSize, 0);
-    wxButton* pause = new wxButton(base, IDC_LOG_PAUSE, wxT("&Pause"),
-        wxDefaultPosition, wxDefaultSize, 0);
-    wxButton* prefs = new wxButton(base, IDC_LOG_PREFS, wxT("C&onfigure"),
-        wxDefaultPosition, wxDefaultSize, 0);
-
-    configSizer->Add(configPrioritySizer, 0, wxALIGN_LEFT);
-    configSizer->Add(clear, 0, wxALIGN_CENTER);
-    configSizer->Add(pause, 0, wxALIGN_CENTER);
-    configSizer->Add(prefs, 0, wxALIGN_RIGHT);
-
-    /*
-     * Create text ctrl.
-     */
-    wxTextCtrl* pTextCtrl;
-    pTextCtrl = new wxTextCtrl(base, IDC_LOG_TEXT, wxT(""),
-        wxDefaultPosition, wxDefaultSize,
-        wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2 | wxTE_NOHIDESEL |
-            wxHSCROLL);
-
-    /*
-     * Add components to master sizer.
-     */
-    masterSizer->AddSpacer(kEdgeSpacing);
-    masterSizer->Add(pTextCtrl, 1, wxEXPAND);
-    masterSizer->AddSpacer(kInterSpacing);
-    masterSizer->Add(configSizer, 0, wxEXPAND);
-    masterSizer->AddSpacer(kEdgeSpacing);
-
-    /*
-     * Indent from sides.
-     */
-    indentSizer->AddSpacer(kEdgeSpacing);
-    indentSizer->Add(masterSizer, 1, wxEXPAND);
-    indentSizer->AddSpacer(kEdgeSpacing);
-
-    base->SetSizer(indentSizer);
-
-    indentSizer->Fit(this);             // shrink-to-fit
-    indentSizer->SetSizeHints(this);    // define minimum size
-}
-
-/*
- * In some cases, this means the user has clicked on our "close" button.
- * We don't really even want one, but both WinXP and KDE put one on our
- * window whether we want it or not.  So, we make it work as a "hide"
- * button instead.
- *
- * This also gets called when the app is shutting down, and we do want
- * to destroy ourselves then, saving various information about our state.
- */
-void LogWindow::OnClose(wxCloseEvent& event)
-{
-    /* just hide the window, unless we're shutting down */
-    if (event.CanVeto()) {
-        event.Veto();
-        Show(false);
-        return;
-    }
-
-    /*
-     * Save some preferences.
-     */
-    SaveWindowPrefs();
-
-    /* if we can't veto the Close(), destroy ourselves */
-    Destroy();
-}
-
-/*
- * Save all of our preferences to the config file.
- */
-void LogWindow::SaveWindowPrefs(void)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-
-    /*
-     * Save shown/hidden state.
-     */
-    pPrefs->SetBool("window-log-show", IsShown());
-
-    /*
-     * Limits and formatting prefs.
-     */
-    pPrefs->SetInt("log-display-msg-count", mMaxDisplayMsgs);
-    pPrefs->SetInt("log-pool-size-kbytes", mPool.GetMaxSize() / 1024);
-
-    pPrefs->SetInt("log-header-format", mHeaderFormat);
-    pPrefs->SetBool("log-single-line", mSingleLine);
-    pPrefs->SetInt("log-extra-spacing", mExtraSpacing);
-    pPrefs->SetInt("log-point-size", mPointSize);
-    pPrefs->SetBool("log-use-color", mUseColor);
-    pPrefs->SetBool("log-font-monospace", mFontMonospace);
-
-    pPrefs->SetBool("log-write-file", mWriteFile);
-    pPrefs->SetString("log-filename", mFileName.ToAscii());
-    pPrefs->SetBool("log-truncate-old", mTruncateOld);
-
-    /*
-     * Save window size and position.
-     */
-    wxPoint posn;
-    wxSize size;
-
-    assert(pPrefs != NULL);
-
-    posn = GetPosition();
-    size = GetSize();
-
-    pPrefs->SetInt("window-log-x", posn.x);
-    pPrefs->SetInt("window-log-y", posn.y);
-    pPrefs->SetInt("window-log-width", size.GetWidth());
-    pPrefs->SetInt("window-log-height", size.GetHeight());
-
-    /*
-     * Save current setting of debug level combo box.
-     */
-    wxComboBox* pCombo;
-    int selection;
-    pCombo = (wxComboBox*) FindWindow(IDC_LOG_LEVEL);
-    selection = pCombo->GetSelection();
-    pPrefs->SetInt("log-display-level", selection);
-}
-
-/*
- * Return the desired position and size.
- */
-/*static*/ wxRect LogWindow::GetPrefWindowRect(void)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    int x, y, width, height;
-
-    assert(pPrefs != NULL);
-
-    x = y = 10;
-    width = 500;
-    height = 200;
-
-    /* these don't modify the arg if the pref doesn't exist */
-    pPrefs->GetInt("window-log-x", &x);
-    pPrefs->GetInt("window-log-y", &y);
-    pPrefs->GetInt("window-log-width", &width);
-    pPrefs->GetInt("window-log-height", &height);
-
-    return wxRect(x, y, width, height);
-}
-
-/*
- * Under Linux+GTK, the first time you show the window, it appears where
- * it's supposed to.  If you then hide it and show it again, it gets
- * moved on top of the parent window.  After that, you can reposition it
- * and it remembers its position across hide/show.
- *
- * To counter this annoyance, we save the position when we hide, and
- * reset the position after a show.  The "newly shown" flag ensures that
- * we only reposition the window as the result of a Show(true) call.
- *
- * Sometimes, something helpful will shift the window over if it's
- * partially straddling a seam between two monitors.  I don't see an easy
- * way to block this, and I'm not sure I want to anyway.
- */
-void LogWindow::OnMove(wxMoveEvent& event)
-{
-    wxPoint point;
-    point = event.GetPosition();
-    //printf("Sim: log window is at (%d,%d) (new=%d)\n", point.x, point.y,
-    //    mNewlyShown);
-
-    if (mNewlyShown) {
-        if (mLastPosition == wxDefaultPosition) {
-            //printf("Sim: no last position established\n");
-        } else {
-            Move(mLastPosition);
-        }
-
-        mNewlyShown = false;
-    }
-}
-
-/*
- * Set the "newly shown" flag.
- */
-bool LogWindow::Show(bool show)
-{
-    if (show) {
-        mNewlyShown = true;
-        Redisplay();
-    } else {
-        mLastPosition = GetPosition();
-    }
-
-    mVisible = show;
-    return wxDialog::Show(show);
-}
-
-/*
- * User has adjusted the log level.  Update the display appropriately.
- *
- * This is a wxEVT_COMMAND_COMBOBOX_SELECTED event.
- */
-void LogWindow::OnLogLevel(wxCommandEvent& event)
-{
-    int selection;
-    android_LogPriority priority;
-
-    selection = event.GetInt();
-    wxComboBox* pCombo = (wxComboBox*) FindWindow(IDC_LOG_LEVEL);
-    priority = (android_LogPriority) (long)pCombo->GetClientData(event.GetInt());
-
-    printf("Sim: log level selected: %d (%s)\n", (int) priority,
-        (const char*) gLogLevels[selection].name.ToAscii());
-    mMinPriority = priority;
-    Redisplay();
-}
-
-/*
- * Clear out the log.
- */
-void LogWindow::OnLogClear(wxCommandEvent& event)
-{
-    ClearDisplay();
-    mPool.Clear();
-}
-
-/*
- * Handle the pause/resume button.
- *
- * If we're un-pausing, we need to get caught up.
- */
-void LogWindow::OnLogPause(wxCommandEvent& event)
-{
-    mPaused = !mPaused;
-
-    wxButton* pButton = (wxButton*) FindWindow(IDC_LOG_PAUSE);
-    if (mPaused) {
-        pButton->SetLabel(wxT("&Resume"));
-
-        mPool.SetBookmark();
-    } else {
-        pButton->SetLabel(wxT("&Pause"));
-
-        LogMessage* pMsg = mPool.GetBookmark();
-        if (pMsg == NULL) {
-            /* bookmarked item fell out of pool */
-            printf("--- bookmark was lost, redisplaying\n");
-            Redisplay();
-        } else {
-            /*
-             * The bookmark points to the last item added to the display.
-             * We want to chase its "prev" pointer to walk toward the head
-             * of the list, adding items from oldest to newest.
-             */
-            pMsg = pMsg->GetPrev();
-            while (pMsg != NULL) {
-                if (FilterMatches(pMsg))
-                    AddToDisplay(pMsg);
-                pMsg = pMsg->GetPrev();
-            }
-        }
-    }
-}
-
-/*
- * Open log preferences dialog.
- */
-void LogWindow::OnLogPrefs(wxCommandEvent& event)
-{
-    LogPrefsDialog dialog(this);
-
-    /*
-     * Set up the dialog.
-     */
-    dialog.mHeaderFormat = mHeaderFormat;
-    dialog.mSingleLine = mSingleLine;
-    dialog.mExtraSpacing = mExtraSpacing;
-    dialog.mPointSize = mPointSize;
-    dialog.mUseColor = mUseColor;
-    dialog.mFontMonospace = mFontMonospace;
-
-    dialog.mDisplayMax = mMaxDisplayMsgs;
-    dialog.mPoolSizeKB = mPool.GetMaxSize() / 1024;
-
-    dialog.mWriteFile = mWriteFile;
-    dialog.mFileName = mFileName;
-    dialog.mTruncateOld = mTruncateOld;
-
-    /*
-     * Show it.  If they hit "OK", copy the updated values out, and
-     * re-display the log output.
-     */
-    if (dialog.ShowModal() == wxID_OK) {
-        /* discard old display arra */
-        ClearDisplay();
-        delete[] mDisplayArray;
-
-        mHeaderFormat = dialog.mHeaderFormat;
-        mSingleLine = dialog.mSingleLine;
-        mExtraSpacing = dialog.mExtraSpacing;
-        mPointSize = dialog.mPointSize;
-        mUseColor = dialog.mUseColor;
-        mFontMonospace = dialog.mFontMonospace;
-
-        assert(dialog.mDisplayMax > 0);
-        assert(dialog.mPoolSizeKB > 0);
-        mMaxDisplayMsgs = dialog.mDisplayMax;
-        mPool.Resize(dialog.mPoolSizeKB * 1024);
-
-        mWriteFile = dialog.mWriteFile;
-        if (mLogFp != NULL && mFileName != dialog.mFileName) {
-            printf("--- log file name changed, closing\n");
-            fclose(mLogFp);
-            mLogFp = NULL;
-        }
-        mFileName = dialog.mFileName;
-        mTruncateOld = dialog.mTruncateOld;
-
-        mDisplayArray = new LogMessage*[mMaxDisplayMsgs];
-        memset(mDisplayArray, 0, sizeof(LogMessage*) * mMaxDisplayMsgs);
-        Redisplay();
-
-        PrepareLogFile();
-    }
-}
-
-/*
- * Handle a log message "user event".  This should only be called in
- * the main UI thread.
- *
- * We take ownership of "*pLogMessage".
- */
-void LogWindow::AddLogMessage(LogMessage* pLogMessage)
-{
-    mPool.Add(pLogMessage);
-
-    if (!mPaused && mVisible && FilterMatches(pLogMessage)) {
-        /*
-         * Thought: keep a reference to the previous message.  If it
-         * matches in most fields (all except timestamp?), hold it and
-         * increment a counter.  If we get a message that doesn't match,
-         * or a timer elapses, synthesize a "previous message repeated N
-         * times" string.
-         */
-        AddToDisplay(pLogMessage);
-    }
-
-    // release the initial ref caused by allocation
-    pLogMessage->Release();
-
-    if (mLogFp != NULL)
-        LogToFile(pLogMessage);
-}
-
-/*
- * Clear out the display, releasing any log messages held in the display
- * array.
- */
-void LogWindow::ClearDisplay(void)
-{
-    wxTextCtrl* pTextCtrl;
-    pTextCtrl = (wxTextCtrl*) FindWindow(IDC_LOG_TEXT);
-    pTextCtrl->Clear();
-
-    /*
-     * Just run through the entire array.
-     */
-    for (int i = 0; i < mMaxDisplayMsgs; i++) {
-        if (mDisplayArray[i] != NULL) {
-            mDisplayArray[i]->Release();
-            mDisplayArray[i] = NULL;
-        }
-    }
-    mTopPtr = -1;
-    mNextPtr = 0;
-}
-
-/*
- * Clear the current display and regenerate it from the log pool.  We need
- * to do this whenever we change filters or log message formatting.
- */
-void LogWindow::Redisplay(void)
-{
-    /*
-     * Freeze output rendering so it doesn't flash during update.  Doesn't
-     * seem to help for GTK, and it leaves garbage on the screen in WinXP,
-     * so I'm leaving it commented out.
-     */
-    //wxTextCtrl* pText = (wxTextCtrl*) FindWindow(IDC_LOG_TEXT);
-    //pText->Freeze();
-
-    //printf("--- redisplay\n");
-    ClearDisplay();
-
-    /*
-     * Set up the default wxWidgets text style stuff.
-     */
-    SetTextStyle();
-
-    /*
-     * Here's the plan:
-     * - Start at the head of the pool (where the most recently added
-     *   items are).
-     * - Check to see if the current item passes our filter.  If it does,
-     *   increment the "found count".
-     * - Continue in this manner until we run out of pool or have
-     *   sufficient items to fill the screen.
-     * - Starting from the current position, walk back toward the head,
-     *   adding the items that meet the current filter criteria.
-     *
-     * Don't forget that the log pool could be empty.
-     */
-    LogMessage* pMsg = mPool.GetHead();
-
-    if (pMsg != NULL) {
-        int foundCount = 0;
-
-        // note this stops before it runs off the end
-        while (pMsg->GetNext() != NULL && foundCount < mMaxDisplayMsgs) {
-            if (FilterMatches(pMsg))
-                foundCount++;
-            pMsg = pMsg->GetNext();
-        }
-
-        while (pMsg != NULL) {
-            if (FilterMatches(pMsg))
-                AddToDisplay(pMsg);
-            pMsg = pMsg->GetPrev();
-        }
-    }
-
-    //pText->Thaw();
-}
-
-
-/*
- * Returns "true" if the currently specified filters would allow this
- * message to be shown.
- */
-bool LogWindow::FilterMatches(const LogMessage* pLogMessage)
-{
-    if (pLogMessage->GetPriority() >= mMinPriority)
-        return true;
-    else
-        return false;
-}
-
-/*
- * Realloc the array of pointers, and remove anything from the display
- * that should no longer be there.
- */
-void LogWindow::SetMaxDisplayMsgs(int max)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-
-    pPrefs->SetInt("log-display-msg-count", max);
-}
-
-/*
- * Add the message to the display array and to the screen.
- */
-void LogWindow::AddToDisplay(LogMessage* pLogMessage)
-{
-    wxTextCtrl* pTextCtrl;
-    pTextCtrl = (wxTextCtrl*) FindWindow(IDC_LOG_TEXT);
-
-    if (mNextPtr == mTopPtr) {
-        /*
-         * The display array is full.
-         *
-         * We need to eliminate the topmost entry.  This requires removing
-         * it from the array and removing the text from the wxTextCtrl.
-         */
-        pTextCtrl->Remove(0, mDisplayArray[mTopPtr]->GetTextCtrlLen());
-        mDisplayArray[mTopPtr]->Release();
-        mTopPtr = (mTopPtr + 1) % mMaxDisplayMsgs;
-    }
-
-    /*
-     * Add formatted text to the text ctrl.  Track how much actual space
-     * is required.  The space may be different on Win32 (CRLF-based) vs.
-     * GTK (LF-based), so we need to measure it, not compute it from the
-     * text string.
-     */
-    long lastBefore, lastAfter;
-    //long insertBefore;
-    //insertBefore = pTextCtrl->GetInsertionPoint();
-    lastBefore = pTextCtrl->GetLastPosition();
-    FormatMessage(pLogMessage, pTextCtrl);
-    lastAfter = pTextCtrl->GetLastPosition();
-    pLogMessage->SetTextCtrlLen(lastAfter - lastBefore);
-
-    /*
-     * If we restore the old insertion point, we will be glued to where
-     * we were.  This is okay until we start deleting text from the top,
-     * at which point we need to adjust it to retain our position.
-     *
-     * If we set the insertion point to the bottom, we effectively
-     * implement "scroll to bottom on output".
-     *
-     * If we don't set it at all, we get slightly strange behavior out
-     * of GTK, which seems to be par for the course here.
-     */
-    //pTextCtrl->SetInsertionPoint(insertBefore);     // restore insertion pt
-    pTextCtrl->SetInsertionPoint(lastAfter);
-
-    /* add it to array, claim ownership */
-    mDisplayArray[mNextPtr] = pLogMessage;
-    pLogMessage->Acquire();
-
-    /* adjust pointers */
-    if (mTopPtr < 0)        // first time only
-        mTopPtr = 0;
-    mNextPtr = (mNextPtr + 1) % mMaxDisplayMsgs;
-}
-
-
-/*
- * Return a human-readable string for the priority level.  Always returns
- * a valid string.
- */
-static const wxCharBuffer GetPriorityString(android_LogPriority priority)
-{
-    int idx;
-
-    idx = (int) priority - (int) ANDROID_LOG_VERBOSE;
-    if (idx < 0 || idx >= NELEM(gLogLevels))
-        return "?unknown?";
-    return gLogLevels[idx].name.ToAscii();
-}
-
-/*
- * Format a message and write it to the text control.
- */
-void LogWindow::FormatMessage(const LogMessage* pLogMessage, 
-    wxTextCtrl* pTextCtrl)
-{
-#if defined(HAVE_LOCALTIME_R)
-    struct tm tmBuf;
-#endif
-    struct tm* ptm;
-    char timeBuf[32];
-    char msgBuf[256];
-    int msgLen = 0;
-    char* outBuf;
-    char priChar;
-    LogPrefsDialog::HeaderFormat headerFmt;
-
-    headerFmt = mHeaderFormat;
-    if (pLogMessage->GetInternal())
-        headerFmt = LogPrefsDialog::kHFInternal;
-
-    priChar = ((const char*)GetPriorityString(pLogMessage->GetPriority()))[0];
-
-    /*
-     * Get the current date/time in pretty form
-     *
-     * It's often useful when examining a log with "less" to jump to
-     * a specific point in the file by searching for the date/time stamp.
-     * For this reason it's very annoying to have regexp meta characters
-     * in the time stamp.  Don't use forward slashes, parenthesis,
-     * brackets, asterisks, or other special chars here.
-     */
-    time_t when = pLogMessage->GetWhen();
-    const char* fmt = NULL;
-#if defined(HAVE_LOCALTIME_R)
-    ptm = localtime_r(&when, &tmBuf);
-#else
-    ptm = localtime(&when);
-#endif
-    switch (headerFmt) {
-    case LogPrefsDialog::kHFFull:
-    case LogPrefsDialog::kHFInternal:
-        fmt = "%m-%d %H:%M:%S";
-        break;
-    case LogPrefsDialog::kHFBrief:
-    case LogPrefsDialog::kHFMinimal:
-        fmt = "%H:%M:%S";
-        break;
-    default:
-        break;
-    }
-    if (fmt != NULL)
-        strftime(timeBuf, sizeof(timeBuf), fmt, ptm);
-    else
-        strcpy(timeBuf, "-");
-
-    const int kMaxExtraNewlines = 2;
-    char hdrNewline[2];
-    char finalNewlines[kMaxExtraNewlines+1 +1];
-
-    if (mSingleLine)
-        hdrNewline[0] = ' ';
-    else
-        hdrNewline[0] = '\n';
-    hdrNewline[1] = '\0';
-
-    assert(mExtraSpacing <= kMaxExtraNewlines);
-    int i;
-    for (i = 0; i < mExtraSpacing+1; i++)
-        finalNewlines[i] = '\n';
-    finalNewlines[i] = '\0';
-
-    wxTextAttr msgColor;
-    switch (pLogMessage->GetPriority()) {
-    case ANDROID_LOG_WARN:
-        msgColor.SetTextColour(*wxBLUE);
-        break;
-    case ANDROID_LOG_ERROR:
-        msgColor.SetTextColour(*wxRED);
-        break;
-    case ANDROID_LOG_VERBOSE:
-    case ANDROID_LOG_DEBUG:
-    case ANDROID_LOG_INFO:
-    default:
-        msgColor.SetTextColour(*wxBLACK);
-        break;
-    }
-    if (pLogMessage->GetInternal())
-        msgColor.SetTextColour(*wxGREEN);
-
-    /*
-     * Construct a buffer containing the log header.
-     */
-    bool splitHeader = true;
-    outBuf = msgBuf;
-    switch (headerFmt) {
-    case LogPrefsDialog::kHFFull:
-        splitHeader = true;
-        msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
-                    "[ %s %5d %c/%-6.6s]%s",
-                    timeBuf, pLogMessage->GetPid(), priChar,
-                    pLogMessage->GetTag(), hdrNewline);
-        break;
-    case LogPrefsDialog::kHFBrief:
-        splitHeader = true;
-        msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
-                    "[%s %5d]%s",
-                    timeBuf, pLogMessage->GetPid(), hdrNewline);
-        break;
-    case LogPrefsDialog::kHFMinimal:
-        splitHeader = false;
-        msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
-                    "%s %5d- %s",
-                    timeBuf, pLogMessage->GetPid(), pLogMessage->GetMsg());
-        break;
-    case LogPrefsDialog::kHFInternal:
-        splitHeader = false;
-        msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
-                    "[%s] %s", timeBuf, pLogMessage->GetMsg());
-        break;
-    default:
-        fprintf(stderr, "Sim: unexpected header format %d\n", headerFmt);
-        assert(false);
-        break;
-    }
-
-    if (msgLen < 0) {
-        fprintf(stderr, "WHOOPS\n");
-        assert(outBuf == msgBuf);
-        return;
-    }
-
-    if (splitHeader) {
-        if (mUseColor)
-            pTextCtrl->SetDefaultStyle(wxTextAttr(*wxLIGHT_GREY));
-        pTextCtrl->AppendText(wxString::FromAscii(outBuf));
-        if (mUseColor)
-            pTextCtrl->SetDefaultStyle(msgColor);
-        pTextCtrl->AppendText(wxString::FromAscii(pLogMessage->GetMsg()));
-        if (mUseColor)
-            pTextCtrl->SetDefaultStyle(*wxBLACK);
-        pTextCtrl->AppendText(wxString::FromAscii(finalNewlines));
-    } else {
-        if (mUseColor)
-            pTextCtrl->SetDefaultStyle(msgColor);
-        pTextCtrl->AppendText(wxString::FromAscii(outBuf));
-        if (mUseColor)
-            pTextCtrl->SetDefaultStyle(*wxBLACK);
-        pTextCtrl->AppendText(wxString::FromAscii(finalNewlines));
-    }
-
-    /* if we allocated storage for this message, free it */
-    if (outBuf != msgBuf)
-        free(outBuf);
-}
-
-/*
- * Write the message to the log file.
- *
- * We can't just do this in FormatMessage(), because that re-writes all
- * messages on the display whenever the output format or filter changes.
- *
- * Use a one-log-per-line format here to make "grep" useful.
- */
-void LogWindow::LogToFile(const LogMessage* pLogMessage)
-{
-#if defined(HAVE_LOCALTIME_R)
-    struct tm tmBuf;
-#endif
-    struct tm* ptm;
-    char timeBuf[32];
-    char msgBuf[256];
-    int msgLen;
-    char* outBuf;
-    char priChar;
-
-    assert(mLogFp != NULL);
-
-    time_t when = pLogMessage->GetWhen();
-#if defined(HAVE_LOCALTIME_R)
-    ptm = localtime_r(&when, &tmBuf);
-#else
-    ptm = localtime(&when);
-#endif
-
-    strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
-    priChar = ((const char*)GetPriorityString(pLogMessage->GetPriority()))[0];
-
-    outBuf = msgBuf;
-    if (pLogMessage->GetInternal()) {
-        msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
-                    "[%s %5d *] %s\n",
-                    timeBuf, pLogMessage->GetPid(), pLogMessage->GetMsg());
-    } else {
-        msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
-                    "[%s %5d %c] %s)\n",
-                    timeBuf, pLogMessage->GetPid(), priChar,
-                    pLogMessage->GetMsg());
-    }
-    if (fwrite(outBuf, msgLen, 1, mLogFp) != 1)
-        fprintf(stderr, "Sim: WARNING: partial log write\n");
-    fflush(mLogFp);
-
-    /* if we allocated storage for this message, free it */
-    if (outBuf != msgBuf)
-        free(outBuf);
-}
-
-/*
- * Get the modification date of a file.
- */
-static bool GetFileModDate(const char* fileName, time_t* pModWhen)
-{
-    struct stat sb;
-
-    if (stat(fileName, &sb) < 0)
-        return false;
-
-    *pModWhen = sb.st_mtime;
-    return true;
-}
-
-/*
- * Open or close the log file as appropriate.
- */
-void LogWindow::PrepareLogFile(void)
-{
-    const int kLogFileMaxAge = 8 * 60 * 60;     // 8 hours
-
-    if (!mWriteFile && mLogFp != NULL) {
-        printf("Sim: closing log file\n");
-        fclose(mLogFp);
-        mLogFp = NULL;
-    } else if (mWriteFile && mLogFp == NULL) {
-        printf("Sim: opening log file '%s'\n", (const char*)mFileName.ToAscii());
-        time_t now, modWhen = 0;
-        const char* openFlags;
-
-        now = time(NULL);
-        if (!mTruncateOld ||
-            (GetFileModDate(mFileName.ToAscii(), &modWhen) &&
-             modWhen + kLogFileMaxAge > now))
-        {
-            if (modWhen != 0) {
-                printf("--- log file is %.3f hours old, appending\n",
-                    (now - modWhen) / 3600.0);
-            }
-            openFlags = "a";        // open for append (text mode)
-        } else {
-            if (modWhen != 0) {
-                printf("--- log file is %.3f hours old, truncating\n",
-                    (now - modWhen) / 3600.0);
-            }
-            openFlags = "w";        // open for writing, truncate (text mode)
-        }
-
-        mLogFp = fopen(mFileName.ToAscii(), openFlags);
-        if (mLogFp == NULL) {
-            fprintf(stderr, "Sim: failed opening log file '%s': %s\n",
-                (const char*) mFileName.ToAscii(), strerror(errno));
-        } else {
-            fprintf(mLogFp, "\n\n");
-            fflush(mLogFp);
-        }
-    }
-}
-
-/*
- * Add a new log message.
- *
- * This function can be called from any thread.  It makes a copy of the
- * stuff in "*pBundle" and sends it to the main UI thread.
- */
-/*static*/ void LogWindow::PostLogMsg(const android_LogBundle* pBundle)
-{
-    LogMessage* pNewMessage = LogMessage::Create(pBundle);
-
-    SendToWindow(pNewMessage);
-}
-
-/*
- * Post a simple string to the log.
- */
-/*static*/ void LogWindow::PostLogMsg(const char* msg)
-{
-    LogMessage* pNewMessage = LogMessage::Create(msg);
-
-    SendToWindow(pNewMessage);
-}
-
-/*
- * Post a simple wxString to the log.
- */
-/*static*/ void LogWindow::PostLogMsg(const wxString& msg)
-{
-    LogMessage* pNewMessage = LogMessage::Create(msg.ToAscii());
-
-    SendToWindow(pNewMessage);
-}
-
-/*
- * Send a log message to the log window.
- */
-/*static*/ void LogWindow::SendToWindow(LogMessage* pMessage)
-{
-    if (pMessage != NULL) {
-        wxWindow* pMainFrame = ((MyApp*)wxTheApp)->GetMainFrame();
-        UserEventMessage* pUem = new UserEventMessage;
-        pUem->CreateLogMessage(pMessage);
-
-        UserEvent uev(0, (void*) pUem);
-
-        pMainFrame->AddPendingEvent(uev);
-    } else {
-        fprintf(stderr, "Sim: failed to add new log message\n");
-    }
-}
-
-
-/*
- * This is a sanity check.  We need to stop somewhere to avoid trashing
- * the system on bad input.
- */
-#define kMaxLen 65536
-
-#define VSNPRINTF vsnprintf     // used to worry about _vsnprintf
-
-
-/*
- * Print a formatted message into a buffer.  Pass in a buffer to try to use.
- *
- * If the buffer isn't big enough to hold the message, allocate storage
- * with malloc() and return that instead.  The caller is responsible for
- * freeing the storage.
- *
- * Returns the length of the string, or -1 if the printf call failed.
- */
-static int android_vsnprintfBuffer(char** pBuf, int bufLen, const char* format, va_list args)
-{
-    int charsOut;
-    char* localBuf = NULL;
-
-    assert(pBuf != NULL && *pBuf != NULL);
-    assert(bufLen > 0);
-    assert(format != NULL);
-
-    while (1) {
-        /*
-         * In some versions of libc, vsnprintf only returns 0 or -1, where
-         * -1 indicates the the buffer wasn't big enough.  In glibc 2.1
-         * and later, it returns the actual size needed.
-         *
-         * MinGW is just returning -1, so we have to retry there.
-         */
-        char* newBuf;
-
-        charsOut = VSNPRINTF(*pBuf, bufLen, format, args);
-
-        if (charsOut >= 0 && charsOut < bufLen)
-            break;
-
-        //fprintf(stderr, "EXCEED: %d vs %d\n", charsOut, bufLen);
-        if (charsOut < 0) {
-            /* exact size not known, double previous size */
-            bufLen *= 2;
-            if (bufLen > kMaxLen)
-                goto fail;
-        } else {
-            /* exact size known, just use that */
-
-            bufLen = charsOut + 1;
-        }
-        //fprintf(stderr, "RETRY at %d\n", bufLen);
-
-        newBuf = (char*) realloc(localBuf, bufLen);
-        if (newBuf == NULL)
-            goto fail;
-        *pBuf = localBuf = newBuf;
-    }
-
-    // On platforms where snprintf() doesn't return the number of
-    // characters output, we would need to call strlen() here.
-
-    return charsOut;
-
-fail:
-    if (localBuf != NULL) {
-        free(localBuf);
-        *pBuf = NULL;
-    }
-    return -1;
-}
-
-/*
- * Variable-arg form of the above.
- */
-static int android_snprintfBuffer(char** pBuf, int bufLen, const char* format, ...)
-{
-    va_list args;
-    int result;
-
-    va_start(args, format);
-    result = android_vsnprintfBuffer(pBuf, bufLen, format, args);
-    va_end(args);
-
-    return result;
-}
-
-
diff --git a/simulator/app/LogWindow.h b/simulator/app/LogWindow.h
deleted file mode 100644
index ca9f133..0000000
--- a/simulator/app/LogWindow.h
+++ /dev/null
@@ -1,127 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Window with log output.
-//
-#ifndef _SIM_LOG_WINDOW_H
-#define _SIM_LOG_WINDOW_H
-
-#include "PhoneData.h"
-#include "UserEvent.h"
-#include "LogMessage.h"
-#include "LogPool.h"
-#include "LogPrefsDialog.h"
-
-
-/*
- * Display log output from runtime process.
- *
- * We receive the messages broken into components (date, log level, tag,
- * function name, etc.) and do the formatting ourselves.  We receive all
- * messages regardless of log level, and provide filter controls in the
- * window.
- *
- * Messages are stored in a "log pool", which has a fixed memory footprint.
- * The messages that are currently visible in the log output window are
- * also pointed at from a fixed-size display array.  Changes to output
- * format cause us to clear the display and re-show everything in the
- * display array, while changes to the output filter cause us to
- * re-evaluate the contents of the display pool.
- */
-class LogWindow : public wxDialog {
-public:
-    LogWindow(wxWindow* parent);
-    virtual ~LogWindow(void);
-
-    /* we override this, to cope with annoying GTK behavior */
-    virtual bool Show(bool show = true);
-
-    /* return preferred size and position */
-    static wxRect GetPrefWindowRect(void);
-
-    /* handle a log message "user event" */
-    void AddLogMessage(LogMessage* pLogMessage);
-
-    /* resize the display messages array */
-    void SetMaxDisplayMsgs(int max);
-
-    /* post a message to the log; may be called from non-main thread */
-    static void PostLogMsg(const android_LogBundle* pBundle);
-    static void PostLogMsg(const wxString& msg);
-    static void PostLogMsg(const char* msg);
-
-private:
-    void OnMove(wxMoveEvent& event);
-    void OnClose(wxCloseEvent& event);
-    void OnLogLevel(wxCommandEvent& event);
-    void OnLogClear(wxCommandEvent& event);
-    void OnLogPause(wxCommandEvent& event);
-    void OnLogPrefs(wxCommandEvent& event);
-
-    /* handle incoming log message */
-    void OnUserEvent(UserEvent& event);
-
-    void SaveWindowPrefs(void);
-    void ConstructControls(void);
-
-    void AddToDisplay(LogMessage* pLogMessage);
-    void ClearDisplay(void);
-    void Redisplay(void);
-    void SetTextStyle(void);
-
-    bool FilterMatches(const LogMessage* pLogMessage);
-
-    void FormatMessage(const LogMessage* pLogMessage, 
-        wxTextCtrl* pTextCtrl);
-
-    void LogToFile(const LogMessage* pLogMessage);
-    void PrepareLogFile(void);
-    static void SendToWindow(LogMessage* pMessage);
-
-    /*
-     * Message pool.
-     */
-    LogPool     mPool;
-
-    /*
-     * Display array.  This is a fixed-size circular array that holds
-     * pointers to the log messages currently displayed on screen.
-     */
-    LogMessage**    mDisplayArray;      // ptrs to messages currently displayed
-    int         mMaxDisplayMsgs;        // max #of messages
-    int         mTopPtr;                // index of top message
-    int         mNextPtr;               // index of next empty slot
-
-    bool        mPaused;                // is output paused for review?
-
-    /*
-     * Current filter.
-     */
-    android_LogPriority mMinPriority;   // messages at or above are shown
-
-    /* format options */
-    LogPrefsDialog::HeaderFormat mHeaderFormat;
-    bool        mSingleLine;            // put whole message on one line?
-    int         mExtraSpacing;          // double/triple-space messages?
-    int         mPointSize;             // text point size;
-    bool        mUseColor;              // colorful messages?
-    bool        mFontMonospace;         // use monospace font?
-
-    /* log file options */
-    bool        mWriteFile;
-    wxString    mFileName;
-    bool        mTruncateOld;
-
-    FILE*       mLogFp;
-
-    /*
-     * Window position stuff.
-     */
-    bool        mNewlyShown;
-    wxPoint     mLastPosition;
-    bool        mVisible;
-
-    DECLARE_EVENT_TABLE()
-};
-
-#endif // _SIM_LOG_WINDOW_H
diff --git a/simulator/app/MainFrame.cpp b/simulator/app/MainFrame.cpp
deleted file mode 100644
index b13caab..0000000
--- a/simulator/app/MainFrame.cpp
+++ /dev/null
@@ -1,1462 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Main window, menu bar, and associated goodies.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/button.h"
-#include "wx/help.h"
-#include "wx/filedlg.h"
-#include "wx/slider.h"
-#include "wx/textctrl.h"
-
-#include "MainFrame.h"
-#include "MyApp.h"
-#include "Resource.h"
-#include "PhoneCollection.h"
-#include "PhoneData.h"
-#include "PhoneWindow.h"
-#include "DeviceWindow.h"
-#include "UserEventMessage.h"
-#include "PrefsDialog.h"
-
-#include "SimRuntime.h"
-
-
-static wxString kStatusNotRunning = wxT("Idle");
-static wxString kStatusRunning = wxT("Run");
-
-static wxString kDeviceMenuString = wxT("&Device");
-
-static const wxString gStdJavaApps[] = {
-    wxT(""),
-    wxT("com.android.testharness.TestList"),
-    wxT("com.android.apps.contacts.ContactsList"),
-    wxT("mikeapp")
-};
-
-
-BEGIN_EVENT_TABLE(MainFrame::MainFrame, wxFrame)
-    EVT_CLOSE(MainFrame::OnClose)
-    EVT_TIMER(kHalfSecondTimerId, MainFrame::OnTimer)
-    //EVT_IDLE(MainFrame::OnIdle)
-  
-    EVT_ACTIVATE(MainFrame::OnActivate)
-    EVT_ACTIVATE_APP(MainFrame::OnActivate)
-    EVT_COMBOBOX(IDC_MODE_SELECT, MainFrame::OnComboBox)
-    EVT_COMBOBOX(IDC_JAVA_VM, MainFrame::OnComboBox)
-    EVT_CHECKBOX(IDC_USE_GDB, MainFrame::OnCheckBox)
-    EVT_CHECKBOX(IDC_USE_VALGRIND, MainFrame::OnCheckBox)
-    EVT_CHECKBOX(IDC_CHECK_JNI, MainFrame::OnCheckBox)
-    EVT_CHECKBOX(IDC_OVERLAY_ONION_SKIN, MainFrame::OnCheckBox)
-    EVT_TEXT(IDC_JAVA_APP_NAME, MainFrame::OnText)
-    EVT_TEXT_ENTER(IDC_ONION_SKIN_FILE_NAME, MainFrame::OnTextEnter)
-    EVT_BUTTON(IDC_ONION_SKIN_BUTTON, MainFrame::OnButton)
-    EVT_COMMAND_SCROLL(IDC_ONION_SKIN_ALPHA_VAL, MainFrame::OnSliderChange)
-
-    EVT_MENU(IDM_FILE_PREFERENCES, MainFrame::OnFilePreferences)
-    EVT_MENU(IDM_FILE_EXIT, MainFrame::OnFileExit)
-    EVT_MENU(IDM_RUNTIME_START, MainFrame::OnSimStart)
-    EVT_UPDATE_UI(IDM_RUNTIME_START, MainFrame::OnUpdateSimStart)
-    EVT_MENU(IDM_RUNTIME_STOP, MainFrame::OnSimStop)
-    EVT_UPDATE_UI(IDM_RUNTIME_STOP, MainFrame::OnUpdateSimStop)
-    EVT_MENU(IDM_RUNTIME_RESTART, MainFrame::OnSimRestart)
-    EVT_UPDATE_UI(IDM_RUNTIME_RESTART, MainFrame::OnUpdateSimRestart)
-    EVT_MENU(IDM_RUNTIME_KILL, MainFrame::OnSimKill)
-    EVT_UPDATE_UI(IDM_RUNTIME_KILL, MainFrame::OnUpdateSimKill)
-    EVT_MENU_RANGE(IDM_DEVICE_SEL0, IDM_DEVICE_SELN,
-        MainFrame::OnDeviceSelected)
-    EVT_MENU(IDM_DEVICE_RESCAN, MainFrame::OnDeviceRescan)
-    EVT_UPDATE_UI(IDM_DEBUG_SHOW_LOG, MainFrame::OnUpdateDebugShowLog)
-    EVT_MENU(IDM_DEBUG_SHOW_LOG, MainFrame::OnDebugShowLog)
-    EVT_MENU(IDM_HELP_CONTENTS, MainFrame::OnHelpContents)
-    EVT_MENU(IDM_HELP_ABOUT, MainFrame::OnHelpAbout)
-
-    EVT_USER_EVENT(MainFrame::OnUserEvent)
-END_EVENT_TABLE()
-
-
-/*
- * Main window constructor.
- *
- * Creates menus and status bar.
- */
-MainFrame::MainFrame(const wxString& title, const wxPoint& pos,
-    const wxSize& size, long style)
-    : wxFrame((wxFrame *)NULL, -1, title, pos, size, style),
-      mSimRunning(false),
-      mRestartRequested(false),
-      mpPhoneWindow(NULL),
-      mPhoneWindowPosn(wxDefaultPosition),
-      mTimer(this, kHalfSecondTimerId)
-{
-    mSimAssetPath = ((MyApp*)wxTheApp)->GetSimAssetPath();
-    mSimAssetPath += wxT("/simulator/default/default");
-
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    int val;
-
-    val = mPhoneWindowPosn.x;
-    pPrefs->GetInt("window-device-x", &val);
-    mPhoneWindowPosn.x = val;
-    val = mPhoneWindowPosn.y;
-    pPrefs->GetInt("window-device-y", &val);
-    mPhoneWindowPosn.y = val;
-
-    /*
-     * Create main menu.
-     */
-    ConstructMenu();
-
-    /*
-     * Create the status bar.
-     */
-    int widths[2] = { -1, 50 };
-    CreateStatusBar(2, wxFULL_REPAINT_ON_RESIZE);   // no wxST_SIZEGRIP
-    SetStatusWidths(2, widths);
-    SetStatusText(wxT("Ready"));
-    SetStatusText(kStatusNotRunning, 1);
-
-    /*
-     * Create main window controls.
-     */
-    ConstructControls();
-
-#if 0
-    /*
-     * Use the standard window color for the main frame (which usually
-     * has a darker color).  This has a dramatic effect under Windows.
-     */
-    wxColour color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
-    SetOwnBackgroundColour(color);
-#endif
-
-    /*
-     * Create the log window.
-     */
-    wxRect layout = LogWindow::GetPrefWindowRect();
-    mpLogWindow = new LogWindow(this);
-    mpLogWindow->Move(layout.GetTopLeft());
-    mpLogWindow->SetSize(layout.GetSize());
-    bool showLogWindow = true;
-    pPrefs->GetBool("window-log-show", &showLogWindow);
-    if (showLogWindow)
-        mpLogWindow->Show();
-
-    /*
-     * Set up a frequent timer.  We use this to keep our "run/idle"
-     * display up to date.  (Ideally this will go away.)
-     */
-    mTimer.Start(400);      // arg is delay in ms
-
-    /*
-     * Handle auto-power-on by sending ourselves an event.  That way it
-     * gets handled after window initialization finishes.
-     */
-    bool autoPowerOn = false;
-    pPrefs->GetBool("auto-power-on", &autoPowerOn);
-    if (autoPowerOn) {
-        printf("Sim: Auto power-up\n");
-        wxCommandEvent startEvent(wxEVT_COMMAND_MENU_SELECTED, IDM_RUNTIME_START);
-        this->AddPendingEvent(startEvent);
-    }
-
-    /*
-     * wxThread wants these to be on the heap -- it will call delete on the
-     * object when the thread exits.
-     */
-    mExternalRuntimeThread = new ExternalRuntime();
-    mExternalRuntimeThread->StartThread();
-    mPropertyServerThread = new PropertyServer();
-    mPropertyServerThread->StartThread();
-}
-
-/*
- * Construct the main menu.  Called from the constructor.
- */
-void MainFrame::ConstructMenu(void)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-
-    /*
-     * Scan for available phones.
-     */
-    PhoneCollection* pCollection = PhoneCollection::GetInstance();
-    pCollection->ScanForPhones(mSimAssetPath.ToAscii());
-
-    /*
-     * Create the "File" menu.
-     */
-    wxMenu* menuFile = new wxMenu;
-
-    menuFile->Append(IDM_FILE_PREFERENCES, wxT("&Preferences..."),
-        wxT("Edit simulator preferences"));
-    menuFile->AppendSeparator();
-    menuFile->Append(IDM_FILE_EXIT, wxT("E&xit\tCtrl-Q"),
-        wxT("Stop simulator and exit"));
-
-    /*
-     * Create the "Runtime" menu.
-     */
-    wxMenu* menuRuntime = new wxMenu;
-    menuRuntime->Append(IDM_RUNTIME_START, wxT("&Power On\tCtrl-G"),
-        wxT("Start the device"));
-//    menuRuntime->Append(IDM_RUNTIME_STOP, wxT("Power &Off"),
-//        wxT("Stop the device"));
-    menuRuntime->AppendSeparator();
-//    menuRuntime->Append(IDM_RUNTIME_RESTART, wxT("&Restart"),
-//        wxT("Restart the device"));
-    menuRuntime->Append(IDM_RUNTIME_KILL, wxT("&Kill\tCtrl-K"),
-        wxT("Kill the runtime processes"));
-
-    /*
-     * Create "Device" menu.
-     */
-    wxString defaultDevice = wxT("Sooner");
-    pPrefs->GetString("default-device", /*ref*/ defaultDevice);
-    wxMenu* menuDevice = CreateDeviceMenu(defaultDevice.ToAscii());
-
-    /*
-     * Create "Debug" menu.
-     */
-    wxMenu* menuDebug = new wxMenu;
-    menuDebug->AppendCheckItem(IDM_DEBUG_SHOW_LOG, wxT("View &Log Output"),
-        wxT("View log output window"));
-
-    /*
-     * Create the "Help" menu.
-     */
-    wxMenu* menuHelp = new wxMenu;
-    menuHelp->Append(IDM_HELP_CONTENTS, wxT("&Contents...\tF1"),
-        wxT("Simulator help"));
-    menuHelp->AppendSeparator();
-    menuHelp->Append(IDM_HELP_ABOUT, wxT("&About..."),
-        wxT("See the fabulous 'about' box"));
-
-    /*
-     * Create the menu bar.
-     */
-    wxMenuBar *menuBar = new wxMenuBar;
-    menuBar->Append(menuFile, wxT("&File"));
-    menuBar->Append(menuDevice, kDeviceMenuString);
-    menuBar->Append(menuRuntime, wxT("&Runtime"));
-    menuBar->Append(menuDebug, wxT("&Debug"));
-    menuBar->Append(menuHelp, wxT("&Help"));
-
-    SetMenuBar(menuBar);
-
-}
-
-/*
- * Construct the "device" menu from our phone collection.
- */
-wxMenu* MainFrame::CreateDeviceMenu(const char* defaultItemName)
-{
-    wxMenu* menuDevice = new wxMenu;
-    PhoneCollection* pCollection = PhoneCollection::GetInstance();
-    int defaultModel = 0;
-
-    for (int i = 0; i < pCollection->GetPhoneCount(); i++) {
-        PhoneData* pPhoneData = pCollection->GetPhoneData(i);
-        assert(pPhoneData != NULL);
-
-        menuDevice->AppendRadioItem(IDM_DEVICE_SEL0 + i,
-            wxString::FromAscii(pPhoneData->GetTitle()));
-
-        // use this one as default if the string matches
-        if (strcasecmp(pPhoneData->GetName(), defaultItemName) == 0)
-            defaultModel = i;
-    }
-
-    menuDevice->Check(IDM_DEVICE_SEL0 + defaultModel, true);
-
-    menuDevice->AppendSeparator();
-    menuDevice->Append(IDM_DEVICE_RESCAN, wxT("Re-scan"));
-
-    return menuDevice;
-}
-
-/*
- * Create some controls in the main window.
- *
- * The main frame doesn't use the normal background color that you find
- * in dialog windows, so we create a "panel" and put all the controls
- * on that.
- */
-void MainFrame::ConstructControls(void)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    wxPanel* base = new wxPanel(this, wxID_ANY);
-    wxBoxSizer* masterSizer = new wxBoxSizer(wxVERTICAL);
-    wxBoxSizer* tmpSizer;
-    wxStaticBoxSizer* displayOptSizer;
-    wxStaticBoxSizer* runtimeOptSizer;
-    wxStaticBoxSizer* onionSkinOptSizer;
-    wxComboBox* pModeSelection;
-    wxCheckBox* pUseGDB;
-    wxCheckBox* pUseValgrind;
-    wxCheckBox* pCheckJni;
-    wxCheckBox* pOverlayOnionSkin;
-    
-    displayOptSizer = new wxStaticBoxSizer(wxHORIZONTAL, base,
-        wxT("Configuration"));
-    runtimeOptSizer = new wxStaticBoxSizer(wxVERTICAL, base,
-        wxT("Runtime Options"));
-    onionSkinOptSizer = new wxStaticBoxSizer(wxVERTICAL, base,
-        wxT("Onion Skin Options"));
-
-    /*
-     * Set up the configuration sizer (nee "display options").
-     */
-    tmpSizer = new wxBoxSizer(wxHORIZONTAL);
-    displayOptSizer->Add(tmpSizer);
-    tmpSizer->Add(
-            new wxStaticText(base, wxID_ANY, wxT("Device mode:"),
-            wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT), 0, wxALIGN_CENTER_VERTICAL);
-    pModeSelection = new wxComboBox(base, IDC_MODE_SELECT, wxT(""),
-            wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY);
-    tmpSizer->AddSpacer(kInterSpacing);
-    tmpSizer->Add(pModeSelection);
-
-    displayOptSizer->AddSpacer(kInterSpacing);
-
-    /*
-     * Configure the runtime options sizer.
-     */
-    wxComboBox* pJavaAppName;
-    tmpSizer = new wxBoxSizer(wxHORIZONTAL);
-    pUseGDB = new wxCheckBox(base, IDC_USE_GDB, wxT("Use &debugger"));
-    tmpSizer->Add(pUseGDB);
-    tmpSizer->AddSpacer(kInterSpacing);
-    pUseValgrind = new wxCheckBox(base, IDC_USE_VALGRIND, wxT("Use &valgrind"));
-    tmpSizer->Add(pUseValgrind);
-    tmpSizer->AddSpacer(kInterSpacing);
-    pCheckJni = new wxCheckBox(base, IDC_CHECK_JNI, wxT("Check &JNI"));
-    tmpSizer->Add(pCheckJni);
-
-    pJavaAppName = new wxComboBox(base, IDC_JAVA_APP_NAME, wxT(""),
-        wxDefaultPosition, wxSize(320, -1), NELEM(gStdJavaApps), gStdJavaApps,
-        wxCB_DROPDOWN);
-    wxBoxSizer* javaAppSizer = new wxBoxSizer(wxHORIZONTAL);
-    javaAppSizer->Add(
-            new wxStaticText(base, wxID_ANY,
-                wxT("Java app:"),
-                wxDefaultPosition, wxDefaultSize,
-                wxALIGN_LEFT),
-            0, wxALIGN_CENTER_VERTICAL);
-    javaAppSizer->AddSpacer(kInterSpacing);
-    javaAppSizer->Add(pJavaAppName);
-
-    runtimeOptSizer->Add(tmpSizer);
-
-    runtimeOptSizer->AddSpacer(kInterSpacing);
-    runtimeOptSizer->Add(javaAppSizer);
-    runtimeOptSizer->AddSpacer(kInterSpacing);
-
-    wxString tmpStr;
-    SetCheckFromPref(pUseGDB, "debug", false);
-    SetCheckFromPref(pUseValgrind, "valgrind", false);
-    SetCheckFromPref(pCheckJni, "check-jni", false);
-    if (pPrefs->GetString("java-app-name", /*ref*/ tmpStr))
-        pJavaAppName->SetValue(tmpStr);
-
-    /*
-     * Configure the onion skin options sizer.
-     */
-    wxTextCtrl* pOnionSkinFileNameText;
-    wxButton* pOnionSkinFileButton;
-    wxSlider* pOnionSkinAlphaSlider;
-    tmpSizer = new wxBoxSizer(wxHORIZONTAL);
-    pOverlayOnionSkin = new wxCheckBox(base, 
-        IDC_OVERLAY_ONION_SKIN, wxT("Overlay &onion skin"));
-    tmpSizer->Add(pOverlayOnionSkin);
-
-    pOnionSkinFileNameText = new wxTextCtrl(base, 
-        IDC_ONION_SKIN_FILE_NAME, wxT(""),
-        wxDefaultPosition, wxSize(250, -1),
-        wxTE_PROCESS_ENTER);
-    pOnionSkinFileButton = new wxButton(base, IDC_ONION_SKIN_BUTTON,
-        wxT("Choose"));
-
-    wxBoxSizer* onionSkinFileNameSizer = new wxBoxSizer(wxHORIZONTAL);
-    onionSkinFileNameSizer->Add(
-        new wxStaticText(base, wxID_ANY,
-            wxT("Filename:"),
-            wxDefaultPosition, wxDefaultSize,
-            wxALIGN_LEFT),
-        0, wxALIGN_CENTER_VERTICAL);
-    onionSkinFileNameSizer->AddSpacer(kInterSpacing);
-    onionSkinFileNameSizer->Add(pOnionSkinFileNameText);
-    onionSkinFileNameSizer->Add(pOnionSkinFileButton);
-
-    wxBoxSizer * onionSkinAlphaSizer = new wxBoxSizer(wxHORIZONTAL);
-    int initialAlphaVal = 127;
-    pPrefs->GetInt("onion-skin-alpha-value", &initialAlphaVal);
-    pOnionSkinAlphaSlider = new wxSlider(base, IDC_ONION_SKIN_ALPHA_VAL,
-        initialAlphaVal, 0, 255, wxDefaultPosition, wxSize(150, 20));
-    onionSkinAlphaSizer->Add(
-        new wxStaticText(base, wxID_ANY,
-            wxT("Transparency:"),
-            wxDefaultPosition, wxDefaultSize,
-            wxALIGN_LEFT),
-        0, wxALIGN_CENTER_VERTICAL);
-    onionSkinAlphaSizer->AddSpacer(kInterSpacing);
-    onionSkinAlphaSizer->Add(pOnionSkinAlphaSlider, 1, wxCENTRE | wxALL, 5);
-
-    onionSkinOptSizer->Add(tmpSizer);
-    onionSkinOptSizer->AddSpacer(kInterSpacing);
-    onionSkinOptSizer->Add(onionSkinFileNameSizer);
-    onionSkinOptSizer->Add(onionSkinAlphaSizer);
-
-    wxString tmpStr2;
-    SetCheckFromPref(pOverlayOnionSkin, "overlay-onion-skin", false);
-    if (pPrefs->GetString("onion-skin-file-name", /*ref*/ tmpStr2))
-        pOnionSkinFileNameText->SetValue(tmpStr2);
-
-    /*
-     * Add the various components to the master sizer.
-     */
-    masterSizer->Add(displayOptSizer);
-    masterSizer->AddSpacer(kInterSpacing * 2);
-    masterSizer->Add(runtimeOptSizer);
-    masterSizer->AddSpacer(kInterSpacing * 2);
-    masterSizer->Add(onionSkinOptSizer);
-    //masterSizer->AddSpacer(kInterSpacing);
-
-    /*
-     * I don't see a way to guarantee that the window is wide enough to
-     * show the entire menu bar, so just throw some pixels at it.
-     */
-    wxBoxSizer* minWidthSizer = new wxBoxSizer(wxVERTICAL);
-    minWidthSizer->Add(300, kEdgeSpacing);       // forces minimum width
-    minWidthSizer->Add(masterSizer);
-    minWidthSizer->AddSpacer(kInterSpacing * 2);
-
-    /* move us a few pixels in from the left */
-    wxBoxSizer* indentSizer = new wxBoxSizer(wxHORIZONTAL);
-    indentSizer->AddSpacer(kEdgeSpacing);
-    indentSizer->Add(minWidthSizer);
-    indentSizer->AddSpacer(kEdgeSpacing);
-
-    base->SetSizer(indentSizer);
-
-    indentSizer->Fit(this);
-    indentSizer->SetSizeHints(this);
-}
-
-/*
- * Set the value of a checkbox based on a value from the config file.
- */
-void MainFrame::SetCheckFromPref(wxCheckBox* pControl, const char* prefStr,
-    bool defaultVal)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    assert(pPrefs != NULL);
-
-    bool val = defaultVal;
-    pPrefs->GetBool(prefStr, &val);
-
-    pControl->SetValue(val);
-}
-
-/*
- * Destructor.
- */
-MainFrame::~MainFrame(void)
-{
-    PhoneCollection::DestroyInstance();
-
-    delete mExternalRuntimeThread;
-    delete mPropertyServerThread;
-
-    // don't touch mpModeSelection -- child of window
-}
-
-/*
- * File->Quit or click on close box.
- *
- * If we want an "are you sure you want to quit" box, add it here.
- */
-void MainFrame::OnClose(wxCloseEvent& event)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-
-/*
-    if (event.CanVeto())
-        printf("Closing (can veto)\n");
-    else
-        printf("Closing (mandatory)\n");
-*/
-
-    /*
-     * Generally speaking, Close() is not guaranteed to close the window.
-     * However, we want to use it here because (a) our windows are
-     * guaranteed to close, and (b) it provides our windows an opportunity
-     * to tell others that they are about to vanish.
-     */
-    if (mpPhoneWindow != NULL)
-        mpPhoneWindow->Close(true);
-
-    /* save position of main window */
-    wxPoint pos = GetPosition();
-    pPrefs->SetInt("window-main-x", pos.x);
-    pPrefs->SetInt("window-main-y", pos.y);
-
-    /* save default device selection */
-    int idx = GetSelectedDeviceIndex();
-    if (idx >= 0) {
-        PhoneCollection* pCollection = PhoneCollection::GetInstance();
-        PhoneData* pPhoneData = pCollection->GetPhoneData(idx);
-        pPrefs->SetString("default-device", pPhoneData->GetName());
-    }
-
-    if (mpLogWindow != NULL)
-        mpLogWindow->Close(true);
-    Destroy();
-}
-
-/*
- * File->Preferences
- */
-void MainFrame::OnFilePreferences(wxCommandEvent& WXUNUSED(event))
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    PrefsDialog dialog(this);
-    int result;
-
-    result = dialog.ShowModal();
-    if (result == wxID_OK) {
-        /*
-         * The dialog handles writing changes to Preferences, so all we
-         * need to deal with here are changes that have an immediate
-         * impact on us. (which is currently nothing)
-         */
-    }
-}
-
-/*
- * File->Exit
- */
-void MainFrame::OnFileExit(wxCommandEvent& WXUNUSED(event))
-{
-    Close(FALSE);       // false means "allow veto"
-}
-
-/*
- * Decide whether Simulator->Start should be enabled.
- */
-void MainFrame::OnUpdateSimStart(wxUpdateUIEvent& event)
-{
-    if (IsRuntimeRunning())
-        event.Enable(FALSE);
-    else
-        event.Enable(TRUE);
-}
-
-/*
- * Simulator->Start
- */
-void MainFrame::OnSimStart(wxCommandEvent& WXUNUSED(event))
-{
-    // keyboard equivalents can still get here even if menu item disabled
-    if (IsRuntimeRunning())
-        return;
-
-    int id = GetSelectedDeviceIndex();
-    if (id < 0) {
-        fprintf(stderr, "Sim: could not identify currently selected device\n");
-        return;
-    }
-
-#if 0
-    static int foo = 0;
-    foo++;
-    if (foo == 2) {
-        Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-
-        pPrefs->SetBool("debug", true);
-    }
-#endif
-
-    SetupPhoneUI(id, NULL);
-    if (mpPhoneWindow != NULL)
-        mpPhoneWindow->GetDeviceManager()->StartRuntime();
-}
-
-/*
- * Decide whether Simulator->Stop should be enabled.
- */
-void MainFrame::OnUpdateSimStop(wxUpdateUIEvent& event)
-{
-    if (IsRuntimeRunning())
-        event.Enable(TRUE);
-    else
-        event.Enable(FALSE);
-}
-
-/*
- * Simulator->Stop
- */
-void MainFrame::OnSimStop(wxCommandEvent& WXUNUSED(event))
-{
-    if (!IsRuntimeRunning())
-        return;
-    assert(mpPhoneWindow != NULL);
-    mpPhoneWindow->GetDeviceManager()->StopRuntime();
-}
-
-/*
- * Decide whether Simulator->Restart should be enabled.
- */
-void MainFrame::OnUpdateSimRestart(wxUpdateUIEvent& event)
-{
-    if (IsRuntimeRunning())
-        event.Enable(TRUE);
-    else
-        event.Enable(FALSE);
-}
-
-/*
- * Simulator->Restart - stop then start the device runtime.
- */
-void MainFrame::OnSimRestart(wxCommandEvent& WXUNUSED(event))
-{
-    if (!IsRuntimeRunning())
-        return;
-
-    printf("Restart requested\n");
-    mpPhoneWindow->GetDeviceManager()->StopRuntime();
-
-    mRestartRequested = true;
-}
-
-/*
- * Decide whether Simulator->Kill should be enabled.
- */
-void MainFrame::OnUpdateSimKill(wxUpdateUIEvent& event)
-{
-    if (IsRuntimeKillable())
-        event.Enable(TRUE);
-    else
-        event.Enable(FALSE);
-}
-
-/*
- * Simulator->Kill
- */
-void MainFrame::OnSimKill(wxCommandEvent& WXUNUSED(event))
-{
-    if (!IsRuntimeKillable())
-        return;
-    assert(mpPhoneWindow != NULL);
-    mpPhoneWindow->GetDeviceManager()->KillRuntime();
-}
-
-
-/*
- * Device->[select]
- */
-void MainFrame::OnDeviceSelected(wxCommandEvent& event)
-{
-    wxBusyCursor busyc;
-    int id = event.GetId() - IDM_DEVICE_SEL0;
-
-    SetupPhoneUI(id, NULL);
-}
-
-/*
- * Device->Rescan
- */
-void MainFrame::OnDeviceRescan(wxCommandEvent& event)
-{
-    wxBusyCursor busyc;
-    wxMenuBar* pMenuBar;
-    PhoneCollection* pCollection;
-    wxMenu* pOldMenu;
-    wxMenu* pNewMenu;
-    const char* curDevName = NULL;
-    int idx;
-    
-    /* figure out the current device name */
-    pCollection = PhoneCollection::GetInstance();
-    idx = GetSelectedDeviceIndex();
-    if (idx >= 0) {
-        PhoneData* pPhoneData;
-
-        pPhoneData = pCollection->GetPhoneData(idx);
-        curDevName = pPhoneData->GetName();
-        printf("--- device name is '%s'\n", (const char*) curDevName);
-    }
-
-    /* reconstruct device menu with new data */
-#ifdef BEFORE_ASSET
-    pCollection->ScanForPhones(mSimAssetPath);
-#else
-    pCollection->ScanForPhones(NULL);
-#endif
-
-    pMenuBar = GetMenuBar();
-    idx = pMenuBar->FindMenu(kDeviceMenuString);
-    if (idx == wxNOT_FOUND) {
-        fprintf(stderr, "Sim: couldn't find %s menu\n", (const char*) kDeviceMenuString.ToAscii());
-        return;
-    }
-
-    pNewMenu = CreateDeviceMenu(curDevName);
-
-    pOldMenu = pMenuBar->Replace(idx, pNewMenu, kDeviceMenuString);
-    delete pOldMenu;
-
-    /* tell the PhoneWindow about it; may cause runtime to exit */
-    if (mpPhoneWindow != NULL)
-        mpPhoneWindow->DevicesRescanned();
-}
-
-/*
- * Set checkbox on menu item.
- */
-void MainFrame::OnUpdateDebugShowLog(wxUpdateUIEvent& event)
-{
-    if (mpLogWindow == NULL) {
-        event.Enable(false);
-    } else {
-        event.Enable(true);
-        event.Check(mpLogWindow->IsShown());
-    }
-}
-
-/*
- * Debug->ShowLog toggle.
- */
-void MainFrame::OnDebugShowLog(wxCommandEvent& WXUNUSED(event))
-{
-    mpLogWindow->Show(!mpLogWindow->IsShown());
-}
-
-/*
- * Help->Contents
- */
-void MainFrame::OnHelpContents(wxCommandEvent& WXUNUSED(event))
-{
-    ((MyApp*)wxTheApp)->GetHelpController()->DisplayContents();
-}
-
-/*
- * Help->About
- */
-void MainFrame::OnHelpAbout(wxCommandEvent& WXUNUSED(event))
-{
-    wxMessageBox(wxT("Android Simulator v0.1\n"
-                     "Copyright 2006 The Android Open Source Project"),
-        wxT("About..."), wxOK | wxICON_INFORMATION, this);
-}
-
-/*
- * Sent from phonewindow or when activated
- */
-void MainFrame::OnActivate(wxActivateEvent& event)
-{
-#if 0
-    if (event.GetActive())
-    {
-        if (mpPhoneWindow != NULL &&
-            mpPhoneWindow->GetDeviceManager()->RefreshRuntime())
-        {
-            wxString msg;
-            int sel;
-
-            msg = wxT("Newer runtime executable found. Would you like to reload the device?");
-
-            sel = wxMessageBox(msg, wxT("Android Safety Patrol"),
-                wxYES | wxNO | wxICON_QUESTION, mpPhoneWindow);
-            //printf("BUTTON was %d (yes=%d)\n", sel, wxYES);
-            if (sel == wxYES)
-            {
-                mpPhoneWindow->GetDeviceManager()->StopRuntime();
-                mpPhoneWindow->Close();
-                mpPhoneWindow = NULL;
-                mRestartRequested = true;
-            }
-            else
-            {
-                mpPhoneWindow->GetDeviceManager()->UserCancelledRefresh();
-            }
-        }
-    }
-#endif
-
-    // let wxWidgets do whatever it needs to do
-    event.Skip();
-}
-            
-
-/*
- * Device mode selection box.
- */
-void MainFrame::OnComboBox(wxCommandEvent& event)
-{
-    const char* pref;
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    assert(pPrefs != NULL);
-
-    if (IDC_MODE_SELECT == event.GetId())
-    {
-        int id = GetSelectedDeviceIndex();
-        if (id < 0)
-            return;
-        //printf("--- mode selected: '%s'\n", (const char*) event.GetString().ToAscii());
-
-        /*
-         * Call the phone window's setup function.  Don't call our SetupPhoneUI
-         * function from here -- updating the combo box from a combo box callback
-         * could cause problems.
-         */
-        if (mpPhoneWindow != NULL) {
-            mpPhoneWindow->SetCurrentMode(event.GetString());
-            mpPhoneWindow->Setup(id);
-        }
-    } else if (event.GetId() == IDC_JAVA_VM) {
-        wxComboBox* pBox = (wxComboBox*) FindWindow(IDC_JAVA_VM);
-        pPrefs->SetString("java-vm", pBox->GetValue().ToAscii());
-    }
-}
-
-/*
- * One of our option checkboxes has been changed.
- *
- * We update the prefs database so that the settings are retained when
- * the simulator is next used.
- */
-void MainFrame::OnCheckBox(wxCommandEvent& event)
-{
-    const char* pref;
-
-    switch (event.GetId()) {
-    case IDC_USE_GDB:               pref = "debug";                 break;
-    case IDC_USE_VALGRIND:          pref = "valgrind";              break;
-    case IDC_CHECK_JNI:             pref = "check-jni";             break;
-    case IDC_OVERLAY_ONION_SKIN:    pref = "overlay-onion-skin";    break; 
-    default:
-        printf("Sim: unrecognized checkbox %d in OnCheckBox\n", event.GetId());
-        return;
-    }
-
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    assert(pPrefs != NULL);
-
-    pPrefs->SetBool(pref, (bool) event.GetInt());
-    //printf("--- set pref '%s' to %d\n", pref, (bool) event.GetInt());
-    if (event.GetId() == IDC_OVERLAY_ONION_SKIN) {
-        BroadcastOnionSkinUpdate();
-    }
-    if (event.GetId() == IDC_CHECK_JNI) {
-        const char* val = "0";
-        if ((bool) event.GetInt())
-            val = "1";
-        mPropertyServerThread->SetProperty(PropertyServer::kPropCheckJni, val);
-
-    }
-}
-
-void MainFrame::BroadcastOnionSkinUpdate() {
-    if (mpPhoneWindow != NULL) {
-        // broadcast a user event indicating an onion skin update
-        UserEvent uev(0, (void*) -1);
-        mpPhoneWindow->GetDeviceManager()->BroadcastEvent(uev);
-    }
-}
-
-/*
- * A text control on the main page is being updated.
- *
- * The current implementation updates the preferences database on every
- * change, which is a bit silly but is easy to do.
- */
-void MainFrame::OnText(wxCommandEvent& event)
-{
-    const char* pref;
-
-    switch (event.GetId()) {
-    case IDC_JAVA_APP_NAME:     pref = "java-app-name"; break;
-    default:
-        printf("Sim: unrecognized textctrl %d in OnText\n", event.GetId());
-        return;
-    }
-
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    assert(pPrefs != NULL);
-
-    // event.GetString() does not work on Mac -- always blank
-    //pPrefs->SetString(pref, event.GetString());
-    assert(event.GetId() == IDC_JAVA_APP_NAME); // fix if we add more
-    wxComboBox* pBox;
-    pBox = (wxComboBox*) FindWindow(IDC_JAVA_APP_NAME);
-    pPrefs->SetString(pref, pBox->GetValue().ToAscii());
-    //printf("--- set pref '%s' to '%s'\n", pref,(const char*)pBox->GetValue());
-}
-
-/*
- * A user pressed enter in a text control on the main page.
- *
- * The current implementation updates the preferences database on every
- * change, which is a bit silly but is easy to do.
- */
-void MainFrame::OnTextEnter(wxCommandEvent& event)
-{
-    const char* pref;
-
-    switch (event.GetId()) {
-    case IDC_ONION_SKIN_FILE_NAME:
-        pref = "onion-skin-file-name";
-        break;
-    default:
-        printf("Sim: unrecognized textctrl %d in OnTextEnter\n", event.GetId());
-        return;
-    }
-
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    assert(pPrefs != NULL);
-
-    assert(event.GetId() == IDC_ONION_SKIN_FILE_NAME); // fix if we add more
-    wxTextCtrl* pTextCtrl;
-    pTextCtrl = (wxTextCtrl*) FindWindow(IDC_ONION_SKIN_FILE_NAME);
-    wxString onionSkinFileNameWxString = pTextCtrl->GetValue();
-    char* onionSkinFileName = "";
-    if (onionSkinFileNameWxString.Len() > 0) {
-        onionSkinFileName = android::strdupNew(onionSkinFileNameWxString.ToAscii());
-    }
-    pPrefs->SetString(pref, onionSkinFileName);
-    BroadcastOnionSkinUpdate();
-}
-
-/*
- * A user pressed a button on the main page
- * 
- */
- void MainFrame::OnButton(wxCommandEvent& event)
- {
-    wxWindow* base;
-    wxFileDialog* pOnionSkinFileChooser;
-    int retVal;
-    switch (event.GetId()) {
-    case IDC_ONION_SKIN_BUTTON:
-        base = FindWindow(IDC_ONION_SKIN_BUTTON)->GetParent();
-        pOnionSkinFileChooser = new wxFileDialog(base, 
-            wxT("Choose the onion skin image file."), 
-            wxT(""), wxT(""), wxT("*.*"),
-            wxOPEN | wxFILE_MUST_EXIST);
-        retVal = pOnionSkinFileChooser->ShowModal();
-        if (retVal == pOnionSkinFileChooser->GetAffirmativeId()) {
-            Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-            assert(pPrefs != NULL);
-            wxString fileNameWxString = pOnionSkinFileChooser->GetPath();
-            const char* fileName = android::strdupNew(fileNameWxString.ToAscii());
-            wxTextCtrl* fileTextCtrl = (wxTextCtrl*) FindWindow(IDC_ONION_SKIN_FILE_NAME);
-            fileTextCtrl->SetValue(fileNameWxString);
-            pPrefs->SetString("onion-skin-file-name", fileName);
-            BroadcastOnionSkinUpdate();
-        }
-        break;
-    default:
-        printf("Sim: unrecognized button %d in OnButton\n", event.GetId());
-        return;
-    }     
- }
- 
- /*
-  * The user moved a slider on the main page
-  */
- void MainFrame::OnSliderChange(wxScrollEvent& event)
- {
-    wxSlider* pSlider;
-    Preferences* pPrefs;
-    switch (event.GetId()) {
-    case IDC_ONION_SKIN_ALPHA_VAL:
-        pSlider = (wxSlider*) FindWindow(IDC_ONION_SKIN_ALPHA_VAL);
-        pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-        assert(pPrefs != NULL);
-        pPrefs->SetInt("onion-skin-alpha-value", pSlider->GetValue());
-        BroadcastOnionSkinUpdate();
-        break;
-    default:
-        printf("Sim: unrecognized scroller or slider %d in OnSliderChange\n", event.GetId());
-        return;
-    }     
- }
-
-#if 0
-/*
- * Idle processing.  Under wxWidgets this only called once after UI
- * activity unless you call event.RequestMore().
- */
-void MainFrame::OnIdle(wxIdleEvent& event)
-{
-    event.Skip();       // let base class handler do stuff
-}
-#endif
-
-/*
- * Handle the timer.
- *
- * This is being called in the main thread, so multithreading with the
- * rest of MainFrame isn't a concern here.
- */
-void MainFrame::OnTimer(wxTimerEvent& event)
-{
-    bool status;
-
-    /*
-     * Check to see if the runtime died without telling us.  This can only
-     * happen if we forcibly kill our thread.  We shouldn't really be
-     * doing that anymore, but keep this in for now just in case.
-     */
-    status = IsRuntimeRunning();
-
-    if (mSimRunning != status) {
-        if (!status) {
-            printf("Sim: fixed mSimRunning=%d actual=%d\n",
-                mSimRunning, status);
-            mSimRunning = status;
-
-            if (!status)
-                HandleRuntimeStop();
-        } else {
-            /*
-             * This was happening when we were shutting down but the
-             * device management thread hadn't completely gone away.  The
-             * simple IsRunning test passes, so we get a false positive.
-             * Ignore it.
-             */
-        }
-    }
-
-    if (gWantToKill) {
-        if (IsRuntimeRunning()) {
-            printf("Sim: handling kill request\n");
-            mpPhoneWindow->GetDeviceManager()->KillRuntime();
-        }
-        gWantToKill = false;
-
-        /* see if Ctrl-C should kill us too */
-        Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-        bool die = false;
-
-        pPrefs->GetBool("trap-sigint-suicide", &die);
-        if (die) {
-            printf("Sim: goodbye cruel world!\n");
-            exit(0);
-        }
-    }
-}
-
-/*
- * Determine whether or not the simulator is running.
- */
-bool MainFrame::IsRuntimeRunning(void)
-{
-    bool result;
-
-    if (mpPhoneWindow == NULL)
-        result = false;
-    else if (!mpPhoneWindow->IsReady())
-        result = false;
-    else
-        result = mpPhoneWindow->GetDeviceManager()->IsRunning();
-
-    return result;
-}
-
-/*
- * Determine whether or not the runtime can be killed.
- */
-bool MainFrame::IsRuntimeKillable(void)
-{
-    bool result;
-
-    result = IsRuntimeRunning();
-    if (result)
-        result = mpPhoneWindow->GetDeviceManager()->IsKillable();
-
-    return result;
-}
-
-/*
- * Determine whether two devices are sufficiently compatible.
- */
-bool MainFrame::CompatibleDevices(PhoneData* pData1, PhoneData* pData2)
-{
-    int displayCount;
-
-    displayCount = pData1->GetNumDisplays();
-    if (pData2->GetNumDisplays() != displayCount)
-        return false;
-
-    for (int i = 0; i < displayCount; i++) {
-        PhoneDisplay* pDisplay1 = pData1->GetPhoneDisplay(i);
-        PhoneDisplay* pDisplay2 = pData2->GetPhoneDisplay(i);
-
-        if (!PhoneDisplay::IsCompatible(pDisplay1, pDisplay2))
-            return false;
-    }
-
-    return true;
-}
-
-/*
- * (Re-)arrange the UI for the currently selected phone model.
- *
- * If the simulator is running, and the set of displays for the current
- * device are incompatible with the new device, we need to restart the
- * runtime.  We need to ask for permission first though.
- */
-void MainFrame::SetupPhoneUI(int idx, const char* defaultMode)
-{
-    PhoneCollection* pCollection;
-    PhoneData* pPhoneData;
-    wxString* choices = NULL;
-    int numChoices = 0;
-    int numKeyboards = 0;
-    bool haveDefaultMode = false;
-    wxCharBuffer currentMode;
-    int i;
-
-    pCollection = PhoneCollection::GetInstance();
-    pPhoneData = pCollection->GetPhoneData(idx);
-    if (pPhoneData == NULL) {
-        fprintf(stderr, "ERROR: device index %d not valid\n", idx);
-        goto bail;
-    }
-
-    /*
-     * We have a window up.  If the displays aren't compatible, we'll
-     * need to recreate it.
-     */
-    if (mpPhoneWindow != NULL) {
-        PhoneData* pCurData = mpPhoneWindow->GetPhoneData();
-
-        if (!CompatibleDevices(pCurData, pPhoneData)) {
-            /*
-             * We need to trash the window.  This will also kill the
-             * runtime.  If it's running, ask permission.
-             */
-            if (IsRuntimeRunning()) {
-                wxString msg;
-                int sel;
-
-                msg =  wxT("Switching to the new device requires restarting the");
-                msg += wxT(" runtime.  Continue?");
-
-                sel = wxMessageBox(msg, wxT("Android Safety Patrol"),
-                    wxOK | wxCANCEL | wxICON_QUESTION, this);
-                printf("BUTTON was %d (ok=%d)\n", sel, wxOK);
-                if (sel == wxCANCEL)
-                    goto bail;
-
-                /* shut it down (politely), ask for an eventual restart */
-                mpPhoneWindow->GetDeviceManager()->StopRuntime();
-                mpPhoneWindow->Close();
-                mpPhoneWindow = NULL;
-                mRestartRequested = true;
-                goto bail;
-            } else {
-                /* not running, just trash the window and continue */
-                mpPhoneWindow->Close();
-                mpPhoneWindow = NULL;
-            }
-        }
-    }
-
-    /*
-     * Figure out the set of available modes.
-     */
-
-    numChoices = pPhoneData->GetNumModes();
-    if (numChoices > 0) {
-        choices = new wxString[numChoices];
-        for (i = 0; i < numChoices; i++) {
-            PhoneMode* pPhoneMode;
-            pPhoneMode = pPhoneData->GetPhoneMode(i);
-            choices[i] = wxString::FromAscii(pPhoneMode->GetName());
-            if (defaultMode != NULL &&
-                strcmp(defaultMode, pPhoneMode->GetName()) == 0)
-            {
-                haveDefaultMode = true;
-            }
-        }
-    }
-
-    if (choices == NULL) {
-        /* had a failure earlier; configure UI with default stuff */
-        choices = new wxString[1];
-        choices[0] = wxT("(none)");
-    }
-
-    if (!haveDefaultMode) {
-        /*
-         * Default mode wasn't found.  If we specify it as the default
-         * in the wxComboBox create call it shows up in the combo box
-         * under Linux, even if it doesn't exist in the list.  So, we
-         * make sure that it doesn't get used if we can't find it.
-         */
-        if (defaultMode != NULL) {
-            printf("Sim: HEY: default mode '%s' not found in list\n",
-                defaultMode);
-        }
-        currentMode = choices[0].ToAscii();
-    } else {
-        currentMode = defaultMode;
-    }
-
-
-    /*
-     * Create the window if necessary.
-     */
-    if (mpPhoneWindow == NULL) {
-        // create, setup, and then show window
-        mpPhoneWindow = new PhoneWindow(this, mPhoneWindowPosn);
-        mpPhoneWindow->SetCurrentMode((const char*)currentMode);
-        if (!mpPhoneWindow->Setup(idx)) {
-            delete mpPhoneWindow;
-            mpPhoneWindow = NULL;
-        }
-        if (mpPhoneWindow != NULL) {
-            mpPhoneWindow->Show();
-            //mpPhoneWindow->CheckPlacement();
-        }
-    } else {
-        // just set up for new device
-        mpPhoneWindow->SetCurrentMode((const char*)currentMode);
-        if (!mpPhoneWindow->Setup(idx)) {
-            // it's in an uncertain state, blow it away
-            delete mpPhoneWindow;
-            mpPhoneWindow = NULL;
-        }
-    }
-
-    /*
-     * Reconfigure mode selection box.
-     */
-    wxComboBox* pModeSelection;
-    pModeSelection = (wxComboBox*)FindWindow(IDC_MODE_SELECT);
-    pModeSelection->Clear();
-    for (i = 0; i < numChoices; i++)
-        pModeSelection->Append(choices[i]);
-    pModeSelection->SetSelection(0);
-    pModeSelection->Enable(numChoices > 1);
-    
-    /*
-     * configure qwerty keyboard attribute
-     */
-    numKeyboards = pPhoneData->GetNumKeyboards();
-    if (numKeyboards > 0) {
-        // only use the first keyboard for now
-        PhoneKeyboard* pPhoneKeyboard;
-        pPhoneKeyboard = pPhoneData->GetPhoneKeyboard(0);
-        if (pPhoneKeyboard->getQwerty()) {
-            printf("Sim: set 'qwerty' env\n");
-            setenv("qwerty", "true", true);
-        }
-    }
-    
-bail:
-    delete[] choices;
-}
-
-/*
- * Figure out which device is currently selected.
- *
- * The easiest way to do this is just run down the list of possible IDs
- * and stop when something claims to be checked.
- *
- * Returns -1 if it can't find a checked item (which can happen if no
- * device layouts were found).
- */
-int MainFrame::GetSelectedDeviceIndex(void)
-{
-    wxMenuBar* pMenuBar;
-    wxMenu* pMenu;
-    int idx;
-    
-    pMenuBar = GetMenuBar();
-    idx = pMenuBar->FindMenu(kDeviceMenuString);
-    if (idx == wxNOT_FOUND) {
-        fprintf(stderr, "Sim: couldn't find %s menu\n", (const char*) kDeviceMenuString.ToAscii());
-        return -1;
-    }
-
-    pMenu = pMenuBar->GetMenu(idx);
-
-    //printf("Menu.MenuItemCount = %d\n", pMenu->GetMenuItemCount());
-    for (int j = pMenu->GetMenuItemCount() -1; j >= 0; j--) {
-        wxMenuItem* pItem;
-
-        pItem = pMenu->FindItemByPosition(j);
-        //printf("ITEM %d: %s\n", j, (const char*) pItem->GetLabel());
-        if (pItem->IsChecked()) {
-            printf("Sim: selected device is '%s'\n",
-                (const char*) pItem->GetLabel().ToAscii());
-            return j;
-        }
-    }
-
-    return -1;
-}
-
-/*
- * Receive a status message from the runtime thread.
- */
-void MainFrame::OnUserEvent(UserEvent& event)
-{
-    UserEventMessage* pUem;
-
-    pUem = (UserEventMessage*) event.GetData();
-    assert(pUem != NULL);
-
-    switch (pUem->GetType()) {
-    case UserEventMessage::kRuntimeStarted:
-        printf("Sim: runtime thread started!\n");
-        HandleRuntimeStart();
-        break;
-    case UserEventMessage::kRuntimeStopped:
-        printf("Sim: runtime thread stopped!\n");
-        HandleRuntimeStop();
-        break;
-    case UserEventMessage::kErrorMessage:
-        {
-            wxString msg = pUem->GetString();
-            wxMessageBox(msg, wxT("Android Runtime Error"),
-                wxOK | wxICON_WARNING, this);
-        }
-        break;
-    case UserEventMessage::kLogMessage:
-        mpLogWindow->AddLogMessage(pUem->GetLogMessage());
-        break;
-    case UserEventMessage::kExternalRuntime:
-        HandleExternalRuntime(pUem->GetReader(), pUem->GetWriter());
-        break;
-    default:
-        printf("Sim: MESSAGE: unknown UserEventMessage rcvd (type=%d)\n",
-            pUem->GetType());
-        break;
-    }
-
-    delete pUem;
-}
-
-/*
- * The device management thread is up, so the runtime should be fully
- * running shortly.
- */
-void MainFrame::HandleRuntimeStart(void)
-{
-    mSimRunning = true;
-
-    SetStatusText(kStatusRunning, 1);
-}
-
-/*
- * The device management thread is exiting, so the runtime must be dead.
- */
-void MainFrame::HandleRuntimeStop(void)
-{
-    mSimRunning = false;
-
-    SetStatusText(kStatusNotRunning, 1);
-
-    if (mRestartRequested) {
-        printf("Sim: restarting runtime\n");
-        mRestartRequested = false;
-        SetupPhoneUI(GetSelectedDeviceIndex(), NULL);
-        if (mpPhoneWindow != NULL)
-            mpPhoneWindow->GetDeviceManager()->StartRuntime();
-    }
-}
-
-/*
- * Handle a connection from an external runtime.
- */
-void MainFrame::HandleExternalRuntime(android::Pipe* reader,
-    android::Pipe* writer)
-{
-    android::MessageStream msgStream;
-    android::Message msg;
-
-    if (IsRuntimeRunning()) {
-        /*
-         * Tell the new guy to go away.
-         */
-        if (!msgStream.init(reader, writer, true)) {
-            fprintf(stderr, "Sim: WARNING: unable to talk to remote runtime\n");
-            goto bail;
-        }
-
-        printf("Sim: telling external runtime to go away\n");
-        msg.setCommand(android::Simulator::kCommandGoAway, 0);
-        msgStream.send(&msg);
-    } else {
-        printf("Sim: new external runtime wants to talk to us\n");
-
-        /*
-         * Launch the pieces necessary to talk to this guy.
-         */
-        int id = GetSelectedDeviceIndex();
-        if (id < 0) {
-            fprintf(stderr,
-                "Sim: could not identify currently selected device\n");
-            goto bail;
-        }
-
-        /* kill existing window, so it pops up and reclaims focus */
-        if (mpPhoneWindow != NULL) {
-            Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-            bool okay;
-
-            if (pPrefs->GetBool("refocus-on-restart", &okay) && okay) {
-                printf("Sim: inducing phone window refocus\n");
-                mpPhoneWindow->Close(TRUE);     // no veto
-                mpPhoneWindow = NULL;
-            }
-        }
-
-        SetupPhoneUI(id, NULL);
-        if (mpPhoneWindow != NULL) {
-            mpPhoneWindow->GetDeviceManager()->StartRuntime(reader, writer);
-        } else {
-            fprintf(stderr, "Sim: ERROR: unable to get runtime going\n");
-            goto bail;
-        }
-
-        // we don't own these anymore
-        reader = writer = NULL;
-    }
-
-bail:
-    delete reader;
-    delete writer;
-}
-
-/*
- * The phone window is about to destroy itself.  Get rid of our pointer
- * to it, and record its last position so we can create the new one in
- * the same place.
- */
-void MainFrame::PhoneWindowClosing(int x, int y)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-
-    mpPhoneWindow = NULL;
-
-    mPhoneWindowPosn.x = x;
-    mPhoneWindowPosn.y = y;
-
-    pPrefs->SetInt("window-device-x", x);
-    pPrefs->SetInt("window-device-y", y);
-}
-
diff --git a/simulator/app/MainFrame.h b/simulator/app/MainFrame.h
deleted file mode 100644
index 817a182..0000000
--- a/simulator/app/MainFrame.h
+++ /dev/null
@@ -1,115 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Main window declaration.
-//
-#ifndef _SIM_MAINFRAME_H
-#define _SIM_MAINFRAME_H
-
-#include "PhoneWindow.h"
-#include "DeviceWindow.h"
-#include "LogWindow.h"
-#include "ExternalRuntime.h"
-#include "PropertyServer.h"
-
-/*
- * Main window.
- */
-class MainFrame : public wxFrame {
-public:
-    /* define a constructor so we can set up menus */
-    MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
-        long style);
-    virtual ~MainFrame(void);
-
-    /* called by modeless phone window dialog when it closes */
-    void PhoneWindowClosing(int x, int y);
-
-    void Vibrate(int vibrateOn) { mpPhoneWindow->Vibrate(vibrateOn); }
-
-    PropertyServer* GetPropertyServer(void) { return mPropertyServerThread; }
-
-private:
-    void ConstructMenu(void);
-    void ConstructControls(void);
-
-    void OnClose(wxCloseEvent& event);
-    void OnTimer(wxTimerEvent& event);
-    //void OnIdle(wxIdleEvent& event);
-    void OnActivate(wxActivateEvent& event);
-    void OnButton(wxCommandEvent& event);
-    void OnComboBox(wxCommandEvent& event);
-    void OnCheckBox(wxCommandEvent& event);
-    void OnText(wxCommandEvent& event);
-    void OnTextEnter(wxCommandEvent& event);
-    void OnUserEvent(UserEvent& event);
-    void OnSliderChange(wxScrollEvent& event);
-
-    void OnFilePreferences(wxCommandEvent& event);
-    void OnFileExit(wxCommandEvent& event);
-    void OnUpdateSimStart(wxUpdateUIEvent& event);
-    void OnSimStart(wxCommandEvent& event);
-    void OnUpdateSimStop(wxUpdateUIEvent& event);
-    void OnSimStop(wxCommandEvent& event);
-    void OnUpdateSimReload(wxUpdateUIEvent& event);
-    void OnSimReload(wxCommandEvent& event);
-    void OnUpdateSimRestart(wxUpdateUIEvent& event);
-    void OnSimRestart(wxCommandEvent& event);
-    void OnUpdateSimKill(wxUpdateUIEvent& event);
-    void OnSimKill(wxCommandEvent& event);
-    void OnDeviceSelected(wxCommandEvent& event);
-    void OnDeviceRescan(wxCommandEvent& event);
-    void OnUpdateDebugShowLog(wxUpdateUIEvent& event);
-    void OnDebugShowLog(wxCommandEvent& event);
-    void OnHelpContents(wxCommandEvent& event);
-    void OnHelpAbout(wxCommandEvent& event);
-
-    wxMenu* CreateDeviceMenu(const char* defaultItemName);
-    void SetCheckFromPref(wxCheckBox* pControl, const char* prefStr,
-        bool defaultVal);
-
-    void UpdateRuntimeExeStr(void);
-
-    /* prep the phone UI; "defaultMode" may be NULL */
-    void SetupPhoneUI(int idx, const char* defaultMode);
-
-    bool CompatibleDevices(PhoneData* pData1, PhoneData* pData2);
-
-    void HandleRuntimeStart(void);
-    void HandleRuntimeStop(void);
-    void HandleExternalRuntime(android::Pipe* reader, android::Pipe* writer);
-
-    int GetSelectedDeviceIndex(void);
-    bool IsRuntimeRunning(void);
-    bool IsRuntimeKillable(void);
-
-    void BroadcastOnionSkinUpdate(void);
-    
-    bool    mSimRunning;
-    bool    mRestartRequested;
-
-    enum { kHalfSecondTimerId = 1000 };
-
-    wxString        mSimAssetPath;
-
-    /* if we have a phone running, this points to its state */
-    PhoneWindow*    mpPhoneWindow;
-
-    /* phone window position */
-    wxPoint         mPhoneWindowPosn;
-
-    /* window that captures log output */
-    LogWindow*      mpLogWindow;
-
-    wxTimer         mTimer;
-
-    /* watches for connection from runtime */
-    ExternalRuntime* mExternalRuntimeThread;
-
-    /* serve up system properties */
-    PropertyServer*  mPropertyServerThread;
-
-    DECLARE_EVENT_TABLE()
-};
-
-#endif // _SIM_MAINFRAME_H
diff --git a/simulator/app/MessageStream.cpp b/simulator/app/MessageStream.cpp
deleted file mode 100644
index c52e7c4..0000000
--- a/simulator/app/MessageStream.cpp
+++ /dev/null
@@ -1,404 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Message stream abstraction.
-//
-#include "MessageStream.h"
-#include "LogBundle.h"
-
-#include "utils/Log.h"
-
-#include <stdint.h>
-#include <string.h>
-#include <assert.h>
-
-using namespace android;
-
-/*
- * ===========================================================================
- *      Message
- * ===========================================================================
- */
-
-/*
- * Send a blob of raw data.
- */
-void Message::setRaw(const unsigned char* data, int len, Cleanup cleanup)
-{
-    reset();
-
-    mData = const_cast<unsigned char*>(data);
-    mLength = len;
-    mCleanup = cleanup;
-    mType = kTypeRaw;
-}
-
-/*
- * Send a "name=value" config pair.
- */
-void Message::setConfig(const char* name, const char* value)
-{
-    reset();
-
-    assert(name != NULL && value != NULL);
-
-    int nlen = strlen(name) +1;
-    int vlen = strlen(value) +1;
-    mData = new unsigned char[nlen+vlen];
-    mCleanup = kCleanupDelete;
-    mLength = nlen + vlen;
-    mType = kTypeConfig;
-
-    memcpy(mData, name, nlen);
-    memcpy(mData + nlen, value, vlen);
-}
-
-/*
- * Try to return the contents of the message as if it were a name/value pair.
- */
-bool Message::getConfig(const char** pName, const char** pValue)
-{
-    if (mLength < 2)
-        return false;
-    assert(mData != NULL);
-
-    *pName = (const char*) mData;
-    *pValue = (const char*) (mData + strlen((char*)mData) +1);
-    return true;
-}
-
-/*
- * Send a command/arg pair.
- */
-void Message::setCommand(int cmd, int arg)
-{
-    reset();
-
-    mData = new unsigned char[sizeof(int) * 2];
-    mCleanup = kCleanupDelete;
-    mLength = sizeof(int) * 2;
-    mType = kTypeCommand;
-
-    int* pInt = (int*) mData;
-    pInt[0] = cmd;
-    pInt[1] = arg;
-}
-
-/*
- * Send a command with 3 args instead of just one.
- */
-void Message::setCommandExt(int cmd, int arg0, int arg1, int arg2)
-{
-    reset();
-
-    mData = new unsigned char[sizeof(int) * 4];
-    mCleanup = kCleanupDelete;
-    mLength = sizeof(int) * 4;
-    mType = kTypeCommandExt;
-
-    int* pInt = (int*) mData;
-    pInt[0] = cmd;
-    pInt[1] = arg0;
-    pInt[2] = arg1;
-    pInt[3] = arg2;
-}
-
-/*
- * Try to return the contents of the message as if it were a "command".
- */
-bool Message::getCommand(int* pCmd, int* pArg)
-{
-    if (mLength != sizeof(int) * 2) {
-        LOG(LOG_WARN, "", "type is %d, len is %d\n", mType, mLength);
-        return false;
-    }
-    assert(mData != NULL);
-
-    const int* pInt = (const int*) mData;
-    *pCmd = pInt[0];
-    *pArg = pInt[1];
-
-    return true;
-}
-
-/*
- * Serialize a log message.
- *
- * DO NOT call LOG() from here.
- */
-void Message::setLogBundle(const android_LogBundle* pBundle)
-{
-    reset();
-
-    /* get string lengths; we add one here to include the '\0' */
-    int tagLen, msgLen;
-    tagLen = strlen(pBundle->tag) + 1;
-    size_t i;
-    msgLen = 0;
-    for (i=0; i<pBundle->msgCount; i++) msgLen += pBundle->msgVec[i].iov_len;
-    msgLen += 1;
-
-    /* set up the structure */
-    mCleanup = kCleanupDelete;
-    mLength =   sizeof(pBundle->when) +
-                sizeof(pBundle->priority) +
-                sizeof(pBundle->pid) +
-                tagLen +
-                msgLen;
-    mData = new unsigned char[mLength];
-    mType = kTypeLogBundle;
-
-    unsigned char* pCur = mData;
-
-    /* copy the stuff over */
-    *((time_t*)pCur) = pBundle->when;
-    pCur += sizeof(pBundle->when);
-    *((android_LogPriority*)pCur) = pBundle->priority;
-    pCur += sizeof(pBundle->priority);
-    *((pid_t*)pCur) = pBundle->pid;
-    pCur += sizeof(pBundle->pid);
-    memcpy(pCur, pBundle->tag, tagLen);
-    pCur += tagLen;
-    for (i=0; i<pBundle->msgCount; i++) {
-        memcpy(pCur, pBundle->msgVec[i].iov_base, pBundle->msgVec[i].iov_len);
-        pCur += pBundle->msgVec[i].iov_len;
-    }
-    *pCur++ = 0;
-
-    assert(pCur - mData == mLength);
-}
-
-/*
- * Extract the components of a log bundle.
- *
- * We're just returning points inside the message buffer, so the caller
- * will need to copy them out before the next reset().
- */
-bool Message::getLogBundle(android_LogBundle* pBundle)
-{
-    if (mLength < (int)(sizeof(time_t) + sizeof(int)*2 + 4)) {
-        LOG(LOG_WARN, "", "type is %d, len is %d, too small\n",
-            mType, mLength);
-        return false;
-    }
-    assert(mData != NULL);
-
-    unsigned char* pCur = mData;
-
-    pBundle->when = *((time_t*) pCur);
-    pCur += sizeof(pBundle->when);
-    pBundle->priority = *((android_LogPriority*) pCur);
-    pCur += sizeof(pBundle->priority);
-    pBundle->pid = *((pid_t*) pCur);
-    pCur += sizeof(pBundle->pid);
-    pBundle->tag = (const char*) pCur;
-    pCur += strlen((const char*) pCur) +1;
-    mVec.iov_base = (char*) pCur;
-    mVec.iov_len = strlen((const char*) pCur);
-    pBundle->msgVec = &mVec;
-    pBundle->msgCount = 1;
-    pCur += mVec.iov_len +1;
-
-    if (pCur - mData != mLength) {
-        LOG(LOG_WARN, "", "log bundle rcvd %d, used %d\n", mLength,
-            (int) (pCur - mData));
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Read the next event from the pipe.
- *
- * This is not expected to work well when multiple threads are reading.
- */
-bool Message::read(Pipe* pPipe, bool wait)
-{
-    if (pPipe == NULL)
-        return false;
-    assert(pPipe->isCreated());
-
-    if (!wait) {
-        if (!pPipe->readReady())
-            return false;
-    }
-
-    reset();
-
-    unsigned char header[4];
-    if (pPipe->read(header, 4) != 4)
-        return false;
-
-    mType = (MessageType) header[2];
-    mLength = header[0] | header[1] << 8;
-    mLength -= 2;   // we already read two of them in the header
-
-    if (mLength > 0) {
-        int actual;
-
-        mData = new unsigned char[mLength];
-        if (mData == NULL) {
-            LOG(LOG_ERROR, "", "alloc failed\n");
-            return false;
-        }
-        mCleanup = kCleanupDelete;
-
-        actual = pPipe->read(mData, mLength);
-        if (actual != mLength) {
-            LOG(LOG_WARN, "", "failed reading message body (%d of %d bytes)\n",
-                actual, mLength);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-/*
- * Write this event to a pipe.
- *
- * It would be easiest to write the header and message body with two
- * separate calls, but that will occasionally fail on multithreaded
- * systems when the writes are interleaved.  We have to allocate a
- * temporary buffer, copy the data, and write it all at once.  This
- * would be easier with writev(), but we can't rely on having that.
- *
- * DO NOT call LOG() from here, as we could be in the process of sending
- * a log message.
- */
-bool Message::write(Pipe* pPipe) const
-{
-    char tmpBuf[128];
-    char* writeBuf = tmpBuf;
-    bool result = false;
-    int kHeaderLen = 4;
-
-    if (pPipe == NULL)
-        return false;
-    assert(pPipe->isCreated());
-
-    if (mData == NULL || mLength < 0)
-        return false;
-
-    /* if it doesn't fit in stack buffer, allocate space */
-    if (mLength + kHeaderLen > (int) sizeof(tmpBuf)) {
-        writeBuf = new char[mLength + kHeaderLen];
-        if (writeBuf == NULL)
-            goto bail;
-    }
-
-    /*
-     * The current value of "mLength" does not include the 4-byte header.
-     * Two of the 4 header bytes are included in the length we output
-     * (the type byte and the pad byte), so we adjust mLength.
-     */
-    writeBuf[0] = (unsigned char) (mLength + kHeaderLen -2);
-    writeBuf[1] = (unsigned char) ((mLength + kHeaderLen -2) >> 8);
-    writeBuf[2] = (unsigned char) mType;
-    writeBuf[3] = 0;
-    if (mLength > 0)
-        memcpy(writeBuf + kHeaderLen, mData, mLength);
-
-    int actual;
-
-    actual = pPipe->write(writeBuf, mLength + kHeaderLen);
-    if (actual != mLength + kHeaderLen) {
-        fprintf(stderr,
-            "Message::write failed writing message body (%d of %d bytes)\n",
-            actual, mLength + kHeaderLen);
-        goto bail;
-    }
-
-    result = true;
-
-bail:
-    if (writeBuf != tmpBuf)
-        delete[] writeBuf;
-    return result;
-}
-
-
-/*
- * ===========================================================================
- *      MessageStream
- * ===========================================================================
- */
-
-/*
- * Get ready to go.
- */
-bool MessageStream::init(Pipe* readPipe, Pipe* writePipe, bool initiateHello)
-{
-    assert(mReadPipe == NULL && mWritePipe == NULL);    // only once
-
-    /*
-     * Swap "hello" messages.
-     *
-     * In a more robust implementation, this would include version numbers
-     * and capability flags.
-     */
-    if (initiateHello) {
-        int32_t data = kHelloMsg;
-        Message msg;
-
-        /* send hello */
-        msg.setRaw((unsigned char*) &data, sizeof(data),
-            Message::kCleanupNoDelete);
-        if (!msg.write(writePipe)) {
-            LOG(LOG_WARN, "", "hello write failed in stream init\n");
-            return false;
-        }
-
-        LOG(LOG_DEBUG, "", "waiting for peer to ack my hello\n");
-
-        /* wait for the ack */
-        if (!msg.read(readPipe, true)) {
-            LOG(LOG_WARN, "", "hello ack read failed in stream init\n");
-            return false;
-        }
-
-        const int32_t* pAck;
-        pAck = (const int32_t*) msg.getData();
-        if (pAck == NULL || *pAck != kHelloAckMsg) {
-            LOG(LOG_WARN, "", "hello ack was bad (%08x vs %08x)\n",
-                *pAck, kHelloAckMsg);
-            return false;
-        }
-    } else {
-        int32_t data = kHelloAckMsg;
-        Message msg;
-
-        LOG(LOG_DEBUG, "", "waiting for hello from peer\n");
-
-        /* wait for the hello */
-        if (!msg.read(readPipe, true)) {
-            LOG(LOG_WARN, "", "hello read failed in stream init\n");
-            return false;
-        }
-
-        const int32_t* pAck;
-        pAck = (const int32_t*) msg.getData();
-        if (pAck == NULL || *pAck != kHelloMsg) {
-            LOG(LOG_WARN, "", "hello was bad\n");
-            return false;
-        }
-
-        /* send hello ack */
-        msg.setRaw((unsigned char*) &data, sizeof(data),
-            Message::kCleanupNoDelete);
-        if (!msg.write(writePipe)) {
-            LOG(LOG_WARN, "", "hello ack write failed in stream init\n");
-            return false;
-        }
-    }
-
-    /* success, set up our local stuff */
-    mReadPipe = readPipe;
-    mWritePipe = writePipe;
-
-    //LOG(LOG_DEBUG, "", "init success\n");
-
-    return true;
-}
-
diff --git a/simulator/app/MessageStream.h b/simulator/app/MessageStream.h
deleted file mode 100644
index 82a9b4c..0000000
--- a/simulator/app/MessageStream.h
+++ /dev/null
@@ -1,190 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// High-level message stream that sits on top of a pair of Pipes.  Useful
-// for inter-process communication, e.g. between "simulator" and "runtime".
-//
-// All messages are sent in packets:
-//  +00 16-bit length (of everything that follows), little-endian
-//  +02 8-bit message type
-//  +03 (reserved, must be zero)
-//  +04 message body
-//
-#ifndef _LIBS_UTILS_MESSAGE_STREAM_H
-#define _LIBS_UTILS_MESSAGE_STREAM_H
-
-#ifdef HAVE_ANDROID_OS
-#error DO NOT USE THIS FILE IN THE DEVICE BUILD
-#endif
-
-#include "Pipe.h"
-#include <stdlib.h>
-#include <cutils/uio.h>
-
-// Defined in LogBundle.h.
-struct android_LogBundle;
-
-namespace android {
-
-/*
- * A single message, which can be filled out and sent, or filled with
- * received data.
- *
- * Message objects are reusable.
- */
-class Message {
-public:
-    Message(void)
-        : mCleanup(kCleanupUnknown)
-        { reset(); }
-    ~Message(void) { reset(); }
-
-    /* values for message type byte */
-    typedef enum MessageType {
-        kTypeUnknown = 0,
-        kTypeRaw,           // chunk of raw data
-        kTypeConfig,        // send a name=value pair to peer
-        kTypeCommand,       // simple command w/arg
-        kTypeCommandExt,    // slightly more complicated command
-        kTypeLogBundle,     // multi-part log message
-    } MessageType;
-
-    /* what to do with data when we're done */
-    typedef enum Cleanup {
-        kCleanupUnknown = 0,
-        kCleanupNoDelete,   // do not delete data when object destroyed
-        kCleanupDelete,     // delete with "delete[]"
-    } Cleanup;
-
-    /*
-     * Stuff raw data into the object.  The caller can use the "cleanup"
-     * parameter to decide whether or not the Message object owns the data.
-     */
-    void setRaw(const unsigned char* data, int len, Cleanup cleanup);
-
-    /*
-     * Send a "name=value" pair.
-     */
-    void setConfig(const char* name, const char* value);
-
-    /*
-     * Send a command/arg pair.
-     */
-    void setCommand(int cmd, int arg);
-    void setCommandExt(int cmd, int arg0, int arg1, int arg2);
-
-    /*
-     * Send a multi-part log message.
-     */
-    void setLogBundle(const android_LogBundle* pBundle);
-
-    /*
-     * Simple accessors.
-     */
-    MessageType getType(void) const { return mType; }
-    const unsigned char* getData(void) const { return mData; }
-    int getLength(void) const { return mLength; }
-
-    /*
-     * Not-so-simple accessors.  These coerce the raw data into an object.
-     *
-     * The data returned by these may not outlive the Message, so make
-     * copies if you plan to use them long-term.
-     */
-    bool getConfig(const char** pName, const char** pValue);
-    bool getCommand(int* pCmd, int* pArg);
-    bool getLogBundle(android_LogBundle* pBundle);
-
-    /*
-     * Read or write this message on the specified pipe.
-     *
-     * If "wait" is true, read() blocks until a message arrives.  Only
-     * one thread should be reading at a time.
-     */
-    bool read(Pipe* pPipe, bool wait);
-    bool write(Pipe* pPipe) const;
-
-private:
-    Message& operator=(const Message&);     // not defined
-    Message(const Message&);                // not defined
-
-    void reset(void) {
-        if (mCleanup == kCleanupDelete)
-            delete[] mData;
-
-        mType = kTypeUnknown;
-        mCleanup = kCleanupNoDelete;
-        mData = NULL;
-        mLength = -1;
-    }
-
-    MessageType     mType;
-    Cleanup         mCleanup;
-    unsigned char*  mData;
-    int             mLength;
-    struct iovec    mVec;
-};
-
-
-/*
- * Abstraction of higher-level communication channel.
- *
- * This may be used from multiple threads simultaneously.  Blocking on
- * the read pipe from multiple threads will have unpredictable behavior.
- *
- * Does not take ownership of the pipes passed in to init().
- */
-class MessageStream {
-public:
-    MessageStream(void)
-        : mReadPipe(NULL), mWritePipe(NULL)
-        {}
-    ~MessageStream(void) {}
-
-    /*
-     * Initialize object and exchange greetings.  "initateHello" determines
-     * whether we send "Hello" or block waiting for it to arrive.  Usually
-     * the "parent" initiates.
-     */
-    bool init(Pipe* readPipe, Pipe* writePipe, bool initiateHello);
-
-    bool isReady(void) const { return mReadPipe != NULL && mWritePipe != NULL; }
-
-    /*
-     * Send a message immediately.
-     */
-    bool send(const Message* pMsg) { return pMsg->write(mWritePipe); }
-
-    /*
-     * Receive a message.
-     */
-    bool recv(Message* pMsg, bool wait) { return pMsg->read(mReadPipe, wait); }
-
-    /*
-     * Close communication pipes.  Further attempts to send or receive
-     * will fail.  Note this doesn't actually "close" the pipes, because
-     * we don't own them.
-     */
-    void close(void) { mReadPipe = mWritePipe = NULL; }
-
-    /*
-     * Get our incoming traffic pipe.  This is useful on Linux systems
-     * because it allows access to the file descriptor which can be used
-     * in a select() call.
-     */
-    Pipe* getReadPipe(void) { return mReadPipe; }
-
-private:
-    enum {
-        kHelloMsg       = 0x4e303047,       // 'N00G'
-        kHelloAckMsg    = 0x31455221,       // '1ER!'
-    };
-
-    /* communication pipes; note we don't own these */
-    Pipe*   mReadPipe;
-    Pipe*   mWritePipe;
-};
-
-}; // namespace android
-
-#endif // _LIBS_UTILS_MESSAGE_STREAM_H
diff --git a/simulator/app/MyApp.cpp b/simulator/app/MyApp.cpp
deleted file mode 100644
index fd610b1..0000000
--- a/simulator/app/MyApp.cpp
+++ /dev/null
@@ -1,547 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Application entry point.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h"   // needed for Windows build
-#include "wx/fs_zip.h"
-
-#include "MainFrame.h"
-#include "MyApp.h"
-#include "executablepath.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <signal.h>
-
-#if defined(HAVE_WINDOWS_PATHS)
-# include <windows.h>
-#endif
-
-
-/* the name of our config file */
-static wxString kConfigFileName = wxT(".android.cf");
-
-#ifdef HAVE_WINDOWS_PATHS
-static wxString kExeSuffix = wxT(".exe");
-#else
-static wxString kExeSuffix = wxT("");
-#endif
-
-/* do we want to kill the runtime? */
-bool gWantToKill = false;
-
-/*
- * Signal handler for Ctrl-C.  Under Linux we seem to get hit twice,
- * possibly once for each thread.
- *
- * Avoid using LOG here -- it's not reentrant.  Actually, just avoid doing
- * anything here.
- *
- * Cygwin will ignore the signal but doesn't seem to call the signal
- * handler.  MinGW just kills the process.
- */
-static void SignalHandler(int sigNum)
-{
-    printf("Sim: received signal %d (%s)\n", sigNum,
-        sigNum == SIGINT ? "SIGINT" : "???");
-    gWantToKill = true;
-}
-
-
-/* wxWidgets magic; creates appropriate main entry function */
-IMPLEMENT_APP(MyApp)
-
-/*
- * Application entry point.
- */
-bool MyApp::OnInit()
-{
-    static wxString helpFilePath = wxT("simulator/help/unnamed.htb");
-
-    /*
-     * Parse args.
-     */
-
-    SetDefaults();
-    
-    char** cargv = (char**)malloc(argc * sizeof(char*));
-    for (int i=0; i<argc; i++) {
-	wxCharBuffer tmp = wxString(argv[i]).ToAscii();
-        cargv[i] = tmp.release();
-    }
-    if (!ParseArgs(argc, cargv)) {
-	for (int i=0; i<argc; i++)
-	    free(cargv[i]);
-	free(cargv);
-        return FALSE;
-    }
-    for (int i=0; i<argc; i++)
-        free(cargv[i]);
-    free(cargv);
-    
-    if (!ProcessConfigFile())
-        return FALSE;
-
-    /*
-     * (Try to) catch SIGINT (Ctrl-C).
-     */
-    bool trapInt = false;
-    mPrefs.GetBool("trap-sigint", &trapInt);
-    if (trapInt) {
-        printf("Sim: catching SIGINT\n");
-        signal(SIGINT, SignalHandler);
-    }
-
-    signal(SIGPIPE, SIG_IGN);
-
-    /*
-     * Set stdout to unbuffered.  This is needed for MinGW/MSYS.
-     * Set stderr while we're at it.
-     */
-    setvbuf(stdout, NULL, _IONBF, 0);
-    setvbuf(stderr, NULL, _IONBF, 0);
-
-    /*
-     * Initialize asset manager.
-     */
-    mpAssetManager = NULL;
-    printf("Sim: looking in '%s' for my assets\n", (const char*) mSimAssetPath.ToAscii());
-    ChangeAssetDirectory(mSimAssetPath);
-
-    /*
-     * Add JPEG and PNG image handlers.
-     */
-    ::wxInitAllImageHandlers();
-
-    /*
-     * Set up the help file browser.  We're using wxHtmlHelpController
-     * because it seems to be the only "portable" version other than
-     * the "use external browser" version.
-     */
-    wxFileSystem::AddHandler(new wxZipFSHandler);
-    mHelpController = new wxHtmlHelpController;
-
-    wxString helpFileName;
-    helpFileName = mSimAssetPath;
-    helpFileName += '/';
-    helpFileName += helpFilePath;
-    mHelpController->Initialize(helpFileName);
-
-    /*
-     * Create the main window, which just holds some of our UI.
-     */
-    wxPoint pos(wxDefaultPosition);
-    mPrefs.GetInt("window-main-x", &pos.x);
-    mPrefs.GetInt("window-main-y", &pos.y);
-    mpMainFrame = new MainFrame(wxT("Android Simulator"), pos, wxDefaultSize,
-        wxDEFAULT_FRAME_STYLE);
-    mpMainFrame->Show(TRUE);
-    SetTopWindow(mpMainFrame);
-
-    return TRUE;
-}
-
-/*
- * Change our asset directory.  This requires deleting the existing
- * AssetManager and creating a new one.  Note that any open Assets will
- * still be valid.
- */
-void MyApp::ChangeAssetDirectory(const wxString& dir)
-{
-    delete mpAssetManager;
-    mpAssetManager = new android::AssetManager;
-    android::String8 path(dir.ToAscii());
-    path.appendPath("simulator.zip");
-    mpAssetManager->addAssetPath(path, NULL);
-    // mpAssetManager->setLocale(xxx);
-    mpAssetManager->setVendor("google");
-}
-
-
-/*
- * App is shutting down.  Save the config file.
- */
-int MyApp::OnExit(void)
-{
-    if (mPrefs.GetDirty()) {
-        printf("Sim: writing config file to '%s'\n",
-            (const char*) mConfigFile.ToAscii());
-        if (!mPrefs.Save(mConfigFile.ToAscii())) {
-            fprintf(stderr, "Sim: ERROR: prefs save to '%s' failed\n",
-                (const char*) mConfigFile.ToAscii());
-        }
-    }
-
-    return 0;
-}
-
-static ssize_t
-find_last_slash(const wxString& s)
-{
-    int slash = s.Last('/');
-    if (slash < 0) {
-        slash = s.Last('\\');
-    }
-    return slash;
-}
-
-
-/*
- * Set some default parameters
- */
-void MyApp::SetDefaults()
-{
-    mDebuggerOption = false;
-
-    /* Get the path to this executable, which should
-     * end in something like "/host/linux-x86/bin/simulator".
-     * (The full path may begin with something like "out"
-     * or "out/debug".)
-     */
-    char exepath[PATH_MAX];
-    executablepath(exepath);
-    wxString out = wxString::FromAscii(exepath);
-
-    /* Get the path to the root host directory;  e.g., "out/host".
-     * We can do this by removing the last three slashes
-     * and everything after/between them ("/linux-x86/bin/simulator").
-     */
-    for (int i = 0; i < 3; i++) {
-        int slash = find_last_slash(out);
-        assert(slash >= 0);
-        out.Truncate(slash);
-    }
-
-    /* Get the location of the assets directory; something like
-     * "out/host/common/sim-assets"
-     */
-    mSimAssetPath = out;
-    mSimAssetPath.Append(wxT("/common/sim-assets"));
-
-    /* Get the location of the simulated device filesystem.
-     * We can't reliably predict this based on the executable
-     * location, so try to get it from the environment.
-     */
-    char *envOut = getenv("ANDROID_PRODUCT_OUT");
-    if (envOut == NULL) {
-        fprintf(stderr,
-                "WARNING: $ANDROID_PRODUCT_OUT not set in environment\n");
-        envOut = "";
-    }
-
-    // the root of the android stuff
-    mAndroidRoot = wxString::FromAscii(envOut);
-    mAndroidRoot.Append(wxT("/system"));
-    
-    // where runtime is
-    mRuntimeExe = mAndroidRoot;
-    mRuntimeExe.Append(wxT("/bin/runtime"));
-    mRuntimeExe.Append(kExeSuffix);
-    
-    printf("mAndroidRoot='%s'\n", (const char*) mAndroidRoot.ToAscii());
-    printf("mSimAssetPath='%s'\n", (const char*) mSimAssetPath.ToAscii());
-}
-
-
-/*
- * Parse command-line arguments.
- *
- * Returns "false" if we have a parsing error.
- */
-bool MyApp::ParseArgs(int argc, char** argv)
-{
-    int ic;
-
-    opterr = 0;     // don't complain about unrecognized options
-
-    if (false) {
-        printf("MyApp args:\n");
-        for (int i = 0; i < argc; i++)
-            printf("  %2d: '%s'\n", i, (const char*) argv[i]);
-    }
-
-    while (1) {
-        ic = getopt(argc, argv, "tj:da:f:rx:");
-        if (ic < 0)
-            break;
-
-        switch (ic) {
-        case 'j':
-            mAutoRunApp = wxString::FromAscii(optarg);
-            break;
-        case 't':
-            mAutoRunApp = wxT("com.android.testharness.RunAll");
-            break;
-        case 'd':
-            mDebuggerOption = true;
-            break;
-        case 'x':
-            mDebuggerScript = wxString::FromAscii(optarg);
-            mDebuggerOption = true;     // force debug if a script is being used
-            break;
-        case 'a':       // simulator asset dir
-            mSimAssetPath = wxString::FromAscii(optarg);
-            break;
-        case 'f':       // simulator config file
-            mConfigFile = wxString::FromAscii(optarg);
-            break;
-        case 'r':       // reset path-based options to defaults
-            mResetPaths = true;
-            break;
-        default:
-            fprintf(stderr, "WARNING: unknown sim option '%c'\n", ic);
-            break;
-        }
-    }
-
-    return true;
-}
-
-
-/*
- * Convert a path to absolute form, if needed.
- *
- * String manipulation would be more efficient than system calls, but
- * less reliable.
- *
- * We need to use GetCurrentDirectory() under Windows because, under
- * Cygwin, some wxWidgets features require "C:" paths rather than
- * local-rooted paths.  Probably needed for stand-alone MinGW too.
- */
-void MyApp::AbsifyPath(wxString& dir)
-{
-    char oldDir[512], newDir[512];
-    wxString newDirStr;
-
-    // We still need to do this under Cygwin even if the path is
-    // already absolute.
-    //if (dir[0] == '/' || dir[0] == '\\')
-    //    return;
-
-    if (getcwd(oldDir, sizeof(oldDir)) == NULL) {
-        fprintf(stderr, "getcwd() failed\n");
-        return;
-    }
-
-    if (chdir(dir.ToAscii()) == 0) {
-#if defined(HAVE_WINDOWS_PATHS)
-        DWORD dwRet;
-        dwRet = GetCurrentDirectory(sizeof(newDir), newDir);
-        if (dwRet == 0 || dwRet > sizeof(newDir))
-            sprintf(newDir, "GET_DIR_FAILED %lu", dwRet);
-#else
-        if (getcwd(newDir, sizeof(newDir)) == NULL)
-            strcpy(newDir, "GET_DIR_FAILED");
-#endif
-        newDirStr = wxString::FromAscii(newDir);
-        chdir(oldDir);
-    } else {
-        fprintf(stderr, "WARNING: unable to chdir to '%s' from '%s'\n",
-            (const char*) dir.ToAscii(), oldDir);
-        newDirStr = dir;
-    }
-
-    //dir = "c:/dev/cygwin";
-    //dir += newDirStr;
-    dir = newDirStr;
-}
-
-
-/*
- * Load and process our configuration file.
- */
-bool MyApp::ProcessConfigFile(void)
-{
-    wxString homeConfig;
-    bool configLoaded = false;
-
-    if (getenv("HOME") != NULL) {
-        homeConfig = wxString::FromAscii(getenv("HOME"));
-        homeConfig += '/';
-        homeConfig += kConfigFileName;
-    } else {
-        homeConfig = wxT("./");
-        homeConfig += kConfigFileName;
-    }
-
-    /*
-     * Part 1: read the config file.
-     */
-
-    if (mConfigFile.Length() > 0) {
-        /*
-         * Read from specified config file.  We absolutify the path
-         * first so that we're guaranteed to be hitting the same file
-         * even if the cwd changes.
-         */
-        if (access(mConfigFile.ToAscii(), R_OK) != 0) {
-            fprintf(stderr, "ERROR: unable to open '%s'\n",
-                (const char*) mConfigFile.ToAscii());
-            return false;
-        }
-        if (!mPrefs.Load(mConfigFile.ToAscii())) {
-            fprintf(stderr, "Failed loading config file '%s'\n",
-                (const char*) mConfigFile.ToAscii());
-            return false;
-        } else {
-            configLoaded = true;
-        }
-    } else {
-        /*
-         * Try ./android.cf, then $HOME/android.cf.  If we find one and
-         * read it successfully, save the name in mConfigFile.
-         */
-        {
-            wxString fileName;
-
-            fileName = wxT(".");
-            AbsifyPath(fileName);
-            fileName += wxT("/");
-            fileName += kConfigFileName;
-
-            if (access(fileName.ToAscii(), R_OK) == 0) {
-                if (mPrefs.Load(fileName.ToAscii())) {
-                    mConfigFile = fileName;
-                    configLoaded = true;
-                } else {
-                    /* damaged config files are always fatal */
-                    fprintf(stderr, "Failed loading config file '%s'\n",
-                        (const char*) fileName.ToAscii());
-                    return false;
-                }
-            }
-        }
-        if (!configLoaded) {
-            if (homeConfig.Length() > 0) {
-                if (access(homeConfig.ToAscii(), R_OK) == 0) {
-                    if (mPrefs.Load(homeConfig.ToAscii())) {
-                        mConfigFile = homeConfig;
-                        configLoaded = true;
-                    } else {
-                        /* damaged config files are always fatal */
-                        fprintf(stderr, "Failed loading config file '%s'\n",
-                            (const char*) homeConfig.ToAscii());
-                        return false;
-                    }
-                }
-            }
-        }
-
-    }
-
-    /* if we couldn't find one to load, create a new one in $HOME */
-    if (!configLoaded) {
-        mConfigFile = homeConfig;
-        if (!mPrefs.Create()) {
-            fprintf(stderr, "prefs creation failed\n");
-            return false;
-        }
-    }
-
-    /*
-     * Part 2: reset some entries if requested.
-     *
-     * If you want to reset local items (like paths to binaries) without
-     * disrupting other options, specifying the "reset" flag will cause
-     * some entries to be removed, and new defaults generated below.
-     */
-
-    if (mResetPaths) {
-        if (mPrefs.RemovePref("debugger"))
-            printf("  removed pref 'debugger'\n");
-        if (mPrefs.RemovePref("valgrinder"))
-            printf("  removed pref 'valgrinder'\n");
-    }
-
-    /*
-     * Find GDB.
-     */
-    if (!mPrefs.Exists("debugger")) {
-        static wxString paths[] = {
-            wxT("/bin"), wxT("/usr/bin"), wxString()
-        };
-        wxString gdbPath;
-
-        FindExe(wxT("gdb"), paths, wxT("/usr/bin/gdb"), &gdbPath);
-        mPrefs.SetString("debugger", gdbPath.ToAscii());
-    }
-
-
-    /*
-     * Find Valgrind.  It currently only exists in Linux, and is installed
-     * in /usr/bin/valgrind by default on our systems.  The default version
-     * is old and sometimes fails, so look for a newer version.
-     */
-    if (!mPrefs.Exists("valgrinder")) {
-        static wxString paths[] = {
-            wxT("/home/fadden/local/bin"), wxT("/usr/bin"), wxString()
-        };
-        wxString valgrindPath;
-
-        FindExe(wxT("valgrind"), paths, wxT("/usr/bin/valgrind"), &valgrindPath);
-        mPrefs.SetString("valgrinder", valgrindPath.ToAscii());
-    }
-
-    /*
-     * Set misc options.
-     */
-    if (!mPrefs.Exists("auto-power-on"))
-        mPrefs.SetBool("auto-power-on", true);
-    if (!mPrefs.Exists("gamma"))
-        mPrefs.SetDouble("gamma", 1.0);
-
-    if (mPrefs.GetDirty()) {
-        printf("Sim: writing config file to '%s'\n",
-            (const char*) mConfigFile.ToAscii());
-        if (!mPrefs.Save(mConfigFile.ToAscii())) {
-            fprintf(stderr, "Sim: ERROR: prefs save to '%s' failed\n",
-                (const char*) mConfigFile.ToAscii());
-        }
-    }
-
-    return true;
-}
-
-/*
- * Find an executable by searching in several places.
- */
-/*static*/ void MyApp::FindExe(const wxString& exeName, const wxString paths[],
-    const wxString& defaultPath, wxString* pOut)
-{
-    wxString exePath;
-    wxString slashExe;
-
-    slashExe = wxT("/");
-    slashExe += exeName;
-    slashExe += kExeSuffix;
-
-    while (!(*paths).IsNull()) {
-        wxString tmp;
-
-        tmp = *paths;
-        tmp += slashExe;
-        if (access(tmp.ToAscii(), X_OK) == 0) {
-            printf("Sim: Found '%s' in '%s'\n", (const char*) exeName.ToAscii(), 
-                    (const char*) tmp.ToAscii());
-            *pOut = tmp;
-            return;
-        }
-
-        paths++;
-    }
-
-    printf("Sim: Couldn't find '%s', defaulting to '%s'\n",
-        (const char*) exeName.ToAscii(), (const char*) defaultPath.ToAscii());
-    *pOut = defaultPath;
-}
-
diff --git a/simulator/app/MyApp.h b/simulator/app/MyApp.h
deleted file mode 100644
index d18368d..0000000
--- a/simulator/app/MyApp.h
+++ /dev/null
@@ -1,93 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Application class.
-//
-#ifndef _SIM_APPMAIN_H
-#define _SIM_APPMAIN_H
-
-#include "wx/help.h"
-#include "wx/html/helpctrl.h"
-
-#include "MainFrame.h"
-#include "DeviceManager.h"
-#include "Preferences.h"
-
-#include <utils/AssetManager.h>
-
-/* flag set from signal handler */
-extern bool gWantToKill;
-
-/*
- * Class representing the application.
- */
-class MyApp : public wxApp {
-public:
-    MyApp(void)
-        : mHelpController(NULL), mpMainFrame(NULL), mpAssetManager(NULL),
-          mResetPaths(false)        // configurable; reset prefs with paths
-        {}
-    ~MyApp(void) 
-    { 
-        delete mpAssetManager;
-        delete mHelpController; 
-    }
-
-    virtual bool OnInit(void);
-    virtual int OnExit(void);
-
-    wxHtmlHelpController* GetHelpController(void) const {
-        return mHelpController;
-    }
-
-    Preferences* GetPrefs(void)                 { return &mPrefs; }
-
-    /* return a pointer to the main window */
-    wxWindow* GetMainFrame(void) { return mpMainFrame; }
-
-    /* get a pointer to our Asset Manager */
-    android::AssetManager* GetAssetManager(void) { return mpAssetManager; }
-
-    /* change the asset dir; requires re-creating Asset Manager */
-    void ChangeAssetDirectory(const wxString& dir);
-
-    const wxString& GetConfigFileName(void) const { return mConfigFile; }
-
-    wxString GetSimAssetPath()                  { return mSimAssetPath; }
-    wxString GetAndroidRoot()                   { return mAndroidRoot; }
-    wxString GetRuntimeExe()                    { return mRuntimeExe; }
-    bool GetDebuggerOption()                    { return mDebuggerOption; }
-    wxString GetDebuggerScript()                { return mDebuggerScript; }
-    wxString GetAutoRunApp()                    { return mAutoRunApp; }
-
-    void Vibrate(int vibrateOn)                 { ((MainFrame*)mpMainFrame)->Vibrate(vibrateOn); }
-
-private:
-    void SetDefaults();
-    bool ParseArgs(int argc, char** argv);
-    void AbsifyPath(wxString& dir);
-    bool ProcessConfigFile(void);
-    static void FindExe(const wxString& exeName, const wxString paths[],
-        const wxString& defaultPath, wxString* pOut);
-
-    wxHtmlHelpController*   mHelpController;
-
-    wxWindow*       mpMainFrame;
-
-    android::AssetManager*  mpAssetManager;
-
-    wxString        mAndroidRoot;
-    wxString        mSimAssetPath;
-    wxString        mRuntimeExe;
-
-    /* command-line options */
-    wxString        mConfigFile;
-    bool            mResetPaths;
-    bool            mDebuggerOption;
-	wxString		mDebuggerScript;
-    wxString        mAutoRunApp;
-
-    Preferences     mPrefs;
-};
-
-#endif // _SIM_APPMAIN_H
diff --git a/simulator/app/PhoneButton.cpp b/simulator/app/PhoneButton.cpp
deleted file mode 100644
index 15c5109..0000000
--- a/simulator/app/PhoneButton.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Simulated device data.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h"   // needed for Windows build
-
-#include "LinuxKeys.h"
-#include "PhoneButton.h"
-
-using namespace android;
-
-
-/*
- * Create a PhoneButton without a backing image.
- */
-bool PhoneButton::Create(const char* label)
-{
-    assert(!mHasImage);     // quick check for re-use
-
-    mKeyCode = LookupKeyCode(label);
-    if (mKeyCode == AKEYCODE_UNKNOWN) {
-        fprintf(stderr, "WARNING: key code '%s' not recognized\n", label);
-        // keep going
-    }
-
-    return true;
-}
-
-/*
- * Create a PhoneButton with an associated image.  Don't load the image yet.
- */
-bool PhoneButton::Create(const char* label, const char* imageFileName,
-    int x, int y)
-{
-    if (!Create(label))
-        return false;
-
-    if (mSelectedImage.Create(imageFileName, x, y))
-        mHasImage = true;
-    else
-        fprintf(stderr, "Warning: image create (%s, %d, %d) failed\n",
-            imageFileName, x, y);
-
-    return true;
-}
-
-/*
- * Load the image, if any.
- */
-bool PhoneButton::LoadResources(void)
-{
-    if (!mHasImage)
-        return true;        // no image associated with this button
-
-    bool result = mSelectedImage.LoadResources();
-    if (result)
-        CreateHighlightedBitmap();
-    return result;
-}
-
-/*
- * Unload the image if we loaded one.
- */
-bool PhoneButton::UnloadResources(void)
-{
-    if (!mHasImage)
-        return true;
-
-    return mSelectedImage.UnloadResources();
-}
-
-/* use an inline instead of macro so we don't evaluate args multiple times */
-static inline int MinVal(int a, int b) { return (a < b ? a : b); }
-
-/*
- * Create the "highlighted" bitmap from the "selected" image.
- */
-void PhoneButton::CreateHighlightedBitmap(void)
-{
-    wxBitmap* src = mSelectedImage.GetBitmap();
-    assert(src != NULL);
-    wxImage tmpImage = src->ConvertToImage();
-
-    unsigned char* pRGB = tmpImage.GetData();       // top-left RGBRGB...
-    int x, y;
-
-    /*
-     * Modify the color used for the "highlight" image.
-     */
-    for (y = tmpImage.GetHeight()-1; y >= 0; --y) {
-        for (x = tmpImage.GetWidth()-1; x >= 0; --x) {
-            *(pRGB)   = MinVal(*(pRGB)   + *(pRGB) / 8, 255);
-            *(pRGB+1) = MinVal(*(pRGB+1) + *(pRGB+1) / 8, 255);
-            *(pRGB+2) = *(pRGB+2) * 5 / 8;
-
-            pRGB += 3;
-        }
-    }
-
-    mHighlightedBitmap = wxBitmap(tmpImage);
-}
-
-/*
- * Check to see if the button "collides" with the specified point.
- *
- * This is currently a simple rectangle check, but could be modified
- * to take image transparency into account.
- */
-bool PhoneButton::CheckCollision(int x, int y) const
-{
-    if (!mHasImage)
-        return false;
-
-    return (x >= mSelectedImage.GetX() &&
-            x < mSelectedImage.GetX() + mSelectedImage.GetWidth() &&
-            y >= mSelectedImage.GetY() &&
-            y < mSelectedImage.GetY() + mSelectedImage.GetHeight());
-}
-
-/*
- * Look up a key code based on a string.
- *
- * Returns AKEYCODE_UNKNOWN if the label doesn't match anything.
- */
-int32_t PhoneButton::LookupKeyCode(const char* label) const
-{
-    static const struct {
-        const char* label;
-        int keyCode;
-    } codeList[] = {
-        { "soft-left",      KEY_MENU },
-        { "soft-right",     KEY_KBDILLUMUP },
-        { "home",           KEY_HOME },
-        { "back",           KEY_BACK },
-        { "call",           KEY_F3 },
-        { "phone-dial",     KEY_F3 },
-        { "end-call",       KEY_F4 },
-        { "phone-hangup",   KEY_F4 },
-        { "0",              KEY_0 },
-        { "1",              KEY_1 },
-        { "2",              KEY_2 },
-        { "3",              KEY_3 },
-        { "4",              KEY_4 },
-        { "5",              KEY_5 },
-        { "6",              KEY_6 },
-        { "7",              KEY_7 },
-        { "8",              KEY_8 },
-        { "9",              KEY_9 },
-        { "star",           KEY_SWITCHVIDEOMODE },
-        { "pound",          KEY_KBDILLUMTOGGLE },
-        { "dpad-up",        KEY_UP },
-        { "dpad-down",      KEY_DOWN },
-        { "dpad-left",      KEY_LEFT },
-        { "dpad-right",     KEY_RIGHT },
-        { "dpad-center",    KEY_REPLY },
-        { "volume-up",      KEY_VOLUMEUP },
-        { "volume-down",    KEY_VOLUMEDOWN },
-        { "power",          KEY_POWER },
-        { "camera",         KEY_CAMERA },
-        //{ "clear",          kKeyCodeClear },
-    };
-    const int numCodes = sizeof(codeList) / sizeof(codeList[0]);
-
-    for (int i = 0; i < numCodes; i++) {
-        if (strcmp(label, codeList[i].label) == 0)
-            return codeList[i].keyCode;
-    }
-
-    return AKEYCODE_UNKNOWN;
-};
-
diff --git a/simulator/app/PhoneButton.h b/simulator/app/PhoneButton.h
deleted file mode 100644
index 86c32dd..0000000
--- a/simulator/app/PhoneButton.h
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Phone button image holder.
-//
-#ifndef _SIM_PHONE_BUTTON_H
-#define _SIM_PHONE_BUTTON_H
-
-#include "LoadableImage.h"
-#include <ui/KeycodeLabels.h>
-
-/*
- * One button on a phone.  Position, size, and a highlight graphic.  The
- * coordinates are relative to the device graphic.
- *
- * We now have a "highlighted" graphic for mouse-overs and a "selected"
- * graphic for button presses.  We assume they have the same dimensions.
- * We currently assume that either both or neither exist, because we
- * generate one from the other.
- */
-class PhoneButton {
-public:
-    PhoneButton(void)
-        : mHasImage(false), mKeyCode(AKEYCODE_UNKNOWN)
-        {}
-    virtual ~PhoneButton(void) {}
-    PhoneButton(const PhoneButton& src)
-        : mHasImage(false), mKeyCode(AKEYCODE_UNKNOWN)
-    {
-        CopyMembers(src);
-    }
-    PhoneButton& operator=(const PhoneButton& src) {
-        if (this != &src) {
-            // Unload any resources in case we're using operator= to
-            // assign to an existing object.
-            mSelectedImage.UnloadResources();
-            // Copy fields.
-            CopyMembers(src);
-        }
-        return *this;
-    }
-    void CopyMembers(const PhoneButton& src) {
-        mSelectedImage = src.mSelectedImage;
-        mHighlightedBitmap = src.mHighlightedBitmap;
-        mHasImage = src.mHasImage;
-        mKeyCode = src.mKeyCode;
-    }
-
-    /* finish construction of PhoneButton, with or without an image */
-    bool Create(const char* label);
-    bool Create(const char* label, const char* imageFileName, int x, int y);
-
-    int GetX(void) const { return mSelectedImage.GetX(); }
-    int GetY(void) const { return mSelectedImage.GetY(); }
-    int GetWidth(void) const { return mSelectedImage.GetWidth(); }
-    int GetHeight(void) const { return mSelectedImage.GetHeight(); }
-    wxBitmap* GetHighlightedBitmap(void) { return &mHighlightedBitmap; }
-    wxBitmap* GetSelectedBitmap(void) const {
-        return mSelectedImage.GetBitmap();
-    }
-
-    bool CheckCollision(int x, int y) const;
-    int32_t GetKeyCode(void) const { return mKeyCode; }
-
-    // load or unload the image bitmap, if any
-    bool LoadResources(void);
-    bool UnloadResources(void);
-
-private:
-    void CreateHighlightedBitmap(void);
-    int32_t LookupKeyCode(const char* label) const;
-
-    LoadableImage       mSelectedImage;
-    wxBitmap            mHighlightedBitmap;
-    bool                mHasImage;          // both exist or neither exist
-
-    int32_t mKeyCode;
-};
-
-#endif // _SIM_PHONE_BUTTON_H
diff --git a/simulator/app/PhoneCollection.cpp b/simulator/app/PhoneCollection.cpp
deleted file mode 100644
index e1882cc..0000000
--- a/simulator/app/PhoneCollection.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Our collection of devices.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-//#include "wx/image.h"   // needed for Windows build
-
-
-#include "PhoneCollection.h"
-#include "PhoneData.h"
-#include "MyApp.h"
-
-#include "utils.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <assert.h>
-
-using namespace android;
-
-/*static*/ PhoneCollection* PhoneCollection::mpInstance = NULL;
-
-/*static*/ const char* PhoneCollection::kLayoutFile = "layout.xml";
-
-
-/*
- * (Re-)scan the specified directory for phones.  We register a hit if we can
- * see a file called "<directory>/layout.xml".
- */
-void PhoneCollection::ScanForPhones(const char* directory)
-{
-    /*
-     * Scan through the directory and find everything that looks like it
-     * might hold phone data.
-     */
-    StringArray strArr;
-
-#ifdef BEFORE_ASSET
-    DIR* dirp;
-    struct dirent* entp;
-
-    dirp = opendir(directory);
-    if (dirp == NULL) {
-        char buf[512];
-        fprintf(stderr, "ERROR: unable to scan directory '%s' for phone data\n",
-            directory);
-        fprintf(stderr, "Current dir is %s\n", getcwd(buf, sizeof(buf)));
-        return;
-    }
-
-    while (1) {
-        wxString dirName;
-        wxString fileName;
-
-        entp = readdir(dirp);
-        if (entp == NULL)
-            break;              // done with scan
-        dirName = directory;
-        dirName += '/';
-        dirName += entp->d_name;
-        fileName = dirName;
-        fileName += '/';
-        fileName += kLayoutFile;
-
-        if (access(fileName, R_OK) == 0) {
-            strArr.push_back(dirName);
-            //printf("--- examining '%s'\n", (const char*) fileName);
-        }
-    }
-    closedir(dirp);
-#else
-    android::AssetManager* pAssetMgr = ((MyApp*)wxTheApp)->GetAssetManager();
-    android::AssetDir* pDir;
-    int i, count;
-
-    pDir = pAssetMgr->openDir("");
-    assert(pDir != NULL);
-    count = pDir->getFileCount();
-
-    for (i = 0; i < count; i++) {
-        android::String8 layoutPath;
-
-        if (pDir->getFileType(i) != kFileTypeDirectory)
-            continue;
-
-        layoutPath = pDir->getFileName(i);
-        layoutPath.appendPath(kLayoutFile);
-
-        if (pAssetMgr->getFileType(layoutPath.string()) == kFileTypeRegular) {
-            strArr.push_back(pDir->getFileName(i).string());
-            printf("--- examining '%s'\n", layoutPath.string());
-        }
-    }
-
-    delete pDir;
-#endif
-
-    if (strArr.size() == 0) {
-        fprintf(stderr, "ERROR: no phone data found in '%s'\n", directory);
-        return;
-    }
-
-    /*
-     * Found some candidates.  If they parse successfully, add them to
-     * our list.
-     *
-     * We sort them first, because it's nice when everybody's user
-     * interface looks the same.  Note we're sorting the directory name,
-     * so it's possible to define a sort order in the filesystem that
-     * doesn't require messing up the phone's title string.
-     */
-    mPhoneList.clear();
-    strArr.sort(StringArray::cmpAscendingAlpha);
-
-    for (int i = 0; i < strArr.size(); i++) {
-        PhoneData tmpPhone;
-
-        if (!tmpPhone.Create(strArr.getEntry(i))) {
-            fprintf(stderr, "Sim: Abandoning phone '%s'\n", strArr.getEntry(i));
-            //strArr.erase(i);
-            //i--;
-        } else {
-            if (GetPhoneData(tmpPhone.GetName()) != NULL) {
-                fprintf(stderr, "Sim: ERROR: duplicate name '%s' in '%s'\n",
-                    tmpPhone.GetName(), strArr.getEntry(i));
-            } else {
-                mPhoneList.push_back(tmpPhone);
-            }
-        }
-    }
-}
-
-
-/*
- * Return the Nth member of the phone data array.  (Replace w/Vector.)
- */
-PhoneData* PhoneCollection::GetPhoneData(int idx)
-{
-    typedef List<PhoneData>::iterator Iter;
-
-    for (Iter ii = mPhoneList.begin(); ii != mPhoneList.end(); ++ii) {
-        if (idx == 0)
-            return &(*ii);
-        --idx;
-    }
-    return NULL;
-}
-
-/*
- * Return the entry whose phone data name matches "name".
- */
-PhoneData* PhoneCollection::GetPhoneData(const char* name)
-{
-    typedef List<PhoneData>::iterator Iter;
-
-    for (Iter ii = mPhoneList.begin(); ii != mPhoneList.end(); ++ii) {
-        if (strcasecmp((*ii).GetName(), name) == 0)
-            return &(*ii);
-    }
-    return NULL;
-}
-
diff --git a/simulator/app/PhoneCollection.h b/simulator/app/PhoneCollection.h
deleted file mode 100644
index d16c4a0..0000000
--- a/simulator/app/PhoneCollection.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Our collection of devices.
-//
-#ifndef _SIM_PHONE_COLLECTION_H
-#define _SIM_PHONE_COLLECTION_H
-
-#include <stdlib.h>
-#include "PhoneData.h"
-
-/*
- * Only one instance of this class exists.  It contains a list of all
- * known devices, and methods for scanning for devices.
- */
-class PhoneCollection {
-public:
-    /* get the global instance */
-    static PhoneCollection* GetInstance(void) {
-        if (mpInstance == NULL)
-            mpInstance = new PhoneCollection;
-        return mpInstance;
-    }
-    /* destroy the global instance when shutting down */
-    static void DestroyInstance(void) {
-        delete mpInstance;
-        mpInstance = NULL;
-    }
-
-    /* scan for phones in subdirectories of "directory" */
-    void ScanForPhones(const char* directory);
-
-    /* get phone data */
-    int GetPhoneCount(void) const { return mPhoneList.size(); } // slow
-    PhoneData* GetPhoneData(int idx);
-    PhoneData* GetPhoneData(const char* name);
-
-    /* layout.xml filename -- a string constant used in various places */
-    static const char* kLayoutFile;
-
-private:
-    PhoneCollection(void) {}
-    ~PhoneCollection(void) {}
-
-    /* the phone data; make this a Vector someday */
-    android::List<PhoneData>    mPhoneList;
-
-    /* storage for global instance pointer */
-    static PhoneCollection* mpInstance;
-};
-
-#endif // _SIM_PHONE_COLLECTION_H
diff --git a/simulator/app/PhoneData.cpp b/simulator/app/PhoneData.cpp
deleted file mode 100644
index f6756f5..0000000
--- a/simulator/app/PhoneData.cpp
+++ /dev/null
@@ -1,868 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Simulated device data.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h"   // needed for Windows build
-
-
-#include "PhoneData.h"
-#include "PhoneButton.h"
-#include "PhoneCollection.h"
-#include "MyApp.h"
-
-#include "utils.h"
-#include <utils/AssetManager.h>
-#include <utils/String8.h>
-
-#include "tinyxml.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-using namespace android;
-
-/* image relative path hack */
-static const char* kRelPathMagic = "::/";
-
-
-/*
- * ===========================================================================
- *      PhoneKeyboard
- * ===========================================================================
- */
-
-/*
- * Load a <keyboard> chunk.
- */
-bool PhoneKeyboard::ProcessAndValidate(TiXmlNode* pNode)
-{
-    //TiXmlNode* pChild;
-    TiXmlElement* pElem;
-    int qwerty = 0;
-    
-    assert(pNode->Type() == TiXmlNode::ELEMENT);
-
-    pElem = pNode->ToElement();
-    pElem->Attribute("qwerty", &qwerty);
-    const char *kmap = pElem->Attribute("keycharmap");
-
-    if (qwerty == 1) {
-        printf("############## PhoneKeyboard::ProcessAndValidate: qwerty = true!\n");
-        mQwerty = true;
-    }
-
-    if (kmap != NULL) {
-        printf("############## PhoneKeyboard::ProcessAndValidate: keycharmap = %s\n", kmap);
-        mKeyMap = strdup(kmap);
-    }
-    
-    return true;
-}
-
-
-/*
- * ===========================================================================
- *      PhoneDisplay
- * ===========================================================================
- */
-
-/*
- * Load a <display> chunk.
- */
-bool PhoneDisplay::ProcessAndValidate(TiXmlNode* pNode)
-{
-    //TiXmlNode* pChild;
-    TiXmlElement* pElem;
-    const char* name;
-    const char* format;
-
-    assert(pNode->Type() == TiXmlNode::ELEMENT);
-
-    /*
-     * Process attributes.  Right now they're all mandatory, but some of
-     * them could be defaulted (e.g. "rotate").
-     *
-     * [We should do some range-checking here.]
-     */
-    pElem = pNode->ToElement();
-    name = pElem->Attribute("name");
-    if (name == NULL)
-        goto missing;
-    if (pElem->Attribute("width", &mWidth) == NULL)
-        goto missing;
-    if (pElem->Attribute("height", &mHeight) == NULL)
-        goto missing;
-    if (pElem->Attribute("refresh", &mRefresh) == NULL)
-        goto missing;
-    format = pElem->Attribute("format");
-    if (format == NULL)
-        goto missing;
-
-    delete[] mName;
-    mName = strdupNew(name);
-
-    if (strcasecmp(format, "rgb565") == 0) {
-        mFormat = android::PIXEL_FORMAT_RGB_565;
-    } else {
-        fprintf(stderr, "SimCFG: unexpected value for display format\n");
-        return false;
-    }
-
-    return true;
-
-missing:
-    fprintf(stderr,
-        "SimCFG: <display> requires name/width/height/format/refresh\n");
-    return false;
-}
-
-
-/*
- * Returns "true" if the two displays are compatible, "false" if not.
- *
- * Compatibility means they have the same resolution, format, refresh
- * rate, and so on.  Anything transmitted to the runtime as part of the
- * initial configuration setup should be tested.
- */
-/*static*/ bool PhoneDisplay::IsCompatible(PhoneDisplay* pDisplay1,
-    PhoneDisplay* pDisplay2)
-{
-    return (pDisplay1->mWidth == pDisplay2->mWidth &&
-            pDisplay1->mHeight == pDisplay2->mHeight &&
-            pDisplay1->mFormat == pDisplay2->mFormat &&
-            pDisplay1->mRefresh == pDisplay2->mRefresh);
-}
-
-
-/*
- * ===========================================================================
- *      PhoneView
- * ===========================================================================
- */
-
-/*
- * Load a <view> chunk.
- */
-bool PhoneView::ProcessAndValidate(TiXmlNode* pNode, const char* directory)
-{
-    TiXmlNode* pChild;
-    TiXmlElement* pElem;
-    int rotate;
-    const char* displayName;
-
-    assert(pNode->Type() == TiXmlNode::ELEMENT);
-
-    /*
-     * Process attributes.  Right now they're all mandatory, but some of
-     * them could be defaulted (e.g. "rotate").
-     *
-     * [We should do some range-checking here.]
-     */
-    pElem = pNode->ToElement();
-    displayName = pElem->Attribute("display");
-    if (displayName == NULL)
-        goto missing;
-    if (pElem->Attribute("x", &mXOffset) == NULL)
-        goto missing;
-    if (pElem->Attribute("y", &mYOffset) == NULL)
-        goto missing;
-    if (pElem->Attribute("rotate", &rotate) == NULL)
-        goto missing;
-
-    switch (rotate) {
-    case 0:     mRotation = kRot0;      break;
-    case 90:    mRotation = kRot90;     break;
-    case 180:   mRotation = kRot180;    break;
-    case 270:   mRotation = kRot270;    break;
-    default:
-                fprintf(stderr, "SimCFG: unexpected value for rotation\n");
-                mRotation = kRotUnknown;
-                return false;
-    }
-
-    delete[] mDisplayName;
-    mDisplayName = android::strdupNew(displayName);
-
-    /*
-     * Process elements.
-     */
-    for (pChild = pNode->FirstChild(); pChild != NULL;
-        pChild = pChild->NextSibling())
-    {
-        if (pChild->Type() == TiXmlNode::COMMENT)
-            continue;
-
-        if (pChild->Type() == TiXmlNode::ELEMENT) {
-            if (strcasecmp(pChild->Value(), "image") == 0) {
-                if (!ProcessImage(pChild, directory))
-                    return false;
-            } else if (strcasecmp(pChild->Value(), "button") == 0) {
-                if (!ProcessButton(pChild, directory))
-                    return false;
-            } else {
-                fprintf(stderr,
-                    "SimCFG: Warning: unexpected elements in <display>\n");
-            }
-        } else {
-            fprintf(stderr, "SimCFG: Warning: unexpected stuff in <display>\n");
-        }
-    }
-
-    return true;
-
-missing:
-    fprintf(stderr,
-        "SimCFG: <view> requires display/x/y/rotate\n");
-    return false;
-}
-
-/*
- * Handle <image src="zzz" x="123" y="123"/>.
- */
-bool PhoneView::ProcessImage(TiXmlNode* pNode, const char* directory)
-{
-    TiXmlNode* pChild;
-    TiXmlElement* pElem;
-    int x, y;
-    const char* src;
-    LoadableImage tmpLimg;
-    android::String8 fileName;
-
-    pChild = pNode->FirstChild();
-    if (pChild != NULL) {
-        fprintf(stderr, "SimCFG: <image> is funky\n");
-        return false;
-    }
-
-    /*
-     * All attributes are mandatory.
-     */
-    pElem = pNode->ToElement();
-    src = pElem->Attribute("src");
-    if (src == NULL)
-        goto missing;
-    if (pElem->Attribute("x", &x) == NULL)
-        goto missing;
-    if (pElem->Attribute("y", &y) == NULL)
-        goto missing;
-
-    if (strncmp(src, kRelPathMagic, strlen(kRelPathMagic)) == 0) {
-        fileName = src + strlen(kRelPathMagic);
-    } else {
-        fileName = directory;
-        fileName += "/";
-        fileName += src;
-    }
-
-    tmpLimg.Create(fileName, x, y);
-    mImageList.push_back(tmpLimg);
-
-    return true;
-
-missing:
-    fprintf(stderr, "SimCFG: <image> requires src/x/y\n");
-    return false;
-}
-
-/*
- * Handle <button keyCode="zzz" src="zzz" x="123" y="123"/> and
- * <button keyCode="zzz"/>.
- */
-bool PhoneView::ProcessButton(TiXmlNode* pNode, const char* directory)
-{
-    TiXmlNode* pChild;
-    TiXmlElement* pElem;
-    int x, y;
-    const char* keyCode;
-    const char* src;
-    PhoneButton tmpButton;
-    android::String8 fileName;
-
-    pChild = pNode->FirstChild();
-    if (pChild != NULL) {
-        fprintf(stderr, "SimCFG: button is funky\n");
-        return false;
-    }
-
-    /*
-     * Only keyCode is mandatory.  If they specify "src", then "x" and "y"
-     * are also required.
-     */
-    pElem = pNode->ToElement();
-    keyCode = pElem->Attribute("keyCode");
-    if (keyCode == NULL)
-        goto missing;
-
-    src = pElem->Attribute("src");
-    if (src != NULL) {
-        if (pElem->Attribute("x", &x) == NULL)
-            goto missing;
-        if (pElem->Attribute("y", &y) == NULL)
-            goto missing;
-    }
-
-    if (src == NULL)
-        tmpButton.Create(keyCode);
-    else {
-        if (strncmp(src, kRelPathMagic, strlen(kRelPathMagic)) == 0) {
-            fileName = src + strlen(kRelPathMagic);
-        } else {
-            fileName = directory;
-            fileName += "/";
-            fileName += src;
-        }
-        tmpButton.Create(keyCode, fileName, x, y);
-    }
-
-    mButtonList.push_back(tmpButton);
-
-    return true;
-
-missing:
-    fprintf(stderr, "SimCFG: <button> requires keycode and may have src/x/y\n");
-    return false;
-}
-
-
-/*
- * Load all resources associated with the display.
- */
-bool PhoneView::LoadResources(void)
-{
-    typedef List<LoadableImage>::iterator LIter;
-    typedef List<PhoneButton>::iterator BIter;
-
-    for (LIter ii = mImageList.begin(); ii != mImageList.end(); ++ii)
-        (*ii).LoadResources();
-    for (BIter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii)
-        (*ii).LoadResources();
-    return true;
-}
-
-/*
- * Unload all resources associated with the display.
- */
-bool PhoneView::UnloadResources(void)
-{
-    typedef List<LoadableImage>::iterator LIter;
-    typedef List<PhoneButton>::iterator BIter;
-
-    for (LIter ii = mImageList.begin(); ii != mImageList.end(); ++ii)
-        (*ii).UnloadResources();
-    for (BIter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii)
-        (*ii).UnloadResources();
-    return true;
-}
-
-
-/*
- * Get the #of images.
- */
-int PhoneView::GetBkgImageCount(void) const
-{
-    return mImageList.size();
-}
-
-/*
- * Return the Nth entry.
- */
-const LoadableImage* PhoneView::GetBkgImage(int idx) const
-{
-    typedef List<LoadableImage>::const_iterator Iter;
-
-    for (Iter ii = mImageList.begin(); ii != mImageList.end(); ++ii) {
-        if (!idx)
-            return &(*ii);
-        --idx;
-    }
-
-    return NULL;
-}
-
-
-/*
- * Find the first button that covers the specified coordinates.
- *
- * The coordinates must be relative to the upper left corner of the
- * phone image.
- */
-PhoneButton* PhoneView::FindButtonHit(int x, int y)
-{
-    typedef List<PhoneButton>::iterator Iter;
-
-    for (Iter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii) {
-        if ((*ii).CheckCollision(x, y))
-            return &(*ii);
-    }
-
-    return NULL;
-}
-
-/*
- * Find the first button with a matching key code.
- */
-PhoneButton* PhoneView::FindButtonByKey(int32_t keyCode)
-{
-    typedef List<PhoneButton>::iterator Iter;
-
-    for (Iter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii) {
-        if ((*ii).GetKeyCode() == keyCode)
-            return &(*ii);
-    }
-
-    return NULL;
-}
-
-
-/*
- * ===========================================================================
- *      PhoneMode
- * ===========================================================================
- */
-
-/*
- * Process a <mode name="zzz"> chunk.
- */
-bool PhoneMode::ProcessAndValidate(TiXmlNode* pNode, const char* directory)
-{
-    TiXmlNode* pChild;
-    const char* name;
-
-    assert(pNode->Type() == TiXmlNode::ELEMENT);
-
-    name = pNode->ToElement()->Attribute("name");
-    if (name == NULL) {
-        fprintf(stderr, "SimCFG: <mode> requires name attrib\n");
-        return false;
-    }
-    SetName(name);
-
-    for (pChild = pNode->FirstChild(); pChild != NULL;
-        pChild = pChild->NextSibling())
-    {
-        if (pChild->Type() == TiXmlNode::COMMENT)
-            continue;
-
-        if (pChild->Type() == TiXmlNode::ELEMENT &&
-            strcasecmp(pChild->Value(), "view") == 0)
-        {
-            PhoneView tmpDisplay;
-            bool result;
-
-            result = tmpDisplay.ProcessAndValidate(pChild, directory);
-            if (!result)
-                return false;
-
-            mViewList.push_back(tmpDisplay);
-        } else {
-            fprintf(stderr, "SimCFG: Warning: unexpected stuff in <mode>\n");
-        }
-    }
-
-    if (mViewList.size() == 0) {
-        fprintf(stderr, "SimCFG: no <view> entries found\n");
-        return false;
-    }
-
-    return true;
-}
-
-
-/*
- * Load all resources associated with the phone.
- */
-bool PhoneMode::LoadResources(void)
-{
-    typedef List<PhoneView>::iterator Iter;
-
-    for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii)
-        (*ii).LoadResources();
-    return true;
-}
-
-/*
- * Unload all resources associated with the phone.
- */
-bool PhoneMode::UnloadResources(void)
-{
-    typedef List<PhoneView>::iterator Iter;
-
-    for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii)
-        (*ii).UnloadResources();
-    return true;
-}
-
-
-/*
- * Return the Nth entry.  [make this a Vector?]
- */
-PhoneView* PhoneMode::GetPhoneView(int viewNum)
-{
-    typedef List<PhoneView>::iterator Iter;
-
-    for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii) {
-        if (viewNum == 0)
-            return &(*ii);
-        --viewNum;
-    }
-    return NULL;
-}
-
-
-/*
- * ===========================================================================
- *      PhoneData
- * ===========================================================================
- */
-
-
-/*
- * Look for a "layout.xml" in the specified directory.  If found, parse
- * the contents out.
- *
- * Returns "true" on success, "false" on failure.
- */
-bool PhoneData::Create(const char* directory)
-{
-    android::String8 fileName;
-
-    SetDirectory(directory);
-
-    fileName = directory;
-    fileName += "/";
-    fileName += PhoneCollection::kLayoutFile;
-
-#ifdef BEFORE_ASSET
-    TiXmlDocument doc(fileName);
-    if (!doc.LoadFile())
-#else
-    android::AssetManager* pAssetMgr = ((MyApp*)wxTheApp)->GetAssetManager();
-    TiXmlDocument doc;
-    android::Asset* pAsset;
-    bool result;
-
-    pAsset = pAssetMgr->open(fileName, Asset::ACCESS_STREAMING);
-    if (pAsset == NULL) {
-        fprintf(stderr, "Unable to open asset '%s'\n", (const char*) fileName);
-        return false;
-    } else {
-        //printf("--- opened asset '%s'\n",
-        //    (const char*) pAsset->getAssetSource());
-    }
-
-    /* TinyXml insists that the buffer be NULL-terminated... ugh */
-    char* buf = new char[pAsset->getLength() +1];
-    pAsset->read(buf, pAsset->getLength());
-    buf[pAsset->getLength()] = '\0';
-
-    delete pAsset;
-    result = doc.Parse(buf);
-    delete[] buf;
-
-    if (!result)
-#endif
-    {
-        fprintf(stderr, "SimCFG: ERROR: failed parsing '%s'\n",
-            (const char*) fileName);
-        if (doc.ErrorRow() != 0)
-            fprintf(stderr, "    XML: %s (row=%d col=%d)\n",
-                doc.ErrorDesc(), doc.ErrorRow(), doc.ErrorCol());
-        else
-            fprintf(stderr, "    XML: %s\n", doc.ErrorDesc());
-        return false;
-    }
-
-    if (!ProcessAndValidate(&doc)) {
-        fprintf(stderr, "SimCFG: ERROR: failed analyzing '%s'\n",
-            (const char*) fileName);
-        return false;
-    }
-
-    printf("SimCFG: loaded data from '%s'\n", (const char*) fileName);
-
-    return true;
-}
-
-/*
- * TinyXml has loaded and parsed the XML document for us.  We need to
- * run through the DOM tree, pull out the interesting bits, and make
- * sure the stuff we need is present.
- *
- * Returns "true" on success, "false" on failure.
- */
-bool PhoneData::ProcessAndValidate(TiXmlDocument* pDoc)
-{
-    bool deviceFound = false;
-    TiXmlNode* pChild;
-
-    assert(pDoc->Type() == TiXmlNode::DOCUMENT);
-
-    for (pChild = pDoc->FirstChild(); pChild != NULL;
-        pChild = pChild->NextSibling())
-    {
-        /*
-         * Find the <device> entry.  There should be exactly one.
-         */
-        if (pChild->Type() == TiXmlNode::ELEMENT) {
-            if (strcasecmp(pChild->Value(), "device") != 0) {
-                fprintf(stderr,
-                    "SimCFG: Warning: unexpected element '%s' at top level\n",
-                    pChild->Value());
-                continue;
-            }
-            if (deviceFound) {
-                fprintf(stderr, "SimCFG: one <device> per customer\n");
-                return false;
-            }
-
-            bool result = ProcessDevice(pChild);
-            if (!result)
-                return false;
-            deviceFound = true;
-        }
-    }
-
-    if (!deviceFound) {
-        fprintf(stderr, "SimCFG: no <device> section found\n");
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Process a <device name="zzz"> chunk.
- */
-bool PhoneData::ProcessDevice(TiXmlNode* pNode)
-{
-    TiXmlNode* pChild;
-    const char* name;
-
-    assert(pNode->Type() == TiXmlNode::ELEMENT);
-
-    name = pNode->ToElement()->Attribute("name");
-    if (name == NULL) {
-        fprintf(stderr, "SimCFG: <device> requires name attrib\n");
-        return false;
-    }
-    SetName(name);
-
-    /*
-     * Walk through the children and find interesting stuff.
-     *
-     * Might be more correct to process all <display> entries and
-     * then process all <view> entries, since <view> has "pointers"
-     * to <display>.  We're deferring the lookup until later, though,
-     * so for now it doesn't really matter.
-     */
-    for (pChild = pNode->FirstChild(); pChild != NULL;
-        pChild = pChild->NextSibling())
-    {
-        bool result;
-
-        if (pChild->Type() == TiXmlNode::COMMENT)
-            continue;
-
-        if (pChild->Type() == TiXmlNode::ELEMENT &&
-            strcasecmp(pChild->Value(), "title") == 0)
-        {
-            result = ProcessTitle(pChild);
-            if (!result)
-                return false;
-        } else if (pChild->Type() == TiXmlNode::ELEMENT &&
-            strcasecmp(pChild->Value(), "display") == 0)
-        {
-            PhoneDisplay tmpDisplay;
-
-            result = tmpDisplay.ProcessAndValidate(pChild);
-            if (!result)
-                return false;
-
-            mDisplayList.push_back(tmpDisplay);
-        } else if (pChild->Type() == TiXmlNode::ELEMENT &&
-            strcasecmp(pChild->Value(), "keyboard") == 0)
-        {
-            PhoneKeyboard tmpKeyboard;
-            result = tmpKeyboard.ProcessAndValidate(pChild);
-            if (!result)
-                return false;
-                
-            mKeyboardList.push_back(tmpKeyboard);           
-        } else if (pChild->Type() == TiXmlNode::ELEMENT &&
-            strcasecmp(pChild->Value(), "mode") == 0)
-        {
-            PhoneMode tmpMode;
-
-            result = tmpMode.ProcessAndValidate(pChild, mDirectory);
-            if (!result)
-                return false;
-
-            mModeList.push_back(tmpMode);
-        } else {
-            fprintf(stderr, "SimCFG: Warning: unexpected stuff in <device>\n");
-        }
-    }
-
-    if (mDisplayList.size() == 0) {
-        fprintf(stderr, "SimCFG: no <display> entries found\n");
-        return false;
-    }
-    if (mModeList.size() == 0) {
-        fprintf(stderr, "SimCFG: no <mode> entries found\n");
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Handle <title>.
- */
-bool PhoneData::ProcessTitle(TiXmlNode* pNode)
-{
-    TiXmlNode* pChild;
-
-    pChild = pNode->FirstChild();
-    if (pChild->Type() != TiXmlNode::TEXT) {
-        fprintf(stderr, "SimCFG: title is funky\n");
-        return false;
-    }
-
-    SetTitle(pChild->Value());
-    return true;
-}
-
-
-/*
- * Load all resources associated with the phone.
- */
-bool PhoneData::LoadResources(void)
-{
-    typedef List<PhoneMode>::iterator Iter;
-
-    for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii)
-        (*ii).LoadResources();
-    return true;
-}
-
-/*
- * Unload all resources associated with the phone.
- */
-bool PhoneData::UnloadResources(void)
-{
-    typedef List<PhoneMode>::iterator Iter;
-
-    for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii)
-        (*ii).UnloadResources();
-    return true;
-}
-
-
-/*
- * Return the PhoneMode entry with the matching name.
- *
- * Returns NULL if no match was found.
- */
-PhoneMode* PhoneData::GetPhoneMode(const char* modeName)
-{
-    typedef List<PhoneMode>::iterator Iter;
-
-    for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii) {
-        if (strcmp((*ii).GetName(), modeName) == 0)
-            return &(*ii);
-    }
-    return NULL;
-}
-
-/*
- * Return the Nth phone mode entry.
- */
-PhoneMode* PhoneData::GetPhoneMode(int idx)
-{
-    typedef List<PhoneMode>::iterator Iter;
-
-    for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii) {
-        if (!idx)
-            return &(*ii);
-        --idx;
-    }
-    return NULL;
-}
-
-
-/*
- * Return the PhoneDisplay entry with the matching name.
- *
- * Returns NULL if no match was found.
- */
-PhoneDisplay* PhoneData::GetPhoneDisplay(const char* dispName)
-{
-    typedef List<PhoneDisplay>::iterator Iter;
-
-    for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
-        if (strcmp((*ii).GetName(), dispName) == 0)
-            return &(*ii);
-    }
-    return NULL;
-}
-
-/*
- * Return the Nth phone mode entry.
- */
-PhoneDisplay* PhoneData::GetPhoneDisplay(int idx)
-{
-    typedef List<PhoneDisplay>::iterator Iter;
-
-    for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
-        if (!idx)
-            return &(*ii);
-        --idx;
-    }
-    return NULL;
-}
-
-/*
- * Find the PhoneDisplay entry with the matching name, and return its index.
- *
- * Returns -1 if the entry wasn't found.
- */
-int PhoneData::GetPhoneDisplayIndex(const char* dispName)
-{
-    typedef List<PhoneDisplay>::iterator Iter;
-    int idx = 0;
-
-    for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
-        if (strcmp((*ii).GetName(), dispName) == 0)
-            return idx;
-        idx++;
-    }
-    return -1;
-}
-
-
-/*
- * Return the Nth phone keyboard entry.
- */
-PhoneKeyboard* PhoneData::GetPhoneKeyboard(int idx)
-{
-    typedef List<PhoneKeyboard>::iterator Iter;
-
-    for (Iter ii = mKeyboardList.begin(); ii != mKeyboardList.end(); ++ii) {
-        if (!idx)
-            return &(*ii);
-        --idx;
-    }
-    return NULL;
-}
diff --git a/simulator/app/PhoneData.h b/simulator/app/PhoneData.h
deleted file mode 100644
index 5a95796..0000000
--- a/simulator/app/PhoneData.h
+++ /dev/null
@@ -1,365 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Simulated device definition.
-//
-// The "root" of the data structures here is PhoneCollection, which may
-// discard the entire set if the user asks to re-scan the phone definitions.
-// These structures should be considered read-only.
-//
-// PhoneCollection (single global instance)
-//    -->PhoneData
-//       -->PhoneDisplay
-//       -->PhoneMode
-//          -->PhoneView
-//
-#ifndef _SIM_PHONE_DATA_H
-#define _SIM_PHONE_DATA_H
-
-#include <stdio.h>
-#include "tinyxml.h"
-
-#include "PhoneButton.h"
-#include "LoadableImage.h"
-#include <ui/PixelFormat.h>
-#include "utils.h"
-
-
-/*
- * This represents the keyboard type of the simulated device
- */
-class PhoneKeyboard {
-public:
-    PhoneKeyboard(void)
-        : mQwerty(false), mKeyMap(NULL)
-        {}       
-    ~PhoneKeyboard(void) {
-        free((void*)mKeyMap);
-    }    
- 
-    PhoneKeyboard(const PhoneKeyboard& src)
-        : mQwerty(false), mKeyMap(NULL)
-    {
-        CopyMembers(src);
-    }
-    PhoneKeyboard& operator=(const PhoneKeyboard& src) {
-        if (this != &src)       // self-assignment
-            CopyMembers(src);
-        return *this;
-    }
-    void CopyMembers(const PhoneKeyboard& src) {
-        mQwerty = src.mQwerty;
-        mKeyMap = src.mKeyMap ? strdup(src.mKeyMap) : NULL;
-    }
-    
-    bool ProcessAndValidate(TiXmlNode* pNode);
-    
-    bool getQwerty() { return mQwerty; }    
-
-    const char *getKeyMap() { return mKeyMap; }
-private:
-    bool    mQwerty;
-    const char * mKeyMap;
-};
-
-/*
- * This represents a single display device, usually an LCD screen.
- * It also includes an optional surrounding graphic, usually a picture of
- * the device itself.
- */
-class PhoneDisplay {
-public:
-    PhoneDisplay(void)
-        : mName(NULL)
-        {}
-    ~PhoneDisplay(void) {
-        delete[] mName;
-    }
-
-    PhoneDisplay(const PhoneDisplay& src)
-        : mName(NULL)
-    {
-        CopyMembers(src);
-    }
-    PhoneDisplay& operator=(const PhoneDisplay& src) {
-        if (this != &src)       // self-assignment
-            CopyMembers(src);
-        return *this;
-    }
-    void CopyMembers(const PhoneDisplay& src) {
-        // Can't memcpy and member-copy the container classes, because the
-        // containers have already been constructed, and for operator= they
-        // might even have stuff in them.
-        delete[] mName;
-        mName = android::strdupNew(src.mName);
-        mWidth = src.mWidth;
-        mHeight = src.mHeight;
-        mFormat = src.mFormat;
-        mRefresh = src.mRefresh;
-    }
-
-    bool ProcessAndValidate(TiXmlNode* pNode);
-
-    const char* GetName(void) const { return mName; }
-    int GetWidth(void) const { return mWidth; }
-    int GetHeight(void) const { return mHeight; }
-    android::PixelFormat GetFormat(void) const { return mFormat; }
-    int GetRefresh(void) const { return mRefresh; }
-
-    static bool IsCompatible(PhoneDisplay* pDisplay1, PhoneDisplay* pDisplay2);
-
-private:
-    char*           mName;
-
-    // display dimensions, in pixels
-    int             mWidth;
-    int             mHeight;
-
-    // frame buffer format
-    android::PixelFormat mFormat;
-
-    // display refresh rate, in fps
-    int             mRefresh;
-};
-
-/*
- * This is a "view" of a device, which includes the display, a background
- * image, and perhaps some clickable keys for input.
- *
- * Because the key graphics are associated with a particular display, we
- * hold a list of keys here.  (It also allows the possibility of handling
- * a situation where the same key shows up in multiple background images,
- * e.g. a flip phone with a "volume" key on the side.  If we include the
- * key in both places, we can highlight it on both displays.)
- */
-class PhoneView {
-public:
-    PhoneView(void)
-        : mDisplayName(NULL)
-        {}
-    ~PhoneView(void) {
-        delete[] mDisplayName;
-    }
-
-    PhoneView(const PhoneView& src) {
-        CopyMembers(src);
-    }
-    PhoneView& operator=(const PhoneView& src) {
-        if (this != &src)       // self-assignment
-            CopyMembers(src);
-        return *this;
-    }
-    void CopyMembers(const PhoneView& src) {
-        // Can't memcpy and member-copy the container classes, because the
-        // containers have already been constructed, and for operator= they
-        // might even have stuff in them.
-        mImageList = src.mImageList;
-        mButtonList = src.mButtonList;
-        mDisplayName = android::strdupNew(src.mDisplayName);
-        mXOffset = src.mXOffset;
-        mYOffset = src.mYOffset;
-        mRotation = src.mRotation;
-    }
-
-    // load or unload resources, e.g. wxBitmaps from image files
-    bool LoadResources(void);
-    bool UnloadResources(void);
-
-    // simple accessors
-    int GetXOffset(void) const { return mXOffset; }
-    int GetYOffset(void) const { return mYOffset; }
-    const char* GetDisplayName(void) const { return mDisplayName; }
-
-    // image list access
-    int GetBkgImageCount(void) const;
-    const LoadableImage* GetBkgImage(int idx) const;
-
-    // find the first button that covers the specified coords
-    PhoneButton* FindButtonHit(int x, int y);
-
-    // find the first button with a matching key code
-    PhoneButton* FindButtonByKey(int32_t keyCode);
-
-    bool ProcessAndValidate(TiXmlNode* pNode, const char* directory);
-    bool ProcessImage(TiXmlNode* pNode, const char* directory);
-    bool ProcessButton(TiXmlNode* pNode, const char* directory);
-
-private:
-    // background images for the phone picture that surrounds the display
-    android::List<LoadableImage> mImageList;
-
-    // list of accessible buttons, some of which have highlight graphics
-    android::List<PhoneButton>  mButtonList;
-
-    char*           mDisplayName;
-
-    // these determine where in the image the display output goes
-    int             mXOffset;
-    int             mYOffset;
-
-    // clockwise rotation of the output; sim must rotate in opposite direction
-    typedef enum Rotation {
-        kRotUnknown = 0,
-        kRot0,
-        kRot90,
-        kRot180,
-        kRot270,
-    } Rotation;
-    Rotation        mRotation;
-};
-
-/*
- * One mode of a phone.  Simple devices only have one mode.  Flip phones
- * have two (opened and closed).  Other devices might have more.  The
- * mode is communicated to the runtime because it may need to process
- * input events differently.
- */
-class PhoneMode {
-public:
-    PhoneMode(void)
-        : mName(NULL)
-        {}
-    ~PhoneMode(void) {
-        delete[] mName;
-    }
-
-    PhoneMode(const PhoneMode& src)
-        : mName(NULL)
-    {
-        CopyMembers(src);
-    }
-    PhoneMode& operator=(const PhoneMode& src) {
-        if (this != &src)       // self-assignment
-            CopyMembers(src);
-        return *this;
-    }
-    void CopyMembers(const PhoneMode& src) {
-        delete[] mName;
-        mName = android::strdupNew(src.mName);
-        mViewList = src.mViewList;
-    }
-
-
-    // load or unload resources for this object and all members of mViewList
-    bool LoadResources(void);
-    bool UnloadResources(void);
-
-    // get the #of views
-    int GetNumViews(void) const { return mViewList.size(); }
-    // get the Nth display
-    PhoneView* GetPhoneView(int viewNum);
-
-    const char* GetName(void) const { return mName; }
-    void SetName(const char* name) {
-        delete[] mName;
-        mName = android::strdupNew(name);
-    }
-
-    // load the <mode> section from the config file
-    bool ProcessAndValidate(TiXmlNode* pNode, const char* directory);
-
-private:
-    char*           mName;
-
-    android::List<PhoneView> mViewList;
-};
-
-/*
- * This holds the data for one device.
- *
- * Each device may have multiple "modes", e.g. a flip-phone that can be
- * open or shut.  Each mode has different configurations for the visible
- * displays and active keys.
- */
-class PhoneData {
-public:
-    PhoneData(void) :
-        mName(NULL), mTitle(NULL), mDirectory(NULL)
-        {}
-    virtual ~PhoneData(void) {
-        delete[] mName;
-        delete[] mTitle;
-        delete[] mDirectory;
-    }
-
-    PhoneData(const PhoneData& src)
-        : mName(NULL), mTitle(NULL), mDirectory(NULL)
-    {
-        CopyMembers(src);
-    }
-    PhoneData& operator=(const PhoneData& src) {
-        if (this != &src)       // self-assignment
-            CopyMembers(src);
-        return *this;
-    }
-    void CopyMembers(const PhoneData& src) {
-        delete[] mName;
-        delete[] mTitle;
-        delete[] mDirectory;
-        mName = android::strdupNew(src.mName);
-        mTitle = android::strdupNew(src.mTitle);
-        mDirectory = android::strdupNew(src.mDirectory);
-        mModeList = src.mModeList;
-        mDisplayList = src.mDisplayList;
-        mKeyboardList = src.mKeyboardList;
-    }
-
-    // initialize the object with the phone data in the specified dir
-    bool Create(const char* directory);
-
-    // load or unload resources, e.g. wxBitmaps from image files
-    bool LoadResources(void);
-    bool UnloadResources(void);
-
-    // simple accessors
-    const char* GetName(void) const { return mName; }
-    void SetName(const char* name) {
-        delete[] mName;
-        mName = android::strdupNew(name);
-    }
-    const char* GetTitle(void) const { return mTitle; }
-    void SetTitle(const char* title) {
-        delete[] mTitle;
-        mTitle = android::strdupNew(title);
-    }
-    const char* GetDirectory(void) const { return mDirectory; }
-    void SetDirectory(const char* dir) {
-        delete[] mDirectory;
-        mDirectory = android::strdupNew(dir);
-    }
-
-    
-    // get number of modes
-    int GetNumModes(void) const { return mModeList.size(); }
-    // get the specified mode object
-    PhoneMode* GetPhoneMode(int idx);
-    PhoneMode* GetPhoneMode(const char* modeName);
-
-    // get number of displays
-    int GetNumDisplays(void) const { return mDisplayList.size(); }
-    // get the specified display object
-    PhoneDisplay* GetPhoneDisplay(int idx);
-    PhoneDisplay* GetPhoneDisplay(const char* displayName);
-    // get the index of the matching display
-    int GetPhoneDisplayIndex(const char* displayName);
-
-    // get number of keyboards
-    int GetNumKeyboards(void) const { return mKeyboardList.size(); }
-    // get the specified display object
-    PhoneKeyboard* GetPhoneKeyboard(int idx);
-    
-private:
-    bool ProcessAndValidate(TiXmlDocument* pDoc);
-    bool ProcessDevice(TiXmlNode* pNode);
-    bool ProcessTitle(TiXmlNode* pNode);
-
-    char*           mName;
-    char*           mTitle;
-    char*           mDirectory;
-
-    android::List<PhoneMode> mModeList;
-    android::List<PhoneDisplay> mDisplayList;
-    android::List<PhoneKeyboard> mKeyboardList;
-};
-
-#endif // _SIM_PHONE_DATA_H
diff --git a/simulator/app/PhoneWindow.cpp b/simulator/app/PhoneWindow.cpp
deleted file mode 100644
index 0a87762..0000000
--- a/simulator/app/PhoneWindow.cpp
+++ /dev/null
@@ -1,1051 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Displays the phone image and handles user input.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h"   // needed for Windows build
-#include "wx/dcbuffer.h"
-
-#include "LinuxKeys.h"
-#include "PhoneWindow.h"
-#include "DeviceWindow.h"
-#include "PhoneData.h"
-#include "PhoneCollection.h"
-#include "MainFrame.h"
-#include "MyApp.h"
-
-using namespace android;
-
-BEGIN_EVENT_TABLE(PhoneWindow, wxWindow)    // NOT wxDialog
-    EVT_ACTIVATE(PhoneWindow::OnActivate)
-    //EVT_ACTIVATE_APP(PhoneWindow::OnActivate)
-    EVT_CLOSE(PhoneWindow::OnClose)
-    EVT_MOVE(PhoneWindow::OnMove)
-    EVT_ERASE_BACKGROUND(PhoneWindow::OnErase)
-    EVT_PAINT(PhoneWindow::OnPaint)
-
-    EVT_KEY_DOWN(PhoneWindow::OnKeyDown)
-    EVT_KEY_UP(PhoneWindow::OnKeyUp)
-    EVT_LEFT_DOWN(PhoneWindow::OnMouseLeftDown)
-    EVT_LEFT_DCLICK(PhoneWindow::OnMouseLeftDown)
-    EVT_LEFT_UP(PhoneWindow::OnMouseLeftUp)
-    EVT_RIGHT_DOWN(PhoneWindow::OnMouseRightDown)
-    EVT_RIGHT_DCLICK(PhoneWindow::OnMouseRightDown)
-    EVT_RIGHT_UP(PhoneWindow::OnMouseRightUp)
-    EVT_MOTION(PhoneWindow::OnMouseMotion)
-    EVT_LEAVE_WINDOW(PhoneWindow::OnMouseLeaveWindow)
-    EVT_TIMER(kVibrateTimerId, PhoneWindow::OnTimer)
-END_EVENT_TABLE()
-
-
-/*
- * Create a new PhoneWindow.  This should be a child of the main frame.
- */
-PhoneWindow::PhoneWindow(wxWindow* parent, const wxPoint& posn)
-    : wxDialog(parent, wxID_ANY, wxT("Device"), posn, wxDefaultSize,
-        wxDEFAULT_DIALOG_STYLE),
-      mpMOHViewIndex(-1),
-      mpMOHButton(NULL),
-      mMouseKeySent(AKEYCODE_UNKNOWN),
-      mpViewInfo(NULL),
-      mNumViewInfo(0),
-      mpDeviceWindow(NULL),
-      mNumDeviceWindows(0),
-      mPhoneModel(-1),
-      mCurrentMode(wxT("(unknown)")),
-      mPlacementChecked(false),
-      mpParent((MainFrame*)parent),
-      mTimer(this, kVibrateTimerId),
-      mTrackingTouch(false)
-{
-    SetBackgroundColour(*wxLIGHT_GREY);
-    SetBackgroundStyle(wxBG_STYLE_CUSTOM);
-
-    //SetCursor(wxCursor(wxCURSOR_HAND));     // a bit distracting (pg.276)
-}
-
-/*
- * Destroy everything we own.
- *
- * This might be called well after we've been closed and another
- * PhoneWindow has been created, because wxWidgets likes to defer things.
- */
-PhoneWindow::~PhoneWindow(void)
-{
-    //printf("--- ~PhoneWindow %p\n", this);
-    delete[] mpViewInfo;
-    if (mpDeviceWindow != NULL) {
-        for (int i = 0; i < mNumDeviceWindows; i++) {
-            /* make sure they don't try to use our member */
-            mpDeviceWindow[i]->DeviceManagerClosing();
-            /* make sure the child window gets destroyed -- not necessary? */
-            mpDeviceWindow[i]->Destroy();
-        }
-
-        /* delete our array of pointers */
-        delete[] mpDeviceWindow;
-    }
-}
-
-/*
- * Check for an updated runtime when window becomes active
- */
-void PhoneWindow::OnActivate(wxActivateEvent& event)
-{
-    /*
-     * DO NOT do this.  Under Windows, it causes the parent window to get
-     * an activate event, which causes our parent to get the focus.  With
-     * this bit of code active it is impossible for the phone window to
-     * receive user input.
-     */
-    //GetParent()->AddPendingEvent(event);
-
-    // If we are being deactivated, go ahead and send key up events so that the
-    // runtime doesn't think we are holding down the key. Issue #685750
-    if (!event.GetActive()) {
-        ListIter iter;
-        for (iter = mPressedKeys.begin(); iter != mPressedKeys.end(); ) {
-            int32_t keyCode = (*iter).GetKeyCode();
-            GetDeviceManager()->SendKeyEvent(keyCode, false);
-            iter = mPressedKeys.erase(iter);
-        }
-    }
-}
-
-/*
- * Close the phone window.
- */
-void PhoneWindow::OnClose(wxCloseEvent& event)
-{
-    //printf("--- PhoneWindow::OnClose %p\n", this);
-#if 0
-    if (mDeviceManager.IsRunning() && !mDeviceManager.IsKillable()) {
-        printf("Sim: refusing to close window on external runtime\n");
-        event.Veto();
-        return;
-    }
-#endif
-
-    wxRect rect = GetRect();
-    printf("Sim: Closing phone window (posn=(%d,%d))\n", rect.x, rect.y);
-
-    /* notify others */
-    mpParent->PhoneWindowClosing(rect.x, rect.y);
-    mDeviceManager.WindowsClosing();
-
-    /* end it all */
-    Destroy();
-}
-
-/*
- * Prep the PhoneWindow to display a specific phone model.  Pass in the
- * model index.
- *
- * This gets called whenever the display changes.  This could be a new
- * device with identical characteristics, or a different mode for the same
- * device.
- *
- * The window can be re-used so long as the display characteristics are
- * the same.  If the display characteristics are different, we have to
- * restart the device.
- */
-bool PhoneWindow::Setup(int phoneIdx)
-{
-    wxString fileName;
-    PhoneCollection* pCollection = PhoneCollection::GetInstance();
-
-    if (phoneIdx < 0 || phoneIdx >= pCollection->GetPhoneCount()) {
-        fprintf(stderr, "Bogus phone index %d\n", phoneIdx);
-        return false;
-    }
-
-    /*
-     * Clear these out so that failure here is noticeable to caller.  We
-     * regenerate the ViewInfo array every time, because the set of Views
-     * is different for every Mode.
-     */
-    delete[] mpViewInfo;
-    mpViewInfo = NULL;
-    mNumViewInfo = -1;
-
-    PhoneData* pPhoneData;
-    PhoneMode* pPhoneMode;
-    PhoneView* pPhoneView;
-
-    pPhoneData = pCollection->GetPhoneData(phoneIdx);
-
-    pPhoneMode = pPhoneData->GetPhoneMode(GetCurrentMode().ToAscii());
-    if (pPhoneMode == NULL) {
-        fprintf(stderr, "current mode (%s) not known\n",
-            (const char*) GetCurrentMode().ToAscii());
-        return false;
-    }
-
-    int numViews = pPhoneMode->GetNumViews();
-    if (numViews == 0) {
-        fprintf(stderr, "Phone %d mode %s has no views\n",
-            phoneIdx, pPhoneMode->GetName());
-        return false;
-    }
-
-    const int kBorder = 2;
-    int i;
-    int maxHeight = 0;
-    int fullWidth = kBorder;
-    ViewInfo* pViewInfo;
-
-    pViewInfo = new ViewInfo[numViews];
-
-    /* figure out individual and overall dimensions */
-    for (i = 0; i < numViews; i++) {
-        pPhoneView = pPhoneMode->GetPhoneView(i);
-        if (pPhoneView == NULL) {
-            fprintf(stderr, "view %d not found\n", i);
-            return false;
-        }
-
-        if (!GetDimensions(pPhoneData, pPhoneView, &pViewInfo[i]))
-            return false;
-
-        if (maxHeight < pViewInfo[i].GetHeight())
-            maxHeight = pViewInfo[i].GetHeight();
-        fullWidth += pViewInfo[i].GetWidth() + kBorder;
-    }
-
-    /* create the device windows if we don't already have them */
-    if (mpDeviceWindow == NULL) {
-        mNumDeviceWindows = pPhoneData->GetNumDisplays();
-        mpDeviceWindow = new DeviceWindow*[mNumDeviceWindows];
-        if (mpDeviceWindow == NULL)
-            return false;
-
-        for (i = 0; i < mNumDeviceWindows; i++) {
-            mpDeviceWindow[i] = new DeviceWindow(this, &mDeviceManager);
-        }
-    } else {
-        assert(pPhoneData->GetNumDisplays() == mNumDeviceWindows);
-    }
-
-    /*
-     * Position device windows within their views, taking into account
-     * border areas.
-     */
-    int shift = kBorder;
-    for (i = 0; i < numViews; i++) {
-        int displayIdx;
-        PhoneDisplay* pPhoneDisplay;
-
-        displayIdx = pViewInfo[i].GetDisplayIndex();
-        pPhoneDisplay = pPhoneData->GetPhoneDisplay(displayIdx);
-        //printf("View %d: display %d\n", i, displayIdx);
-
-        pViewInfo[i].SetX(shift);
-        pViewInfo[i].SetY(kBorder);
-
-        mpDeviceWindow[displayIdx]->SetSize(
-            pViewInfo[i].GetX() + pViewInfo[i].GetDisplayX(),
-            pViewInfo[i].GetY() + pViewInfo[i].GetDisplayY(),
-            pPhoneDisplay->GetWidth(), pPhoneDisplay->GetHeight());
-
-        // incr by width of view
-        shift += pViewInfo[i].GetWidth() + kBorder;
-    }
-
-    /* configure the device manager if it's not already running */
-    if (!mDeviceManager.IsInitialized()) {
-        mDeviceManager.Init(pPhoneData->GetNumDisplays(), mpParent);
-
-        for (i = 0; i < pPhoneData->GetNumDisplays(); i++) {
-            PhoneDisplay* pPhoneDisplay;
-            bool res;
-
-            pPhoneDisplay = pPhoneData->GetPhoneDisplay(i);
-
-            res = mDeviceManager.SetDisplayConfig(i, mpDeviceWindow[i],
-                pPhoneDisplay->GetWidth(), pPhoneDisplay->GetHeight(),
-                pPhoneDisplay->GetFormat(), pPhoneDisplay->GetRefresh());
-            if (!res) {
-                fprintf(stderr, "Sim: ERROR: could not configure device mgr\n");
-                return false;
-            }
-        }
-        const char *kmap = pPhoneData->GetPhoneKeyboard(0)->getKeyMap();
-        mDeviceManager.SetKeyboardConfig(kmap);
-    } else {
-        assert(pPhoneData->GetNumDisplays() == mDeviceManager.GetNumDisplays());
-    }
-
-    /*
-     * Success.  Finish up.
-     */
-    mPhoneModel = phoneIdx;
-    mpViewInfo = pViewInfo;
-    mNumViewInfo = numViews;
-
-    /* set up our window */
-    SetClientSize(fullWidth, maxHeight + kBorder * 2);
-    SetBackgroundColour(*wxLIGHT_GREY);
-    //SetBackgroundColour(*wxBLUE);
-    SetTitle(wxString::FromAscii(pPhoneData->GetTitle()));
-
-    SetFocus();     // set keyboard input focus
-
-    return true;
-}
-
-/*
- * The device table has been reloaded.  We need to throw out any pointers
- * we had into it and possibly reload some stuff.
- */
-void PhoneWindow::DevicesRescanned(void)
-{
-    mpMOHButton = NULL;
-    mpMOHViewIndex = -1;
-
-    /*
-     * Re-evaluate phone definition.  There is an implicit assumption
-     * that the re-scanned version is compatible with the previous
-     * version (i.e. it still exists and has the same screen size).
-     *
-     * We're also currently assuming that no phone definitions have been
-     * added or removed, which is bad -- we should get the new index for
-     * for phone by searching for it by name.
-     *
-     * TODO: don't make these assumptions.
-     */
-    Setup(mPhoneModel);
-}
-
-/*
- * Check the initial placement of the window.  We get one of these messages
- * when the window is first placed, and every time it's moved thereafter.
- *
- * Right now we're just trying to make sure wxWidgets doesn't shove it off
- * the top of the screen under Linux.  Might want to change this to
- * remember the previous placement and put the window back.
- */
-void PhoneWindow::OnMove(wxMoveEvent& event)
-{
-    if (mPlacementChecked)
-        return;
-
-    wxPoint point;
-    point = event.GetPosition();
-    if (point.y < 0) {
-        printf("Sim: window is at (%d,%d), adjusting\n", point.x, point.y);
-        point.y = 0;
-        Move(point);
-    }
-
-    mPlacementChecked = true;
-}
-
-/*
- * Figure out the dimensions required to contain the specified view.
- *
- * This is usually the size of the background image, but if we can't
- * load it or it's too small just create a trivial window.
- */
-bool PhoneWindow::GetDimensions(PhoneData* pPhoneData, PhoneView* pPhoneView,
-    ViewInfo* pInfo)
-{
-    PhoneDisplay* pPhoneDisplay;
-    int xoff=0, yoff=0, width, height;
-    int displayIdx;
-
-    displayIdx = pPhoneData->GetPhoneDisplayIndex(pPhoneView->GetDisplayName());
-    if (displayIdx < 0)
-        return false;
-
-    pPhoneDisplay = pPhoneData->GetPhoneDisplay(displayIdx);
-    if (pPhoneDisplay == NULL) {
-        fprintf(stderr, "display '%s' not found in device '%s'\n",
-            pPhoneView->GetDisplayName(), pPhoneData->GetName());
-        return false;
-    }
-
-    // load images for this phone
-    (void) pPhoneView->LoadResources();
-
-    width = height = 0;
-
-    // by convention, the background bitmap is the first image in the list
-    if (pPhoneView->GetBkgImageCount() > 0) {
-        wxBitmap* pBitmap = pPhoneView->GetBkgImage(0)->GetBitmap();
-        if (pBitmap != NULL) {
-            // size window to match bitmap
-            xoff = pPhoneView->GetXOffset();
-            yoff = pPhoneView->GetYOffset();
-            width = pBitmap->GetWidth();
-            height = pBitmap->GetHeight();
-        }
-    }
-
-    // no bitmap, or bitmap is smaller than display
-    if (width < pPhoneDisplay->GetWidth() ||
-        height < pPhoneDisplay->GetHeight())
-    {
-        // create window to just hold display
-        xoff = yoff = 0;
-        width = pPhoneDisplay->GetWidth();
-        height = pPhoneDisplay->GetHeight();
-    }
-    if (width <= 0 || height <= 0) {
-        fprintf(stderr, "ERROR: couldn't determine display size\n");
-        return false;
-    }
-
-    pInfo->SetX(0);
-    pInfo->SetY(0);             // another function determines these
-    pInfo->SetDisplayX(xoff);
-    pInfo->SetDisplayY(yoff);
-    pInfo->SetWidth(width);
-    pInfo->SetHeight(height);
-    pInfo->SetDisplayIndex(displayIdx);
-
-    //printf("xoff=%d yoff=%d width=%d height=%d index=%d\n",
-    //    pInfo->GetDisplayX(), pInfo->GetDisplayY(),
-    //    pInfo->GetWidth(), pInfo->GetHeight(), pInfo->GetDisplayIndex());
-
-    return true;
-}
-
-/*
- * Return PhoneData pointer for the current phone model.
- */
-PhoneData* PhoneWindow::GetPhoneData(void) const
-{
-    PhoneCollection* pCollection = PhoneCollection::GetInstance();
-    return pCollection->GetPhoneData(mPhoneModel);
-}
-
-/*
- * Convert a wxWidgets key code into a device key code.
- *
- * Someday we may want to make this configurable.
- *
- * NOTE: we need to create a mapping between simulator key and desired
- * function.  The "return" key should always mean "select", whether
- * it's a "select" button or pressing in on the d-pad.  Ditto for
- * the arrow keys, whether we have a joystick, d-pad, or four buttons.
- * Each key here should have a set of things that it could possibly be,
- * and we match it up with the set of buttons actually defined for the
- * phone.  [for convenience, need to ensure that buttons need not have
- * an associated image]
- */
-int PhoneWindow::ConvertKeyCode(int wxKeyCode) const
-{
-    switch (wxKeyCode) {
-    case WXK_NUMPAD_INSERT:
-    case WXK_NUMPAD0:
-    case '0':                   return KEY_0;
-    case WXK_NUMPAD_HOME:
-    case WXK_NUMPAD1:
-    case '1':                   return KEY_1;
-    case WXK_NUMPAD_UP:
-    case WXK_NUMPAD2:
-    case '2':                   return KEY_2;
-    case WXK_NUMPAD_PRIOR:
-    case WXK_NUMPAD3:
-    case '3':                   return KEY_3;
-    case WXK_NUMPAD_LEFT:
-    case WXK_NUMPAD4:
-    case '4':                   return KEY_4;
-    case WXK_NUMPAD_BEGIN:
-    case WXK_NUMPAD5:
-    case '5':                   return KEY_5;
-    case WXK_NUMPAD_RIGHT:
-    case WXK_NUMPAD6:
-    case '6':                   return KEY_6;
-    case WXK_NUMPAD_END:
-    case WXK_NUMPAD7:
-    case '7':                   return KEY_7;
-    case WXK_NUMPAD_DOWN:
-    case WXK_NUMPAD8:
-    case '8':                   return KEY_8;
-    case WXK_NUMPAD_NEXT:
-    case WXK_NUMPAD9:
-    case '9':                   return KEY_9;
-    case WXK_NUMPAD_MULTIPLY:   return KEY_SWITCHVIDEOMODE; //AKEYCODE_STAR;
-    case WXK_LEFT:              return KEY_LEFT;
-    case WXK_RIGHT:             return KEY_RIGHT;
-    case WXK_UP:                return KEY_UP;
-    case WXK_DOWN:              return KEY_DOWN;
-    case WXK_NUMPAD_ENTER:      return KEY_REPLY; //AKEYCODE_DPAD_CENTER;
-    case WXK_HOME:              return KEY_HOME;
-    case WXK_PRIOR:
-    case WXK_PAGEUP:            return KEY_MENU; //AKEYCODE_SOFT_LEFT;
-    case WXK_NEXT:
-    case WXK_PAGEDOWN:          return KEY_KBDILLUMUP; //AKEYCODE_SOFT_RIGHT;
-    case WXK_DELETE:            
-    case WXK_BACK:              return KEY_BACKSPACE; //AKEYCODE_DEL;
-    case WXK_ESCAPE:
-    case WXK_END:               return KEY_BACK; //AKEYCODE_BACK;
-    case WXK_NUMPAD_DELETE:
-    case WXK_NUMPAD_DECIMAL:    return KEY_KBDILLUMTOGGLE; //AKEYCODE_POUND;
-    case WXK_SPACE:             return KEY_SPACE; //AKEYCODE_SPACE;
-    case WXK_RETURN:            return KEY_ENTER; //AKEYCODE_ENTER;
-    case WXK_F3:                return KEY_F3; //AKEYCODE_CALL;
-    case WXK_F4:                return KEY_F4; //AKEYCODE_END_CALL;
-    case WXK_NUMPAD_ADD:
-    case WXK_F5:                return KEY_VOLUMEUP;
-    case WXK_NUMPAD_SUBTRACT:
-    case WXK_F6:                return KEY_VOLUMEDOWN;
-    case WXK_F7:                return KEY_POWER;
-    case WXK_F8:                return KEY_CAMERA;
-    case 'A':                   return KEY_A;
-    case 'B':                   return KEY_B;
-    case 'C':                   return KEY_C;
-    case 'D':                   return KEY_D;
-    case 'E':                   return KEY_E;
-    case 'F':                   return KEY_F;
-    case 'G':                   return KEY_G;
-    case 'H':                   return KEY_H;
-    case 'I':                   return KEY_I;
-    case 'J':                   return KEY_J;
-    case 'K':                   return KEY_K;
-    case 'L':                   return KEY_L;
-    case 'M':                   return KEY_M;
-    case 'N':                   return KEY_N;
-    case 'O':                   return KEY_O;
-    case 'P':                   return KEY_P;
-    case 'Q':                   return KEY_Q;
-    case 'R':                   return KEY_R;
-    case 'S':                   return KEY_S;
-    case 'T':                   return KEY_T;
-    case 'U':                   return KEY_U;
-    case 'V':                   return KEY_V;
-    case 'W':                   return KEY_W;
-    case 'X':                   return KEY_X;
-    case 'Y':                   return KEY_Y;
-    case 'Z':                   return KEY_Z;
-    case ',':                   return KEY_COMMA;
-    case '.':                   return KEY_DOT;
-    case '<':                   return KEY_COMMA;
-    case '>':                   return KEY_DOT;
-    case '`':                   return KEY_GREEN; /*KEY_GRAVE;*/
-    case '-':                   return KEY_MINUS;
-    case '=':                   return KEY_EQUAL;
-    case '[':                   return KEY_LEFTBRACE;
-    case ']':                   return KEY_RIGHTBRACE;
-    case '\\':                  return KEY_BACKSLASH;
-    case ';':                   return KEY_SEMICOLON;
-    case '\'':                  return KEY_APOSTROPHE;
-    case '/':                   return KEY_SLASH;
-    case WXK_SHIFT:             return KEY_LEFTSHIFT;
-    case WXK_CONTROL:
-    case WXK_ALT:               return KEY_LEFTALT;
-    case WXK_TAB:               return KEY_TAB;
-    // don't show "ignoring key" message for these
-    case WXK_MENU:
-        break;
-    default:
-        printf("(ignoring key %d)\n", wxKeyCode);
-        break;
-    }
-
-    return AKEYCODE_UNKNOWN;
-}
-
-
-/*
- * Keyboard handling.  These get converted into Android-defined key
- * constants here.
- *
- * NOTE: would be nice to handle menu keyboard accelerators here.
- * Simply stuffing the key events into MainFrame with AddPendingEvent
- * didn't seem to do the trick.
- */
-void PhoneWindow::OnKeyDown(wxKeyEvent& event)
-{
-    int32_t keyCode;
-
-    keyCode = ConvertKeyCode(event.GetKeyCode());
-    if (keyCode != AKEYCODE_UNKNOWN) {
-        if (!IsKeyPressed(keyCode)) {
-            //printf("PW: down: key %d\n", keyCode);
-            GetDeviceManager()->SendKeyEvent(keyCode, true);
-            AddPressedKey(keyCode);
-        }
-    } else {
-        //printf("PW: down: %d\n", event.GetKeyCode());
-        event.Skip();       // not handled by us
-    }
-}
-
-/*
- * Pass key-up events to runtime.
- */
-void PhoneWindow::OnKeyUp(wxKeyEvent& event)
-{
-    int32_t keyCode;
-
-    keyCode = ConvertKeyCode(event.GetKeyCode());
-    if (keyCode != AKEYCODE_UNKNOWN) {
-        // Send the key event if we already have this key pressed.
-        if (IsKeyPressed(keyCode)) {
-            //printf("PW:   up: key %d\n", keyCode);
-            GetDeviceManager()->SendKeyEvent(keyCode, false);
-            RemovePressedKey(keyCode);
-        }
-    } else {
-        //printf("PW:   up: %d\n", event.GetKeyCode());
-        event.Skip();       // not handled by us
-    }
-}
-
-/*
- * Mouse handling.
- *
- * Unlike more conventional button tracking, we highlight on mouse-over
- * and send the key on mouse-down.  This behavior may be confusing for
- * people expecting standard behavior, but it allows us to simulate the
- * effect of holding a key down.
- *
- * We want to catch both "down" and "double click" events; otherwise
- * fast clicking results in a lot of discarded events.
- */
-void PhoneWindow::OnMouseLeftDown(wxMouseEvent& event)
-{
-    if (mpMOHButton != NULL) {
-        //printf("PW: left down\n");
-        int32_t keyCode = mpMOHButton->GetKeyCode();
-        GetDeviceManager()->SendKeyEvent(keyCode, true);
-        mMouseKeySent = keyCode;
-        AddPressedKey(keyCode);
-    } else {
-        int screenX, screenY;
-
-        if (GetTouchPosition(event, &screenX, &screenY)) {
-            //printf("TOUCH at %d,%d\n", screenX, screenY);
-            mTrackingTouch = true;
-            mTouchX = screenX;
-            mTouchY = screenY;
-            GetDeviceManager()->SendTouchEvent(Simulator::kTouchDown,
-                mTouchX, mTouchY);
-        } else {
-            //printf("(ignoring left click)\n");
-        }
-    }
-}
-
-/*
- * Left button has been released.  Do something clever.
- *
- * On some platforms we will lose this if the mouse leaves the window.
- */
-void PhoneWindow::OnMouseLeftUp(wxMouseEvent& WXUNUSED(event))
-{
-    if (mMouseKeySent != AKEYCODE_UNKNOWN) {
-        //printf("PW: left up\n");
-        GetDeviceManager()->SendKeyEvent(mMouseKeySent, false);
-        RemovePressedKey(mMouseKeySent);
-    } else {
-        if (mTrackingTouch) {
-            //printf("TOUCH release (last was %d,%d)\n", mTouchX, mTouchY);
-            mTrackingTouch = false;
-            GetDeviceManager()->SendTouchEvent(Simulator::kTouchUp,
-                mTouchX, mTouchY);
-        } else {
-            //printf("(ignoring left-up)\n");
-        }
-    }
-    mMouseKeySent = AKEYCODE_UNKNOWN;
-}
-
-void PhoneWindow::OnMouseRightDown(wxMouseEvent& event)
-{
-    //printf("(ignoring right-down)\n");
-}
-void PhoneWindow::OnMouseRightUp(wxMouseEvent& event)
-{
-    //printf("(ignoring right-up)\n");
-}
-
-/*
- * Track mouse motion so we can do mouse-over button highlighting.
- */
-void PhoneWindow::OnMouseMotion(wxMouseEvent& event)
-{
-    /*
-     * If the mouse motion event occurred inside the device window,
-     * we treat it differently than mouse movement over the picture of
-     * the device.
-     */
-    if (event.GetEventObject() == mpDeviceWindow[0]) {
-        if (mpMOHViewIndex >= 0) {
-            /* can happen if the mouse moves fast enough */
-            //printf("Mouse now in dev window, clearing button highlight\n");
-            mpMOHViewIndex = -1;
-            mpMOHButton = NULL;
-            Refresh();
-        }
-
-        if (!event.LeftIsDown() && event.RightIsDown()) {
-            /* right-button movement */
-            //printf("(ignoring right-drag)\n");
-            return;
-        }
-
-        //printf("moveto: %d,%d\n", event.m_x, event.m_y);
-
-        int screenX, screenY;
-        if (mTrackingTouch) {
-            if (GetTouchPosition(event, &screenX, &screenY)) {
-                //printf("TOUCH moved to %d,%d\n", screenX, screenY);
-                mTouchX = screenX;
-                mTouchY = screenY;
-                GetDeviceManager()->SendTouchEvent(Simulator::kTouchDrag,
-                    mTouchX, mTouchY);
-            } else {
-                //printf("TOUCH moved off screen\n");
-            }
-        }
-
-        return;
-    }
-
-    PhoneData* pPhoneData = GetPhoneData();
-    if (pPhoneData == NULL)
-        return;
-
-    /*
-     * Check to see if we're on top of a button.  If our "on top of
-     * something" state has changed, force a redraw.
-     *
-     * We have to run through the list of Views and check all of the
-     * buttons in each.
-     */
-    PhoneMode* pMode = pPhoneData->GetPhoneMode(GetCurrentMode().ToAscii());
-    if (pMode == NULL)
-        return;
-
-    int viewIndex = -1;
-    PhoneButton* pHighlight = NULL;
-    int i;
-
-    for (i = pMode->GetNumViews()-1; i >= 0; i--) {
-        PhoneView* pView = pMode->GetPhoneView(i);
-        assert(pView != NULL);
-
-        /* convert from window-relative to view-relative */
-        pHighlight = pView->FindButtonHit(event.m_x - mpViewInfo[i].GetX(),
-                                          event.m_y - mpViewInfo[i].GetY());
-        if (pHighlight != NULL) {
-            viewIndex = i;
-            break;
-        }
-    }
-
-    if (viewIndex == mpMOHViewIndex && pHighlight == mpMOHButton) {
-        /* still hovering over same button */
-    } else {
-        /* mouse has moved, possibly to a new button */
-
-        mpMOHViewIndex = viewIndex;
-        mpMOHButton = pHighlight;
-
-        /* force refresh */
-        Refresh();
-    }
-}
-
-/*
- * Mouse has left the building.  All keys and mouse buttons up.
- *
- * We get one of these if the mouse moves over a child window, such as
- * our DeviceWindow, so it is not the case that we no longer receive
- * key input after getting this event.
- */
-void PhoneWindow::OnMouseLeaveWindow(wxMouseEvent& WXUNUSED(event))
-{
-    //printf("--- mouse is GONE\n");
-    ClearPressedKeys();
-}
-
-/*
- * Determine device touch screen (x,y) based on window position.
- *
- * Returns "true" if the click corresponds to a location on the display.
- *
- * TODO: should return display index as well -- currently this only
- * supports touch on the main display.
- */
-bool PhoneWindow::GetTouchPosition(const wxMouseEvent& event, int* pScreenX,
-    int* pScreenY)
-{
-    /*
-     * If the click came from our device window, treat it as a touch.
-     */
-    if (event.GetEventObject() != mpDeviceWindow[0])
-        return false;
-
-    *pScreenX = event.m_x;
-    *pScreenY = event.m_y;
-    return true;
-}
-
-/*
- * We don't want to erase the background now, because it causes flicker
- * under Windows.
- */
-void PhoneWindow::OnErase(wxEraseEvent& WXUNUSED(event))
-{
-    //printf("erase\n");
-}
-
-/*
- * Paint the phone and any highlighted buttons.
- *
- * The device output is drawn by DeviceWindow.
- */
-void PhoneWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
-{
-    int view;
-
-    /*
-     * Under Mac OS X, the parent window is redrawn every time the child
-     * window is redrawn.  This causes poor performance in the simulator.
-     * If we're being asked to update a region that corresponds exactly
-     * to one of the device output windows, skip the redraw.
-     */
-    assert(mpViewInfo != NULL);
-    for (view = 0; view < mNumViewInfo; view++) {
-        int displayIndex;
-
-        displayIndex = mpViewInfo[view].GetDisplayIndex();
-        assert(displayIndex >= 0);
-        DeviceWindow* pDeviceWindow = mpDeviceWindow[displayIndex];
-        assert(pDeviceWindow != NULL);
-
-        wxRect displayRect = pDeviceWindow->GetRect();
-        wxRect updateRect = GetUpdateClientRect();
-
-        if (displayRect == updateRect) {
-            //printf("(skipping redraw)\n");
-            return;
-        }
-    }
-
-    wxBufferedPaintDC dc(this);
-
-    /*
-     * Erase the background to the currently-specified background color.
-     */
-    wxColour backColor = GetBackgroundColour();
-    dc.SetBrush(wxBrush(backColor));
-    dc.SetPen(wxPen(backColor, 1));
-    wxRect windowRect(wxPoint(0, 0), GetClientSize());
-    dc.DrawRectangle(windowRect);
-
-    PhoneData* pPhoneData = GetPhoneData();
-    if (pPhoneData == NULL) {
-        fprintf(stderr, "OnPaint: no phone data\n");
-        return;
-    }
-
-    PhoneMode* pPhoneMode;
-    PhoneView* pPhoneView;
-    int numImages;
-
-    pPhoneMode = pPhoneData->GetPhoneMode(GetCurrentMode().ToAscii());
-    if (pPhoneMode == NULL) {
-        fprintf(stderr, "current mode (%s) not known\n",
-            (const char*) GetCurrentMode().ToAscii());
-        return;
-    }
-
-    for (view = 0; view < pPhoneMode->GetNumViews(); view++) {
-        pPhoneView = pPhoneMode->GetPhoneView(view);
-        if (pPhoneView == NULL) {
-            fprintf(stderr, "view %d not found\n", view);
-            return;
-        }
-
-        /* draw background image and "button patches" */
-        numImages = pPhoneView->GetBkgImageCount();
-        for (int i = 0; i < numImages; i++) {
-            const LoadableImage* pLimg = pPhoneView->GetBkgImage(i);
-            wxBitmap* pBitmap = pLimg->GetBitmap();
-            if (pBitmap != NULL)
-                dc.DrawBitmap(*pBitmap,
-                    mpViewInfo[view].GetX() + pLimg->GetX(),
-                    mpViewInfo[view].GetY() + pLimg->GetY(),
-                    TRUE);
-        }
-    }
-
-
-    /*
-     * Draw button mouse-over highlight.
-     *
-     * Currently we don't do anything different when the button is held down.
-     */
-    if (mpMOHViewIndex >= 0 && mpMOHButton != NULL) {
-        // button must have graphic, or hit-testing wouldn't have worked
-        assert(mpMOHButton->GetHighlightedBitmap() != NULL);
-        dc.DrawBitmap(*mpMOHButton->GetHighlightedBitmap(),
-            mpViewInfo[mpMOHViewIndex].GetX() + mpMOHButton->GetX(),
-            mpViewInfo[mpMOHViewIndex].GetY() + mpMOHButton->GetY(),
-            TRUE);
-    }
-
-    /*
-     * Highlight pressed keys.  We want to do this in all views, because
-     * some buttons on the side of the phone might be visible in more
-     * than one view.
-     */
-    for (view = 0; view < pPhoneMode->GetNumViews(); view++) {
-        pPhoneView = pPhoneMode->GetPhoneView(view);
-        assert(pPhoneView != NULL);
-
-        ListIter iter;
-        for (iter = mPressedKeys.begin(); iter != mPressedKeys.end(); ++iter) {
-            int32_t keyCode;
-            PhoneButton* pButton;
-
-            keyCode = (*iter).GetKeyCode();
-            pButton = pPhoneView->FindButtonByKey(keyCode);
-            if (pButton != NULL) {
-                wxBitmap* pBitmap = pButton->GetSelectedBitmap();
-                if (pBitmap != NULL) {
-                    dc.DrawBitmap(*pBitmap,
-                        mpViewInfo[view].GetX() + pButton->GetX(),
-                        mpViewInfo[view].GetY() + pButton->GetY(),
-                        TRUE);
-                }
-            }
-        }
-    }
-}
-
-
-/*
- * Press a key on the device.
- *
- * Schedules a screen refresh if the set of held-down keys changes.
- */
-void PhoneWindow::AddPressedKey(int32_t keyCode)
-{
-    /*
-     * See if the key is already down.  This usually means that the key
-     * repeat has kicked into gear.  It could also mean that we
-     * missed the key-up event, or the user has hit the same device
-     * key with both mouse and keyboard.  Either way, we don't add it
-     * a second time.  This way, if we did lose a key-up somehow, they
-     * can "clear" the stuck key by hitting it again.
-     */
-    if (keyCode == AKEYCODE_UNKNOWN) {
-        //printf("--- not adding AKEYCODE_UNKNOWN!\n");
-        return;
-    }
-
-    ListIter iter;
-    for (iter = mPressedKeys.begin(); iter != mPressedKeys.end(); ++iter) {
-        if ((*iter).GetKeyCode() == keyCode)
-            break;
-    }
-    if (iter == mPressedKeys.end()) {
-        KeyInfo newInfo;
-        newInfo.SetKeyCode(keyCode);
-        mPressedKeys.push_back(newInfo);
-        //printf("---  added down=%d\n", keyCode);
-        Refresh();      // redraw w/ highlight
-    } else {
-        //printf("---  already have down=%d\n", keyCode);
-    }
-}
-
-/*
- * Release a key on the device.
- *
- * Schedules a screen refresh if the set of held-down keys changes.
- */
-void PhoneWindow::RemovePressedKey(int32_t keyCode)
-{
-    /*
-     * Release the key.  If it's not in the list, we either missed a
-     * key-down event, or the user used both mouse and keyboard and we
-     * removed the key when the first device went up.
-     */
-    ListIter iter;
-    for (iter = mPressedKeys.begin(); iter != mPressedKeys.end(); ++iter) {
-        if ((*iter).GetKeyCode() == keyCode) {
-            mPressedKeys.erase(iter);
-            //printf("---  removing down=%d\n", keyCode);
-            Refresh();      // redraw w/o highlight
-            break;
-        }
-    }
-    if (iter == mPressedKeys.end()) {
-        //printf("---  didn't find down=%d\n", keyCode);
-    }
-}
-
-/*
- * Clear the set of keys that we think are being held down.
- */
-void PhoneWindow::ClearPressedKeys(void)
-{
-    //printf("--- All keys up (count=%d)\n", mPressedKeys.size());
-
-    if (!mPressedKeys.empty()) {
-        ListIter iter = mPressedKeys.begin();
-        while (iter != mPressedKeys.end()) {
-            int32_t keyCode = (*iter).GetKeyCode();
-            GetDeviceManager()->SendKeyEvent(keyCode, false);
-            iter = mPressedKeys.erase(iter);
-        }
-        Refresh();
-    }
-}
-
-/*
- * Returns "true" if the specified key is currently pressed.
- */
-bool PhoneWindow::IsKeyPressed(int32_t keyCode)
-{
-    ListIter iter;
-    for (iter = mPressedKeys.begin(); iter != mPressedKeys.end(); ++iter) {
-        if ((*iter).GetKeyCode() == keyCode)
-            return true;
-    }
-    return false;
-}
-
-void PhoneWindow::Vibrate(int vibrateOn)
-{
-    wxRect rect = GetRect();
-    if(vibrateOn)
-    {
-        mVibrateX = 0;
-        mTimer.Start(25);      // arg is delay in ms
-        Move(rect.x-2,rect.y);
-    }
-    else if(mTimer.IsRunning())
-    {
-        mTimer.Stop();
-        if(mVibrateX&1)
-            Move(rect.x-2,rect.y);
-        else
-            Move(rect.x+2,rect.y);
-    }
-}
-
-void PhoneWindow::OnTimer(wxTimerEvent& event)
-{
-    wxRect rect = GetRect();
-    mVibrateX++;
-    if(mVibrateX&1)
-        Move(rect.x+4,rect.y);
-    else
-        Move(rect.x-4,rect.y);
-}
diff --git a/simulator/app/PhoneWindow.h b/simulator/app/PhoneWindow.h
deleted file mode 100644
index a346e9c..0000000
--- a/simulator/app/PhoneWindow.h
+++ /dev/null
@@ -1,186 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Window with simulated phone.
-//
-#ifndef _SIM_PHONE_WINDOW_H
-#define _SIM_PHONE_WINDOW_H
-
-#include "PhoneData.h"
-#include "DeviceManager.h"
-#include "DeviceWindow.h"
-#include <ui/KeycodeLabels.h>
-
-class MainFrame;
-
-/*
- * This window displays the simulated phone views, and handles keyboard and
- * mouse input.
- *
- * If we switch to a different "mode", we may display different "views",
- * but the set of "displays" remains the same.  (Got that?)
- *
- * We can't just do these things in the main frame because we can't easily
- * grab the keyboard input.
- */
-class PhoneWindow : public wxDialog {
-public:
-    PhoneWindow(wxWindow* parent, const wxPoint& posn);
-    virtual ~PhoneWindow(void);
-
-    /* call this initially, and after a mode change */
-    bool Setup(int phoneIdx);
-
-    bool IsReady(void) const {
-        return (mNumViewInfo > 0 && mpViewInfo != NULL);
-    }
-
-    PhoneData* GetPhoneData(void) const;
-
-    const wxString& GetCurrentMode(void) const { return mCurrentMode; }
-    void SetCurrentMode(const wxString& mode) { mCurrentMode = mode; }
-    void SetCurrentMode(const char* mode) { mCurrentMode = wxString::FromAscii(mode); }
-
-    DeviceManager* GetDeviceManager(void) { return &mDeviceManager; }
-
-    /* this is called when the phone data is reloaded */
-    void DevicesRescanned(void);
-
-    void Vibrate(int vibrateOn);
-
-private:
-    /*
-     * Hold some information about the "views" being shown in our window.
-     */
-    class ViewInfo {
-    public:
-        ViewInfo(void)
-            : mX(-1), mY(-1), mDisplayX(-1), mDisplayY(-1),
-              mWidth(-1), mHeight(-1), mDisplayIndex(-1)
-        {}
-        ~ViewInfo(void) {}
-
-        int GetX(void) const { return mX; }
-        int GetY(void) const { return mY; }
-        int GetDisplayX(void) const { return mDisplayX; }
-        int GetDisplayY(void) const { return mDisplayY; }
-        int GetWidth(void) const { return mWidth; }
-        int GetHeight(void) const { return mHeight; }
-        int GetDisplayIndex(void) const { return mDisplayIndex; }
-
-        void SetX(int val) { mX = val; }
-        void SetY(int val) { mY = val; }
-        void SetDisplayX(int val) { mDisplayX = val; }
-        void SetDisplayY(int val) { mDisplayY = val; }
-        void SetWidth(int val) { mWidth = val; }
-        void SetHeight(int val) { mHeight = val; }
-        void SetDisplayIndex(int val) { mDisplayIndex = val; }
-
-    private:
-        int     mX, mY;                 // view offset within PhoneWindow
-        int     mDisplayX, mDisplayY;   // display offset within view
-        int     mWidth, mHeight;        // view dimensions
-
-        int     mDisplayIndex;          // index into mpDeviceWindow
-    };
-
-    /*
-     * Hold information about currently pressed keys.
-     */
-    class KeyInfo {
-    public:
-        KeyInfo(void) : mKeyCode(AKEYCODE_UNKNOWN) {}
-        KeyInfo(const KeyInfo& src) {
-            mKeyCode = src.mKeyCode;
-        }
-        ~KeyInfo(void) {}
-
-        KeyInfo& operator=(const KeyInfo& src) {
-            if (this != &src) {
-                mKeyCode = src.mKeyCode;
-            }
-            return *this;
-        }
-
-        int32_t GetKeyCode(void) const { return mKeyCode; }
-        void SetKeyCode(int32_t keyCode) { mKeyCode = keyCode; }
-
-        //PhoneButton* GetPhoneButton(void) const { return mpButton; }
-        //void SetPhoneButton(PhoneButton* pButton) { mpButton = pButton; }
-
-    private:
-        int32_t mKeyCode;
-        //PhoneButton*        mpButton;
-    };
-
-    void OnActivate(wxActivateEvent& event);
-    void OnMove(wxMoveEvent& event);
-    void OnClose(wxCloseEvent& event);
-    void OnTimer(wxTimerEvent& event);
-    void OnKeyDown(wxKeyEvent& event);
-    void OnKeyUp(wxKeyEvent& event);
-    void OnErase(wxEraseEvent& event);
-    void OnPaint(wxPaintEvent& WXUNUSED(event));
-    void OnMouseLeftDown(wxMouseEvent& event);
-    void OnMouseLeftUp(wxMouseEvent& event);
-    void OnMouseRightDown(wxMouseEvent& event);
-    void OnMouseRightUp(wxMouseEvent& event);
-    void OnMouseMotion(wxMouseEvent& event);
-    void OnMouseLeaveWindow(wxMouseEvent& WXUNUSED(event));
-    bool GetTouchPosition(const wxMouseEvent& event, int* pScreenX,
-        int* pScreenY);
-
-    bool GetDimensions(PhoneData* pPhoneData, PhoneView* pPhoneView,
-        ViewInfo* pDim);
-    int ConvertKeyCode(int wxKeyCode) const;
-
-    /* press a key on the device */
-    void AddPressedKey(int32_t keyCode);
-    /* release a key on the device */
-    void RemovePressedKey(int32_t keyCode);
-    /* "raise" all keys */
-    void ClearPressedKeys(void);
-    /* determine whether a key is down */
-    bool IsKeyPressed(int32_t keyCode);
-
-    /* manage the device runtime */
-    DeviceManager   mDeviceManager;
-
-    /* button mouse-over highlight handling */
-    int             mpMOHViewIndex;     // mouse is in this view
-    PhoneButton*    mpMOHButton;        //   over this button
-    int32_t         mMouseKeySent;     // to handle "key up" for mouse button
-
-    /* handle multiple simultaneous key presses */
-    android::List<KeyInfo>  mPressedKeys;
-    typedef android::List<KeyInfo>::iterator ListIter;
-
-    /* ViewInfos, 1:1 with PhoneView entries for the current mode */
-    ViewInfo*       mpViewInfo;         // array of view data
-    int             mNumViewInfo;       // #of elements in mpViewInfo
-
-    /* DeviceWindows, 1:1 with PhoneDisplay entries for this device */
-    DeviceWindow**  mpDeviceWindow;     // array of pointers to device windows
-    int             mNumDeviceWindows;  // #of device windows
-
-    /* state */
-    int             mPhoneModel;        // index into model list
-    wxString        mCurrentMode;
-
-    bool            mPlacementChecked;  // leave it offscreen if they want
-
-    MainFrame*      mpParent;           // retain pointer to parent window
-
-    enum { kVibrateTimerId = 1010 };
-    wxTimer         mTimer;
-    int             mVibrateX;
-
-    /* touchscreen simulation */
-    bool            mTrackingTouch;
-    int             mTouchX;
-    int             mTouchY;
-
-    DECLARE_EVENT_TABLE()
-};
-
-#endif // _SIM_PHONE_WINDOW_H
diff --git a/simulator/app/Pipe.cpp b/simulator/app/Pipe.cpp
deleted file mode 100644
index 05ce790..0000000
--- a/simulator/app/Pipe.cpp
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * 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 "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/simulator/app/Pipe.h b/simulator/app/Pipe.h
deleted file mode 100644
index 6404168..0000000
--- a/simulator/app/Pipe.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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/simulator/app/Preferences.cpp b/simulator/app/Preferences.cpp
deleted file mode 100644
index 039f1ff..0000000
--- a/simulator/app/Preferences.cpp
+++ /dev/null
@@ -1,475 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Preferences file access.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-//# include "wx/wx.h"
-# include "wx/string.h"
-#endif
-
-#include "Preferences.h"
-
-#include "utils.h"
-#include "tinyxml.h"
-
-static const char* kName = "name";
-static const char* kValue = "value";
-
-
-/*
- * Load from a file.
- */
-bool Preferences::Load(const char* fileName)
-{
-    assert(fileName != NULL);
-    printf("SimPref: reading preferences file '%s'\n", fileName);
-
-    // throw out any existing stuff
-    delete mpDoc;
-
-    mpDoc = new TiXmlDocument;
-    if (mpDoc == NULL)
-        return false;
-
-    if (!mpDoc->LoadFile(fileName)) {
-        fprintf(stderr, "SimPref: ERROR: failed loading '%s'\n", fileName);
-        if (mpDoc->ErrorRow() != 0)
-            fprintf(stderr, "    XML: %s (row=%d col=%d)\n",
-                mpDoc->ErrorDesc(), mpDoc->ErrorRow(), mpDoc->ErrorCol());
-        else
-            fprintf(stderr, "    XML: %s\n", mpDoc->ErrorDesc());
-        goto fail;
-    }
-
-    TiXmlNode* pPrefs;
-    pPrefs = mpDoc->FirstChild("prefs");
-    if (pPrefs == NULL) {
-        fprintf(stderr, "SimPref: ERROR: could not find <prefs> in '%s'\n",
-            fileName);
-        goto fail;
-    }
-
-    // set defaults for anything we haven't set explicitly
-    SetDefaults();
-
-    return true;
-
-fail:
-    delete mpDoc;
-    mpDoc = NULL;
-    return false;
-}
-
-/*
- * Save to a file.
- */
-bool Preferences::Save(const char* fileName)
-{
-    assert(fileName != NULL);
-
-    if (mpDoc == NULL)
-        return false;
-
-    if (!mpDoc->SaveFile(fileName)) {
-        fprintf(stderr, "SimPref: ERROR: failed saving '%s': %s\n",
-            fileName, mpDoc->ErrorDesc());
-        return false;
-    }
-
-    mDirty = false;
-
-    return true;
-}
-
-/*
- * Create an empty collection of preferences.
- */
-bool Preferences::Create(void)
-{
-    static const char* docBase =
-        "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
-        "<!-- Android device simulator preferences -->\n"
-        "<!-- This file is updated by the simulator -->\n"
-        "<prefs>\n"
-        "</prefs>\n";
-
-    // throw out any existing stuff
-    delete mpDoc;
-
-    // alloc and initialize
-    mpDoc = new TiXmlDocument;
-    if (mpDoc == NULL)
-        return false;
-
-    if (!mpDoc->Parse(docBase)) {
-        fprintf(stderr, "SimPref: bad docBase: %s\n", mpDoc->ErrorDesc());
-        return false;
-    }
-
-    SetDefaults();
-    mDirty = true;      // should already be, mbut make sure
-    return true;
-}
-
-/*
- * Add default values to XML doc.
- *
- * This isn't strictly necessary, because the functions that are interested
- * in the preferences can set appropriate defaults themselves when the
- * "get" function returns "false".  However, in some cases a preference
- * can be interesting to more than one function, and you either have to
- * cut & paste the default value or write a "get default for xxx" function.
- *
- * We want this to work even if they already have an older config file, so
- * this only sets values that don't already exist.
- */
-void Preferences::SetDefaults(void)
-{
-    /* table of default values */
-    static const struct {
-        const char* type;
-        const char* name;
-        const char* value;
-    } kDefault[] = {
-        { "pref",           "auto-power-on",        "true" },
-        { "pref",           "debug",                "false" },
-        { "pref",           "valgrind",             "false" },
-        { "pref",           "check-jni",            "true" },
-        { "pref",           "enable-sound",         "true" },
-        { "pref",           "enable-fake-camera",   "true" },
-        { "pref",           "java-vm",              "Dalvik" },
-        /* goobuntu dapper needed LD_ASSUME_KERNEL or gdb choked badly */
-        { "pref",           "ld-assume-kernel",     "" /*2.4.19*/ },
-        { "pref",           "launch-command",
-            "xterm -geom 80x60+10+10 -sb -title Simulator -e" },
-        { "pref",           "launch-wrapper-args",  "-wait" },
-    };
-    TiXmlNode* pPrefs;
-
-    assert(mpDoc != NULL);
-
-    pPrefs = mpDoc->FirstChild("prefs");
-
-    /*
-     * Look up the name.  If it doesn't exist, add it.
-     */
-    for (int i = 0; i < NELEM(kDefault); i++) {
-        TiXmlNode* pNode = _FindNode(kDefault[i].type, kDefault[i].name);
-
-        if (pNode == NULL) {
-            TiXmlElement elem(kDefault[i].type);
-            elem.SetAttribute(kName, kDefault[i].name);
-            elem.SetAttribute(kValue, kDefault[i].value);
-            pPrefs->InsertEndChild(elem);
-
-            printf("SimPref: added default <%s> '%s'='%s'\n",
-                kDefault[i].type, kDefault[i].name, kDefault[i].value);
-        } else {
-            printf("SimPref: found existing <%s> '%s'\n", 
-                kDefault[i].type, kDefault[i].name);
-        }
-    }
-}
-
-static TiXmlNode* get_next_node(TiXmlNode* pNode)
-{
-  if (!pNode->NoChildren())
-  {
-      pNode = pNode->FirstChild();
-  }
-  else if (pNode->NoChildren() && 
-           (pNode->NextSibling() == NULL))
-  {
-      pNode = pNode->Parent()->NextSibling();
-  }
-  else
-  {
-      pNode = pNode->NextSibling();
-  }
-  return pNode;
-}
-
-/*
- * Returns the node with element type and name specified
- *
- * WARNING: this searches through the tree and returns the first matching
- * node.
- */
-TiXmlNode* Preferences::_FindNode(const char* type, const char* str) const
-{
-    assert((type != NULL) && (str != NULL));
-    TiXmlNode* pRoot;
-    TiXmlNode* pNode;
-
-    pRoot = mpDoc->FirstChild("prefs");
-    assert(pRoot != NULL);
-
-    for (pNode = pRoot->FirstChild(); pNode != NULL;)
-    {
-        if (pNode->Type() != TiXmlNode::ELEMENT ||
-            strcasecmp(pNode->Value(), type) != 0)
-        {
-            pNode = get_next_node(pNode);
-            continue;
-        }
-
-        TiXmlElement* pElem = pNode->ToElement();
-        assert(pElem != NULL);
-
-        const char* name = pElem->Attribute(kName);
-
-        /* 1. If the name is blank, something is wrong with the config file
-         * 2. If the name matches the passed in string, we found the node
-         * 3. If the node has children, descend another level
-         * 4. If there are no children and no siblings of the node, go up a level
-         * 5. Otherwise, grab the next sibling
-         */
-        if (name == NULL)
-        {
-            fprintf(stderr, "WARNING: found <%s> without name\n", type);
-            continue;
-        }
-        else if (strcasecmp(name, str) == 0)
-        {
-            return pNode;
-        }
-        else 
-        {
-            pNode = get_next_node(pNode);
-        }
-    }
-
-    return NULL;
-}
-
-/*
- * Locate the specified preference.
- */
-TiXmlNode* Preferences::FindPref(const char* str) const
-{
-    TiXmlNode* pNode = _FindNode("pref", str);
-    return pNode;
-}
-
-/*
- * Like FindPref(), but returns a TiXmlElement.
- */
-TiXmlElement* Preferences::FindPrefElement(const char* str) const
-{
-    TiXmlNode* pNode;
-
-    pNode = FindPref(str);
-    if (pNode != NULL)
-        return pNode->ToElement();
-    return NULL;
-}
-
-/*
- * Add a new preference entry with a blank entry for value.  Returns a
- * pointer to the new element.
- */
-TiXmlElement* Preferences::AddPref(const char* str)
-{
-    assert(FindPref(str) == NULL);
-
-    TiXmlNode* pPrefs;
-
-    pPrefs = mpDoc->FirstChild("prefs");
-    assert(pPrefs != NULL);
-
-    TiXmlElement elem("pref");
-    elem.SetAttribute(kName, str);
-    elem.SetAttribute(kValue, "");
-    pPrefs->InsertEndChild(elem);
-
-    TiXmlNode* pNewPref = FindPref(str);
-    return pNewPref->ToElement();
-}
-
-/*
- * Remove a node from the tree
- */
-bool Preferences::_RemoveNode(TiXmlNode* pNode)
-{
-    if (pNode == NULL)
-        return false;
-
-    TiXmlNode* pParent = pNode->Parent();
-    if (pParent == NULL)
-        return false;
-
-    pParent->RemoveChild(pNode);
-    mDirty = true;
-    return true;
-}
-
-/*
- * Remove a preference entry.
- */
-bool Preferences::RemovePref(const char* delName)
-{
-    return _RemoveNode(FindPref(delName));
-}
-
-/*
- * Test for existence.
- */
-bool Preferences::Exists(const char* name) const
-{
-    TiXmlElement* pElem = FindPrefElement(name);
-    return (pElem != NULL);
-}
-
-/*
- * Internal implemenations for getting values 
- */
-bool Preferences::_GetBool(TiXmlElement* pElem, bool* pVal) const
-{
-    if (pElem != NULL) 
-    {
-        const char* str = pElem->Attribute(kValue);
-        if (str != NULL) 
-        {
-            if (strcasecmp(str, "true") == 0)
-                *pVal = true;
-            else if (strcasecmp(str, "false") == 0)
-                *pVal = false;
-            else 
-            {
-                printf("SimPref: evaluating as bool name='%s' val='%s'\n",
-                pElem->Attribute(kName), str);
-                return false;
-            }
-            return true;
-        }
-    }
-    return false;
-}
-
-bool Preferences::_GetInt(TiXmlElement* pElem, int* pInt) const
-{
-    int val;
-    if (pElem != NULL && pElem->Attribute(kValue, &val) != NULL) {
-        *pInt = val;
-        return true;
-    }
-    return false;
-}
-
-bool Preferences::_GetDouble(TiXmlElement* pElem, double* pDouble) const
-{
-    double val;
-    if (pElem != NULL && pElem->Attribute(kValue, &val) != NULL) {
-        *pDouble = val;
-        return true;
-    }
-    return false;
-}
-
-bool Preferences::_GetString(TiXmlElement* pElem, wxString& str) const
-{
-    const char* val;
-    if (pElem != NULL) {
-        val = pElem->Attribute(kValue);
-        if (val != NULL) {
-            str = wxString::FromAscii(val);
-            return true;
-        }
-    }
-    return false;
-}
-
-/*
- * Get a value.  Do not disturb "*pVal" unless we have something to return.
- */
-bool Preferences::GetBool(const char* name, bool* pVal) const
-{
-    return _GetBool(FindPrefElement(name), pVal);
-}
-
-bool Preferences::GetInt(const char* name, int* pInt) const
-{
-    return _GetInt(FindPrefElement(name), pInt);
-}
-
-bool Preferences::GetDouble(const char* name, double* pDouble) const
-{
-    return _GetDouble(FindPrefElement(name), pDouble);
-}
-
-bool Preferences::GetString(const char* name, char** pVal) const
-{
-    wxString str = wxString::FromAscii(*pVal);
-    if (_GetString(FindPrefElement(name), str))
-    {
-        *pVal = android::strdupNew(str.ToAscii());
-        return true;
-    }
-    return false;   
-}
-
-bool Preferences::GetString(const char* name, wxString& str) const
-{
-    return _GetString(FindPrefElement(name), str);
-}
-
-/*
- * Set a value.  If the preference already exists, and the value hasn't
- * changed, don't do anything.  This avoids setting the "dirty" flag
- * unnecessarily.
- */
-void Preferences::SetBool(const char* name, bool val)
-{
-    bool oldVal;
-    if (GetBool(name, &oldVal) && val == oldVal)
-        return;
-
-    SetString(name, val ? "true" : "false");
-    mDirty = true;
-}
-
-void Preferences::SetInt(const char* name, int val)
-{
-    int oldVal;
-    if (GetInt(name, &oldVal) && val == oldVal)
-        return;
-
-    TiXmlElement* pElem = FindPrefElement(name);
-    if (pElem == NULL)
-        pElem = AddPref(name);
-    pElem->SetAttribute(kValue, val);
-    mDirty = true;
-}
-
-void Preferences::SetDouble(const char* name, double val)
-{
-    double oldVal;
-    if (GetDouble(name, &oldVal) && val == oldVal)
-        return;
-
-    TiXmlElement* pElem = FindPrefElement(name);
-    if (pElem == NULL)
-        pElem = AddPref(name);
-    pElem->SetDoubleAttribute(kValue, val);
-    mDirty = true;
-}
-
-void Preferences::SetString(const char* name, const char* val)
-{
-    wxString oldVal;
-    if (GetString(name, /*ref*/oldVal) && strcmp(oldVal.ToAscii(), val) == 0)
-        return;
-
-    TiXmlElement* pElem = FindPrefElement(name);
-    if (pElem == NULL)
-        pElem = AddPref(name);
-    pElem->SetAttribute(kValue, val);
-    mDirty = true;
-}
-
-
diff --git a/simulator/app/Preferences.h b/simulator/app/Preferences.h
deleted file mode 100644
index 91c35de..0000000
--- a/simulator/app/Preferences.h
+++ /dev/null
@@ -1,104 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Preferences file access.
-//
-#ifndef _SIM_PREFERENCES_H
-#define _SIM_PREFERENCES_H
-
-#include "tinyxml.h"
-
-/*
- * This class provides access to a preferences file.  It's possible to
- * have more than one instance, though it's probably unwise to have multiple
- * objects for the same file on disk.
- *
- * All value are stored as strings.  The class doesn't really try to
- * enforce type safety, but it will complain if you try to do something
- * nonsensical (like convert "foo" to an integer).
- */
-class Preferences {
-public:
-    Preferences(void) :
-        mpDoc(NULL), mDirty(false)
-        {}
-    ~Preferences(void) {
-        delete mpDoc;
-    }
-
-    /* load all preferences from a file */
-    bool Load(const char* fileName);
-
-    /* save all preferences to a file */
-    bool Save(const char* fileName);
-
-    /* create new preferences set (use when file does not exist) */
-    bool Create(void);
-
-    /*
-     * Retrieve a value from the preferences database.
-     *
-     * These return "false" if the value was not found or could not be
-     * converted to the expected type.  The value pointed to be the second
-     * arg is guaranteed to be left undisturbed in this case.
-     *
-     * The value set by GetString(const char*, char**) will be set to
-     * newly-allocated storage that must be freed with "delete[]".  This
-     * is done instead of returning a const char* because it's unclear
-     * what guarantees TinyXml makes wrt string lifetime (especially in
-     * a multithreaded environment).
-     */
-    bool GetBool(const char* name, bool* pVal) const;
-    bool GetInt(const char* name, int* pInt) const;
-    bool GetDouble(const char* name, double* pDouble) const;
-    bool GetString(const char* name, char** pVal) const;
-    bool GetString(const char* name, wxString& str) const;
-
-    /*
-     * Set a value in the database.
-     */
-    void SetBool(const char* name, bool val);
-    void SetInt(const char* name, int val);
-    void SetDouble(const char* name, double val);
-    void SetString(const char* name, const char* val);
-
-    /*
-     * Just test for existence.
-     */
-    bool Exists(const char* name) const;
-    
-    /*
-     * Remove a <pref> from the config file.
-     */
-    bool RemovePref(const char* name);
-    
-    /*
-     * Get the value of the "dirty" flag.
-     */
-    bool GetDirty(void) const { return mDirty; }
-
-private:
-    /* Implementation of getters */
-    bool _GetBool(TiXmlElement* pElem, bool* pVal) const;
-    bool _GetInt(TiXmlElement* pElem, int* pInt) const;
-    bool _GetDouble(TiXmlElement* pElem, double* pDouble) const;
-    bool _GetString(TiXmlElement* pElem, wxString& str) const;
-    
-    /* this can be used to generate some defaults */
-    void SetDefaults(void);
-
-    /* locate the named preference */
-    TiXmlNode* _FindNode(const char* type, const char* name) const;
-    TiXmlNode* FindPref(const char* str) const;
-    /* like FindPref, but returns a TiXmlElement */
-    TiXmlElement* FindPrefElement(const char* str) const;
-    /* add a new preference entry */
-    TiXmlElement* AddPref(const char* str);
-    /* removes a node */
-    bool _RemoveNode(TiXmlNode* pNode);
-    
-    TiXmlDocument*  mpDoc;
-    bool            mDirty;
-};
-
-#endif // _SIM_PREFERENCES_H
diff --git a/simulator/app/PrefsDialog.cpp b/simulator/app/PrefsDialog.cpp
deleted file mode 100644
index e146a56..0000000
--- a/simulator/app/PrefsDialog.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Preferences modal dialog.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-
-#include "PrefsDialog.h"
-#include "Preferences.h"
-#include "MyApp.h"
-#include "Resource.h"
-
-BEGIN_EVENT_TABLE(PrefsDialog, wxDialog)
-END_EVENT_TABLE()
-
-/*
- * Constructor.
- */
-PrefsDialog::PrefsDialog(wxWindow* parent)
-    : wxDialog(parent, IDD_PREFS, wxT("Preferences"), wxDefaultPosition,
-        wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
-      mAutoPowerOn(false),
-      mGammaCorrection(1.0),
-      mEnableSound(true),
-      mEnableFakeCamera(true),
-      mLogLevel(0)
-{
-    LoadPreferences();   
-    CreateControls();
-}
-
-/*
- * Destructor.  Not much to do.
- */
-PrefsDialog::~PrefsDialog()
-{
-}
-
-/*
- * Create all of the pages and add them to the notebook.
- */
-void PrefsDialog::CreateControls(void)
-{
-    wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
-    wxBoxSizer* okCancelSizer = new wxBoxSizer(wxHORIZONTAL);
-    mNotebook.Create(this, wxID_ANY);
-    wxPanel* page;
-
-    /* pages added to notebook are owned by notebook */
-    page = CreateSimulatorPage(&mNotebook);
-    mNotebook.AddPage(page, wxT("Simulator"), true);       // selected page
-    page = CreateRuntimePage(&mNotebook);
-    mNotebook.AddPage(page, wxT("Runtime"), false);
-
-    wxButton* cancel = new wxButton(this, wxID_CANCEL, wxT("&Cancel"),
-        wxDefaultPosition, wxDefaultSize, 0);
-    okCancelSizer->Add(cancel, 0, wxALL | wxALIGN_RIGHT, kInterSpacing);
-
-    wxButton* ok = new wxButton(this, wxID_OK, wxT("&OK"),
-        wxDefaultPosition, wxDefaultSize, 0);
-    okCancelSizer->Add(ok, 0, wxALL | wxALIGN_RIGHT, kInterSpacing);
-
-    mainSizer->Add(&mNotebook, 1, wxEXPAND);
-    mainSizer->Add(okCancelSizer, 0, wxALIGN_RIGHT);
-
-    SetSizer(mainSizer);
-
-    mainSizer->Fit(this);           // shrink-to-fit
-    mainSizer->SetSizeHints(this);  // define minimum size
-}
-
-/*
- * Load preferences from config file
- */
-void PrefsDialog::LoadPreferences(void)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    assert(pPrefs != NULL);
-
-    /*
-     * Load preferences.
-     */
-    mConfigFile = ((MyApp*)wxTheApp)->GetConfigFileName();
-
-    pPrefs->GetDouble("gamma", &mGammaCorrection);
-    pPrefs->GetString("debugger", /*ref*/ mDebugger);
-    pPrefs->GetString("valgrinder", /*ref*/ mValgrinder);
-    pPrefs->GetBool("auto-power-on", &mAutoPowerOn);
-    pPrefs->GetBool("enable-sound", &mEnableSound);
-    pPrefs->GetBool("enable-fake-camera", &mEnableFakeCamera);
-}
-
-/*
- * Transfer data from our members to the window controls.
- *
- * First we have to pull the data out of the preferences database.
- * Anything that hasn't already been added with a default value will
- * be given a default here, which may or may not match the default
- * behavior elsewhere.  The best solution to this is to define the
- * default when the preferences file is created or read, so that we're
- * never left guessing here.
- */
-bool PrefsDialog::TransferDataToWindow(void)
-{
-    /*
-     * Do standard dialog setup.
-     */
-    wxTextCtrl* configFileName = (wxTextCtrl*) FindWindow(IDC_SPREFS_CONFIG_NAME);
-    wxTextCtrl* debugger = (wxTextCtrl*) FindWindow(IDC_SPREFS_DEBUGGER);
-    wxTextCtrl* valgrinder = (wxTextCtrl*) FindWindow(IDC_SPREFS_VALGRINDER);
-    wxCheckBox* autoPowerOn = (wxCheckBox*) FindWindow(IDC_SPREFS_AUTO_POWER_ON);
-    wxCheckBox* enableSound = (wxCheckBox*) FindWindow(IDC_RPREFS_ENABLE_SOUND);
-    wxCheckBox* enableFakeCamera = (wxCheckBox*) FindWindow(IDC_RPREFS_ENABLE_FAKE_CAMERA);
-
-    wxTextCtrl* gamma = (wxTextCtrl*) FindWindow(IDC_RPREFS_GAMMA);
-
-    configFileName->SetValue(mConfigFile);
-    debugger->SetValue(mDebugger);
-    valgrinder->SetValue(mValgrinder);
-    autoPowerOn->SetValue(mAutoPowerOn);
-    enableSound->SetValue(mEnableSound);
-    enableFakeCamera->SetValue(mEnableFakeCamera);
-
-    wxString tmpStr;
-    tmpStr.Printf(wxT("%.3f"), mGammaCorrection);
-    gamma->SetValue(tmpStr);
-
-    return true;
-}
-
-/*
- * Transfer and validate data from the window controls.
- *
- * This doesn't get called if the user cancels out of the dialog.
- */
-bool PrefsDialog::TransferDataFromControls(void)
-{
-    /*
-     * Do standard dialog export.
-     *
-     * We should error-check all of these.
-     */
-    // configName is read-only, don't need it here
-    wxTextCtrl* debugger = (wxTextCtrl*) FindWindow(IDC_SPREFS_DEBUGGER);
-    wxTextCtrl* valgrinder = (wxTextCtrl*) FindWindow(IDC_SPREFS_VALGRINDER);
-    wxCheckBox* autoPowerOn = (wxCheckBox*) FindWindow(IDC_SPREFS_AUTO_POWER_ON);
-    wxCheckBox* enableSound = (wxCheckBox*) FindWindow(IDC_RPREFS_ENABLE_SOUND);
-    wxCheckBox* enableFakeCamera = (wxCheckBox*) FindWindow(IDC_RPREFS_ENABLE_FAKE_CAMERA);
-
-    wxTextCtrl* gamma = (wxTextCtrl*) FindWindow(IDC_RPREFS_GAMMA);
-
-    mDebugger = debugger->GetValue();
-    mValgrinder = valgrinder->GetValue();
-    mAutoPowerOn = autoPowerOn->GetValue();
-    mEnableSound = enableSound->GetValue();
-    mEnableFakeCamera = enableFakeCamera->GetValue();
-
-    wxString tmpStr;
-    tmpStr = gamma->GetValue();
-    bool toDouble = tmpStr.ToDouble(&mGammaCorrection);    // returns 0.0 on err; use strtof()?
-
-    if (!toDouble || mGammaCorrection <= 0.0 || mGammaCorrection > 2.0) {
-        wxMessageBox(wxT("Bad value for gamma -- must be > 0.0 and <= 2.0"),
-            wxT("Hoser"), wxOK, this);
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Transfer preferences to config file
- */
-bool PrefsDialog::TransferDataFromWindow(void)
-{
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    assert(pPrefs != NULL);
-
-    /*
-     * Grab the information from the controls and save in member field
-     */
-
-    if (!TransferDataFromControls())
-        return false;
-
-    pPrefs->SetString("debugger", mDebugger.ToAscii());
-    pPrefs->SetString("valgrinder", mValgrinder.ToAscii());
-    pPrefs->SetBool("auto-power-on", mAutoPowerOn);
-    pPrefs->SetBool("enable-sound", mEnableSound);
-    pPrefs->SetBool("enable-fake-camera", mEnableFakeCamera);
-
-    pPrefs->SetDouble("gamma", mGammaCorrection);
-
-    return true;
-}
-
-
-/*
- * Create the Simulator Preferences page.
- */
-wxPanel* PrefsDialog::CreateSimulatorPage(wxBookCtrlBase* parent)
-{
-    wxPanel* panel = new wxPanel(parent);
-
-    wxStaticText* configNameDescr = new wxStaticText(panel, wxID_STATIC,
-        wxT("Config file:"));
-    wxTextCtrl* configName = new wxTextCtrl(panel, IDC_SPREFS_CONFIG_NAME,
-        wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_READONLY);
-    // make it visibly different; unfortunately this kills scroll, copy&paste
-    configName->Enable(false);
-
-    wxStaticText* debuggerDescr = new wxStaticText(panel, wxID_STATIC,
-        wxT("Debugger:"));
-    wxTextCtrl* debugger = new wxTextCtrl(panel, IDC_SPREFS_DEBUGGER);
-
-    wxStaticText* valgrinderDescr = new wxStaticText(panel, wxID_STATIC,
-        wxT("Valgrind:"));
-    wxTextCtrl* valgrinder = new wxTextCtrl(panel, IDC_SPREFS_VALGRINDER);
-
-    wxCheckBox* autoPowerOn = new wxCheckBox(panel, IDC_SPREFS_AUTO_POWER_ON,
-        wxT("Boot runtime when simulator starts"));
-
-    wxBoxSizer* sizerPanel = new wxBoxSizer(wxVERTICAL);
-    sizerPanel->Add(kMinWidth, kEdgeSpacing);       // forces minimum width
-    sizerPanel->Add(configNameDescr);
-    sizerPanel->Add(configName, 0, wxEXPAND);
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->Add(debuggerDescr);
-    sizerPanel->Add(debugger, 0, wxEXPAND);
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->Add(valgrinderDescr);
-    sizerPanel->Add(valgrinder, 0, wxEXPAND);
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->Add(autoPowerOn);
-    sizerPanel->AddSpacer(kInterSpacing);
-
-    wxBoxSizer* horizIndent = new wxBoxSizer(wxHORIZONTAL);
-    horizIndent->AddSpacer(kEdgeSpacing);
-    horizIndent->Add(sizerPanel, wxSHAPED);
-    horizIndent->AddSpacer(kEdgeSpacing);
-    panel->SetSizer(horizIndent);
-
-    return panel;
-}
-
-/*
- * Create the Runtime Preferences page.
- */
-wxPanel* PrefsDialog::CreateRuntimePage(wxBookCtrlBase* parent)
-{
-    wxPanel* panel = new wxPanel(parent);
-
-    wxStaticText* gammaStrDescr = new wxStaticText(panel, wxID_STATIC,
-        wxT("Gamma correction:"));
-    wxTextCtrl* gammaStr = new wxTextCtrl(panel, IDC_RPREFS_GAMMA);
-
-    wxBoxSizer* gammaSizer = new wxBoxSizer(wxHORIZONTAL);
-    gammaSizer->Add(gammaStrDescr, 0, wxALIGN_CENTER_VERTICAL);
-    gammaSizer->AddSpacer(kInterSpacing);
-    gammaSizer->Add(gammaStr);
-
-    wxBoxSizer* sizerPanel = new wxBoxSizer(wxVERTICAL);
-    sizerPanel->Add(kMinWidth, kEdgeSpacing);       // forces minimum width
-    sizerPanel->Add(gammaSizer);
-    sizerPanel->AddSpacer(kInterSpacing);
-
-    wxCheckBox* enableSound = new wxCheckBox(panel, IDC_RPREFS_ENABLE_SOUND,
-        wxT("Enable Sound"));
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->Add(enableSound);
-
-    wxCheckBox* enableFakeCamera = new wxCheckBox(panel, IDC_RPREFS_ENABLE_FAKE_CAMERA,
-        wxT("Enable Fake Camera"));
-    sizerPanel->AddSpacer(kInterSpacing);
-    sizerPanel->Add(enableFakeCamera);
-
-    wxBoxSizer* horizIndent = new wxBoxSizer(wxHORIZONTAL);
-    horizIndent->AddSpacer(kEdgeSpacing);
-    horizIndent->Add(sizerPanel, wxEXPAND);
-    horizIndent->AddSpacer(kEdgeSpacing);
-    panel->SetSizer(horizIndent);
-
-    return panel;
-}
-
diff --git a/simulator/app/PrefsDialog.h b/simulator/app/PrefsDialog.h
deleted file mode 100644
index 250f79e..0000000
--- a/simulator/app/PrefsDialog.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Prefs modal dialog.
-//
-#ifndef _SIM_PREFS_DIALOG_H
-#define _SIM_PREFS_DIALOG_H
-
-/*
- * Declaration of preferences dialog.  This class defines the outer
- * wrapper as well as all of the pages.
- */
-class PrefsDialog : public wxDialog {
-    //DECLARE_CLASS(PrefsDialog)    // shown in book, but causes link problems
-    DECLARE_EVENT_TABLE()
-
-public:
-    PrefsDialog(wxWindow* parent);
-    virtual ~PrefsDialog();
-
-    void CreateControls(void);
-
-    wxString    mConfigFile;
-
-private:
-    bool TransferDataToWindow(void);
-    bool TransferDataFromWindow(void);
-    bool TransferDataFromControls(void);
-    void LoadPreferences(void);
-    
-    wxPanel* CreateSimulatorPage(wxBookCtrlBase* parent);
-    wxPanel* CreateRuntimePage(wxBookCtrlBase* parent);
-
-    /* main notebook; for aesthetic reasons we may want a Choicebook */
-    wxNotebook    mNotebook;
-
-    /* Global simulator options */
-    wxString    mDebugger;
-    wxString    mValgrinder;
-    bool        mAutoPowerOn;
-    // log window size?
-
-    /* Global runtime options */
-    double      mGammaCorrection;
-    bool        mEnableSound;
-    bool        mEnableFakeCamera;
-    int         mLogLevel;
-
-    enum {
-        kMinWidth = 300,        // minimum prefs dialog width, in pixels
-    };
-};
-
-#endif // _SIM_PREFS_DIALOG_H
diff --git a/simulator/app/PropertyServer.cpp b/simulator/app/PropertyServer.cpp
deleted file mode 100644
index 91223ef..0000000
--- a/simulator/app/PropertyServer.cpp
+++ /dev/null
@@ -1,489 +0,0 @@
-//
-// Copyright 2007 The Android Open Source Project
-//
-// Property sever.  Mimics behavior provided on the device by init(8) and
-// some code built into libc.
-//
-    
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-    
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h"
-    
-#include "PropertyServer.h"
-#include "MyApp.h"
-#include "Preferences.h"
-#include "MainFrame.h"
-#include "utils.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-
-
-using namespace android;
-
-const char* PropertyServer::kPropCheckJni = "ro.kernel.android.checkjni";
-
-/*
- * Destructor.
- */
-PropertyServer::~PropertyServer(void)
-{
-    if (IsRunning()) {
-        // TODO: cause thread to stop, then Wait for it
-    }
-    printf("Sim: in ~PropertyServer()\n");
-}
-
-/*
- * Create and run the thread.
- */
-bool PropertyServer::StartThread(void)
-{
-    if (Create() != wxTHREAD_NO_ERROR) {
-        fprintf(stderr, "Sim: ERROR: can't create PropertyServer thread\n");
-        return false;
-    }
-
-    Run();
-    return true;
-}
-
-
-/*
- * Clear out the list.
- */
-void PropertyServer::ClearProperties(void)
-{
-    typedef List<Property>::iterator PropIter;
-
-    for (PropIter pi = mPropList.begin(); pi != mPropList.end(); ++pi) {
-        pi = mPropList.erase(pi);
-    }
-}
-
-/*
- * Set default values for several properties.
- */
-void PropertyServer::SetDefaultProperties(void)
-{
-    static const struct {
-        const char* key;
-        const char* value;
-    } propList[] = {
-        { "net.bt.name", "Android" },
-        { "ro.kernel.mem", "60M" },
-        { "ro.kernel.board_sardine.version", "4" },
-        { "ro.kernel.console", "null" },
-        { "ro.build.id", "engineering" },
-        { "ro.build.date", "Wed Nov 28 07:44:14 PST 2007" },
-        { "ro.build.date.utc", "1196264654" },
-        { "ro.build.type", "eng" },
-        { "ro.build.version.sdk", "8" },
-        { "ro.build.version.codename", "Froyo" },
-        { "ro.build.version.release", "Froyo" },
-        { "ro.product.device", "simulator" /*"sooner"*/ },
-        { "ro.product.brand", "generic" },
-        { "ro.build.user", "fadden" },
-        { "ro.build.host", "marathon" },
-        { "ro.config.nocheckin", "yes" },
-        { "ro.product.manufacturer", "" },
-        { "ro.radio.use-ppp", "no" },
-        { "ro.FOREGROUND_APP_ADJ", "0" },
-        { "ro.VISIBLE_APP_ADJ", "1" },
-        { "ro.PERCEPTIBLE_APP_ADJ", "2" },
-        { "ro.HEAVY_WEIGHT_APP_ADJ", "3" },
-        { "ro.SECONDARY_SERVER_ADJ", "2" },
-        { "ro.HIDDEN_APP_MIN_ADJ", "7" },
-        { "ro.CONTENT_PROVIDER_ADJ", "14" },
-        { "ro.EMPTY_APP_ADJ", "15" },
-        { "ro.FOREGROUND_APP_MEM", "1536" },
-        { "ro.VISIBLE_APP_MEM", "2048" },
-        { "ro.PERCEPTIBLE_APP_MEM", "4096" },
-        { "ro.HEAVY_WEIGHT_APP_MEM", "4096" },
-        { "ro.SECONDARY_SERVER_MEM", "4096" },
-        { "ro.HIDDEN_APP_MEM", "8192" },
-        { "ro.EMPTY_APP_MEM", "16384" },
-        { "ro.HOME_APP_ADJ", "4" },
-        { "ro.HOME_APP_MEM", "4096" },
-        { "ro.BACKUP_APP_ADJ", "2" },
-        { "ro.BACKUP_APP_MEM", "4096" },
-        { "ro.PERCEPTIBLE_APP_ADJ", "2" },
-        { "ro.PERCEPTIBLE_APP_MEM", "4096" },
-        { "ro.HEAVY_WEIGHT_APP_ADJ", "3" },
-        { "ro.HEAVY_WEIGHT_APP_MEM", "4096" },
-        //{ "init.svc.adbd", "running" },       // causes ADB-JDWP
-        { "init.svc.usbd", "running" },
-        { "init.svc.debuggerd", "running" },
-        { "init.svc.ril-daemon", "running" },
-        { "init.svc.zygote", "running" },
-        { "init.svc.runtime", "running" },
-        { "init.svc.dbus", "running" },
-        { "init.svc.pppd_gprs", "running" },
-        { "adb.connected", "0" },
-        /*
-        { "status.battery.state", "Slow" },
-        { "status.battery.level", "5" },
-        { "status.battery.level_raw", "50" },
-        { "status.battery.level_scale", "9" },
-        */
-
-        /* disable the annoying setup wizard */
-        { "app.setupwizard.disable", "1" },
-
-        /* Dalvik options, set by AndroidRuntime */
-        { "dalvik.vm.stack-trace-file", "/data/anr/traces.txt" },
-        //{ "dalvik.vm.execution-mode", "int:portable" },
-        { "dalvik.vm.enableassertions", "all" },    // -ea
-        { "dalvik.vm.dexopt-flags", "" },           // e.g. "v=a,o=v,m=n"
-        { "dalvik.vm.deadlock-predict", "off" },    // -Xdeadlockpredict
-        //{ "dalvik.vm.jniopts", "forcecopy" },       // -Xjniopts
-        { "log.redirect-stdio", "false" },          // -Xlog-stdio
-
-        /* SurfaceFlinger options */
-        { "ro.sf.lcd_density", "160" },
-        { "debug.sf.nobootanimation", "1" },
-        { "debug.sf.showupdates", "0" },
-        { "debug.sf.showcpu", "0" },
-        { "debug.sf.showbackground", "0" },
-        { "debug.sf.showfps", "0" },
-        { "default", "default" },
-
-        /* Stagefright options */
-        { "media.stagefright.enable-player", "true" },
-        { "media.stagefright.enable-meta", "true" },
-        { "media.stagefright.enable-scan", "true" },
-        { "media.stagefright.enable-http", "true" },
-    };
-
-    for (int i = 0; i < NELEM(propList); i++)
-        SetProperty(propList[i].key, propList[i].value);
-
-    Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-    bool doCheckJni = false;
-
-    pPrefs->GetBool("check-jni", &doCheckJni);
-    if (doCheckJni)
-        SetProperty(kPropCheckJni, "1");
-    else
-        SetProperty(kPropCheckJni, "0");
-}
-
-/*
- * Get the value of a property.
- *
- * "valueBuf" must hold at least PROPERTY_VALUE_MAX bytes.
- *
- * Returns "true" if the property was found.
- */
-bool PropertyServer::GetProperty(const char* key, char* valueBuf)
-{
-    typedef List<Property>::iterator PropIter;
-
-    assert(key != NULL);
-    assert(valueBuf != NULL);
-
-    for (PropIter pi = mPropList.begin(); pi != mPropList.end(); ++pi) {
-        Property& prop = *pi;
-        if (strcmp(prop.key, key) == 0) {
-            if (strlen(prop.value) >= PROPERTY_VALUE_MAX) {
-                fprintf(stderr,
-                    "GLITCH: properties table holds '%s' '%s' (len=%d)\n",
-                    prop.key, prop.value, (int) strlen(prop.value));
-                abort();
-            }
-            assert(strlen(prop.value) < PROPERTY_VALUE_MAX);
-            strcpy(valueBuf, prop.value);
-            return true;
-        }
-    }
-
-    //printf("Prop: get [%s] not found\n", key);
-    return false;
-}
-
-/*
- * Set the value of a property, replacing it if it already exists.
- *
- * If "value" is NULL, the property is removed.
- *
- * If the property is immutable, this returns "false" without doing
- * anything.  (Not implemented.)
- */
-bool PropertyServer::SetProperty(const char* key, const char* value)
-{
-    typedef List<Property>::iterator PropIter;
-
-    assert(key != NULL);
-    assert(value != NULL);
-
-    for (PropIter pi = mPropList.begin(); pi != mPropList.end(); ++pi) {
-        Property& prop = *pi;
-        if (strcmp(prop.key, key) == 0) {
-            if (value != NULL) {
-                //printf("Prop: replacing [%s]: [%s] with [%s]\n",
-                //    prop.key, prop.value, value);
-                strcpy(prop.value, value);
-            } else {
-                //printf("Prop: removing [%s]\n", prop.key);
-                mPropList.erase(pi);
-            }
-            return true;
-        }
-    }
-
-    //printf("Prop: adding [%s]: [%s]\n", key, value);
-    Property tmp;
-    strcpy(tmp.key, key);
-    strcpy(tmp.value, value);
-    mPropList.push_back(tmp);
-    return true;
-}
-
-/*
- * Create a UNIX domain socket, carefully removing it if it already
- * exists.
- */
-bool PropertyServer::CreateSocket(const char* fileName)
-{
-    struct stat sb;
-    bool result = false;
-    int sock = -1;
-    int cc;
-
-    cc = stat(fileName, &sb);
-    if (cc < 0) {
-        if (errno != ENOENT) {
-            LOG(LOG_ERROR, "sim-prop",
-                "Unable to stat '%s' (errno=%d)\n", fileName, errno);
-            goto bail;
-        }
-    } else {
-        /* don't touch it if it's not a socket */
-        if (!(S_ISSOCK(sb.st_mode))) {
-            LOG(LOG_ERROR, "sim-prop",
-                "File '%s' exists and is not a socket\n", fileName);
-            goto bail;
-        }
-
-        /* remove the cruft */
-        if (unlink(fileName) < 0) {
-            LOG(LOG_ERROR, "sim-prop",
-                "Unable to remove '%s' (errno=%d)\n", fileName, errno);
-            goto bail;
-        }
-    }
-
-    struct sockaddr_un addr;
-
-    sock = ::socket(AF_UNIX, SOCK_STREAM, 0);
-    if (sock < 0) {
-        LOG(LOG_ERROR, "sim-prop",
-            "UNIX domain socket create failed (errno=%d)\n", errno);
-        goto bail;
-    }
-
-    /* bind the socket; this creates the file on disk */
-    strcpy(addr.sun_path, fileName);    // max 108 bytes
-    addr.sun_family = AF_UNIX;
-    cc = ::bind(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
-    if (cc < 0) {
-        LOG(LOG_ERROR, "sim",
-            "AF_UNIX bind failed for '%s' (errno=%d)\n", fileName, errno);
-        goto bail;
-    }
-
-    cc = ::listen(sock, 5);
-    if (cc < 0) {
-        LOG(LOG_ERROR, "sim", "AF_UNIX listen failed (errno=%d)\n", errno);
-        goto bail;
-    }
-
-    mListenSock = sock;
-    sock = -1;
-    result = true;
-
-bail:
-    if (sock >= 0)
-        close(sock);
-    return result;
-}
-
-/*
- * Handle a client request.
- *
- * Returns true on success, false if the fd should be closed.
- */
-bool PropertyServer::HandleRequest(int fd)
-{
-    char reqBuf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX];
-    char valueBuf[1 + PROPERTY_VALUE_MAX];
-    ssize_t actual;
-
-    memset(valueBuf, 'x', sizeof(valueBuf));        // placate valgrind
-
-    /* read the command byte; this determines the message length */
-    actual = read(fd, reqBuf, 1);
-    if (actual <= 0)
-        return false;
-
-    if (reqBuf[0] == kSystemPropertyGet) {
-        actual = read(fd, reqBuf, PROPERTY_KEY_MAX);
-
-        if (actual != PROPERTY_KEY_MAX) {
-            fprintf(stderr, "Bad read on get: %d of %d\n",
-                (int) actual, PROPERTY_KEY_MAX);
-            return false;
-        }
-        if (GetProperty(reqBuf, valueBuf+1))
-            valueBuf[0] = 1;
-        else
-            valueBuf[0] = 0;
-        //printf("GET property [%s]: (found=%d) [%s]\n",
-        //    reqBuf, valueBuf[0], valueBuf+1);
-        if (write(fd, valueBuf, sizeof(valueBuf)) != sizeof(valueBuf)) {
-            fprintf(stderr, "Bad write on get\n");
-            return false;
-        }
-    } else if (reqBuf[0] == kSystemPropertySet) {
-        actual = read(fd, reqBuf, PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX);
-        if (actual != PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX) {
-            fprintf(stderr, "Bad read on set: %d of %d\n",
-                (int) actual, PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX);
-            return false;
-        }
-        //printf("SET property '%s'\n", reqBuf);
-        if (SetProperty(reqBuf, reqBuf + PROPERTY_KEY_MAX))
-            valueBuf[0] = 1;
-        else
-            valueBuf[0] = 0;
-        if (write(fd, valueBuf, 1) != 1) {
-            fprintf(stderr, "Bad write on set\n");
-            return false;
-        }
-    } else if (reqBuf[0] == kSystemPropertyList) {
-        /* TODO */
-        assert(false);
-    } else {
-        fprintf(stderr, "Unexpected request %d from prop client\n", reqBuf[0]);
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Serve up properties.
- */
-void PropertyServer::ServeProperties(void)
-{
-    typedef List<int>::iterator IntIter;
-    fd_set readfds;
-    int maxfd;
-
-    while (true) {
-        int cc;
-
-        FD_ZERO(&readfds);
-        FD_SET(mListenSock, &readfds);
-        maxfd = mListenSock;
-
-        for (IntIter ii = mClientList.begin(); ii != mClientList.end(); ++ii) {
-            int fd = (*ii);
-
-            FD_SET(fd, &readfds);
-            if (maxfd < fd)
-                maxfd = fd;
-        }
-
-        cc = select(maxfd+1, &readfds, NULL, NULL, NULL);
-        if (cc < 0) {
-            if (errno == EINTR) {
-                printf("hiccup!\n");
-                continue;
-            }
-            return;
-        }
-        if (FD_ISSET(mListenSock, &readfds)) {
-            struct sockaddr_un from;
-            socklen_t fromlen;
-            int newSock;
-
-            fromlen = sizeof(from);
-            newSock = ::accept(mListenSock, (struct sockaddr*) &from, &fromlen);
-            if (newSock < 0) {
-                LOG(LOG_WARN, "sim",
-                    "AF_UNIX accept failed (errno=%d)\n", errno);
-            } else {
-                //printf("new props connection on %d --> %d\n",
-                //    mListenSock, newSock);
-
-                mClientList.push_back(newSock);
-            }
-        }
-
-        for (IntIter ii = mClientList.begin(); ii != mClientList.end(); ) {
-            int fd = (*ii);
-            bool ok = true;
-
-            if (FD_ISSET(fd, &readfds)) {
-                //printf("--- activity on %d\n", fd);
-
-                ok = HandleRequest(fd);
-            }
-
-            if (ok) {
-                ++ii;
-            } else {
-                //printf("--- closing %d\n", fd);
-                close(fd);
-                ii = mClientList.erase(ii);
-            }
-        }
-    }
-}
-
-/*
- * Thread entry point.
- *
- * This just sits and waits for a new connection.  It hands it off to the
- * main thread and then goes back to waiting.
- *
- * There is currently no "polite" way to shut this down.
- */
-void* PropertyServer::Entry(void)
-{
-    if (CreateSocket(SYSTEM_PROPERTY_PIPE_NAME)) {
-        assert(mListenSock >= 0);
-        SetDefaultProperties();
-
-        /* loop until it's time to exit or we fail */
-        ServeProperties();
-
-        ClearProperties();
-
-        /*
-         * Close listen socket and all clients.
-         */
-        LOG(LOG_INFO, "sim", "Cleaning up socket list\n");
-        typedef List<int>::iterator IntIter;
-        for (IntIter ii = mClientList.begin(); ii != mClientList.end(); ++ii)
-            close((*ii));
-        close(mListenSock);
-    }
-
-    LOG(LOG_INFO, "sim", "PropertyServer thread exiting\n");
-    return NULL;
-}
-
diff --git a/simulator/app/PropertyServer.h b/simulator/app/PropertyServer.h
deleted file mode 100644
index 193dd70..0000000
--- a/simulator/app/PropertyServer.h
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// Copyright 2007 The Android Open Source Project
-//
-// Serve properties to the simulated runtime.
-//
-#ifndef _SIM_PROPERTY_SERVER_H
-#define _SIM_PROPERTY_SERVER_H
-
-#include "cutils/properties.h"
-#include "utils/List.h"
-
-/*
- * Define a thread that responds to requests from clients to get/set/list
- * system properties.
- */
-class PropertyServer : public wxThread {
-public:
-    PropertyServer(void) : mListenSock(-1) {}
-    virtual ~PropertyServer(void);
-
-    /* start the thread running */
-    bool StartThread(void);
-
-    /* thread entry point */
-    virtual void* Entry(void);
-
-    /* clear out all properties */
-    void ClearProperties(void);
-
-    /* add some default values */
-    void SetDefaultProperties(void);
-
-    /* copy a property into valueBuf; returns false if property not found */
-    bool GetProperty(const char* key, char* valueBuf);
-
-    /* set the property, replacing it if it already exists */
-    bool SetProperty(const char* key, const char* value);
-
-    /* property name constants */
-    static const char* kPropCheckJni;
-
-private:
-    /* one property entry */
-    typedef struct Property {
-        char    key[PROPERTY_KEY_MAX];
-        char    value[PROPERTY_VALUE_MAX];
-    } Property;
-
-    /* create the UNIX-domain socket we listen on */
-    bool CreateSocket(const char* fileName);
-
-    /* serve up properties */
-    void ServeProperties(void);
-
-    /* handle a client request */
-    bool HandleRequest(int fd);
-
-    /* listen here for new connections */
-    int     mListenSock;
-
-    /* list of connected fds to scan */
-    android::List<int>      mClientList;
-
-    /* set of known properties */
-    android::List<Property> mPropList;
-};
-
-#endif // PROPERTY_SERVER_H
diff --git a/simulator/app/README b/simulator/app/README
deleted file mode 100644
index 5a51f63..0000000
--- a/simulator/app/README
+++ /dev/null
@@ -1,74 +0,0 @@
-Android Simulator README
-Last updated: 14-Nov-2007
-
-See "docs/sim-layout-xml.txt" for a description of the layout.xml files
-in the device directories.
-
-The coding conventions here are generally aligned with wxWidgets' style,
-which is similar to standard Windows style.  The only significant shift
-from Android style is that function names are capitalized.  Note the
-simulator code is not part of the "android" namespace.
-
-
-===== Arguments =====
-
-The config file for the simulator, ".android.cf", can live in your
-$HOME directory or in $cwd.  The copy in $cwd takes priority.  If a
-config file does not exist, one will be created in your home directory.
-(Note that the current directory is set by "runsim.sh", so if you launch
-the simulator from the script it will look for the config file in your
-"install" directory.)
-
-The simulator takes the following optional arguments:
-
- -f <file> : specify the configuration file to use.
-
- -p <platform> : specify platform information.  This is usually
-    something like "Linux-release" or "CYGWIN_NT-5.1-debug".
-
- -r : reset paths.  This causes the simulator to regenerate the paths
-    based on defaults.  This is useful when copying your .android.cf from
-    a different system, because it updates all the local paths without
-    disturbing the other options.
-
-
-===== Preferences Quick Reference =====
-
-Path preferences.  These are reset by the "-r" flag:
-
-"debugger"            (str) Path to the debugger (usually /usr/bin/gdb).
-"valgrinder"          (str) Path to valgrind (usually /usr/bin/valgrind).
-
-Common prefs:
-
-"auto-power-on"       (bool) Automatically start runtime on simulator start.
-"debug"               (bool) Launch the runtime inside <debugger>.
-"valgrind"            (bool) Launch the runtime inside <valgrinder>.
-"log-*"               (various) Preferences for the log window.
-"window-*"            (int) Positions and sizes of windows.
-"default-device"      (str) Name of the device that opens initially.
-"ld-assume-kernel"    (str) Hack to make goobuntu GDB work; use "" to disable.
-
-Less-common prefs:
-
-"gamma"               (float) Gamma correction factor (default 1.0).
-"window-device-x"     (int) Position of device window.
-"window-device-y"     (int) Position of device window.
-"trap-sigint"         (bool) Catch Ctrl-C.  Kill the runtime when we do.
-"refocus-on-restart"  (bool) When runtime rstarts, give focus to phone window.
-"launch-command"      (str) Command to run, e.g. "xterm -e" (cmd is appended).
-"launch-wrapper-args" (str) Args to launch wrapper, e.g. "-wait -output foo".
-
-
-(If you prefer gnome-terminal to xterm, you can use something like
-"gnome-terminal --disable-factory -x".  The "disable-factory" arg is
-needed to ensure that it inherits the environment variables.)
-
-
-***** NOTE *****
-
-If you're using a non-goobuntu system, make sure "ld-assume-kernel" is ""
-in your .android.cf.  gdb works correctly on Ubuntu 7.04 (fiesty) and 7.10
-(gutsy), and the goobuntu workaround will cause shared library version
-failures on startup.
-
diff --git a/simulator/app/Resource.h b/simulator/app/Resource.h
deleted file mode 100644
index 1602428..0000000
--- a/simulator/app/Resource.h
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Resource enumeration.
-//
-#ifndef _SIM_RESOURCE_H
-#define _SIM_RESOURCE_H
-
-/*
- * IDs for dialogs, controls, menu items, and whatever else comes along.
- *
- * Some standard defs are in "wx/defs.h".  They run from 5000 to 6000.
- */
-enum {
-    // common stuff
-    //ID_ANONYMOUS = -1,        // use wxID_ANY(-1) or wxID_STATIC(5105)
-
-
-    // Menu item IDs
-    IDM_FILE_PREFERENCES = 100,
-    IDM_FILE_EXIT,
-
-    IDM_RUNTIME_START,
-    IDM_RUNTIME_STOP,
-    IDM_RUNTIME_RESTART,
-    IDM_RUNTIME_KILL,
-
-    IDM_DEVICE,
-    IDM_DEVICE_SEL0,
-    // leave space; each phone model gets a menu item ID
-    IDM_DEVICE_SELN = IDM_DEVICE_SEL0 + 32,
-    IDM_DEVICE_RESCAN,
-
-    IDM_DEBUG_SHOW_LOG,
-
-    IDM_HELP_CONTENTS,
-    IDM_HELP_ABOUT,
-
-
-    // Dialog IDs
-    IDD_PREFS,
-    IDD_LOG_PREFS,
-
-    // Control IDs
-    IDC_MODE_SELECT,            // main - combobox
-    IDC_USE_GDB,                // main - checkbox
-    IDC_USE_VALGRIND,           // main - checkbox
-    IDC_CHECK_JNI,              // main - checkbox
-    IDC_JAVA_APP_NAME,          // main - combobox
-    IDC_JAVA_VM,                // main - combobox
-    IDC_OVERLAY_ONION_SKIN,		// main - combobox
-    IDC_ONION_SKIN_FILE_NAME,	// main - textctrl
-    IDC_ONION_SKIN_BUTTON,		// main - button
-    IDC_ONION_SKIN_ALPHA_VAL,	// main - slider
-	
-    IDC_SPREFS_CONFIG_NAME,     // sim prefs page - textctrl
-    IDC_SPREFS_DEBUGGER,        // sim prefs page - textctrl
-    IDC_SPREFS_VALGRINDER,      // sim prefs page - textctrl
-    IDC_SPREFS_AUTO_POWER_ON,   // sim prefs page - checkbox
-
-    IDC_RPREFS_GAMMA,           // runtime prefs page - textctrl
-    IDC_RPREFS_ENABLE_SOUND,    // runtime prefs page - checkbox
-    IDC_RPREFS_ENABLE_FAKE_CAMERA,// runtime prefs page - checkbox
-
-    IDC_LOG_TEXT,               // log window - textctrl
-    IDC_LOG_LEVEL,              // log window - combobox
-    IDC_LOG_CLEAR,              // log window - button
-    IDC_LOG_PAUSE,              // log window - button
-    IDC_LOG_PREFS,              // log window - button
-
-    IDC_LOG_PREFS_FMT_FULL,     // log prefs - radio button
-    IDC_LOG_PREFS_FMT_BRIEF,    // log prefs - radio button
-    IDC_LOG_PREFS_FMT_MINIMAL,  // log prefs - radio button
-    IDC_LOG_PREFS_SINGLE_LINE,  // log prefs - checkbox
-    IDC_LOG_PREFS_EXTRA_SPACING, // log prefs - combobox
-    IDC_LOG_PREFS_POINT_SIZE,   // log prefs - textctrl
-    IDC_LOG_PREFS_USE_COLOR,    // log prefs - checkbox
-    IDC_LOG_PREFS_FONT_MONO,    // log prefs - checkbox
-
-    IDC_LOG_PREFS_DISPLAY_MAX,  // log prefs - textctrl
-    IDC_LOG_PREFS_POOL_SIZE,    // log prefs - textctrl
-
-    IDC_LOG_PREFS_WRITE_FILE,   // log prefs - checkbox
-    IDC_LOG_PREFS_FILENAME,     // log prefs - textctrl
-    IDC_LOG_PREFS_TRUNCATE_OLD, // log prefs - textctrl
-};
-
-/*
- * Common definitions for control spacing.
- *
- * Doesn't really belong here, but it'll do.
- */
-enum {
-    kEdgeSpacing = 4,       // padding at edge of prefs pages, in pixels
-    kInterSpacing = 5,      // padding between controls, in pixels
-};
-
-#endif // _SIM_RESOURCE_H
diff --git a/simulator/app/Semaphore.cpp b/simulator/app/Semaphore.cpp
deleted file mode 100644
index 3b6ee7b..0000000
--- a/simulator/app/Semaphore.cpp
+++ /dev/null
@@ -1,516 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Inter-process semaphores.
-//
-#include "Semaphore.h"
-
-#if defined(HAVE_MACOSX_IPC)
-# include <semaphore.h>
-#elif defined(HAVE_SYSV_IPC)
-# include <sys/types.h>
-# include <sys/ipc.h>
-# include <sys/sem.h>
-#elif defined(HAVE_WIN32_IPC)
-# include <windows.h>
-#elif defined(HAVE_ANDROID_IPC)
-// not yet
-#else
-# error "unknown sem config"
-#endif
-
-#include <utils/Log.h>
-
-#include <errno.h>
-#include <assert.h>
-
-using namespace android;
-
-
-#if defined(HAVE_ANDROID_IPC) // ----------------------------------------------
-
-Semaphore::Semaphore(void)
-    : mHandle(0), mCreator(false), mKey(-1)
-{}
-
-Semaphore::~Semaphore(void)
-{}
-
-bool Semaphore::create(int key, int initialValue, bool deleteExisting)
-{
-    return false;
-}
-
-bool Semaphore::attach(int key)
-{
-    return false;
-}
-
-void Semaphore::acquire(void)
-{}
-
-void Semaphore::release(void)
-{}
-
-bool Semaphore::tryAcquire(void)
-{
-    return false;
-}
-
-#elif defined(HAVE_MACOSX_IPC) // ---------------------------------------------
-
-/*
- * The SysV semaphores don't work on all of our machines.  The POSIX
- * named semaphores seem to work better.
- */
-
-#define kInvalidHandle SEM_FAILED
-
-static const char* kSemStr = "/tmp/android-sem-";
-
-/*
- * Constructor.  Just init fields.
- */
-Semaphore::Semaphore(void)
-    : mHandle((unsigned long) kInvalidHandle), mCreator(false), mKey(-1)
-{
-}
-
-/*
- * Destructor.  If we created the semaphore, destroy it.
- */
-Semaphore::~Semaphore(void)
-{
-    LOG(LOG_VERBOSE, "sem", "~Semaphore(handle=%ld creator=%d)\n",
-        mHandle, mCreator);
-
-    if (mHandle != (unsigned long) kInvalidHandle) {
-        sem_close((sem_t*) mHandle);
-
-        if (mCreator) {
-            char nameBuf[64];
-            int cc;
-
-            snprintf(nameBuf, sizeof(nameBuf), "%s%d", kSemStr, mKey);
-
-            cc = sem_unlink(nameBuf);
-            if (cc != 0) {
-                LOG(LOG_ERROR, "sem",
-                    "Failed to remove sem '%s' (errno=%d)\n", nameBuf, errno);
-            }
-        }
-    }
-}
-
-/*
- * Create the semaphore.
- */
-bool Semaphore::create(int key, int initialValue, bool deleteExisting)
-{
-    int cc;
-    char nameBuf[64];
-
-    snprintf(nameBuf, sizeof(nameBuf), "%s%d", kSemStr, key);
-
-    if (deleteExisting) {
-        cc = sem_unlink(nameBuf);
-        if (cc != 0 && errno != ENOENT) {
-            LOG(LOG_WARN, "sem", "Warning: failed to remove sem '%s'\n",
-                nameBuf);
-            /* keep going? */
-        }
-    }
-
-    /* create and set initial value */
-    sem_t* semPtr;
-    semPtr = sem_open(nameBuf, O_CREAT | O_EXCL, 0666, 1);
-    if (semPtr == (sem_t*)SEM_FAILED) {
-        LOG(LOG_ERROR, "sem",
-            "ERROR: sem_open failed to create '%s' (errno=%d)\n",
-            nameBuf, errno);
-        return false;
-    }
-
-    mHandle = (unsigned long) semPtr;
-    mCreator = true;
-    mKey = key;
-
-    return true;
-}
-
-/*
- * Attach to an existing semaphore.
- */
-bool Semaphore::attach(int key)
-{
-    char nameBuf[64];
-
-    snprintf(nameBuf, sizeof(nameBuf), "%s%d", kSemStr, key);
-
-    sem_t* semPtr;
-    semPtr = sem_open(nameBuf, 0, 0666, 0);
-    if (semPtr == (sem_t*) SEM_FAILED) {
-        LOG(LOG_ERROR, "sem",
-            "ERROR: sem_open failed to attach to '%s' (errno=%d)\n",
-            nameBuf, errno);
-        return false;
-    }
-
-    mHandle = (unsigned long) semPtr;
-    assert(mCreator == false);
-    mKey = key;
-
-    return true;
-}
-
-/*
- * Acquire or release the semaphore.
- */
-void Semaphore::acquire(void)
-{
-    int cc = sem_wait((sem_t*) mHandle);
-    if (cc != 0)
-        LOG(LOG_WARN, "sem", "acquire failed (errno=%d)\n", errno);
-}
-void Semaphore::release(void)
-{
-    int cc = sem_post((sem_t*) mHandle);
-    if (cc != 0)
-        LOG(LOG_WARN, "sem", "release failed (errno=%d)\n", errno);
-}
-bool Semaphore::tryAcquire(void)
-{
-    int cc = sem_trywait((sem_t*) mHandle);
-    if (cc != 0) {
-        if (errno != EAGAIN)
-            LOG(LOG_WARN, "sem", "tryAcquire failed (errno=%d)\n", errno);
-        return false;
-    }
-    return true;
-}
-
-
-#elif defined(HAVE_SYSV_IPC) // -----------------------------------------------
-
-/*
- * Basic SysV semaphore stuff.
- */
-
-#define kInvalidHandle  ((unsigned long)-1)
-
-#if defined(_SEM_SEMUN_UNDEFINED)
-/* according to X/OPEN we have to define it ourselves */
-union semun {
-    int val;                  /* value for SETVAL */
-    struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
-    unsigned short *array;    /* array for GETALL, SETALL */
-                              /* Linux specific part: */
-    struct seminfo *__buf;    /* buffer for IPC_INFO */
-};
-#endif
-
-/*
- * Constructor.  Just init fields.
- */
-Semaphore::Semaphore(void)
-    : mHandle(kInvalidHandle), mCreator(false)
-{
-}
-
-/*
- * Destructor.  If we created the semaphore, destroy it.
- */
-Semaphore::~Semaphore(void)
-{
-    LOG(LOG_VERBOSE, "sem", "~Semaphore(handle=%ld creator=%d)\n",
-        mHandle, mCreator);
-
-    if (mCreator && mHandle != kInvalidHandle) {
-        int cc;
-
-        cc = semctl((int) mHandle, 0, IPC_RMID);
-        if (cc != 0) {
-            LOG(LOG_WARN, "sem",
-                "Destructor failed to destroy key=%ld\n", mHandle);
-        }
-    }
-}
-
-/*
- * Create the semaphore.
- */
-bool Semaphore::create(int key, int initialValue, bool deleteExisting)
-{
-    int semid, cc;
-
-    if (deleteExisting) {
-        semid = semget(key, 1, 0);
-        if (semid != -1) {
-            LOG(LOG_DEBUG, "sem", "Key %d exists (semid=%d), removing\n",
-                key, semid);
-            cc = semctl(semid, 0, IPC_RMID);
-            if (cc != 0) {
-                LOG(LOG_ERROR, "sem", "Failed to remove key=%d semid=%d\n",
-                    key, semid);
-                return false;
-            } else {
-                LOG(LOG_DEBUG, "sem",
-                    "Removed previous semaphore with key=%d\n", key);
-            }
-        }
-    }
-
-    semid = semget(key, 1, 0600 | IPC_CREAT | IPC_EXCL);
-    if (semid == -1) {
-        LOG(LOG_ERROR, "sem", "Failed to create key=%d (errno=%d)\n",
-            key, errno);
-        return false;
-    }
-
-    mHandle = semid;
-    mCreator = true;
-    mKey = key;
-
-    /*
-     * Set initial value.
-     */
-    union semun init;
-    init.val = initialValue;
-    cc = semctl(semid, 0, SETVAL, init);
-    if (cc == -1) {
-        LOG(LOG_ERROR, "sem",
-            "Unable to initialize semaphore, key=%d iv=%d (errno=%d)\n",
-            key, initialValue, errno);
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Attach to an existing semaphore.
- */
-bool Semaphore::attach(int key)
-{
-    int semid;
-
-    semid = semget(key, 0, 0);
-    if (semid == -1) {
-        LOG(LOG_ERROR, "sem", "Failed to find key=%d\n", key);
-        return false;
-    }
-
-    mHandle = semid;
-    assert(mCreator == false);
-    mKey = key;
-
-    return true;
-}
-
-/*
- * Acquire or release the semaphore.
- */
-void Semaphore::acquire(void)
-{
-    assert(mHandle != kInvalidHandle);
-    adjust(-1, true);
-}
-void Semaphore::release(void)
-{
-    assert(mHandle != kInvalidHandle);
-    adjust(1, true);
-}
-bool Semaphore::tryAcquire(void)
-{
-    assert(mHandle != kInvalidHandle);
-    return adjust(-1, false);
-}
-
-/*
- * Do the actual semaphore manipulation.
- *
- * The semaphore's value indicates the number of free resources.  Pass
- * in a negative value for "adj" to acquire resources, or a positive
- * value to free resources.
- *
- * Returns true on success, false on failure.
- */
-bool Semaphore::adjust(int adj, bool wait)
-{
-    struct sembuf op;
-    int cc;
-
-    op.sem_num = 0;
-    op.sem_op = adj;
-    op.sem_flg = SEM_UNDO;
-    if (!wait)
-        op.sem_flg |= IPC_NOWAIT;
-
-    cc = semop((int) mHandle, &op, 1);
-    if (cc != 0) {
-        if (wait || errno != EAGAIN) {
-            LOG(LOG_WARN, "sem",
-                "semaphore adjust by %d failed for semid=%ld (errno=%d)\n",
-                adj, mHandle, errno);
-        }
-        return false;
-    }
-
-    //LOG(LOG_VERBOSE, "sem",
-    //    "adjusted semaphore by %d (semid=%ld)\n", adj, mHandle);
-
-    return true;
-}
-
-
-#elif defined(HAVE_WIN32_IPC) // ----------------------------------------------
-
-/*
- * Win32 semaphore implementation.
- *
- * Pretty straightforward.
- */
-
-static const char* kSemStr = "android-sem-";
-
-/*
- * Constructor.  Just init fields.
- */
-Semaphore::Semaphore(void)
-    : mHandle((unsigned long) INVALID_HANDLE_VALUE), mCreator(false)
-{
-}
-
-/*
- * Destructor.  Just close the semaphore handle.
- */
-Semaphore::~Semaphore(void)
-{
-    LOG(LOG_DEBUG, "sem", "~Semaphore(handle=%ld creator=%d)\n",
-        mHandle, mCreator);
-
-    if (mHandle != (unsigned long) INVALID_HANDLE_VALUE)
-        CloseHandle((HANDLE) mHandle);
-}
-
-/*
- * Create the semaphore.
- */
-bool Semaphore::create(int key, int initialValue, bool deleteExisting)
-{
-    char keyBuf[64];
-    HANDLE hSem;
-    long max;
-
-    snprintf(keyBuf, sizeof(keyBuf), "%s%d", kSemStr, key);
-
-    if (initialValue == 0)
-        max = 1;
-    else
-        max = initialValue;
-
-    hSem = CreateSemaphore(
-            NULL,                       // security attributes
-            initialValue,               // initial count
-            max,                        // max count, must be >= initial
-            keyBuf);                    // object name
-    if (hSem == NULL) {
-        DWORD err = GetLastError();
-        if (err == ERROR_ALREADY_EXISTS) {
-            LOG(LOG_ERROR, "sem", "Semaphore '%s' already exists\n", keyBuf);
-        } else {
-            LOG(LOG_ERROR, "sem", "CreateSemaphore(%s) failed (err=%ld)\n",
-                keyBuf, err);
-        }
-        return false;
-    }
-
-    mHandle = (unsigned long) hSem;
-    mCreator = true;
-    mKey = key;
-
-    //LOG(LOG_DEBUG, "sem", "Semaphore '%s' created (handle=0x%08lx)\n",
-    //    keyBuf, mHandle);
-
-    return true;
-}
-
-/*
- * Attach to an existing semaphore.
- */
-bool Semaphore::attach(int key)
-{
-    char keyBuf[64];
-    HANDLE hSem;
-
-    snprintf(keyBuf, sizeof(keyBuf), "%s%d", kSemStr, key);
-
-    hSem = OpenSemaphore(
-            //SEMAPHORE_MODIFY_STATE,   // mostly-full access
-            SEMAPHORE_ALL_ACCESS,       // full access
-            FALSE,                      // don't let kids inherit handle
-            keyBuf);                    // object name
-    if (hSem == NULL) {
-        LOG(LOG_ERROR, "sem", "OpenSemaphore(%s) failed (err=%ld)\n",
-            keyBuf, GetLastError());
-        return false;
-    }
-
-    mHandle = (unsigned long) hSem;
-    assert(mCreator == false);
-    mKey = key;
-
-    return true;
-}
-
-/*
- * Acquire or release the semaphore.
- */
-void Semaphore::acquire(void)
-{
-    DWORD result;
-
-    assert(mHandle != (unsigned long) INVALID_HANDLE_VALUE);
-
-    result = WaitForSingleObject((HANDLE) mHandle, INFINITE);
-    if (result != WAIT_OBJECT_0) {
-        LOG(LOG_WARN, "sem",
-            "WaitForSingleObject(INF) on semaphore returned %ld (err=%ld)\n",
-            result, GetLastError());
-    }
-}
-void Semaphore::release(void)
-{
-    DWORD result;
-
-    assert(mHandle != (unsigned long) INVALID_HANDLE_VALUE);
-
-    result = ReleaseSemaphore((HANDLE) mHandle, 1, NULL);    // incr by 1
-    if (result == 0) {
-        LOG(LOG_WARN, "sem", "ReleaseSemaphore failed (err=%ld)\n",
-            GetLastError());
-    }
-}
-bool Semaphore::tryAcquire(void)
-{
-    DWORD result;
-
-    assert(mHandle != (unsigned long) INVALID_HANDLE_VALUE);
-    result = WaitForSingleObject((HANDLE) mHandle, 0);
-    if (result == WAIT_OBJECT_0)
-        return true;        // grabbed it
-    else if (result == WAIT_TIMEOUT)
-        return false;       // not available
-    else if (result == WAIT_FAILED) {
-        LOG(LOG_WARN, "sem", "WaitForSingleObject(0) on sem failed (err=%ld)\n",
-            GetLastError());
-        return false;
-    } else {
-        LOG(LOG_WARN, "sem",
-            "WaitForSingleObject(0) on sem returned %ld (err=%ld)\n",
-            result, GetLastError());
-        return false;
-    }
-}
-
-#endif // ---------------------------------------------------------------------
diff --git a/simulator/app/Semaphore.h b/simulator/app/Semaphore.h
deleted file mode 100644
index 3b834f3..0000000
--- a/simulator/app/Semaphore.h
+++ /dev/null
@@ -1,59 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Inter-process semaphore.
-//
-// These are meant for IPC, not thread management.  The Mutex and Condition
-// classes are much lighter weight.
-//
-#ifndef __LIBS_SEMAPHORE_H
-#define __LIBS_SEMAPHORE_H
-
-#ifdef HAVE_ANDROID_OS
-#error DO NOT USE THIS FILE IN THE DEVICE BUILD
-#endif
-
-namespace android {
-
-/*
- * Platform-independent semaphore class.
- *
- * Each object holds a single semaphore.
- *
- * The "key" is usually the process ID of the process that created the
- * semaphore (following POSIX semantics).  See the comments in shmem.h.
- */
-class Semaphore {
-public:
-    Semaphore(void);
-    virtual ~Semaphore(void);
-
-    /*
-     * Create a new semaphore, with the specified initial value.  The
-     * value indicates the number of resources available.
-     */
-    bool create(int key, int initialValue, bool deleteExisting);
-
-    /*
-     * Attach to an existing semaphore.
-     */
-    bool attach(int key);
-
-    /*
-     * Acquire or release the semaphore.
-     */
-    void acquire(void);
-    void release(void);
-    bool tryAcquire(void);      // take a timeout?
-
-private:
-    bool adjust(int adj, bool wait);
-
-    unsigned long   mHandle;    // semid(int) or HANDLE
-    bool            mCreator;
-    int             mKey;
-};
-
-}; // namespace android
-
-#endif // __LIBS_SEMAPHORE_H
diff --git a/simulator/app/Shmem.cpp b/simulator/app/Shmem.cpp
deleted file mode 100644
index 4c619c2..0000000
--- a/simulator/app/Shmem.cpp
+++ /dev/null
@@ -1,558 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Shared memory interface.
-//
-#include "Shmem.h"
-#include "utils/Log.h"
-
-#if defined(HAVE_MACOSX_IPC) || defined(HAVE_ANDROID_IPC)
-#  include <sys/mman.h>
-#  include <fcntl.h>
-#  include <unistd.h>
-#elif defined(HAVE_SYSV_IPC)
-# include <sys/types.h>
-# include <sys/ipc.h>
-# include <sys/shm.h>
-#elif defined(HAVE_WIN32_IPC)
-# include <windows.h>
-#else
-# error "unknown shm config"
-#endif
-
-#include <errno.h>
-#include <assert.h>
-
-using namespace android;
-
-
-#if defined(HAVE_MACOSX_IPC) || defined(HAVE_ANDROID_IPC)
-
-/*
- * SysV IPC under Mac OS X seems to have problems.  It works fine on
- * some machines but totally fails on others.  We're working around it
- * here by using mmap().
- */
-
-#define kInvalidHandle  ((unsigned long)-1)
-
-static const char* kShmemFile = "/tmp/android-";
-
-/*
- * Constructor.  Just set up the fields.
- */
-Shmem::Shmem(void)
-    : mHandle(kInvalidHandle), mAddr(MAP_FAILED), mLength(-1), mCreator(false),
-      mKey(-1)
-{
-}
-
-/*
- * Destructor.  Detach and, if we created it, mark the segment for
- * destruction.
- */
-Shmem::~Shmem(void)
-{
-    if (mAddr != MAP_FAILED)
-        munmap(mAddr, mLength);
-    if ((long)mHandle >= 0) {
-        close(mHandle);
-
-        if (mCreator) {
-            char nameBuf[64];
-            int cc;
-
-            snprintf(nameBuf, sizeof(nameBuf), "%s%d", kShmemFile, mKey);
-            cc = unlink(nameBuf);
-            if (cc != 0) {
-                LOG(LOG_WARN, "shmem", "Couldn't clean up '%s'\n", nameBuf);
-                /* oh well */
-            }
-        }
-    }
-}
-
-/*
- * Create the segment and attach ourselves to it.
- */
-bool Shmem::create(int key, long size, bool deleteExisting)
-{
-    char nameBuf[64];
-    int fd, cc;
-
-    snprintf(nameBuf, sizeof(nameBuf), "%s%d", kShmemFile, key);
-
-    if (deleteExisting) {
-        cc = unlink(nameBuf);
-        if (cc != 0 && errno != ENOENT) {
-            LOG(LOG_ERROR, "shmem", "Failed to remove old map file '%s'\n",
-                nameBuf);
-            return false;
-        }
-    }
-
-    fd = open(nameBuf, O_CREAT|O_EXCL|O_RDWR, 0600);
-    if (fd < 0) {
-        LOG(LOG_ERROR, "shmem", "Unable to create map file '%s' (errno=%d)\n",
-            nameBuf, errno);
-        return false;
-    }
-
-    /*
-     * Set the file size by seeking and writing.
-     */
-    if (ftruncate(fd, size) == -1) {
-        LOG(LOG_ERROR, "shmem", "Unable to set file size in '%s' (errno=%d)\n",
-            nameBuf, errno);
-        close(fd);
-        return false;
-    }
-
-    mAddr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-    if (mAddr == MAP_FAILED) {
-        LOG(LOG_ERROR, "shmem", "mmap failed (errno=%d)\n", errno);
-        close(fd);
-        return false;
-    }
-
-    mHandle = fd;
-    mLength = size;
-    mCreator = true;
-    mKey = key;
-
-    /* done with shmem, create the associated semaphore */
-    if (!mSem.create(key, 1, true)) {
-        LOG(LOG_ERROR, "shmem",
-            "Failed creating semaphore for Shmem (key=%d)\n", key);
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Attach ourselves to an existing segment.
- */
-bool Shmem::attach(int key)
-{
-    char nameBuf[64];
-    int fd;
-
-    snprintf(nameBuf, sizeof(nameBuf), "%s%d", kShmemFile, key);
-    fd = open(nameBuf, O_RDWR, 0600);
-    if (fd < 0) {
-        LOG(LOG_ERROR, "shmem", "Unable to open map file '%s' (errno=%d)\n",
-            nameBuf, errno);
-        return false;
-    }
-
-    off_t len;
-    len = lseek(fd, 0, SEEK_END);
-    if (len == (off_t) -1) {
-        LOG(LOG_ERROR, "shmem",
-            "Could not determine file size of '%s' (errno=%d)\n",
-            nameBuf, errno);
-        close(fd);
-        return false;
-    }
-
-    mAddr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-    if (mAddr == MAP_FAILED) {
-        LOG(LOG_ERROR, "shmem", "mmap failed (errno=%d)\n", errno);
-        close(fd);
-        return false;
-    }
-
-    mHandle = fd;
-    mLength = len;
-    assert(mCreator == false);
-    mKey = key;
-
-    /* done with shmem, attach to associated semaphore */
-    if (!mSem.attach(key)) {
-        LOG(LOG_ERROR, "shmem",
-            "Failed to attach to semaphore for Shmem (key=%d)\n", key);
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Get address.
- */
-void* Shmem::getAddr(void)
-{
-    assert(mAddr != MAP_FAILED);
-    return mAddr;
-}
-
-/*
- * Return the length of the segment.
- *
- * Returns -1 on failure.
- */
-long Shmem::getLength(void)
-{
-    if (mLength >= 0)
-        return mLength;
-
-    // we should always have it by now
-    assert(false);
-    return -1;
-}
-
-
-#elif defined(HAVE_SYSV_IPC) // ----------------------------------------------
-
-/*
- * SysV-style IPC.  The SysV shared memory API is fairly annoying to
- * deal with, but it's present on many UNIX-like systems.
- */
-
-#define kInvalidHandle  ((unsigned long)-1)
-
-/*
- * Constructor.  Just set up the fields.
- */
-Shmem::Shmem(void)
-    : mHandle(kInvalidHandle), mAddr(NULL), mLength(-1), mCreator(false),
-      mKey(-1)
-{
-}
-
-/*
- * Destructor.  Detach and, if we created it, mark the segment for
- * destruction.
- */
-Shmem::~Shmem(void)
-{
-    int cc;
-
-    //LOG(LOG_DEBUG, "shmem", "~Shmem(handle=%ld creator=%d)",
-    //    mHandle, mCreator);
-
-    if (mAddr != NULL)
-        cc = shmdt(mAddr);
-
-    if (mCreator && mHandle != kInvalidHandle) {
-        cc = shmctl((int) mHandle, IPC_RMID, NULL);
-        if (cc != 0) {
-            LOG(LOG_WARN, "shmem",
-                "Destructor failed to remove shmid=%ld (errno=%d)\n",
-                mHandle, errno);
-        }
-    }
-}
-
-/*
- * Create the segment and attach ourselves to it.
- */
-bool Shmem::create(int key, long size, bool deleteExisting)
-{
-    int shmid, cc;
-
-    if (deleteExisting) {
-        shmid = shmget(key, size, 0);
-        if (shmid != -1) {
-            LOG(LOG_DEBUG, "shmem",
-                "Key %d exists (shmid=%d), marking for destroy", key, shmid);
-            cc = shmctl(shmid, IPC_RMID, NULL);
-            if (cc != 0) {
-                LOG(LOG_ERROR, "shmem",
-                    "Failed to remove key=%d shmid=%d (errno=%d)\n",
-                    key, shmid, errno);
-                return false;   // IPC_CREAT | IPC_EXCL will fail, so bail now
-            } else {
-                LOG(LOG_DEBUG, "shmem",
-                    "Removed previous segment with key=%d\n", key);
-            }
-        }
-    }
-
-    shmid = shmget(key, size, 0600 | IPC_CREAT | IPC_EXCL);
-    if (shmid == -1) {
-        LOG(LOG_ERROR, "shmem", "Failed to create key=%d (errno=%d)\n",
-            key, errno);
-        return false;
-    }
-
-    mHandle = shmid;
-    mCreator = true;
-    mKey = key;
-
-    void* addr = shmat(shmid, NULL, 0);
-    if (addr == (void*) -1) {
-        LOG(LOG_ERROR, "shmem",
-            "Could not attach to key=%d shmid=%d (errno=%d)\n",
-            key, shmid, errno);
-        return false;
-    }
-
-    mAddr = addr;
-    mLength = size;
-
-    /* done with shmem, create the associated semaphore */
-    if (!mSem.create(key, 1, true)) {
-        LOG(LOG_ERROR, "shmem",
-            "Failed creating semaphore for Shmem (key=%d)\n", key);
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Attach ourselves to an existing segment.
- */
-bool Shmem::attach(int key)
-{
-    int shmid;
-
-    shmid = shmget(key, 0, 0);
-    if (shmid == -1) {
-        LOG(LOG_ERROR, "shmem", "Failed to find key=%d\n", key);
-        return false;
-    }
-
-    mHandle = shmid;
-    assert(mCreator == false);
-    mKey = key;
-
-    void* addr = shmat(shmid, NULL, 0);
-    if (addr == (void*) -1) {
-        LOG(LOG_ERROR, "shmem", "Could not attach to key=%d shmid=%d\n",
-            key, shmid);
-        return false;
-    }
-
-    mAddr = addr;
-
-    /* done with shmem, attach to associated semaphore */
-    if (!mSem.attach(key)) {
-        LOG(LOG_ERROR, "shmem",
-            "Failed to attach to semaphore for Shmem (key=%d)\n", key);
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Get address.
- */
-void* Shmem::getAddr(void)
-{
-    assert(mAddr != NULL);
-    return mAddr;
-}
-
-/*
- * Return the length of the segment.
- *
- * Returns -1 on failure.
- */
-long Shmem::getLength(void)
-{
-    if (mLength >= 0)
-        return mLength;
-
-    assert(mHandle != kInvalidHandle);
-
-    struct shmid_ds shmids;
-    int cc;
-
-    cc = shmctl((int) mHandle, IPC_STAT, &shmids);
-    if (cc != 0) {
-        LOG(LOG_ERROR, "shmem", "Could not IPC_STAT shmid=%ld\n", mHandle);
-        return -1;
-    }
-    mLength = shmids.shm_segsz;     // save a copy to avoid future lookups
-
-    return mLength;
-}
-
-
-#elif defined(HAVE_WIN32_IPC) // ---------------------------------------------
-
-/*
- * Win32 shared memory implementation.
- *
- * Shared memory is implemented as an "anonymous" file mapping, using the
- * memory-mapped I/O interfaces.
- */
-
-static const char* kShmemStr = "android-shmem-";
-
-/*
- * Constructor.  Just set up the fields.
- */
-Shmem::Shmem(void)
-    : mHandle((unsigned long) INVALID_HANDLE_VALUE),
-      mAddr(NULL), mLength(-1), mCreator(false), mKey(-1)
-{
-}
-
-/*
- * Destructor.  The Win32 API doesn't require a distinction between
- * the "creator" and other mappers.
- */
-Shmem::~Shmem(void)
-{
-    LOG(LOG_DEBUG, "shmem", "~Shmem(handle=%ld creator=%d)",
-        mHandle, mCreator);
-
-    if (mAddr != NULL)
-        UnmapViewOfFile(mAddr);
-    if (mHandle != (unsigned long) INVALID_HANDLE_VALUE)
-        CloseHandle((HANDLE) mHandle);
-}
-
-/*
- * Create the segment and map it.
- */
-bool Shmem::create(int key, long size, bool deleteExisting)
-{
-    char keyBuf[64];
-    HANDLE hMapFile;
-
-    snprintf(keyBuf, sizeof(keyBuf), "%s%d", kShmemStr, key);
-
-    hMapFile = CreateFileMapping(
-                INVALID_HANDLE_VALUE,       // use paging file, not actual file
-                NULL,                       // default security
-                PAGE_READWRITE,             // read/write access
-                0,                          // max size; no need to cap
-                size,                       // min size
-                keyBuf);                    // mapping name
-    if (hMapFile == NULL || hMapFile == INVALID_HANDLE_VALUE) {
-        LOG(LOG_ERROR, "shmem",
-            "Could not create mapping object '%s' (err=%ld)\n",
-            keyBuf, GetLastError());
-        return false;
-    }
-
-    mHandle = (unsigned long) hMapFile;
-    mCreator = true;
-    mKey = key;
-
-    mAddr = MapViewOfFile(
-                hMapFile,                   // handle to map object
-                FILE_MAP_ALL_ACCESS,        // read/write
-                0,                          // offset (hi)
-                0,                          // offset (lo)
-                size);                      // #of bytes to map
-    if (mAddr == NULL) {
-        LOG(LOG_ERROR, "shmem", "Could not map shared area (err=%ld)\n",
-            GetLastError());
-        return false;
-    }
-    mLength = size;
-
-    /* done with shmem, create the associated semaphore */
-    if (!mSem.create(key, 1, true)) {
-        LOG(LOG_ERROR, "shmem",
-            "Failed creating semaphore for Shmem (key=%d)\n", key);
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Attach ourselves to an existing segment.
- */
-bool Shmem::attach(int key)
-{
-    char keyBuf[64];
-    HANDLE hMapFile;
-
-    snprintf(keyBuf, sizeof(keyBuf), "%s%d", kShmemStr, key);
-
-    hMapFile = OpenFileMapping(
-                FILE_MAP_ALL_ACCESS,        // read/write
-                FALSE,                      // don't let kids inherit handle
-                keyBuf);                    // mapping name
-    if (hMapFile == NULL) {
-        LOG(LOG_ERROR, "shmem",
-            "Could not open mapping object '%s' (err=%ld)\n",
-            keyBuf, GetLastError());
-        return false;
-    }
-
-    mHandle = (unsigned long) hMapFile;
-    assert(mCreator == false);
-    mKey = key;
-
-    mAddr = MapViewOfFile(
-                hMapFile,                   // handle to map object
-                FILE_MAP_ALL_ACCESS,        // read/write
-                0,                          // offset (hi)
-                0,                          // offset (lo)
-                0);                        // #of bytes to map
-    if (mAddr == NULL) {
-        LOG(LOG_ERROR, "shmem", "Could not map shared area (err=%ld)\n",
-            GetLastError());
-        return false;
-    }
-
-    /* done with shmem, attach to associated semaphore */
-    if (!mSem.attach(key)) {
-        LOG(LOG_ERROR, "shmem",
-            "Failed to attach to semaphore for Shmem (key=%d)\n", key);
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Get address.
- */
-void* Shmem::getAddr(void)
-{
-    assert(mAddr != NULL);
-    return mAddr;
-}
-
-/*
- * Get the length of the segment.
- */
-long Shmem::getLength(void)
-{
-    SIZE_T size;
-    MEMORY_BASIC_INFORMATION mbInfo;
-
-    if (mLength >= 0)
-        return mLength;
-
-    assert(mAddr != NULL);
-
-    size = VirtualQuery(mAddr, &mbInfo, sizeof(mbInfo));
-    if (size == 0) {
-        LOG(LOG_WARN, "shmem", "VirtualQuery returned no data\n");
-        return -1;
-    }
-
-    mLength = mbInfo.RegionSize;
-    return mLength;
-}
-
-#endif // --------------------------------------------------------------------
-
-/*
- * Semaphore operations.
- */
-void Shmem::lock(void)
-{
-    mSem.acquire();
-}
-void Shmem::unlock(void)
-{
-    mSem.release();
-}
-bool Shmem::tryLock(void)
-{
-    return mSem.tryAcquire();
-}
-
diff --git a/simulator/app/Shmem.h b/simulator/app/Shmem.h
deleted file mode 100644
index 3d53b58..0000000
--- a/simulator/app/Shmem.h
+++ /dev/null
@@ -1,95 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Inter-process shared memory.
-//
-#ifndef __LIBS_SHMEM_H
-#define __LIBS_SHMEM_H
-
-#ifdef HAVE_ANDROID_OS
-#error DO NOT USE THIS FILE IN THE DEVICE BUILD
-#endif
-
-#include "Semaphore.h"
-
-namespace android {
-
-/*
- * Platform-independent shared memory.  Each object can be used to
- * create a chunk of memory that is shared between processes.
- *
- * For convenience, a semaphore is associated with each segment.
- * (Whether this should have been done in a subclass is debatable.)
- *
- * The "key" is usually the process ID of the process that created the
- * segment.  The goal is to avoid clashing with other processes that are
- * trying to do the same thing.  It's a little awkward to use when you
- * want to have multiple shared segments created in one process.  In
- * SysV you can work around this by using a "private" key and sharing
- * the shmid with your friends, in Win32 you can use a string, but we're
- * in lowest-common-denominator mode here.  Assuming we have 16-bit PIDs,
- * the upper 16 bits can be used to serialize keys.
- *
- * When the object goes out of scope, the shared memory segment is
- * detached from the process.  If the object was responsible for creating
- * the segment, it is also marked for destruction on SysV systems.  This
- * will make it impossible for others to attach to.
- *
- * On some systems, the length returned by getLength() may be different
- * for parent and child due to page size rounding.
- */
-class Shmem {
-public:
-    Shmem(void);
-    virtual ~Shmem(void);
-
-    /*
-     * Create a new shared memory segment, with the specified size.  If
-     * "deleteExisting" is set, any existing segment will be deleted first
-     * (useful for SysV IPC).
-     *
-     * Returns "true" on success, "false" on failure.
-     */
-    bool create(int key, long size, bool deleteExisting);
-
-    /*
-     * Attach to a shared memory segment.  Use this from the process that
-     * didn't create the segment.
-     *
-     * Returns "true" on success, "false" on failure.
-     */
-    bool attach(int key);
-
-    /*
-     * Get the memory segment address and length.  These will not change
-     * for the lifetime of the object, so it's okay to cache the results.
-     *
-     * On failure, getAddr() returns NULL and getLength() returns -1.
-     */
-    void* getAddr(void);
-    long getLength(void);
-
-    /*
-     * Lock or unlock the shared memory segment.  This is useful if you
-     * are updating pieces of shared data.  The segment is initially
-     * "unlocked".
-     *
-     * This does *not* lock down the segment in the virtual paging system.
-     * It's just a mutex.
-     */
-    void lock(void);
-    void unlock(void);
-    bool tryLock(void);
-
-private:
-    Semaphore       mSem;       // uses the same value for "key"
-    unsigned long   mHandle;    // shmid(int) or HANDLE
-    void*           mAddr;      // address
-    long            mLength;    // length of segment (cached)
-    bool            mCreator;   // true if we created the segment
-    int             mKey;       // key passed in as arg
-};
-
-}; // namespace android
-
-#endif // __LIBS_SHMEM_H
diff --git a/simulator/app/SimRuntime.h b/simulator/app/SimRuntime.h
deleted file mode 100644
index 6dadfb2..0000000
--- a/simulator/app/SimRuntime.h
+++ /dev/null
@@ -1,124 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Miscellaneous definitions and declarations used for interaction
-// between the device and the simulator.
-//
-// This header is included on both sides, so try not to include
-// any other headers from here.
-//
-#ifndef _RUNTIME_SIMULATOR_H
-#define _RUNTIME_SIMULATOR_H
-
-#include "MessageStream.h"
-#include "Shmem.h"
-//#include "utils/RefBase.h"
-#include "utils/Log.h"
-
-namespace android {
-
-#define ANDROID_PIPE_NAME "runtime"
-
-/*
- * Hold simulator state.
- */
-class Simulator {
-public:
-    Simulator(void);
-    ~Simulator(void);
-
-    /*
-     * Commands exchanged between simulator and runtime.
-     */
-    typedef enum Command {
-        kCommandUnknown = 0,
-
-        /* sent from sim to runtime */
-        kCommandGoAway,             // sim says: go away, I'm busy
-        kCommandConfigDone,         // sim says: done sending config
-        kCommandQuit,               // quit nicely
-        kCommandNewPGroup,          // process group management
-        kCommandKeyDown,            // key has been pressed
-        kCommandKeyUp,              // key has been released
-        kCommandTouch,              // finger touched/lifted/dragged
-
-        /* sent from runtime to sim */
-        kCommandNewPGroupCreated,    // send process group as argument
-        kCommandRuntimeReady,       // we're initialized and about to start
-        kCommandUpdateDisplay,      // display has been updated
-        kCommandVibrate,            // vibrate on or off
-    } Command;
-
-    typedef enum TouchMode {
-        kTouchDown = 0,
-        kTouchUp = 1,
-        kTouchDrag = 2
-    } TouchMode;
-
-    /*
-     * Some parameters for config exchange.
-     */
-    enum {
-        kDisplayConfigMagic = 0x44495350,
-        kValuesPerDisplay = 5,
-    };
-
-    /*
-     * Set up communication with parent process.
-     */
-    //bool create(ParentProcess* pParent);
-
-    /*
-     * Set up communication with detached simulator.
-     */
-    bool create(Pipe* reader, Pipe* writer);
-
-    /*
-     * Tell simulator that we're ready to go.
-     */
-    void sendRuntimeReady(void);
-
-    /*
-     * Tell the simulator that a display has been refreshed.
-     */
-    void sendDisplayUpdate(int displayIndex);
-
-    /*
-     * Tell the simulator to turn the vibrator on or off
-     */
-    void sendVibrate(int vibrateOn);
-
-    /*
-     * Get a pointer to the shared memory for the Nth display.
-     */
-    Shmem* getGraphicsBuffer(int displayIndex);
-
-    /*
-     * Return a copy of our input pipe so the event system can monitor
-     * it for pending activity.
-     */
-    Pipe* getReadPipe(void) { return mStream.getReadPipe(); }
-
-    /*
-     * Retrieve the next command from the parent.  Returns NO_ERROR
-     * if all is okay, WOULD_BLOCK if blocking is false and there
-     * are no pending commands, or INVALID_OPERATION if the simulator
-     * has disappeared.
-     */
-    int getNextKey(int32_t* outKey, bool* outDown);
-
-    /*
-     * Log system callback function.
-     */
-    static void writeLogMsg(const android_LogBundle* pBundle);
-
-private:
-    bool finishCreate(void);
-    bool handleDisplayConfig(const long* pData, int length);
-
-    MessageStream   mStream;
-};
-
-}; // namespace android
-
-#endif // _RUNTIME_SIMULATOR_H
diff --git a/simulator/app/UserEvent.cpp b/simulator/app/UserEvent.cpp
deleted file mode 100644
index 01d3337..0000000
--- a/simulator/app/UserEvent.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Some additional glue for "user event" type.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-
-#include "UserEvent.h"
-
-DEFINE_EVENT_TYPE(wxEVT_USER_EVENT)
-
-IMPLEMENT_DYNAMIC_CLASS(UserEvent, wxEvent)
-
diff --git a/simulator/app/UserEvent.h b/simulator/app/UserEvent.h
deleted file mode 100644
index 76664e1..0000000
--- a/simulator/app/UserEvent.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// A "user event" for wxWidgets.
-//
-#ifndef _SIM_USER_EVENT_H
-#define _SIM_USER_EVENT_H
-
-/*
- * Event declaration.  The book says to use DECLARE_EVENT_TYPE, but that
- * causes a compiler warning and a link failure with gcc under MinGW.
- *
- * It looks like the "magic number", in this case 12345, is just picked
- * by hand.  There may be a better mechanism in this version of
- * wxWidgets, but the documentation and sample code doesn't reflect it.
- */
-BEGIN_DECLARE_EVENT_TYPES()
-    DECLARE_LOCAL_EVENT_TYPE(wxEVT_USER_EVENT, 12345)
-END_DECLARE_EVENT_TYPES()
-
-/*
- * A "user event" class.  This can be used like any other wxWidgets
- * event, but we get to stuff anything we want to in it.
- */
-class UserEvent : public wxEvent {
-public:
-    UserEvent(int id = 0, void* data = (void*) 0)
-        : wxEvent(id, wxEVT_USER_EVENT), mData(data)
-        {}
-    UserEvent(const UserEvent& event)
-        : wxEvent(event), mData(event.mData)
-        {}
-
-    virtual wxEvent* Clone() const {
-        return new UserEvent(*this);
-    }
-
-    void* GetData(void) const { return mData; }
-
-    DECLARE_DYNAMIC_CLASS(UserEvent);
-
-private:
-    UserEvent& operator=(const UserEvent&);     // not implemented
-    void*   mData;
-};
-
-typedef void (wxEvtHandler::*UserEventFunction)(UserEvent&);
-
-#define EVT_USER_EVENT(fn) \
-        DECLARE_EVENT_TABLE_ENTRY(wxEVT_USER_EVENT, wxID_ANY, wxID_ANY, \
-            (wxObjectEventFunction)(wxEventFunction)(UserEventFunction)&fn, \
-            (wxObject*) NULL ),
-
-#endif // _SIM_USER_EVENT_H
diff --git a/simulator/app/UserEventMessage.h b/simulator/app/UserEventMessage.h
deleted file mode 100644
index 9b94ea7..0000000
--- a/simulator/app/UserEventMessage.h
+++ /dev/null
@@ -1,84 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Contents of the "user event" sent from the device thread.
-//
-#ifndef _SIM_USER_EVENT_MESSAGE_H
-#define _SIM_USER_EVENT_MESSAGE_H
-
-#include "utils.h"
-#include "LogMessage.h"
-
-/*
- * This gets stuffed into a UserEvent, which is posted to the main thread
- * from a worker thread.
- *
- * The object does NOT own anything you stuff into it.  It's just a vehicle
- * for carting data from one thread to another in a wxWidgets-safe manner,
- * usually as pointers to data that can be shared between threads.
- */
-class UserEventMessage {
-public:
-    /*
-     * What type of message is this?
-     */
-    typedef enum UEMType {
-        kUnknown = 0,
-
-        kRuntimeStarted,
-        kRuntimeStopped,
-        kErrorMessage,      // message in mString
-        kLogMessage,        // ptr to heap-allocated LogMessage
-        kExternalRuntime,   // external runtime wants to party
-    } UEMType;
-
-    UserEventMessage(void)
-        : mType(kUnknown), mpLogMessage(NULL)
-        {}
-    ~UserEventMessage(void) {
-    }
-
-    /*
-     * Create one of our various messages.
-     */
-    void CreateRuntimeStarted(void) {
-        mType = kRuntimeStarted;
-    }
-    void CreateRuntimeStopped(void) {
-        mType = kRuntimeStopped;
-    }
-    void CreateErrorMessage(wxString& str) {
-        mType = kErrorMessage;
-        mString = str;
-    }
-    void CreateLogMessage(LogMessage* pLogMessage) {
-        mType = kLogMessage;
-        mpLogMessage = pLogMessage;
-    }
-    void CreateExternalRuntime(android::Pipe* reader, android::Pipe* writer) {
-        mType = kExternalRuntime;
-        mReader = reader;
-        mWriter = writer;
-    }
-
-    /*
-     * Accessors.
-     */
-    UEMType GetType(void) const { return mType; }
-    const wxString& GetString(void) const { return mString; }
-    LogMessage* GetLogMessage(void) const { return mpLogMessage; }
-    android::Pipe* GetReader(void) const { return mReader; }
-    android::Pipe* GetWriter(void) const { return mWriter; }
-
-private:
-    UserEventMessage& operator=(const UserEventMessage&);   // not implemented
-    UserEventMessage(const UserEventMessage&);              // not implemented
-
-    UEMType     mType;
-    wxString    mString;            // for kErrorMessage
-    LogMessage* mpLogMessage;       // for kLogMessage
-    android::Pipe*  mReader;        // for kExternalRuntime
-    android::Pipe*  mWriter;        // for kExternalRuntime
-};
-
-#endif // _SIM_USER_EVENT_MESSAGE_H
diff --git a/simulator/app/assets/android-dream/arrow_down.png b/simulator/app/assets/android-dream/arrow_down.png
deleted file mode 100644
index 19b3764..0000000
--- a/simulator/app/assets/android-dream/arrow_down.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/arrow_left.png b/simulator/app/assets/android-dream/arrow_left.png
deleted file mode 100644
index 113e584..0000000
--- a/simulator/app/assets/android-dream/arrow_left.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/arrow_right.png b/simulator/app/assets/android-dream/arrow_right.png
deleted file mode 100644
index ffe3356..0000000
--- a/simulator/app/assets/android-dream/arrow_right.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/arrow_up.png b/simulator/app/assets/android-dream/arrow_up.png
deleted file mode 100644
index 81c54df..0000000
--- a/simulator/app/assets/android-dream/arrow_up.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/back.png b/simulator/app/assets/android-dream/back.png
deleted file mode 100644
index 41034d9..0000000
--- a/simulator/app/assets/android-dream/back.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/background.png b/simulator/app/assets/android-dream/background.png
deleted file mode 100644
index bab8c6d..0000000
--- a/simulator/app/assets/android-dream/background.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/end.png b/simulator/app/assets/android-dream/end.png
deleted file mode 100644
index 6830a60..0000000
--- a/simulator/app/assets/android-dream/end.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/home.png b/simulator/app/assets/android-dream/home.png
deleted file mode 100644
index 7d02136..0000000
--- a/simulator/app/assets/android-dream/home.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/key.png b/simulator/app/assets/android-dream/key.png
deleted file mode 100644
index 7a3f563..0000000
--- a/simulator/app/assets/android-dream/key.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/layout.xml b/simulator/app/assets/android-dream/layout.xml
deleted file mode 100644
index 8a7c5f8..0000000
--- a/simulator/app/assets/android-dream/layout.xml
+++ /dev/null
@@ -1,356 +0,0 @@
-<?xml version="1.0" ?>
-<!-- Copyright 2006 The Android Open Source Project -->
-
-<device name="Dream">
-    <!-- title for menus -->
-    <title>Android Dream</title>
-
-    <display name="main" width="320" height="480" format="rgb565" refresh="30"/>
-
-    <keyboard qwerty="1" keycharmap="qwerty2" />
-    
-    <mode name="closed">
-        <view display="main" x="75" y="84" rotate="0">
-
-            <!-- surrounding device image and "patches", drawn in order -->
-            <image src="background.png" x="0" y="0"/>
-
-            <!-- buttons for which we have highlight images -->
-            <button keyCode="1"             src="key.png"           x="468" y="276"/>
-            <button keyCode="q"             src="key.png"           x="468" y="312"/>
-            <button keyCode="power"         src="power.png"         x="7"   y="66"/>
-            <button keyCode="volume-up"     src="volume_up.png"     x="407" y="274"/>
-            <button keyCode="volume-down"   src="volume_down.png"   x="407" y="324"/>
-
-            <button keyCode="home"          src="home.png"          x="93"  y="602"/>
-            <button keyCode="back"          src="back.png"          x="331" y="602"/>
-            <button keyCode="dpad-up"       src="arrow_up.png"      x="185" y="608"/>
-            <button keyCode="dpad-down"     src="arrow_down.png"    x="185" y="669"/>
-            <button keyCode="dpad-left"     src="arrow_left.png"    x="155" y="610"/>
-            <button keyCode="dpad-right"    src="arrow_right.png"   x="266" y="610"/>
-            <button keyCode="dpad-center"   src="select.png"        x="186" y="637"/>
-            <button keyCode="phone-dial"    src="send.png"          x="93"  y="658"/>
-            <button keyCode="phone-hangup"  src="end.png"           x="331" y="658"/>
-            <button keyCode="soft-left"     src="menu.png"          x="192" y="569"/>
-
-<!--
-            1 {
-               image  key.png
-               x  468
-               y  302
-            }
-            2 {
-               image  key.png
-               x 505
-               y 302
-            }
-            3 {
-               image  key.png
-               x 543
-               y 302
-            }
-            4 {
-               image  key.png
-               x 579
-               y 302
-            }
-            5 {
-               image  key.png
-               x 616
-               y 302
-            }
-            6 {
-               image  key.png
-               x 653
-               y 302
-            }
-            7 {
-               image  key.png
-               x 690
-               y 302
-            }
-            8 {
-               image  key.png
-               x 727
-               y 302
-            }
-            9 {
-               image  key.png
-               x 763
-               y 302
-            }
-            0 {
-               image  key.png
-               x 801
-               y 302
-            }
-
-            q {
-               image  key.png
-               x  468
-               y  338
-            }
-            w {
-               image  key.png
-               x 505
-               y 338
-            }
-            e {
-               image  key.png
-               x 543
-               y 338
-            }
-            r {
-               image  key.png
-               x 579
-               y 338
-            }
-            t {
-               image  key.png
-               x 616
-               y 338
-            }
-            y {
-               image  key.png
-               x 653
-               y 338
-            }
-            u {
-               image  key.png
-               x 690
-               y 338
-            }
-            i {
-               image  key.png
-               x 727
-               y 338
-            }
-            o {
-               image  key.png
-               x 763
-               y 338
-            }
-            p {
-               image  key.png
-               x 801
-               y 338
-            }
-
-            a {
-               image  key.png
-               x  468
-               y  374
-            }
-            s {
-               image  key.png
-               x 505
-               y 374
-            }
-            d {
-               image  key.png
-               x 543
-               y 374
-            }
-            f {
-               image  key.png
-               x 579
-               y 374
-            }
-            g {
-               image  key.png
-               x 616
-               y 374
-            }
-            h {
-               image  key.png
-               x 653
-               y 374
-            }
-            j {
-               image  key.png
-               x 690
-               y 374
-            }
-            k {
-               image  key.png
-               x 727
-               y 374
-            }
-            l {
-               image  key.png
-               x 763
-               y 374
-            }
-            DEL {
-               image  key.png
-               x 801
-               y 374
-            }
-
-            CAP {
-               image  key.png
-               x  468
-               y  410
-            }
-            z {
-               image  key.png
-               x 505
-               y 410
-            }
-            x {
-               image  key.png
-               x 543
-               y 410
-            }
-            c {
-               image  key.png
-               x 579
-               y 410
-            }
-            v {
-               image  key.png
-               x 616
-               y 410
-            }
-            b {
-               image  key.png
-               x 653
-               y 410
-            }
-            n {
-               image  key.png
-               x 690
-               y 410
-            }
-            m {
-               image  key.png
-               x 727
-               y 410
-            }
-            PERIOD {
-               image  key.png
-               x 763
-               y 410
-            }
-            ENTER {
-               image  key.png
-               x 801
-               y 410
-            }
-
-            ALT {
-               image  key.png
-               x  468
-               y  446
-            }
-            SYM {
-               image  key.png
-               x 505
-               y 446
-            }
-            AT {
-               image  key.png
-               x 543
-               y 446
-            }
-            SPACE {
-               image  spacebar.png
-               x 579
-               y 446
-            }
-            SLASH {
-               image  key.png
-               x 727
-               y 446
-            }
-            COMMA {
-               image  key.png
-               x 763
-               y 446
-            }
-            ALT2 {
-               image  key.png
-               x 801
-               y 446
-            }
-
-            soft-left {
-                image menu.png
-                x 192
-                y 623
-            }
-            home {
-                image home.png
-                x 93
-                y 656
-            }
-            back {
-                image back.png
-                x 331
-                y 656
-            }
-            dpad-up {
-                image arrow_up.png
-                x 185
-                y 662
-            }
-            dpad-down {
-                image arrow_down.png
-                x 185
-                y 723
-            }
-            dpad-left {
-                image arrow_left.png
-                x 155
-                y 664
-            }
-            dpad-right {
-                image arrow_right.png
-                x 266
-                y 664
-            }
-            dpad-center {
-                image select.png
-                x 186
-                y 691
-            }
-            phone-dial {
-                image send.png
-                x 93
-                y 712
-            }
-            phone-hangup {
-                image end.png
-                x 331
-                y 712
-            }
-
-            power {
-                image power.png
-                x 7
-                y 120
-            }
-
-            volume-up {
-                image volume_up.png
-                x 407
-                y 328
-            }
-
-            volume-down {
-                image volume_down.png
-                x 407
-                y 378
-            }
--->
-        </view>
-    </mode>
-
-<!--
-    <mode name="open">
-        <view display="main" x="0" y="0" rotate="90">
-        </view>
-    </mode>
--->
-
-</device>
diff --git a/simulator/app/assets/android-dream/menu.png b/simulator/app/assets/android-dream/menu.png
deleted file mode 100644
index e81d8ab..0000000
--- a/simulator/app/assets/android-dream/menu.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/power.png b/simulator/app/assets/android-dream/power.png
deleted file mode 100644
index 5894288..0000000
--- a/simulator/app/assets/android-dream/power.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/select.png b/simulator/app/assets/android-dream/select.png
deleted file mode 100644
index 803d493..0000000
--- a/simulator/app/assets/android-dream/select.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/send.png b/simulator/app/assets/android-dream/send.png
deleted file mode 100644
index f547c88..0000000
--- a/simulator/app/assets/android-dream/send.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/spacebar.png b/simulator/app/assets/android-dream/spacebar.png
deleted file mode 100644
index 19fe604..0000000
--- a/simulator/app/assets/android-dream/spacebar.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/volume_down.png b/simulator/app/assets/android-dream/volume_down.png
deleted file mode 100644
index f8a88de..0000000
--- a/simulator/app/assets/android-dream/volume_down.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-dream/volume_up.png b/simulator/app/assets/android-dream/volume_up.png
deleted file mode 100644
index 940457f..0000000
--- a/simulator/app/assets/android-dream/volume_up.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/back.png b/simulator/app/assets/android-sooner/back.png
deleted file mode 100644
index 5190939..0000000
--- a/simulator/app/assets/android-sooner/back.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/background.png b/simulator/app/assets/android-sooner/background.png
deleted file mode 100644
index 32534b9..0000000
--- a/simulator/app/assets/android-sooner/background.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/down.png b/simulator/app/assets/android-sooner/down.png
deleted file mode 100644
index 1d602b0..0000000
--- a/simulator/app/assets/android-sooner/down.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/end.png b/simulator/app/assets/android-sooner/end.png
deleted file mode 100644
index 17d8cc7..0000000
--- a/simulator/app/assets/android-sooner/end.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/favorites.png b/simulator/app/assets/android-sooner/favorites.png
deleted file mode 100644
index ad85c5c..0000000
--- a/simulator/app/assets/android-sooner/favorites.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/home.png b/simulator/app/assets/android-sooner/home.png
deleted file mode 100644
index 04f9a21..0000000
--- a/simulator/app/assets/android-sooner/home.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/imap b/simulator/app/assets/android-sooner/imap
deleted file mode 100644
index 64c9aff..0000000
--- a/simulator/app/assets/android-sooner/imap
+++ /dev/null
@@ -1,15 +0,0 @@
-# awk '{print $1, $4-$2 "x" $5-$3 "+" $2 "+" $3}'
-
-BACKGROUND=background-alpha.png
-
-convert $BACKGROUND -crop 43x47+55+410 send.png
-convert $BACKGROUND -crop 43x47+338+411 end.png
-convert $BACKGROUND -crop 43x40+98+393 menu.png
-convert $BACKGROUND -crop 43x40+98+433 back.png
-convert $BACKGROUND -crop 47x40+291+393 favorites.png
-convert $BACKGROUND -crop 47x40+291+433 home.png
-convert $BACKGROUND -crop 81x24+177+422 select.png
-convert $BACKGROUND -crop 81x30+177+392 up.png
-convert $BACKGROUND -crop 81x30+177+446 down.png
-convert $BACKGROUND -crop 31x84+146+392 left.png
-convert $BACKGROUND -crop 31x84+258+392 right.png
diff --git a/simulator/app/assets/android-sooner/layout.xml b/simulator/app/assets/android-sooner/layout.xml
deleted file mode 100644
index d17b9d8..0000000
--- a/simulator/app/assets/android-sooner/layout.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" ?>
-<!-- Copyright 2006 The Android Open Source Project -->
-
-<device name="Sooner">
-    <!-- title for menus -->
-    <title>Android Sooner</title>
-
-    <display name="main" width="320" height="240" format="rgb565" refresh="30"/>
-
-    <keyboard qwerty="1" keycharmap="qwerty" />
-    
-    <mode name="default">
-        <view display="main" x="53" y="95" rotate="0">
-
-            <!-- surrounding device image and "patches", drawn in order -->
-            <image src="background.png" x="0" y="0"/>
-
-            <!-- buttons for which we have highlight images -->
-            <button keyCode="soft-left"     src="menu.png"          x="93"  y="367"/>
-            <button keyCode="soft-right"    src="favorites.png"     x="286" y="367"/>
-            <button keyCode="home"          src="home.png"          x="286" y="407"/>
-            <button keyCode="back"          src="back.png"          x="93"  y="407"/>
-            <button keyCode="dpad-up"       src="up.png"            x="172" y="366"/>
-            <button keyCode="dpad-down"     src="down.png"          x="172" y="420"/>
-            <button keyCode="dpad-left"     src="left.png"          x="141" y="366"/>
-            <button keyCode="dpad-right"    src="right.png"         x="253" y="366"/>
-            <button keyCode="dpad-center"   src="select.png"        x="172" y="396"/>
-
-            <button keyCode="phone-dial"    src="send.png"          x="50"  y="384"/>
-            <button keyCode="phone-hangup"  src="end.png"           x="333" y="385"/>
-        </view>
-    </mode>
-
-</device>
diff --git a/simulator/app/assets/android-sooner/left.png b/simulator/app/assets/android-sooner/left.png
deleted file mode 100644
index f712f5c..0000000
--- a/simulator/app/assets/android-sooner/left.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/menu.png b/simulator/app/assets/android-sooner/menu.png
deleted file mode 100644
index 4c7f15a..0000000
--- a/simulator/app/assets/android-sooner/menu.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/right.png b/simulator/app/assets/android-sooner/right.png
deleted file mode 100644
index b1aa1f9..0000000
--- a/simulator/app/assets/android-sooner/right.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/select.png b/simulator/app/assets/android-sooner/select.png
deleted file mode 100644
index 79606d1..0000000
--- a/simulator/app/assets/android-sooner/select.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/send.png b/simulator/app/assets/android-sooner/send.png
deleted file mode 100644
index 9bf103d..0000000
--- a/simulator/app/assets/android-sooner/send.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/android-sooner/up.png b/simulator/app/assets/android-sooner/up.png
deleted file mode 100644
index 324d67e..0000000
--- a/simulator/app/assets/android-sooner/up.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/chimera-2000/layout.xml b/simulator/app/assets/chimera-2000/layout.xml
deleted file mode 100644
index d808281..0000000
--- a/simulator/app/assets/chimera-2000/layout.xml
+++ /dev/null
@@ -1,194 +0,0 @@
-<?xml version="1.0" ?>
-<!-- Copyright 2005 The Android Open Source Project -->
-
-<!--
-This is a silly, contrived example of a dual-screen display device.
-The "front" and "back" are shown side-by-side.  I used the phone graphics
-from two phones, which are presented as if they were glued back-to-back.
-
-This also illustrates front and back views, which for our purposes just
-determines which phone is on the left.
-
-This used to use relative paths (../whatever) to get at the phone content,
-but relative paths aren't supported in the "AssetManager" world.  We now
-use "::/whatever", which is interpreted by the simulator.  (The change from
-'.' to ':' was done to make it obvious that we weren't using UNIX paths.)
--->
-
-
-<device name="Chimera2000">
-    <!-- title for menus -->
-    <title>Chimera WeirdPhone 2000</title>
-
-    <!-- primary display characteristics -->
-    <display name="top" width="176" height="220" format="rgb565" refresh="30"/>
-    <display name="bottom" width="176" height="220" format="rgb565" refresh="30"/>
-
-	<mode name="front">
-        <!-- the "top" device looks like a Samsung phone -->
-		<view display="top" x="49" y="73" rotate="0">
-
-			<!-- surrounding device image and "patches", drawn in order -->
-			<!-- (phone image is optional) -->
-            <image src="::/samsung-flip-2005/background-176x220.png" x="0" y="0"/>
-            <image src="::/samsung-flip-2005/home-background.png" x="22" y="426"/>
-            <image src="::/samsung-flip-2005/back-background.png" x="179" y="426"/>
-
-			<!-- buttons for which we have highlight images -->
-            <button keyCode="soft-left"     src="::/samsung-flip-2005/soft-left.png"     x="24" y="388"/>
-            <button keyCode="soft-right"    src="::/samsung-flip-2005/soft-right.png"    x="182" y="388"/>
-            <button keyCode="home"          src="::/samsung-flip-2005/home.png"          x="22" y="426"/>
-            <button keyCode="back"          src="::/samsung-flip-2005/back.png"          x="179" y="426"/>
-            <button keyCode="dpad-up"       src="::/samsung-flip-2005/arrow-up.png"      x="99" y="399"/>
-            <button keyCode="dpad-down"     src="::/samsung-flip-2005/arrow-down.png"    x="99" y="461"/>
-            <button keyCode="dpad-left"     src="::/samsung-flip-2005/arrow-left.png"    x="82" y="411"/>
-            <button keyCode="dpad-right"    src="::/samsung-flip-2005/arrow-right.png"   x="147" y="411"/>
-            <button keyCode="dpad-center"   src="::/samsung-flip-2005/select.png"        x="115" y="431"/>
-
-            <button keyCode="1"             src="::/samsung-flip-2005/1.png"             x="24" y="533"/>
-            <button keyCode="2"             src="::/samsung-flip-2005/2.png"             x="94" y="544"/>
-            <button keyCode="3"             src="::/samsung-flip-2005/3.png"             x="173" y="534"/>
-            <button keyCode="4"             src="::/samsung-flip-2005/4.png"             x="25" y="576"/>
-            <button keyCode="5"             src="::/samsung-flip-2005/5.png"             x="94" y="581"/>
-            <button keyCode="6"             src="::/samsung-flip-2005/6.png"             x="172" y="576"/>
-            <button keyCode="7"             src="::/samsung-flip-2005/7.png"             x="27" y="619"/>
-            <button keyCode="8"             src="::/samsung-flip-2005/8.png"             x="95" y="621"/>
-            <button keyCode="9"             src="::/samsung-flip-2005/9.png"             x="168" y="620"/>
-            <button keyCode="0"             src="::/samsung-flip-2005/0.png"             x="96" y="658"/>
-            <button keyCode="star"          src="::/samsung-flip-2005/star.png"          x="31" y="659"/>
-            <button keyCode="pound"         src="::/samsung-flip-2005/pound.png"         x="169" y="659"/>
-
-            <!-- buttons we haven't bothered to create highlight images for,
-                 or that aren't visible on-screen -->
-			<button keyCode="volume-up"/>
-			<button keyCode="volume-down"/>
-			<button keyCode="power"/>
-			<button keyCode="clear"/>
-		</view>
-
-        <!-- the "bottom" device looks like an HTC phone -->
-		<view display="bottom" x="36" y="73" rotate="0">
-
-			<!-- surrounding device image and "patches", drawn in order -->
-			<!-- (phone image is optional) -->
-            <image src="::/htc-audiovox-5600/background.png" x="0" y="0"/>
-
-			<!-- buttons for which we have highlight images -->
-            <button keyCode="soft-left"     src="::/htc-audiovox-5600/soft-left.png"     x="40" y="312"/>
-            <button keyCode="soft-right"    src="::/htc-audiovox-5600/soft-right.png"    x="145" y="312"/>
-            <button keyCode="home"          src="::/htc-audiovox-5600/home.png"          x="57" y="331"/>
-            <button keyCode="back"          src="::/htc-audiovox-5600/back.png"          x="123" y="333"/>
-            <button keyCode="dpad-up"       src="::/htc-audiovox-5600/arrow-up.png"      x="59" y="364"/>
-            <button keyCode="dpad-down"     src="::/htc-audiovox-5600/arrow-down.png"    x="60" y="393"/>
-            <button keyCode="dpad-left"/>
-            <button keyCode="dpad-right"/>
-            <button keyCode="dpad-center"   src="::/htc-audiovox-5600/select.png"        x="103" y="381"/>
-
-            <button keyCode="1"             src="::/htc-audiovox-5600/1.png"             x="30" y="411"/>
-            <button keyCode="2"             src="::/htc-audiovox-5600/2.png"             x="90" y="409"/>
-            <button keyCode="3"             src="::/htc-audiovox-5600/3.png"             x="159" y="413"/>
-            <button keyCode="4"             src="::/htc-audiovox-5600/4.png"             x="32" y="445"/>
-            <button keyCode="5"             src="::/htc-audiovox-5600/5.png"             x="92" y="445"/>
-            <button keyCode="6"             src="::/htc-audiovox-5600/6.png"             x="157" y="444"/>
-            <button keyCode="7"             src="::/htc-audiovox-5600/7.png"             x="28" y="476"/>
-            <button keyCode="8"             src="::/htc-audiovox-5600/8.png"             x="94" y="480"/>
-            <button keyCode="9"             src="::/htc-audiovox-5600/9.png"             x="156" y="477"/>
-            <button keyCode="0"             src="::/htc-audiovox-5600/0.png"             x="97" y="513"/>
-            <button keyCode="star"          src="::/htc-audiovox-5600/star.png"          x="45" y="509"/>
-            <button keyCode="pound"         src="::/htc-audiovox-5600/pound.png"         x="155" y="511"/>
-
-            <!-- buttons we haven't bothered to create highlight images for,
-                 or that aren't visible on-screen -->
-			<button keyCode="volume-up"/>
-			<button keyCode="volume-down"/>
-			<button keyCode="power"/>
-			<button keyCode="clear"/>
-
-		</view>
-	</mode>
-
-	<mode name="back">
-        <!-- show the back view first, then the front view -->
-		<view display="bottom" x="36" y="73" rotate="0">
-
-			<!-- surrounding device image and "patches", drawn in order -->
-			<!-- (phone image is optional) -->
-            <image src="::/htc-audiovox-5600/background.png" x="0" y="0"/>
-
-			<!-- buttons for which we have highlight images -->
-            <button keyCode="soft-left"     src="::/htc-audiovox-5600/soft-left.png"     x="40" y="312"/>
-            <button keyCode="soft-right"    src="::/htc-audiovox-5600/soft-right.png"    x="145" y="312"/>
-            <button keyCode="home"          src="::/htc-audiovox-5600/home.png"          x="57" y="331"/>
-            <button keyCode="back"          src="::/htc-audiovox-5600/back.png"          x="123" y="333"/>
-            <button keyCode="dpad-up"       src="::/htc-audiovox-5600/arrow-up.png"      x="59" y="364"/>
-            <button keyCode="dpad-down"     src="::/htc-audiovox-5600/arrow-down.png"    x="60" y="393"/>
-            <button keyCode="dpad-left"/>
-            <button keyCode="dpad-right"/>
-            <button keyCode="dpad-center"   src="::/htc-audiovox-5600/select.png"        x="103" y="381"/>
-
-            <button keyCode="1"             src="::/htc-audiovox-5600/1.png"             x="30" y="411"/>
-            <button keyCode="2"             src="::/htc-audiovox-5600/2.png"             x="90" y="409"/>
-            <button keyCode="3"             src="::/htc-audiovox-5600/3.png"             x="159" y="413"/>
-            <button keyCode="4"             src="::/htc-audiovox-5600/4.png"             x="32" y="445"/>
-            <button keyCode="5"             src="::/htc-audiovox-5600/5.png"             x="92" y="445"/>
-            <button keyCode="6"             src="::/htc-audiovox-5600/6.png"             x="157" y="444"/>
-            <button keyCode="7"             src="::/htc-audiovox-5600/7.png"             x="28" y="476"/>
-            <button keyCode="8"             src="::/htc-audiovox-5600/8.png"             x="94" y="480"/>
-            <button keyCode="9"             src="::/htc-audiovox-5600/9.png"             x="156" y="477"/>
-            <button keyCode="0"             src="::/htc-audiovox-5600/0.png"             x="97" y="513"/>
-            <button keyCode="star"          src="::/htc-audiovox-5600/star.png"          x="45" y="509"/>
-            <button keyCode="pound"         src="::/htc-audiovox-5600/pound.png"         x="155" y="511"/>
-
-            <!-- buttons we haven't bothered to create highlight images for,
-                 or that aren't visible on-screen -->
-			<button keyCode="volume-up"/>
-			<button keyCode="volume-down"/>
-			<button keyCode="power"/>
-			<button keyCode="clear"/>
-
-		</view>
-
-        <!-- our view of the device that shows the main display -->
-		<view display="top" x="49" y="73" rotate="0">
-
-			<!-- surrounding device image and "patches", drawn in order -->
-			<!-- (phone image is optional) -->
-            <image src="::/samsung-flip-2005/background-176x220.png" x="0" y="0"/>
-            <image src="::/samsung-flip-2005/home-background.png" x="22" y="426"/>
-            <image src="::/samsung-flip-2005/back-background.png" x="179" y="426"/>
-
-			<!-- buttons for which we have highlight images -->
-            <button keyCode="soft-left"     src="::/samsung-flip-2005/soft-left.png"     x="24" y="388"/>
-            <button keyCode="soft-right"    src="::/samsung-flip-2005/soft-right.png"    x="182" y="388"/>
-            <button keyCode="home"          src="::/samsung-flip-2005/home.png"          x="22" y="426"/>
-            <button keyCode="back"          src="::/samsung-flip-2005/back.png"          x="179" y="426"/>
-            <button keyCode="dpad-up"       src="::/samsung-flip-2005/arrow-up.png"      x="99" y="399"/>
-            <button keyCode="dpad-down"     src="::/samsung-flip-2005/arrow-down.png"    x="99" y="461"/>
-            <button keyCode="dpad-left"     src="::/samsung-flip-2005/arrow-left.png"    x="82" y="411"/>
-            <button keyCode="dpad-right"    src="::/samsung-flip-2005/arrow-right.png"   x="147" y="411"/>
-            <button keyCode="dpad-center"   src="::/samsung-flip-2005/select.png"        x="115" y="431"/>
-
-            <button keyCode="1"             src="::/samsung-flip-2005/1.png"             x="24" y="533"/>
-            <button keyCode="2"             src="::/samsung-flip-2005/2.png"             x="94" y="544"/>
-            <button keyCode="3"             src="::/samsung-flip-2005/3.png"             x="173" y="534"/>
-            <button keyCode="4"             src="::/samsung-flip-2005/4.png"             x="25" y="576"/>
-            <button keyCode="5"             src="::/samsung-flip-2005/5.png"             x="94" y="581"/>
-            <button keyCode="6"             src="::/samsung-flip-2005/6.png"             x="172" y="576"/>
-            <button keyCode="7"             src="::/samsung-flip-2005/7.png"             x="27" y="619"/>
-            <button keyCode="8"             src="::/samsung-flip-2005/8.png"             x="95" y="621"/>
-            <button keyCode="9"             src="::/samsung-flip-2005/9.png"             x="168" y="620"/>
-            <button keyCode="0"             src="::/samsung-flip-2005/0.png"             x="96" y="658"/>
-            <button keyCode="star"          src="::/samsung-flip-2005/star.png"          x="31" y="659"/>
-            <button keyCode="pound"         src="::/samsung-flip-2005/pound.png"         x="169" y="659"/>
-
-            <!-- buttons we haven't bothered to create highlight images for,
-                 or that aren't visible on-screen -->
-			<button keyCode="volume-up"/>
-			<button keyCode="volume-down"/>
-			<button keyCode="power"/>
-			<button keyCode="clear"/>
-		</view>
-
-	</mode>
-</device>
-
diff --git a/simulator/app/assets/danger-hiptop-m1/background-open.png b/simulator/app/assets/danger-hiptop-m1/background-open.png
deleted file mode 100644
index 62d2c29..0000000
--- a/simulator/app/assets/danger-hiptop-m1/background-open.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/danger-hiptop-m1/background.png b/simulator/app/assets/danger-hiptop-m1/background.png
deleted file mode 100644
index f8c58c7..0000000
--- a/simulator/app/assets/danger-hiptop-m1/background.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/danger-hiptop-m1/layout.xml b/simulator/app/assets/danger-hiptop-m1/layout.xml
deleted file mode 100644
index f8d7cba..0000000
--- a/simulator/app/assets/danger-hiptop-m1/layout.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" ?>
-<!-- Copyright 2005 The Android Open Source Project -->
-
-<device name="DangerM1">
-    <!-- title for menus -->
-    <title>Danger hiptop M1</title>
-
-    <display name="main" width="240" height="160" format="rgb565" refresh="30"/>
-
-	<keyboard qwerty="1" />
-	
-    <mode name="closed">
-        <!-- hiptop when closed -->
-        <view display="main" x="160" y="69" rotate="0">
-
-            <!-- surrounding device image and "patches", drawn in order -->
-            <image src="background.png" x="0" y="0"/>
-
-        </view>
-    </mode>
-
-    <mode name="open">
-        <!-- hiptop when flipped open -->
-        <view display="main" x="172" y="60" rotate="180">
-
-            <image src="background-open.png" x="0" y="0"/>
-        </view>
-    </mode>
-
-</device>
-
diff --git a/simulator/app/assets/htc-audiovox-5600/0.png b/simulator/app/assets/htc-audiovox-5600/0.png
deleted file mode 100644
index 1fa4b72..0000000
--- a/simulator/app/assets/htc-audiovox-5600/0.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/1.png b/simulator/app/assets/htc-audiovox-5600/1.png
deleted file mode 100644
index f939334..0000000
--- a/simulator/app/assets/htc-audiovox-5600/1.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/2.png b/simulator/app/assets/htc-audiovox-5600/2.png
deleted file mode 100644
index 09be58b..0000000
--- a/simulator/app/assets/htc-audiovox-5600/2.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/3.png b/simulator/app/assets/htc-audiovox-5600/3.png
deleted file mode 100644
index 91c70c1..0000000
--- a/simulator/app/assets/htc-audiovox-5600/3.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/4.png b/simulator/app/assets/htc-audiovox-5600/4.png
deleted file mode 100644
index da930ff..0000000
--- a/simulator/app/assets/htc-audiovox-5600/4.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/5.png b/simulator/app/assets/htc-audiovox-5600/5.png
deleted file mode 100644
index 5c4625a..0000000
--- a/simulator/app/assets/htc-audiovox-5600/5.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/6.png b/simulator/app/assets/htc-audiovox-5600/6.png
deleted file mode 100644
index f309960..0000000
--- a/simulator/app/assets/htc-audiovox-5600/6.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/7.png b/simulator/app/assets/htc-audiovox-5600/7.png
deleted file mode 100644
index e09b08c..0000000
--- a/simulator/app/assets/htc-audiovox-5600/7.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/8.png b/simulator/app/assets/htc-audiovox-5600/8.png
deleted file mode 100644
index c8b3dcc..0000000
--- a/simulator/app/assets/htc-audiovox-5600/8.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/9.png b/simulator/app/assets/htc-audiovox-5600/9.png
deleted file mode 100644
index f284212..0000000
--- a/simulator/app/assets/htc-audiovox-5600/9.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/arrow-down.png b/simulator/app/assets/htc-audiovox-5600/arrow-down.png
deleted file mode 100644
index 08a17ea..0000000
--- a/simulator/app/assets/htc-audiovox-5600/arrow-down.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/arrow-up.png b/simulator/app/assets/htc-audiovox-5600/arrow-up.png
deleted file mode 100644
index f2998b9..0000000
--- a/simulator/app/assets/htc-audiovox-5600/arrow-up.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/back.png b/simulator/app/assets/htc-audiovox-5600/back.png
deleted file mode 100644
index 4110ec7..0000000
--- a/simulator/app/assets/htc-audiovox-5600/back.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/background-orange.png b/simulator/app/assets/htc-audiovox-5600/background-orange.png
deleted file mode 100644
index b147546..0000000
--- a/simulator/app/assets/htc-audiovox-5600/background-orange.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/background.png b/simulator/app/assets/htc-audiovox-5600/background.png
deleted file mode 100644
index 9ffd7f3..0000000
--- a/simulator/app/assets/htc-audiovox-5600/background.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/home.png b/simulator/app/assets/htc-audiovox-5600/home.png
deleted file mode 100644
index a10d293..0000000
--- a/simulator/app/assets/htc-audiovox-5600/home.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/layout.xml b/simulator/app/assets/htc-audiovox-5600/layout.xml
deleted file mode 100644
index 9e68c0f..0000000
--- a/simulator/app/assets/htc-audiovox-5600/layout.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" ?>
-<!-- Copyright 2005 The Android Open Source Project -->
-
-<device name="HTC5600">
-    <!-- title for menus -->
-    <title>HTC AudioVox 5600</title>
-
-    <!-- primary display characteristics -->
-    <display name="main" width="176" height="220" format="rgb565" refresh="30"/>
-
-	<mode name="default">
-		<view display="main" x="36" y="73" rotate="0">
-
-			<!-- surrounding device image and "patches", drawn in order -->
-			<!-- (phone image is optional) -->
-			<image src="background.png" x="0" y="0"/>
-
-			<!-- buttons for which we have highlight images -->
-			<button keyCode="soft-left"     src="soft-left.png"     x="40" y="312"/>
-			<button keyCode="soft-right"    src="soft-right.png"    x="145" y="312"/>
-			<button keyCode="home"          src="home.png"          x="57" y="331"/>
-			<button keyCode="back"          src="back.png"          x="123" y="333"/>
-			<button keyCode="dpad-up"       src="arrow-up.png"      x="59" y="364"/>
-			<button keyCode="dpad-down"     src="arrow-down.png"    x="60" y="393"/>
-            <button keyCode="dpad-left"/>
-            <button keyCode="dpad-right"/>
-			<button keyCode="dpad-center"   src="select.png"        x="103" y="381"/>
-
-			<button keyCode="1"             src="1.png"             x="30" y="411"/>
-			<button keyCode="2"             src="2.png"             x="90" y="409"/>
-			<button keyCode="3"             src="3.png"             x="159" y="413"/>
-			<button keyCode="4"             src="4.png"             x="32" y="445"/>
-			<button keyCode="5"             src="5.png"             x="92" y="445"/>
-			<button keyCode="6"             src="6.png"             x="157" y="444"/>
-			<button keyCode="7"             src="7.png"             x="28" y="476"/>
-			<button keyCode="8"             src="8.png"             x="94" y="480"/>
-			<button keyCode="9"             src="9.png"             x="156" y="477"/>
-			<button keyCode="0"             src="0.png"             x="97" y="513"/>
-			<button keyCode="star"          src="star.png"          x="45" y="509"/>
-			<button keyCode="pound"         src="pound.png"         x="155" y="511"/>
-
-            <!-- buttons we haven't bothered to create highlight images for,
-                 or that aren't visible on-screen -->
-			<button keyCode="volume-up"/>
-			<button keyCode="volume-down"/>
-			<button keyCode="power"/>
-			<button keyCode="clear"/>
-
-		</view>
-	</mode>
-
-</device>
-
diff --git a/simulator/app/assets/htc-audiovox-5600/pound.png b/simulator/app/assets/htc-audiovox-5600/pound.png
deleted file mode 100644
index 90df1fa..0000000
--- a/simulator/app/assets/htc-audiovox-5600/pound.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/select.png b/simulator/app/assets/htc-audiovox-5600/select.png
deleted file mode 100644
index 509082c..0000000
--- a/simulator/app/assets/htc-audiovox-5600/select.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/soft-left.png b/simulator/app/assets/htc-audiovox-5600/soft-left.png
deleted file mode 100644
index ce8cc5c..0000000
--- a/simulator/app/assets/htc-audiovox-5600/soft-left.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/soft-right.png b/simulator/app/assets/htc-audiovox-5600/soft-right.png
deleted file mode 100644
index f3c76c7..0000000
--- a/simulator/app/assets/htc-audiovox-5600/soft-right.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-audiovox-5600/star.png b/simulator/app/assets/htc-audiovox-5600/star.png
deleted file mode 100644
index 19aa057..0000000
--- a/simulator/app/assets/htc-audiovox-5600/star.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/0.png b/simulator/app/assets/htc-tornado/0.png
deleted file mode 100644
index a40e898..0000000
--- a/simulator/app/assets/htc-tornado/0.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/1.png b/simulator/app/assets/htc-tornado/1.png
deleted file mode 100644
index 92c6782..0000000
--- a/simulator/app/assets/htc-tornado/1.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/2.png b/simulator/app/assets/htc-tornado/2.png
deleted file mode 100644
index 42a79ec..0000000
--- a/simulator/app/assets/htc-tornado/2.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/3.png b/simulator/app/assets/htc-tornado/3.png
deleted file mode 100644
index 7e685a8..0000000
--- a/simulator/app/assets/htc-tornado/3.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/4.png b/simulator/app/assets/htc-tornado/4.png
deleted file mode 100644
index c1b8060..0000000
--- a/simulator/app/assets/htc-tornado/4.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/5.png b/simulator/app/assets/htc-tornado/5.png
deleted file mode 100644
index 29d2607..0000000
--- a/simulator/app/assets/htc-tornado/5.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/6.png b/simulator/app/assets/htc-tornado/6.png
deleted file mode 100644
index 509aae5..0000000
--- a/simulator/app/assets/htc-tornado/6.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/7.png b/simulator/app/assets/htc-tornado/7.png
deleted file mode 100644
index 1608777..0000000
--- a/simulator/app/assets/htc-tornado/7.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/8.png b/simulator/app/assets/htc-tornado/8.png
deleted file mode 100644
index 9fac3e6..0000000
--- a/simulator/app/assets/htc-tornado/8.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/9.png b/simulator/app/assets/htc-tornado/9.png
deleted file mode 100644
index 6a357cb..0000000
--- a/simulator/app/assets/htc-tornado/9.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/arrow-down.png b/simulator/app/assets/htc-tornado/arrow-down.png
deleted file mode 100644
index c00787f..0000000
--- a/simulator/app/assets/htc-tornado/arrow-down.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/arrow-left.png b/simulator/app/assets/htc-tornado/arrow-left.png
deleted file mode 100644
index 1180a94..0000000
--- a/simulator/app/assets/htc-tornado/arrow-left.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/arrow-right.png b/simulator/app/assets/htc-tornado/arrow-right.png
deleted file mode 100644
index 6a511d2..0000000
--- a/simulator/app/assets/htc-tornado/arrow-right.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/arrow-up.png b/simulator/app/assets/htc-tornado/arrow-up.png
deleted file mode 100644
index da50871..0000000
--- a/simulator/app/assets/htc-tornado/arrow-up.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/back.png b/simulator/app/assets/htc-tornado/back.png
deleted file mode 100644
index d12273d..0000000
--- a/simulator/app/assets/htc-tornado/back.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/background.png b/simulator/app/assets/htc-tornado/background.png
deleted file mode 100644
index 09169b8..0000000
--- a/simulator/app/assets/htc-tornado/background.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/home.png b/simulator/app/assets/htc-tornado/home.png
deleted file mode 100644
index 90775a8..0000000
--- a/simulator/app/assets/htc-tornado/home.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/internet.png b/simulator/app/assets/htc-tornado/internet.png
deleted file mode 100644
index 47f1bb4..0000000
--- a/simulator/app/assets/htc-tornado/internet.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/layout.xml b/simulator/app/assets/htc-tornado/layout.xml
deleted file mode 100644
index 55c1d65..0000000
--- a/simulator/app/assets/htc-tornado/layout.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" ?>
-<!-- Copyright 2005 The Android Open Source Project -->
-
-<device name="HTC_Tornado">
-    <!-- title for menus -->
-    <title>HTC Tornado</title>
-
-    <!-- primary display characteristics -->
-    <display name="main" width="240" height="320" format="rgb565" refresh="30"/>
-
-    <!-- display is 33.84mm x 45.12mm -->
-
-	<mode name="default">
-		<view display="main" x="58" y="117" rotate="0">
-
-			<!-- surrounding device image and "patches", drawn in order -->
-			<!-- (phone image is optional) -->
-			<image src="background.png" x="0" y="0"/>
-
-			<!-- buttons for which we have highlight images -->
-			<button keyCode="soft-left"     src="soft-left.png"     x="49" y="450"/>
-			<button keyCode="soft-right"    src="soft-right.png"    x="249" y="450"/>
-			<button keyCode="home"          src="home.png"          x="115" y="450"/>
-			<button keyCode="back"          src="back.png"          x="182" y="450"/>
-			<button keyCode="dpad-up"       src="arrow-up.png"      x="159" y="542"/>
-			<button keyCode="dpad-down"     src="arrow-down.png"    x="160" y="573"/>
-			<button keyCode="dpad-left"       src="arrow-left.png"    x="152" y="549"/>
-			<button keyCode="dpad-right"     src="arrow-right.png"   x="183" y="549"/>
-			<button keyCode="dpad-center"   src="select.png"        x="167" y="556"/>
-
-			<button keyCode="1"             src="1.png"             x="51" y="595"/>
-			<button keyCode="2"             src="2.png"             x="133" y="595"/>
-			<button keyCode="3"             src="3.png"             x="221" y="595"/>
-			<button keyCode="4"             src="4.png"             x="51" y="633"/>
-			<button keyCode="5"             src="5.png"             x="133" y="633"/>
-			<button keyCode="6"             src="6.png"             x="221" y="633"/>
-			<button keyCode="7"             src="7.png"             x="51" y="666"/>
-			<button keyCode="8"             src="8.png"             x="133" y="666"/>
-			<button keyCode="9"             src="9.png"             x="221" y="666"/>
-			<button keyCode="0"             src="0.png"             x="133" y="699"/>
-			<button keyCode="star"          src="star.png"          x="51" y="699"/>
-			<button keyCode="pound"         src="pound.png"         x="221" y="699"/>
-
-			<button keyCode="phone-dial"	src="phone-dial.png"	x="51" y="547"/>
-			<button keyCode="phone-hangup"	src="phone-hangup.png"	x="221" y="547"/>
-
-			<button keyCode="internet"	src="internet.png"	x="52" y="490"/>
-			<button keyCode="skip-backward"	src="skip-backward.png"	x="121" y="490"/>
-			<button keyCode="pause-play"	src="pause-play.png"	x="191" y="490"/>
-			<button keyCode="skip-forward"	src="skip-forward.png"	x="260" y="490"/>
-
-
-            <!-- buttons we haven't bothered to create highlight images for,
-                 or that aren't visible on-screen -->
-			<button keyCode="volume-up"/>
-			<button keyCode="volume-down"/>
-			<button keyCode="power"/>
-			<button keyCode="clear"/>
-
-		</view>
-	</mode>
-
-</device>
-
diff --git a/simulator/app/assets/htc-tornado/pause-play.png b/simulator/app/assets/htc-tornado/pause-play.png
deleted file mode 100644
index ae74d9f..0000000
--- a/simulator/app/assets/htc-tornado/pause-play.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/phone-dial.png b/simulator/app/assets/htc-tornado/phone-dial.png
deleted file mode 100644
index 30bdf9e..0000000
--- a/simulator/app/assets/htc-tornado/phone-dial.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/phone-hangup.png b/simulator/app/assets/htc-tornado/phone-hangup.png
deleted file mode 100644
index 68fe47b..0000000
--- a/simulator/app/assets/htc-tornado/phone-hangup.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/pound.png b/simulator/app/assets/htc-tornado/pound.png
deleted file mode 100644
index 92e49cb..0000000
--- a/simulator/app/assets/htc-tornado/pound.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/select.png b/simulator/app/assets/htc-tornado/select.png
deleted file mode 100644
index a89db9a..0000000
--- a/simulator/app/assets/htc-tornado/select.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/skip-backward.png b/simulator/app/assets/htc-tornado/skip-backward.png
deleted file mode 100644
index 263b3d6..0000000
--- a/simulator/app/assets/htc-tornado/skip-backward.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/skip-forward.png b/simulator/app/assets/htc-tornado/skip-forward.png
deleted file mode 100644
index e069db1..0000000
--- a/simulator/app/assets/htc-tornado/skip-forward.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/soft-left.png b/simulator/app/assets/htc-tornado/soft-left.png
deleted file mode 100644
index ab6dff1..0000000
--- a/simulator/app/assets/htc-tornado/soft-left.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/soft-right.png b/simulator/app/assets/htc-tornado/soft-right.png
deleted file mode 100644
index 590982e..0000000
--- a/simulator/app/assets/htc-tornado/soft-right.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/htc-tornado/star.png b/simulator/app/assets/htc-tornado/star.png
deleted file mode 100644
index 9b7d79a..0000000
--- a/simulator/app/assets/htc-tornado/star.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/back.png b/simulator/app/assets/motorola-q/back.png
deleted file mode 100644
index 6be2512..0000000
--- a/simulator/app/assets/motorola-q/back.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/background.png b/simulator/app/assets/motorola-q/background.png
deleted file mode 100644
index d9b30ad..0000000
--- a/simulator/app/assets/motorola-q/background.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/down.png b/simulator/app/assets/motorola-q/down.png
deleted file mode 100644
index bbe3a18..0000000
--- a/simulator/app/assets/motorola-q/down.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/end.png b/simulator/app/assets/motorola-q/end.png
deleted file mode 100644
index daff163..0000000
--- a/simulator/app/assets/motorola-q/end.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/home.png b/simulator/app/assets/motorola-q/home.png
deleted file mode 100644
index 4f65f91..0000000
--- a/simulator/app/assets/motorola-q/home.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/layout.xml b/simulator/app/assets/motorola-q/layout.xml
deleted file mode 100644
index c48bce6..0000000
--- a/simulator/app/assets/motorola-q/layout.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" ?>
-<!-- Copyright 2006 The Android Open Source Project -->
-
-<device name="MotorolaQ">
-    <!-- title for menus -->
-    <title>Motorola Q</title>
-
-    <display name="main" width="320" height="240" format="rgb565" refresh="30"/>
-
-	<keyboard qwerty="1" />
-	
-    <mode name="default">
-        <!-- hiptop when closed -->
-        <view display="main" x="58" y="121" rotate="0">
-
-            <!-- surrounding device image and "patches", drawn in order -->
-            <image src="background.png" x="0" y="0"/>
-
-			<!-- buttons for which we have highlight images -->
-			<button keyCode="soft-left"     src="menu-left.png"     x="35"  y="385"/>
-			<button keyCode="soft-right"    src="menu-right.png"    x="270" y="385"/>
-			<button keyCode="home"          src="home.png"          x="92"  y="425"/>
-			<button keyCode="back"          src="back.png"          x="264" y="425"/>
- 			<button keyCode="dpad-up"       src="up.png"            x="166" y="400"/>
-			<button keyCode="dpad-down"     src="down.png"          x="166" y="444"/>
-			<button keyCode="dpad-left"     src="left.png"          x="158" y="406"/>
-			<button keyCode="dpad-right"    src="right.png"         x="224" y="406"/>
-			<button keyCode="dpad-center"   src="select.png"        x="194" y="419"/>
-
-			<button keyCode="phone-dial"	src="send.png"	        x="35"  y="421"/>
-			<button keyCode="phone-hangup"	src="end.png"	        x="333" y="422"/>
-        </view>
-    </mode>
-
-</device>
-
diff --git a/simulator/app/assets/motorola-q/left.png b/simulator/app/assets/motorola-q/left.png
deleted file mode 100644
index 3204f9b..0000000
--- a/simulator/app/assets/motorola-q/left.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/menu-left.png b/simulator/app/assets/motorola-q/menu-left.png
deleted file mode 100644
index 4d1bc11..0000000
--- a/simulator/app/assets/motorola-q/menu-left.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/menu-right.png b/simulator/app/assets/motorola-q/menu-right.png
deleted file mode 100644
index 58f31c6..0000000
--- a/simulator/app/assets/motorola-q/menu-right.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/right.png b/simulator/app/assets/motorola-q/right.png
deleted file mode 100644
index b6190c9..0000000
--- a/simulator/app/assets/motorola-q/right.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/select.png b/simulator/app/assets/motorola-q/select.png
deleted file mode 100644
index 343fb45..0000000
--- a/simulator/app/assets/motorola-q/select.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/send.png b/simulator/app/assets/motorola-q/send.png
deleted file mode 100644
index b3ebcd5..0000000
--- a/simulator/app/assets/motorola-q/send.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/motorola-q/up.png b/simulator/app/assets/motorola-q/up.png
deleted file mode 100644
index 7df6736..0000000
--- a/simulator/app/assets/motorola-q/up.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/panasonic-x70/arrow-down.png b/simulator/app/assets/panasonic-x70/arrow-down.png
deleted file mode 100644
index 7ab16b4..0000000
--- a/simulator/app/assets/panasonic-x70/arrow-down.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/panasonic-x70/arrow-up.png b/simulator/app/assets/panasonic-x70/arrow-up.png
deleted file mode 100644
index 6fb2454..0000000
--- a/simulator/app/assets/panasonic-x70/arrow-up.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/panasonic-x70/back.png b/simulator/app/assets/panasonic-x70/back.png
deleted file mode 100644
index 04b91ef..0000000
--- a/simulator/app/assets/panasonic-x70/back.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/panasonic-x70/background.png b/simulator/app/assets/panasonic-x70/background.png
deleted file mode 100644
index 25bc3eb..0000000
--- a/simulator/app/assets/panasonic-x70/background.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/panasonic-x70/home.png b/simulator/app/assets/panasonic-x70/home.png
deleted file mode 100644
index 12ac7bb..0000000
--- a/simulator/app/assets/panasonic-x70/home.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/panasonic-x70/layout.xml b/simulator/app/assets/panasonic-x70/layout.xml
deleted file mode 100644
index 0cb8bbd..0000000
--- a/simulator/app/assets/panasonic-x70/layout.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" ?>
-<!-- Copyright 2005 The Android Open Source Project -->
-
-<device name="PanasonicX70">
-    <!-- title for menus -->
-    <title>Panasonic X70</title>
-
-    <display name="main" width="176" height="220" format="rgb565" refresh="30"/>
-
-	<mode name="default">
-		<!-- primary display characteristics -->
-		<view display="main" x="39" y="43" rotate="0">
-
-			<!-- surrounding device image and "patches", drawn in order -->
-			<!-- (phone image is optional) -->
-			<image src="background.png" x="0" y="0"/>
-
-			<button keyCode="soft-left"     src="soft-left.png"     x="45" y="324"/>
-			<button keyCode="soft-right"    src="soft-right.png"    x="146" y="324"/>
-			<button keyCode="home"          src="home.png"          x="21" y="345"/>
-			<button keyCode="back"          src="back.png"          x="180" y="347"/>
-			<button keyCode="dpad-up"       src="arrow-up.png"      x="88" y="348"/>
-			<button keyCode="dpad-down"     src="arrow-down.png"    x="95" y="414"/>
-            <button keyCode="dpad-left"/>
-            <button keyCode="dpad-right"/>
-			<button keyCode="dpad-center"   src="select.png"        x="101" y="377"/>
-
-            <button keyCode="1"/>
-            <button keyCode="2"/>
-            <button keyCode="3"/>
-            <button keyCode="4"/>
-            <button keyCode="5"/>
-            <button keyCode="6"/>
-            <button keyCode="7"/>
-            <button keyCode="8"/>
-            <button keyCode="9"/>
-            <button keyCode="0"/>
-            <button keyCode="star"/>
-            <button keyCode="pound"/>
-
-			<button keyCode="volume-up"/>
-			<button keyCode="volume-down"/>
-			<button keyCode="power"/>
-			<button keyCode="clear"/>
-
-		</view>
-	</mode>
-
-</device>
-
diff --git a/simulator/app/assets/panasonic-x70/select.png b/simulator/app/assets/panasonic-x70/select.png
deleted file mode 100644
index 993ecad..0000000
--- a/simulator/app/assets/panasonic-x70/select.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/panasonic-x70/soft-left.png b/simulator/app/assets/panasonic-x70/soft-left.png
deleted file mode 100644
index c384bb7..0000000
--- a/simulator/app/assets/panasonic-x70/soft-left.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/panasonic-x70/soft-right.png b/simulator/app/assets/panasonic-x70/soft-right.png
deleted file mode 100644
index 948e40f..0000000
--- a/simulator/app/assets/panasonic-x70/soft-right.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/0.png b/simulator/app/assets/samsung-flip-2005/0.png
deleted file mode 100644
index 839e6d1..0000000
--- a/simulator/app/assets/samsung-flip-2005/0.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/1.png b/simulator/app/assets/samsung-flip-2005/1.png
deleted file mode 100644
index 499cf6c..0000000
--- a/simulator/app/assets/samsung-flip-2005/1.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/2.png b/simulator/app/assets/samsung-flip-2005/2.png
deleted file mode 100644
index 93207cc..0000000
--- a/simulator/app/assets/samsung-flip-2005/2.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/3.png b/simulator/app/assets/samsung-flip-2005/3.png
deleted file mode 100644
index 499efdb..0000000
--- a/simulator/app/assets/samsung-flip-2005/3.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/4.png b/simulator/app/assets/samsung-flip-2005/4.png
deleted file mode 100644
index 775b15d..0000000
--- a/simulator/app/assets/samsung-flip-2005/4.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/5.png b/simulator/app/assets/samsung-flip-2005/5.png
deleted file mode 100644
index b8a5723..0000000
--- a/simulator/app/assets/samsung-flip-2005/5.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/6.png b/simulator/app/assets/samsung-flip-2005/6.png
deleted file mode 100644
index b6e0de9..0000000
--- a/simulator/app/assets/samsung-flip-2005/6.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/7.png b/simulator/app/assets/samsung-flip-2005/7.png
deleted file mode 100644
index 5416186..0000000
--- a/simulator/app/assets/samsung-flip-2005/7.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/8.png b/simulator/app/assets/samsung-flip-2005/8.png
deleted file mode 100644
index 2dfcae3..0000000
--- a/simulator/app/assets/samsung-flip-2005/8.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/9.png b/simulator/app/assets/samsung-flip-2005/9.png
deleted file mode 100644
index 6c11eed..0000000
--- a/simulator/app/assets/samsung-flip-2005/9.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/abc.png b/simulator/app/assets/samsung-flip-2005/abc.png
deleted file mode 100644
index 9f43afe..0000000
--- a/simulator/app/assets/samsung-flip-2005/abc.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/arrow-down.png b/simulator/app/assets/samsung-flip-2005/arrow-down.png
deleted file mode 100644
index 0f7ea7b..0000000
--- a/simulator/app/assets/samsung-flip-2005/arrow-down.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/arrow-left.png b/simulator/app/assets/samsung-flip-2005/arrow-left.png
deleted file mode 100644
index ad1982f..0000000
--- a/simulator/app/assets/samsung-flip-2005/arrow-left.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/arrow-right.png b/simulator/app/assets/samsung-flip-2005/arrow-right.png
deleted file mode 100644
index bf9cf48..0000000
--- a/simulator/app/assets/samsung-flip-2005/arrow-right.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/arrow-up.png b/simulator/app/assets/samsung-flip-2005/arrow-up.png
deleted file mode 100644
index ab62e33..0000000
--- a/simulator/app/assets/samsung-flip-2005/arrow-up.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/back-background.png b/simulator/app/assets/samsung-flip-2005/back-background.png
deleted file mode 100644
index 741db99..0000000
--- a/simulator/app/assets/samsung-flip-2005/back-background.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/back.png b/simulator/app/assets/samsung-flip-2005/back.png
deleted file mode 100644
index 9eb9a17..0000000
--- a/simulator/app/assets/samsung-flip-2005/back.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/background-176_208.png b/simulator/app/assets/samsung-flip-2005/background-176_208.png
deleted file mode 100644
index 1ed1248..0000000
--- a/simulator/app/assets/samsung-flip-2005/background-176_208.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/background-176x220.png b/simulator/app/assets/samsung-flip-2005/background-176x220.png
deleted file mode 100644
index 361304e..0000000
--- a/simulator/app/assets/samsung-flip-2005/background-176x220.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/clear.png b/simulator/app/assets/samsung-flip-2005/clear.png
deleted file mode 100644
index f9c421c..0000000
--- a/simulator/app/assets/samsung-flip-2005/clear.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/end.png b/simulator/app/assets/samsung-flip-2005/end.png
deleted file mode 100644
index 5d0056c..0000000
--- a/simulator/app/assets/samsung-flip-2005/end.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/home-background.png b/simulator/app/assets/samsung-flip-2005/home-background.png
deleted file mode 100644
index 3ceee9c..0000000
--- a/simulator/app/assets/samsung-flip-2005/home-background.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/home.png b/simulator/app/assets/samsung-flip-2005/home.png
deleted file mode 100644
index 8510b7e..0000000
--- a/simulator/app/assets/samsung-flip-2005/home.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/layout.xml b/simulator/app/assets/samsung-flip-2005/layout.xml
deleted file mode 100644
index 3bc2ddd..0000000
--- a/simulator/app/assets/samsung-flip-2005/layout.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" ?>
-<!-- Copyright 2005 The Android Open Source Project -->
-
-<device name="Samsung1234">
-    <!-- title for menus -->
-    <title>Samsung Flip Phone</title>
-
-    <!-- primary display characteristics -->
-    <display name="main" width="176" height="220" format="rgb565" refresh="30"/>
-
-	<mode name="default">
-        <!-- our view of the device that shows the main display -->
-		<view display="main" x="49" y="73" rotate="0">
-
-			<!-- surrounding device image and "patches", drawn in order -->
-			<!-- (phone image is optional) -->
-			<image src="background-176x220.png" x="0" y="0"/>
-			<image src="home-background.png" x="22" y="426"/>
-			<image src="back-background.png" x="179" y="426"/>
-
-			<!-- buttons for which we have highlight images -->
-			<button keyCode="soft-left"     src="soft-left.png"     x="24" y="388"/>
-			<button keyCode="soft-right"    src="soft-right.png"    x="182" y="388"/>
-			<button keyCode="home"          src="home.png"          x="22" y="426"/>
-			<button keyCode="back"          src="back.png"          x="179" y="426"/>
-			<button keyCode="dpad-up"       src="arrow-up.png"      x="99" y="399"/>
-			<button keyCode="dpad-down"     src="arrow-down.png"    x="99" y="461"/>
-			<button keyCode="dpad-left"     src="arrow-left.png"    x="82" y="411"/>
-			<button keyCode="dpad-right"    src="arrow-right.png"   x="147" y="411"/>
-			<button keyCode="dpad-center"   src="select.png"        x="115" y="431"/>
-
-			<button keyCode="1"             src="1.png"             x="24" y="533"/>
-			<button keyCode="2"             src="2.png"             x="94" y="544"/>
-			<button keyCode="3"             src="3.png"             x="173" y="534"/>
-			<button keyCode="4"             src="4.png"             x="25" y="576"/>
-			<button keyCode="5"             src="5.png"             x="94" y="581"/>
-			<button keyCode="6"             src="6.png"             x="172" y="576"/>
-			<button keyCode="7"             src="7.png"             x="27" y="619"/>
-			<button keyCode="8"             src="8.png"             x="95" y="621"/>
-			<button keyCode="9"             src="9.png"             x="168" y="620"/>
-			<button keyCode="0"             src="0.png"             x="96" y="658"/>
-			<button keyCode="star"          src="star.png"          x="31" y="659"/>
-			<button keyCode="pound"         src="pound.png"         x="169" y="659"/>
-
-            <!-- buttons we haven't bothered to create highlight images for,
-                 or that aren't visible on-screen -->
-			<button keyCode="volume-up"/>
-			<button keyCode="volume-down"/>
-			<button keyCode="power"/>
-			<button keyCode="clear"/>
-
-		</view>
-	</mode>
-
-</device>
-
diff --git a/simulator/app/assets/samsung-flip-2005/menu.png b/simulator/app/assets/samsung-flip-2005/menu.png
deleted file mode 100644
index 7ac077c..0000000
--- a/simulator/app/assets/samsung-flip-2005/menu.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/pound.png b/simulator/app/assets/samsung-flip-2005/pound.png
deleted file mode 100644
index 22440bc..0000000
--- a/simulator/app/assets/samsung-flip-2005/pound.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/select.png b/simulator/app/assets/samsung-flip-2005/select.png
deleted file mode 100644
index 1c735f8..0000000
--- a/simulator/app/assets/samsung-flip-2005/select.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/send.png b/simulator/app/assets/samsung-flip-2005/send.png
deleted file mode 100644
index 23cea52..0000000
--- a/simulator/app/assets/samsung-flip-2005/send.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/soft-left.png b/simulator/app/assets/samsung-flip-2005/soft-left.png
deleted file mode 100644
index 224d281..0000000
--- a/simulator/app/assets/samsung-flip-2005/soft-left.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/soft-right.png b/simulator/app/assets/samsung-flip-2005/soft-right.png
deleted file mode 100644
index a8eec97..0000000
--- a/simulator/app/assets/samsung-flip-2005/soft-right.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/assets/samsung-flip-2005/star.png b/simulator/app/assets/samsung-flip-2005/star.png
deleted file mode 100644
index 457348d..0000000
--- a/simulator/app/assets/samsung-flip-2005/star.png
+++ /dev/null
Binary files differ
diff --git a/simulator/app/executablepath_darwin.cpp b/simulator/app/executablepath_darwin.cpp
deleted file mode 100644
index 9ec1c18..0000000
--- a/simulator/app/executablepath_darwin.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 "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/simulator/app/executablepath_linux.cpp b/simulator/app/executablepath_linux.cpp
deleted file mode 100644
index e4a3a2b..0000000
--- a/simulator/app/executablepath_linux.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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 "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/simulator/app/help/unnamed.htb b/simulator/app/help/unnamed.htb
deleted file mode 100644
index 3933e69..0000000
--- a/simulator/app/help/unnamed.htb
+++ /dev/null
Binary files differ
diff --git a/simulator/app/ported.cpp b/simulator/app/ported.cpp
deleted file mode 100644
index 232b302..0000000
--- a/simulator/app/ported.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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 "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/simulator/app/ported.h b/simulator/app/ported.h
deleted file mode 100644
index eb3be01..0000000
--- a/simulator/app/ported.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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/simulator/app/utils.h b/simulator/app/utils.h
deleted file mode 100644
index b74845f..0000000
--- a/simulator/app/utils.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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 _SIM_UTILS_H
-#define _SIM_UTILS_H
-
-#include "ported.h"
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
-#include <utils/List.h>
-#include <utils/StringArray.h>
-#include <utils/misc.h>
-#include <utils/Errors.h>
-
-#endif // _SIM_UTILS_H
diff --git a/simulator/wrapsim/Android.mk b/simulator/wrapsim/Android.mk
deleted file mode 100644
index 7c2cbf2..0000000
--- a/simulator/wrapsim/Android.mk
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2007 The Android Open Source Project
-
-#
-# Build instructions for simulator LD_PRELOAD wrapper.
-#
-ifeq ($(TARGET_SIMULATOR),true)
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	BitVector.c \
-	DevAudio.c \
-	DevConsoleTty.c \
-	DevEvent.c \
-	DevFb.c \
-	DevLog.c \
-	DevPower.c \
-	DevVibrator.c \
-	FakeDev.c \
-	Init.c \
-	Intercept.c \
-	Log.c \
-	SimMgr.c \
-	SysPower.c \
-	Util.c
-
-LOCAL_MODULE := libwrapsim
-
-# Relying on other Android libraries is probably a bad idea, since any
-# library or system calls they make could lead to recursive behavior.
-LOCAL_LDLIBS += -lpthread -ldl
-
-ifeq ($(BUILD_SIM_WITHOUT_AUDIO),true)
-LOCAL_CFLAGS += -DBUILD_SIM_WITHOUT_AUDIO=1
-else
-LOCAL_LDLIBS += -lasound
-endif
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-
-#
-# Build instructions for simulator runtime launch wrapper.
-#
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	LaunchWrapper.c
-
-LOCAL_MODULE := launch-wrapper
-include $(BUILD_EXECUTABLE)
-
-endif # ifeq ($(TARGET_SIMULATOR),true)
diff --git a/simulator/wrapsim/BitVector.c b/simulator/wrapsim/BitVector.c
deleted file mode 100644
index aaa1408..0000000
--- a/simulator/wrapsim/BitVector.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Simple bit vector.
- */
-#include "Common.h"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <assert.h>
-
-#define kBitVectorGrowth    4   /* increase by 4 uint32_t when limit hit */
-
-
-/*
- * Allocate a bit vector with enough space to hold at least the specified
- * number of bits.
- */
-BitVector* wsAllocBitVector(int startBits, int isExpandable)
-{
-    BitVector* bv;
-    int count;
-
-    assert(sizeof(bv->storage[0]) == 4);        /* assuming 32-bit units */
-    assert(startBits > 0);
-
-    bv = (BitVector*) malloc(sizeof(BitVector));
-
-    count = (startBits + 31) >> 5;
-
-    bv->storageSize = count;
-    bv->isExpandable = isExpandable;
-    bv->storage = (uint32_t*) malloc(count * sizeof(uint32_t));
-    memset(bv->storage, 0xff, count * sizeof(uint32_t));
-    return bv;
-}
-
-/*
- * Free a BitVector.
- */
-void wsFreeBitVector(BitVector* pBits)
-{
-    if (pBits == NULL)
-        return;
-
-    free(pBits->storage);
-    free(pBits);
-}
-
-/*
- * "Allocate" the first-available bit in the bitmap.
- *
- * This is not synchronized.  The caller is expected to hold some sort of
- * lock that prevents multiple threads from executing simultaneously in
- * dvmAllocBit/dvmFreeBit.
- *
- * The bitmap indicates which resources are free, so we use '1' to indicate
- * available and '0' to indicate allocated.
- */
-int wsAllocBit(BitVector* pBits)
-{
-    int word, bit;
-
-retry:
-    for (word = 0; word < pBits->storageSize; word++) {
-        if (pBits->storage[word] != 0) {
-            /*
-             * There are unallocated bits in this word.  Return the first.
-             */
-            bit = ffs(pBits->storage[word]) -1;
-            assert(bit >= 0 && bit < 32);
-            pBits->storage[word] &= ~(1 << bit);
-            return (word << 5) | bit;
-        }
-    }
-
-    /*
-     * Ran out of space, allocate more if we're allowed to.
-     */
-    if (!pBits->isExpandable)
-        return -1;
-
-    pBits->storage = realloc(pBits->storage,
-                    (pBits->storageSize + kBitVectorGrowth) * sizeof(uint32_t));
-    memset(&pBits->storage[pBits->storageSize], 0xff,
-        kBitVectorGrowth * sizeof(uint32_t));
-    pBits->storageSize += kBitVectorGrowth;
-    goto retry;
-}
-
-/*
- * Mark the specified bit as "free".
- */
-void wsFreeBit(BitVector* pBits, int num)
-{
-    assert(num >= 0 &&
-           num < (int) pBits->storageSize * (int)sizeof(uint32_t) * 8);
-
-    pBits->storage[num >> 5] |= 1 << (num & 0x1f);
-}
-
diff --git a/simulator/wrapsim/BitVector.h b/simulator/wrapsim/BitVector.h
deleted file mode 100644
index 048cf91..0000000
--- a/simulator/wrapsim/BitVector.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Simple bit vector.
- */
-#ifndef _WRAPSIM_BITVECTOR_H
-#define _WRAPSIM_BITVECTOR_H
-
-#include <stdint.h>
-
-/*
- * Expanding bitmap, used for tracking resources.  Bits are numbered starting
- * from zero.
- */
-typedef struct BitVector {
-    int         isExpandable;   /* expand bitmap if we run out? */
-    int         storageSize;    /* current size, in 32-bit words */
-    uint32_t*   storage;
-} BitVector;
-
-/* allocate a bit vector with enough space to hold "startBits" bits */
-BitVector* wsAllocBitVector(int startBits, int isExpandable);
-void wsFreeBitVector(BitVector* pBits);
-
-/*
- * Set/clear a single bit; assumes external synchronization.
- *
- * We always allocate the first possible bit.  If we run out of space in
- * the bitmap, and it's not marked expandable, dvmAllocBit returns -1.
- */
-int wsAllocBit(BitVector* pBits);
-void wsFreeBit(BitVector* pBits, int num);
-
-#endif /*_WRAPSIM_BITVECTOR_H*/
diff --git a/simulator/wrapsim/Common.h b/simulator/wrapsim/Common.h
deleted file mode 100644
index 463262f..0000000
--- a/simulator/wrapsim/Common.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Common defines and includes.
- */
-#ifndef _WRAPSIM_COMMON_H
-#define _WRAPSIM_COMMON_H
-
-#include <unistd.h>
-#include <sys/types.h>
-
-#include "BitVector.h"
-#include "FakeDev.h"
-#include "Log.h"
-#include "SimMgr.h"
-#include "Globals.h"
-#include "Util.h"
-
-#endif /*_WRAPSIM_COMMON_H*/
diff --git a/simulator/wrapsim/DevAudio.c b/simulator/wrapsim/DevAudio.c
deleted file mode 100644
index a8f5c16..0000000
--- a/simulator/wrapsim/DevAudio.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Audio output device.
- */
-#include "Common.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <alsa/asoundlib.h>
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/input.h>
-
-
-/*
- * Input event device state.
- */
-typedef struct AudioState {
-    snd_pcm_t *handle;
-} AudioState;
-
-/*
- * Set some stuff up.
- */
-static int configureInitialState(const char* pathName, AudioState* audioState)
-{
-#if BUILD_SIM_WITHOUT_AUDIO
-    return 0;
-#else
-    audioState->handle = NULL;
-
-    snd_pcm_open(&audioState->handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
-
-    if (audioState->handle) {
-        snd_pcm_hw_params_t *params;
-        snd_pcm_hw_params_malloc(&params);
-        snd_pcm_hw_params_any(audioState->handle, params);
-        snd_pcm_hw_params_set_access(audioState->handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
-        snd_pcm_hw_params_set_format(audioState->handle, params, SND_PCM_FORMAT_S16_LE);
-        unsigned int rate = 44100;
-        snd_pcm_hw_params_set_rate_near(audioState->handle, params, &rate, NULL);
-        snd_pcm_hw_params_set_channels(audioState->handle, params, 2);
-        snd_pcm_hw_params(audioState->handle, params);
-        snd_pcm_hw_params_free(params);
-    } else {
-        wsLog("Couldn't open audio hardware, faking it\n");
-    }
-
-    return 0;
-#endif
-}
-
-/*
- * Write audio data.
- */
-static ssize_t writeAudio(FakeDev* dev, int fd, const void* buf, size_t count)
-{
-#if BUILD_SIM_WITHOUT_AUDIO
-    return 0;
-#else
-    AudioState *state = (AudioState*)dev->state;
-    if (state->handle != NULL) {
-        snd_pcm_writei(state->handle, buf, count / 4);
-        return count;
-    }
-
-    // fake timing
-    usleep(count * 10000 / (441 * 4));
-    return count;
-#endif
-}
-
-/*
- * Handle event ioctls.
- */
-static int ioctlAudio(FakeDev* dev, int fd, int request, void* argp)
-{
-    return -1;
-}
-
-/*
- * Free up our state before closing down the fake descriptor.
- */
-static int closeAudio(FakeDev* dev, int fd)
-{
-#if BUILD_SIM_WITHOUT_AUDIO
-    return 0;
-#else
-    AudioState *state = (AudioState*)dev->state;
-    snd_pcm_close(state->handle);
-    free(state);
-    dev->state = NULL;
-    return 0;
-#endif
-}
-
-/*
- * Open an audio output device.
- */
-FakeDev* wsOpenDevAudio(const char* pathName, int flags)
-{
-    FakeDev* newDev = wsCreateFakeDev(pathName);
-    if (newDev != NULL) {
-        newDev->write = writeAudio;
-        newDev->ioctl = ioctlAudio;
-        newDev->close = closeAudio;
-
-        AudioState* eventState = calloc(1, sizeof(AudioState));
-
-        if (configureInitialState(pathName, eventState) != 0) {
-            free(eventState);
-            return NULL;
-        }
-        newDev->state = eventState;
-    }
-
-    return newDev;
-}
diff --git a/simulator/wrapsim/DevConsoleTty.c b/simulator/wrapsim/DevConsoleTty.c
deleted file mode 100644
index 166d648..0000000
--- a/simulator/wrapsim/DevConsoleTty.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Console tty device.
- */
-#include "Common.h"
-
-#include <string.h>
-
-#include <sys/ioctl.h>
-#include <linux/vt.h>
-
-
-/*
- * Handle the various console ioctls, most of which we can just ignore.
- */
-static int ioctlConsoleTty(FakeDev* dev, int fd, int request, void* argp)
-{
-    wsLog("%s: ioctl(0x%x, %p)\n", dev->debugName, request, argp);
-    switch (request) {
-    case VT_GETSTATE:       // struct vt_stat*
-        /*
-         * Looks like they want vs.v_active.  This just gets fed back into
-         * another console ioctl, so we don't really need to do anything.
-         * We zero out the struct so the data will at least appear to be
-         * initialized.
-         */
-        memset(argp, 0, sizeof(struct vt_stat));
-        break;
-    case VT_OPENQRY:        // int*
-        /* they want the console number */
-        *(int*)argp = 123;
-        break;
-    default:
-        /* ignore anything we don't understand */
-        break;
-    }
-
-    return 0;
-}
-
-/*
- * Open the console TTY device, which responds to a collection of ioctl()s.
- */
-FakeDev* wsOpenDevConsoleTty(const char* pathName, int flags)
-{
-    FakeDev* newDev = wsCreateFakeDev(pathName);
-    if (newDev != NULL) {
-        newDev->ioctl = ioctlConsoleTty;
-    }
-    return newDev;
-}
-
diff --git a/simulator/wrapsim/DevEvent.c b/simulator/wrapsim/DevEvent.c
deleted file mode 100644
index 60060f4..0000000
--- a/simulator/wrapsim/DevEvent.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Input event device.
- */
-#include "Common.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/input.h>
-
-
-/*
- * Input event device state.
- */
-typedef struct EventState {
-    struct input_id ident;
-
-    char*   name;
-    char*   location;
-    char*   idstr;
-    int     protoVersion;
-} EventState;
-
-/*
- * Key bit mask, for EVIOCGBIT(EV_KEY).
- *
- * (For now, just pretend to be a "goldfish" like the emulator.)
- */
-static const unsigned char gKeyBitMask[64] = {
-    // These bits indicate which keys the device has
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-    // These bits indicate other capabilities, such
-    // as whether it's a trackball or a touchscreen
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // touchscreen
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-/*
- * Abs bit mask, for EVIOCGBIT(EV_ABS).
- *
- * Pretend to be a normal single touch panel
- */
-static const unsigned char gAbsBitMask[64] = {
-    // these bits indicate the capabilities of the touch screen
-    0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ABS_X, ABS_Y
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-/*
- * Set some stuff up.
- */
-static void configureInitialState(const char* pathName, EventState* eventState)
-{
-    /*
-     * Swim like a goldfish.
-     */
-    eventState->ident.bustype = 0;
-    eventState->ident.vendor = 0;
-    eventState->ident.product = 0;
-    eventState->ident.version = 0;
-
-    eventState->name = strdup(gWrapSim.keyMap);
-    eventState->location = strdup("");
-    eventState->idstr = strdup("");
-    eventState->protoVersion = 0x010000;
-}
-
-/*
- * Free up the state structure.
- */
-static void freeState(EventState* eventState)
-{
-    if (eventState != NULL) {
-        free(eventState->name);
-        free(eventState->location);
-        free(eventState->idstr);
-        free(eventState);
-    }
-}
-
-/*
- * Handle one of the EVIOCGABS requests.
- *
- * Currently not doing much here.
- */
-static void handleAbsGet(int reqIdx, void* argp)
-{
-    struct input_absinfo info;
-
-    switch (reqIdx) {
-    case ABS_X:
-        wsLog("  req for abs X\n");
-        break;
-    case ABS_Y:
-        wsLog("  req for abs Y\n");
-        break;
-    case ABS_PRESSURE:
-        wsLog("  req for abs PRESSURE\n");
-        break;
-    case ABS_TOOL_WIDTH:
-        wsLog("  req for abs TOOL_WIDTH\n");
-        break;
-    default:
-        wsLog("  req for unexpected event abs 0x%02x\n", reqIdx);
-        break;
-    }
-
-    memset(&info, 0, sizeof(info));
-    memcpy(argp, &info, sizeof(struct input_absinfo));
-}
-
-/*
- * Return the next available input event.
- *
- * We just pass this through to the real "read", since "fd" is real.
- */
-static ssize_t readEvent(FakeDev* dev, int fd, void* buf, size_t count)
-{
-    return _ws_read(fd, buf, count);
-}
-
-/*
- * Somebody is trying to write to the event pipe.  This can be used to set
- * the state of LED.
- */
-static ssize_t writeEvent(FakeDev* dev, int fd, const void* buf, size_t count)
-{
-    const struct input_event* piev;
-
-    if (count == sizeof(*piev)) {
-        piev = (const struct input_event*) buf;
-
-        if (piev->type == EV_LED) {
-            wsLog("%s: set LED code=%d value=%d\n",
-                dev->debugName, piev->code, piev->value);
-        } else {
-            wsLog("%s: writeEvent got %d bytes, type=%d\n",
-                dev->debugName, count, piev->type);
-        }
-    } else {
-        wsLog("%s: warning: writeEvent got %d bytes, not sure why\n",
-            dev->debugName, count);
-    }
-
-    return count;
-}
-
-/*
- * Handle event ioctls.
- */
-static int ioctlEvent(FakeDev* dev, int fd, int request, void* argp)
-{
-    EventState* state = (EventState*) dev->state;
-    unsigned int urequest = (unsigned int) request;
-
-    wsLog("%s: ioctl(0x%x, %p)\n", dev->debugName, urequest, argp);
-
-    if (_IOC_TYPE(urequest) != _IOC_TYPE(EVIOCGVERSION)) {
-        wsLog("%s: inappropriate ioctl 0x%08x\n", dev->debugName, urequest);
-        return -1;
-    }
-
-    if (urequest == EVIOCGVERSION) {
-        *(int*)argp = state->protoVersion;
-    } else if (urequest == EVIOCGID) {
-        memcpy(argp, &state->ident, sizeof(struct input_id));
-    } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGNAME(0))) {
-        int maxLen = _IOC_SIZE(urequest);
-        int strLen = (int) strlen(state->name);
-        if (strLen >= maxLen) {
-            errno = EINVAL;
-            return -1;
-        }
-        memcpy(argp, state->name, strLen+1);
-        return strLen;
-    } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGPHYS(0))) {
-        int maxLen = _IOC_SIZE(urequest);
-        int strLen = (int) strlen(state->location);
-        if (strLen >= maxLen) {
-            errno = EINVAL;
-            return -1;
-        }
-        memcpy(argp, state->location, strLen+1);
-        return strLen;
-    } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGUNIQ(0))) {
-        /* device doesn't seem to support this, neither will we */
-        return -1;
-    } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGBIT(EV_KEY,0))) {
-        /* keys */
-        int maxLen = _IOC_SIZE(urequest);
-        if (maxLen > (int) sizeof(gKeyBitMask))
-            maxLen = sizeof(gKeyBitMask);
-        memcpy(argp, gKeyBitMask, maxLen);
-    } else if (_IOC_NR(urequest) == _IOC_NR(EVIOCGBIT(EV_REL,0))) {
-        /* relative controllers (trackball) */
-        int maxLen = _IOC_SIZE(urequest);
-        memset(argp, 0xff, maxLen);
-    } else if (!getenv("NOTOUCH") && _IOC_NR(urequest) == _IOC_NR(EVIOCGBIT(EV_ABS,0))) {
-        // absolute controllers (touch screen)
-        int maxLen = _IOC_SIZE(urequest);
-        if (maxLen > (int) sizeof(gAbsBitMask))
-            maxLen = sizeof(gAbsBitMask);
-        memcpy(argp, gAbsBitMask, maxLen);
-
-    } else if (_IOC_NR(urequest) >= _IOC_NR(EVIOCGABS(ABS_X)) &&
-               _IOC_NR(urequest) <= _IOC_NR(EVIOCGABS(ABS_MAX)))
-    {
-        /* get abs value / limits */
-        int reqIdx = _IOC_NR(urequest) - _IOC_NR(EVIOCGABS(ABS_X));
-        handleAbsGet(reqIdx, argp);
-    } else {
-        wsLog("GLITCH: UNKNOWN ioctl request 0x%x on %s\n",
-            urequest, dev->debugName);
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Free up our state before closing down the fake descriptor.
- */
-static int closeEvent(FakeDev* dev, int fd)
-{
-    freeState((EventState*)dev->state);
-    dev->state = NULL;
-    if (gWrapSim.keyInputDevice == dev) {
-        gWrapSim.keyInputDevice = NULL;
-        wsLog("Sim input device closed\n");
-    }
-    return 0;
-}
-
-/*
- * Open an input event device.
- */
-FakeDev* wsOpenDevEvent(const char* pathName, int flags)
-{
-    FakeDev* newDev = wsCreateRealFakeDev(pathName);
-    if (newDev != NULL) {
-        newDev->read = readEvent;
-        newDev->write = writeEvent;
-        newDev->ioctl = ioctlEvent;
-        newDev->close = closeEvent;
-
-        EventState* eventState = calloc(1, sizeof(EventState));
-
-        configureInitialState(pathName, eventState);
-        newDev->state = eventState;
-
-        /*
-         * First one opened becomes the place where we queue up input
-         * events from the simulator.  This approach will fail if the
-         * app opens the device, then opens it a second time for input,
-         * then closes the first.  The app doesn't currently do this (though
-         * it does do quick opens to fiddle with LEDs).
-         */
-        if (gWrapSim.keyInputDevice == NULL) {
-            gWrapSim.keyInputDevice = newDev;
-            wsLog("Device %p / %d will receive sim input events\n",
-                newDev, newDev->fd);
-        }
-    }
-
-    return newDev;
-}
-
-/*
- * Write a key event.
- */
-static int sendKeyEvent(FakeDev* dev, int code, int isDown)
-{
-    struct input_event iev;
-    ssize_t actual;
-
-    gettimeofday(&iev.time, NULL);
-    iev.type = EV_KEY;
-    iev.code = code;
-    iev.value = (isDown != 0) ? 1 : 0;
-
-    actual = _ws_write(dev->otherFd, &iev, sizeof(iev));
-    if (actual != (ssize_t) sizeof(iev)) {
-        wsLog("WARNING: send key event partial write (%d of %d)\n",
-            actual, sizeof(iev));
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Write an absolute (touch screen) event.
- */
-static int sendAbsButton(FakeDev* dev, int x, int y, int isDown)
-{
-    struct input_event iev;
-    ssize_t actual;
-
-    wsLog("absButton x=%d y=%d down=%d\n", x, y, isDown);
-
-    gettimeofday(&iev.time, NULL);
-    iev.type = EV_KEY;
-    iev.code = BTN_TOUCH;
-    iev.value = (isDown != 0) ? 1 : 0;
-
-    actual = _ws_write(dev->otherFd, &iev, sizeof(iev));
-    if (actual != (ssize_t) sizeof(iev)) {
-        wsLog("WARNING: send touch event partial write (%d of %d)\n",
-            actual, sizeof(iev));
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Write an absolute (touch screen) event.
- */
-static int sendAbsMovement(FakeDev* dev, int x, int y)
-{
-    struct input_event iev;
-    ssize_t actual;
-
-    wsLog("absMove x=%d y=%d\n", x, y);
-
-    gettimeofday(&iev.time, NULL);
-    iev.type = EV_ABS;
-    iev.code = ABS_X;
-    iev.value = x;
-
-    actual = _ws_write(dev->otherFd, &iev, sizeof(iev));
-    if (actual != (ssize_t) sizeof(iev)) {
-        wsLog("WARNING: send abs movement event partial X write (%d of %d)\n",
-            actual, sizeof(iev));
-        return -1;
-    }
-
-    iev.code = ABS_Y;
-    iev.value = y;
-
-    actual = _ws_write(dev->otherFd, &iev, sizeof(iev));
-    if (actual != (ssize_t) sizeof(iev)) {
-        wsLog("WARNING: send abs movement event partial Y write (%d of %d)\n",
-            actual, sizeof(iev));
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Not quite sure what this is for, but the emulator does it.
- */
-static int sendAbsSyn(FakeDev* dev)
-{
-    struct input_event iev;
-    ssize_t actual;
-
-    gettimeofday(&iev.time, NULL);
-    iev.type = EV_SYN;
-    iev.code = 0;
-    iev.value = 0;
-
-    actual = _ws_write(dev->otherFd, &iev, sizeof(iev));
-    if (actual != (ssize_t) sizeof(iev)) {
-        wsLog("WARNING: send abs movement syn (%d of %d)\n",
-            actual, sizeof(iev));
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Send a key event to the fake key event device.
- *
- * We have to translate the simulator key event into one or more device
- * key events.
- */
-void wsSendSimKeyEvent(int key, int isDown)
-{
-    FakeDev* dev;
-    EventState* state;
-
-    dev = gWrapSim.keyInputDevice;
-    if (dev == NULL)
-        return;
-
-    sendKeyEvent(dev, key, isDown);
-}
-
-/*
- * Send a touch-screen event to the fake key event device.
- *
- * We have to translate the simulator key event into one or more device
- * key events.
- */
-void wsSendSimTouchEvent(int action, int x, int y)
-{
-    FakeDev* dev;
-    EventState* state;
-
-    dev = gWrapSim.keyInputDevice;
-    if (dev == NULL)
-        return;
-
-    if (action == kTouchDown) {
-        sendAbsMovement(dev, x, y);
-        sendAbsButton(dev, x, y, 1);
-        sendAbsSyn(dev);
-    } else if (action == kTouchUp) {
-        sendAbsButton(dev, x, y, 0);
-        sendAbsSyn(dev);
-    } else if (action == kTouchDrag) {
-        sendAbsMovement(dev, x, y);
-        sendAbsSyn(dev);
-    } else {
-        wsLog("WARNING: unexpected sim touch action  %d\n", action);
-    }
-}
-
diff --git a/simulator/wrapsim/DevFb.c b/simulator/wrapsim/DevFb.c
deleted file mode 100644
index bfdbb22..0000000
--- a/simulator/wrapsim/DevFb.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Fake device support.
- */
-#include "Common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-#include <linux/fb.h>
-
-typedef struct FbState {
-
-    /* refcount for dup() */
-    int refCount;
-
-    /* index into gWrapSim.display[] */
-    int     displayIdx;
-
-    /* VRAM address, set by mmap() call */
-    void*   vramAddr;
-
-    /* kernel data structures */
-    struct fb_var_screeninfo    vinfo;
-    struct fb_fix_screeninfo    finfo;
-} FbState;
-
-
-/*
- * Set up the initial values of the structs.
- *
- * The FbState struct is zeroed out initially, so we only need to set the
- * fields that don't default to zero.
- */
-static void configureInitialState(int displayIdx, FbState* fbState)
-{
-    int width, height;
-
-    assert(displayIdx >= 0 && displayIdx < gWrapSim.numDisplays);
-
-    width = gWrapSim.display[displayIdx].width;
-    height = gWrapSim.display[displayIdx].height;
-    wsLog("Configuring FbState for display %d (%dx%x key=0x%08x)\n",
-        displayIdx, width, height, gWrapSim.display[displayIdx].shmemKey);
-
-    /* fb_fix_screeninfo */
-    strcpy(fbState->finfo.id, "omapfb");
-    fbState->finfo.smem_len = (width * 2) * height * 2;
-    fbState->finfo.line_length = width * 2;
-
-    /* fb_var_screeninfo */
-    fbState->vinfo.xres = width;
-    fbState->vinfo.yres = height;
-    fbState->vinfo.xres_virtual = width;
-    fbState->vinfo.yres_virtual = height * 2;
-    fbState->vinfo.bits_per_pixel = 16;
-
-    fbState->vinfo.red.offset = 11;
-    fbState->vinfo.red.length = 5;
-    fbState->vinfo.green.offset = 5;
-    fbState->vinfo.green.length = 6;
-    fbState->vinfo.blue.offset = 0;
-    fbState->vinfo.blue.length = 5;
-
-    fbState->vinfo.width = 51;           // physical dimension, used for dpi
-    fbState->vinfo.height = 76;
-
-    fbState->vinfo.pixclock = 103092;    
-    fbState->vinfo.upper_margin = 3;
-    fbState->vinfo.lower_margin = 227;
-    fbState->vinfo.left_margin = 12;
-    fbState->vinfo.right_margin = 8;
-}
-
-/*
- * Free allocated state.
- */
-static void freeState(FbState* fbState)
-{
-    int oldcount;
-
-    oldcount = wsAtomicAdd(&fbState->refCount, -1);
-
-    if (oldcount == 0) {
-        free(fbState);
-    }
-}
-
-/*
- * Wait for our synthetic vsync to happen.
- */
-static void waitForVsync(FbState* state)
-{
-    /* TODO: simulate a real interval */
-    usleep(1000000/60);
-}
-
-/*
- * Forward pixels to the simulator.
- */
-static void sendPixelsToSim(FbState* state)
-{
-    if (state->vramAddr == 0) {
-        wsLog("## not sending pixels (no addr yet)\n");
-        return;
-    }
-
-    //wsLog("+++ sending pixels to sim (disp=%d yoff=%d)\n",
-    //    state->displayIdx, state->vinfo.yoffset);
-
-    wsLockDisplay(state->displayIdx);
-
-    uint8_t* dst = gWrapSim.display[state->displayIdx].addr;
-
-    int l,t,r,b,w,h;
-    w = gWrapSim.display[state->displayIdx].width;
-    h = gWrapSim.display[state->displayIdx].height;
-
-#if 0
-    /*
-     * TODO: surfaceflinger encodes the dirty region in vinfo.reserved[].  We
-     * can use that to perform a partial update.
-     */
-    const Rect dirty(dirtyReg.bounds());
-    l = dirty.left  >=0 ? dirty.left : 0;
-    t = dirty.top   >=0 ? dirty.top  : 0;
-    r = dirty.right <=w ? dirty.right  : w;
-    b = dirty.bottom<=h ? dirty.bottom : h;
-#else
-    l = t = 0;
-    r = w;
-    b = h;
-#endif
-
-    /* find the right page */
-    int ypage = state->vinfo.yoffset;
-
-    int x, y;
-    for (y = t ; y < b ; y++) {
-        // no "stride" issues with this display
-        uint8_t* outPtr = dst + (y*w+l)*3;
-        const uint16_t* ptr16 = (uint16_t*)state->vramAddr + ((y+ypage)*w+l);
-        for (x = l; x < r; x++) {
-            uint16_t in = *ptr16++;
-            uint32_t R,G,B;
-            R = ((in>>8)&0xF8) | (in>>(8+5));
-            G = (in & 0x7E0)>>3;
-            G |= G>>6;
-            B = (in & 0x1F)<<3;
-            B |= B>>5;
-            *outPtr++ = R;
-            *outPtr++ = G;
-            *outPtr++ = B;
-        }
-    }
-
-    wsUnlockDisplay(state->displayIdx);
-
-    /* notify the simulator */
-    wsPostDisplayUpdate(state->displayIdx);
-}
-
-/*
- * Provide a memory-mapped region for framebuffer data.  We want to use a
- * real mmap() call, not fake it with a malloc, so that related calls
- * (munmap, madvise) will just work.
- */
-static void* mmapFb(FakeDev* dev, void* start, size_t length, int prot,
-    int flags, int fd, __off_t offset)
-{
-    FbState* state = (FbState*) dev->state;
-    void* map;
-
-    /* be reasonable */
-    if (length > (640*480*2)*4) {
-        errno = EINVAL;
-        return MAP_FAILED;
-    }
-
-    /* this is supposed to be VRAM, so just map a chunk */
-    map = mmap(start, length, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
-
-    /* update our "VRAM address"; this feels a bit fragile */
-    if (state->vramAddr != NULL) {
-        wsLog("%s: NOTE: changing vram address from %p\n",
-            dev->debugName, state->vramAddr);
-    }
-    state->vramAddr = map;
-
-    wsLog("%s: mmap %u bytes --> %p\n", dev->debugName, length, map);
-    return map;
-}
-
-/*
- * Handle framebuffer ioctls.
- */
-static int ioctlFb(FakeDev* dev, int fd, int request, void* argp)
-{
-    FbState* state = (FbState*) dev->state;
-
-    wsLog("%s: ioctl(0x%x, %p)\n", dev->debugName, request, argp);
-
-    switch (request) {
-    case FBIOGET_FSCREENINFO:       // struct fb_fix_screeninfo*
-        memcpy(argp, &state->finfo, sizeof(struct fb_fix_screeninfo));
-        break;
-    case FBIOGET_VSCREENINFO:       // struct fb_var_screeninfo*
-        memcpy(argp, &state->vinfo, sizeof(struct fb_var_screeninfo));
-        break;
-    case FBIOPUT_VSCREENINFO:       // struct fb_var_screeninfo*
-        memcpy(&state->vinfo, argp, sizeof(struct fb_var_screeninfo));
-        if (state->vinfo.activate == FB_ACTIVATE_NOW) {
-            //wsLog("%s: activate now\n", dev->debugName);
-            sendPixelsToSim(state);
-        } else if (state->vinfo.activate == FB_ACTIVATE_VBL) {
-            //wsLog("%s: activate on VBL\n", dev->debugName);
-            sendPixelsToSim(state);
-            /* we wait *after* so other process gets scheduled to draw */
-            waitForVsync(state);
-        } else {
-            wsLog("%s: activate value is %d\n",
-                dev->debugName, state->vinfo.activate);
-        }
-        break;
-    case FBIOGET_VBLANK:            // struct fb_vblank*
-        /* the device doesn't actually implement this */
-        //memset(argp, 0, sizeof(struct fb_vblank));
-        errno = EINVAL;
-        return -1;
-    default:
-    /*case FBIO_WAITFORVSYNC:*/
-        wsLog("GLITCH: UNKNOWN ioctl request 0x%x on %s\n",
-            request, dev->debugName);
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Free up our state before closing down the fake descriptor.
- */
-static int closeFb(FakeDev* dev, int fd)
-{
-    freeState((FbState*)dev->state);
-    dev->state = NULL;
-    return 0;
-}
-
-/*
- * dup() an existing fake descriptor
- */
-static FakeDev* dupFb(FakeDev* dev, int fd)
-{
-    FakeDev* newDev = wsCreateFakeDev(dev->debugName);
-    if (newDev != NULL) {
-        newDev->mmap = mmapFb;
-        newDev->ioctl = ioctlFb;
-        newDev->close = closeFb;
-        newDev->dup = dupFb;
-
-        /* use state from existing FakeDev */
-        FbState* fbState = dev->state;
-        wsAtomicAdd(&fbState->refCount, 1);
-
-        newDev->state = fbState;
-    }
-
-    return newDev;
-}
-
-/*
- * Open the console TTY device, which responds to a collection of ioctl()s.
- */
-FakeDev* wsOpenDevFb(const char* pathName, int flags)
-{
-    FakeDev* newDev = wsCreateFakeDev(pathName);
-    if (newDev != NULL) {
-        newDev->mmap = mmapFb;
-        newDev->ioctl = ioctlFb;
-        newDev->close = closeFb;
-        newDev->dup = dupFb;
-
-        FbState* fbState = calloc(1, sizeof(FbState));
-
-        /* establish a connection to the front-end if necessary */
-        /* (also gets display configuration) */
-        wsSimConnect();
-
-        configureInitialState(0, fbState);  // always use display 0 for now
-        newDev->state = fbState;
-    }
-
-    return newDev;
-}
-
diff --git a/simulator/wrapsim/DevLog.c b/simulator/wrapsim/DevLog.c
deleted file mode 100644
index fe1144d..0000000
--- a/simulator/wrapsim/DevLog.c
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Log devices.  We want to filter and display messages, with separate
- * treatment for "debug" and "event" logs.
- *
- * All messages are just dumped to stderr.
- */
-#include "Common.h"
-
-#include "cutils/logd.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include <fcntl.h>
-
-#define kMaxTagLen  16      /* from utils/Log.cpp */
-
-#define kTagSetSize 16      /* arbitrary */
-
-/* from utils/Log.cpp */
-typedef enum {
-    FORMAT_OFF = 0,
-    FORMAT_BRIEF,
-    FORMAT_PROCESS,
-    FORMAT_TAG,
-    FORMAT_THREAD,
-    FORMAT_RAW,
-    FORMAT_TIME,
-    FORMAT_LONG
-} LogFormat;
-
-
-/*
- * Log driver state.
- */
-typedef struct LogState {
-    /* nonzero if this is a binary log */
-    int     isBinary;
-
-    /* global minimum priority */
-    int     globalMinPriority;
-
-    /* output format */
-    LogFormat outputFormat;
-
-    /* tags and priorities */
-    struct {
-        char    tag[kMaxTagLen];
-        int     minPriority;
-    } tagSet[kTagSetSize];
-} LogState;
-
-
-/*
- * Configure logging based on ANDROID_LOG_TAGS environment variable.  We
- * need to parse a string that looks like
- *
- *  '*:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
- *
- * The tag (or '*' for the global level) comes first, followed by a colon
- * and a letter indicating the minimum priority level we're expected to log.
- * This can be used to reveal or conceal logs with specific tags.
- *
- * We also want to check ANDROID_PRINTF_LOG to determine how the output
- * will look.
- */
-static void configureInitialState(const char* pathName, LogState* logState)
-{
-    static const int kDevLogLen = 9;    /* strlen("/dev/log/") */
-
-    /* identify binary logs */
-    if (strcmp(pathName + kDevLogLen, "events") == 0) {
-        logState->isBinary = 1;
-    }
-
-    /* global min priority defaults to "info" level */
-    logState->globalMinPriority = ANDROID_LOG_INFO;
-
-    /*
-     * This is based on the utils/Log.cpp code.
-     */
-    const char* tags = getenv("ANDROID_LOG_TAGS");
-    wsLog("Found ANDROID_LOG_TAGS='%s'\n", tags);
-    if (tags != NULL) {
-        int entry = 0;
-
-        while (*tags != '\0') {
-            char tagName[kMaxTagLen];
-            int i, minPrio;
-
-            while (isspace(*tags))
-                tags++;
-
-            i = 0;
-            while (*tags != '\0' && !isspace(*tags) && *tags != ':' &&
-                i < kMaxTagLen)
-            {
-                tagName[i++] = *tags++;
-            }
-            if (i == kMaxTagLen) {
-                wsLog("ERROR: env tag too long (%d chars max)\n", kMaxTagLen-1);
-                return;
-            }
-            tagName[i] = '\0';
-
-            /* default priority, if there's no ":" part; also zero out '*' */
-            minPrio = ANDROID_LOG_VERBOSE;
-            if (tagName[0] == '*' && tagName[1] == '\0') {
-                minPrio = ANDROID_LOG_DEBUG;
-                tagName[0] = '\0';
-            }
-
-            if (*tags == ':') {
-                tags++;
-                if (*tags >= '0' && *tags <= '9') {
-                    if (*tags >= ('0' + ANDROID_LOG_SILENT))
-                        minPrio = ANDROID_LOG_VERBOSE;
-                    else
-                        minPrio = *tags - '\0';
-                } else {
-                    switch (*tags) {
-                    case 'v':   minPrio = ANDROID_LOG_VERBOSE;  break;
-                    case 'd':   minPrio = ANDROID_LOG_DEBUG;    break;
-                    case 'i':   minPrio = ANDROID_LOG_INFO;     break;
-                    case 'w':   minPrio = ANDROID_LOG_WARN;     break;
-                    case 'e':   minPrio = ANDROID_LOG_ERROR;    break;
-                    case 'f':   minPrio = ANDROID_LOG_FATAL;    break;
-                    case 's':   minPrio = ANDROID_LOG_SILENT;   break;
-                    default:    minPrio = ANDROID_LOG_DEFAULT;  break;
-                    }
-                }
-
-                tags++;
-                if (*tags != '\0' && !isspace(*tags)) {
-                    wsLog("ERROR: garbage in tag env; expected whitespace\n");
-                    wsLog("       env='%s'\n", tags);
-                    return;
-                }
-            }
-
-            if (tagName[0] == 0) {
-                logState->globalMinPriority = minPrio;
-                wsLog("+++ global min prio %d\n", logState->globalMinPriority);
-            } else {
-                logState->tagSet[entry].minPriority = minPrio;
-                strcpy(logState->tagSet[entry].tag, tagName);
-                wsLog("+++ entry %d: %s:%d\n",
-                    entry,
-                    logState->tagSet[entry].tag,
-                    logState->tagSet[entry].minPriority);
-                entry++;
-            }
-        }
-    }
-
-
-    /*
-     * Taken from utils/Log.cpp
-     */
-    const char* fstr = getenv("ANDROID_PRINTF_LOG");
-    LogFormat format;
-    if (fstr == NULL) {
-        format = FORMAT_BRIEF;
-    } else {
-        if (strcmp(fstr, "brief") == 0)
-            format = FORMAT_BRIEF;
-        else if (strcmp(fstr, "process") == 0)
-            format = FORMAT_PROCESS;
-        else if (strcmp(fstr, "tag") == 0)
-            format = FORMAT_PROCESS;
-        else if (strcmp(fstr, "thread") == 0)
-            format = FORMAT_PROCESS;
-        else if (strcmp(fstr, "raw") == 0)
-            format = FORMAT_PROCESS;
-        else if (strcmp(fstr, "time") == 0)
-            format = FORMAT_PROCESS;
-        else if (strcmp(fstr, "long") == 0)
-            format = FORMAT_PROCESS;
-        else
-            format = (LogFormat) atoi(fstr);        // really?!
-    }
-
-    logState->outputFormat = format;
-}
-
-/*
- * Free up the state structure.
- */
-static void freeState(LogState* logState)
-{
-    free(logState);
-}
-
-/*
- * Return a human-readable string for the priority level.  Always returns
- * a valid string.
- */
-static const char* getPriorityString(int priority)
-{
-    /* the first character of each string should be unique */
-    static const char* priorityStrings[] = {
-        "Verbose", "Debug", "Info", "Warn", "Error", "Assert"
-    };
-    int idx;
-
-    idx = (int) priority - (int) ANDROID_LOG_VERBOSE;
-    if (idx < 0 ||
-        idx >= (int) (sizeof(priorityStrings) / sizeof(priorityStrings[0])))
-        return "?unknown?";
-    return priorityStrings[idx];
-}
-
-/*
- * Show a log message.  We write it to stderr and send a copy to the
- * simulator front-end for the log window.
- *
- * Taken from utils/Log.cpp.
- */
-static void showLog(FakeDev* dev, int logPrio, const char* tag, const char* msg)
-{
-    LogState* state = (LogState*) dev->state;
-
-#if defined(HAVE_LOCALTIME_R)
-    struct tm tmBuf;
-#endif
-    struct tm* ptm;
-    char timeBuf[32];
-    char prefixBuf[128], suffixBuf[128];
-    char priChar;
-    time_t when;
-    pid_t pid, tid;
-
-    //wsLog("LOG %d: %s %s", logPrio, tag, msg);
-    wsPostLogMessage(logPrio, tag, msg);
-
-    priChar = getPriorityString(logPrio)[0];
-    when = time(NULL);
-    pid = tid = getpid();       // find gettid()?
-
-    /*
-     * Get the current date/time in pretty form
-     *
-     * It's often useful when examining a log with "less" to jump to
-     * a specific point in the file by searching for the date/time stamp.
-     * For this reason it's very annoying to have regexp meta characters
-     * in the time stamp.  Don't use forward slashes, parenthesis,
-     * brackets, asterisks, or other special chars here.
-     */
-#if defined(HAVE_LOCALTIME_R)
-    ptm = localtime_r(&when, &tmBuf);
-#else
-    ptm = localtime(&when);
-#endif
-    //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
-    strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
-
-    /*
-     * Construct a buffer containing the log header and log message.
-     */
-    size_t prefixLen, suffixLen;
-
-    switch (state->outputFormat) {
-    case FORMAT_TAG:
-        prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
-            "%c/%-8s: ", priChar, tag);
-        strcpy(suffixBuf, "\n"); suffixLen = 1;
-        break;
-    case FORMAT_PROCESS:
-        prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
-            "%c(%5d) ", priChar, pid);
-        suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
-            "  (%s)\n", tag);
-        break;
-    case FORMAT_THREAD:
-        prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
-            "%c(%5d:%p) ", priChar, pid, (void*)tid);
-        strcpy(suffixBuf, "\n"); suffixLen = 1;
-        break;
-    case FORMAT_RAW:
-        prefixBuf[0] = 0; prefixLen = 0;
-        strcpy(suffixBuf, "\n"); suffixLen = 1;
-        break;
-    case FORMAT_TIME:
-        prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
-            "%s %-8s\n\t", timeBuf, tag);
-        strcpy(suffixBuf, "\n"); suffixLen = 1;
-        break;
-    case FORMAT_LONG:
-        prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
-            "[ %s %5d:%p %c/%-8s ]\n",
-            timeBuf, pid, (void*)tid, priChar, tag);
-        strcpy(suffixBuf, "\n\n"); suffixLen = 2;
-        break;
-    default:
-        prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
-            "%c/%-8s(%5d): ", priChar, tag, pid);
-        strcpy(suffixBuf, "\n"); suffixLen = 1;
-        break;
-     }
-
-    /*
-     * Figure out how many lines there will be.
-     */
-    const char* end = msg + strlen(msg);
-    size_t numLines = 0;
-    const char* p = msg;
-    while (p < end) {
-        if (*p++ == '\n') numLines++;
-    }
-    if (p > msg && *(p-1) != '\n') numLines++;
-    
-    /*
-     * Create an array of iovecs large enough to write all of
-     * the lines with a prefix and a suffix.
-     */
-    const size_t INLINE_VECS = 6;
-    struct iovec stackVec[INLINE_VECS];
-    struct iovec* vec = stackVec;
-    
-    numLines *= 3;  // 3 iovecs per line.
-    if (numLines > INLINE_VECS) {
-        vec = (struct iovec*)malloc(sizeof(struct iovec)*numLines);
-        if (vec == NULL) {
-            msg = "LOG: write failed, no memory";
-            numLines = 3;
-        }
-    }
-    
-    /*
-     * Fill in the iovec pointers.
-     */
-    p = msg;
-    struct iovec* v = vec;
-    int totalLen = 0;
-    while (p < end) {
-        if (prefixLen > 0) {
-            v->iov_base = prefixBuf;
-            v->iov_len = prefixLen;
-            totalLen += prefixLen;
-            v++;
-        }
-        const char* start = p;
-        while (p < end && *p != '\n') p++;
-        if ((p-start) > 0) {
-            v->iov_base = (void*)start;
-            v->iov_len = p-start;
-            totalLen += p-start;
-            v++;
-        }
-        if (*p == '\n') p++;
-        if (suffixLen > 0) {
-            v->iov_base = suffixBuf;
-            v->iov_len = suffixLen;
-            totalLen += suffixLen;
-            v++;
-        }
-    }
-    
-    /*
-     * Write the entire message to the log file with a single writev() call.
-     * We need to use this rather than a collection of printf()s on a FILE*
-     * because of multi-threading and multi-process issues.
-     *
-     * If the file was not opened with O_APPEND, this will produce interleaved
-     * output when called on the same file from multiple processes.
-     *
-     * If the file descriptor is actually a network socket, the writev()
-     * call may return with a partial write.  Putting the writev() call in
-     * a loop can result in interleaved data.  This can be alleviated
-     * somewhat by wrapping the writev call in the Mutex.
-     */
-
-    for(;;) {
-        int cc;
-
-        cc = writev(fileno(stderr), vec, v-vec);
-        if (cc == totalLen) break;
-        
-        if (cc < 0) {
-            if(errno == EINTR) continue;
-            
-                /* can't really log the failure; for now, throw out a stderr */
-            fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
-            break;
-        } else {
-                /* shouldn't happen when writing to file or tty */
-            fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", cc, totalLen);
-            break;
-        }
-    }
-
-    /* if we allocated storage for the iovecs, free it */
-    if (vec != stackVec)
-        free(vec);
-}
-
-
-/*
- * Receive a log message.  We happen to know that "vector" has three parts:
- *
- *  priority (1 byte)
- *  tag (N bytes -- null-terminated ASCII string)
- *  message (N bytes -- null-terminated ASCII string)
- */
-static ssize_t writevLog(FakeDev* dev, int fd, const struct iovec* vector,
-    int count)
-{
-    LogState* state = (LogState*) dev->state;
-    int ret = 0;
-
-    if (state->isBinary) {
-        wsLog("%s: ignoring binary log\n", dev->debugName);
-        goto bail;
-    }
-
-    if (count != 3) {
-        wsLog("%s: writevLog with count=%d not expected\n",
-            dev->debugName, count);
-        errno = EINVAL;
-        return -1;
-    }
-
-    /* pull out the three fields */
-    int logPrio = *(const char*)vector[0].iov_base;
-    const char* tag = (const char*) vector[1].iov_base;
-    const char* msg = (const char*) vector[2].iov_base;
-
-    /* see if this log tag is configured */
-    int i;
-    int minPrio = state->globalMinPriority;
-    for (i = 0; i < kTagSetSize; i++) {
-        if (state->tagSet[i].minPriority == ANDROID_LOG_UNKNOWN)
-            break;      /* reached end of configured values */
-
-        if (strcmp(state->tagSet[i].tag, tag) == 0) {
-            //wsLog("MATCH tag '%s'\n", tag);
-            minPrio = state->tagSet[i].minPriority;
-            break;
-        }
-    }
-
-    if (logPrio >= minPrio) {
-        showLog(dev, logPrio, tag, msg);
-    } else {
-        //wsLog("+++ NOLOG(%d): %s %s", logPrio, tag, msg);
-    }
-
-bail:
-    for (i = 0; i < count; i++)
-        ret += vector[i].iov_len;
-    return ret;
-}
-
-/*
- * Free up our state before closing down the fake descriptor.
- */
-static int closeLog(FakeDev* dev, int fd)
-{
-    freeState((LogState*)dev->state);
-    dev->state = NULL;
-    return 0;
-}
-
-/*
- * Open a log output device.
- */
-FakeDev* wsOpenDevLog(const char* pathName, int flags)
-{
-    FakeDev* newDev = wsCreateFakeDev(pathName);
-    if (newDev != NULL) {
-        newDev->writev = writevLog;
-        newDev->close = closeLog;
-
-        LogState* logState = calloc(1, sizeof(LogState));
-
-        configureInitialState(pathName, logState);
-        newDev->state = logState;
-    }
-
-    return newDev;
-}
-
diff --git a/simulator/wrapsim/DevPower.c b/simulator/wrapsim/DevPower.c
deleted file mode 100644
index b44231b..0000000
--- a/simulator/wrapsim/DevPower.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Magic entries in /sys/class/power_supply/.
- */
-#include "Common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-/*
- * Map filename to device index.
- *
- * [ not using DeviceIndex -- would be useful if we need to return something
- * other than a static string ]
- */
-static const struct {
-    const char*     name;
-    //DeviceIndex     idx;
-    const char*     data;
-} gDeviceMap[] = {
-    { "ac/online",
-        "0\n" },
-
-    { "battery/batt_temp",
-        "281\n", },
-    { "battery/batt_vol",
-        "4170\n" },
-    { "battery/capacity",
-        "100\n" },
-    { "battery/health",
-        "Good\n" },
-    { "battery/present",
-        "0\n" },
-    { "battery/status",
-        "Full" },
-    { "battery/technology",
-        "Li-ion\n" },
-
-    { "usb/online",
-        "1\n" },
-};
-
-/*
- * Power driver state.
- *
- * Right now we just ignore everything written.
- */
-typedef struct PowerState {
-    int         which;
-} PowerState;
-
-
-/*
- * Figure out who we are, based on "pathName".
- */
-static void configureInitialState(const char* pathName, PowerState* powerState)
-{
-    const char* cp = pathName + strlen("/sys/class/power_supply/");
-    int i;
-
-    powerState->which = -1;
-    for (i = 0; i < (int) (sizeof(gDeviceMap) / sizeof(gDeviceMap[0])); i++) {
-        if (strcmp(cp, gDeviceMap[i].name) == 0) {
-            powerState->which = i;
-            break;
-        }
-    }
-
-    if (powerState->which == -1) {
-        wsLog("Warning: access to unknown power device '%s'\n", pathName);
-        return;
-    }
-}
-
-/*
- * Free up the state structure.
- */
-static void freeState(PowerState* powerState)
-{
-    free(powerState);
-}
-
-/*
- * Read data from the device.
- *
- * We don't try to keep track of how much was read -- existing clients just
- * try to read into a large buffer.
- */
-static ssize_t readPower(FakeDev* dev, int fd, void* buf, size_t count)
-{
-    PowerState* state = (PowerState*) dev->state;
-    int dataLen;
-
-    wsLog("%s: read %d\n", dev->debugName, count);
-
-    if (state->which < 0 ||
-        state->which >= (int) (sizeof(gDeviceMap)/sizeof(gDeviceMap[0])))
-    {
-        return 0;
-    }
-
-    const char* data = gDeviceMap[state->which].data;
-    size_t strLen = strlen(data);
-
-    while(strLen == 0)
-        sleep(10); // block forever
-
-    ssize_t copyCount = (strLen < count) ? strLen : count;
-    memcpy(buf, data, copyCount);
-    return copyCount;
-}
-
-/*
- * Ignore the request.
- */
-static ssize_t writePower(FakeDev* dev, int fd, const void* buf, size_t count)
-{
-    wsLog("%s: write %d bytes\n", dev->debugName, count);
-    return count;
-}
-
-/*
- * Our Java classes want to be able to do ioctl(FIONREAD) on files.  The
- * battery power manager is blowing up if we get an error other than
- * ENOTTY (meaning a device that doesn't understand buffering).
- */
-static int ioctlPower(FakeDev* dev, int fd, int request, void* argp)
-{
-    if (request == FIONREAD) {
-        wsLog("%s: ioctl(FIONREAD, %p)\n", dev->debugName, argp);
-        errno = ENOTTY;
-        return -1;
-    } else {
-        wsLog("%s: ioctl(0x%08x, %p) ??\n", dev->debugName, request, argp);
-        errno = EINVAL;
-        return -1;
-    }
-}
-
-/*
- * Free up our state before closing down the fake descriptor.
- */
-static int closePower(FakeDev* dev, int fd)
-{
-    freeState((PowerState*)dev->state);
-    dev->state = NULL;
-    return 0;
-}
-
-/*
- * Open a power device.
- */
-FakeDev* wsOpenDevPower(const char* pathName, int flags)
-{
-    FakeDev* newDev = wsCreateFakeDev(pathName);
-    if (newDev != NULL) {
-        newDev->read = readPower;
-        newDev->write = writePower;
-        newDev->ioctl = ioctlPower;
-        newDev->close = closePower;
-
-        PowerState* powerState = calloc(1, sizeof(PowerState));
-
-        configureInitialState(pathName, powerState);
-        newDev->state = powerState;
-    }
-
-    return newDev;
-}
-
diff --git a/simulator/wrapsim/DevVibrator.c b/simulator/wrapsim/DevVibrator.c
deleted file mode 100644
index b736f75..0000000
--- a/simulator/wrapsim/DevVibrator.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Vibrating notification device.
- */
-#include "Common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include <unistd.h>
-
-
-/*
- * The user will write a decimal integer indicating the time, in milliseconds,
- * that the device should vibrate.  In current usage, this is either -1
- * (meaning vibrate forever) or 0 (don't vibrate).
- */
-static ssize_t writeVibrator(FakeDev* dev, int fd, const void* buf,
-    size_t count)
-{
-    if (count == 2 && memcmp(buf, "0\n", 2) == 0) {
-        wsEnableVibration(0);
-    } else if (count == 3 && memcmp(buf, "-1\n", 3) == 0) {
-        wsEnableVibration(1);
-    } else {
-        wsLog("%s: got %d bytes: '%*s'\n",
-            dev->debugName, count, count, (const char*) buf);
-    }
-
-    return count;
-}
-
-/*
- * Open the vibration control device.
- */
-FakeDev* wsOpenDevVibrator(const char* pathName, int flags)
-{
-    FakeDev* newDev = wsCreateFakeDev(pathName);
-    if (newDev != NULL) {
-        newDev->write = writeVibrator;
-    }
-
-    return newDev;
-}
-
diff --git a/simulator/wrapsim/FakeDev.c b/simulator/wrapsim/FakeDev.c
deleted file mode 100644
index f03dd29..0000000
--- a/simulator/wrapsim/FakeDev.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Fake device support.
- */
-/*
-Implementation notes:
-
-There are a couple of basic scenarios, exemplified by the "fb" and
-"events" devices.  The framebuffer driver is pretty simple, handling a
-few ioctl()s and managing a stretch of memory.  We can just intercept a
-few calls.  The input event driver can be used in a select() or poll()
-call with other file descriptors, which either requires us to do some
-fancy tricks with select() and poll(), or requires that we return a real
-file descriptor (perhaps based on a socketpair).
-
-We have three basic approaches to dealing with "fake" file descriptors:
-
-(1) Always use real fds.  We can dup() an open /dev/null to get a number
-    for the cases where we don't need a socketpair.
-(2) Always use fake fds with absurdly high numeric values.  Testing to see
-    if the fd is one we handle is trivial (range check).  This doesn't
-    work for select(), which uses fd bitmaps accessed through macros.
-(3) Use a mix of real and fake fds, in a high range (512-1023).  Because
-    it's in the "real" range, we can pass real fds around for things that
-    are handed to poll() and select(), but because of the high numeric
-    value we *should* be able to get away with a trivial range check.
-
-Approach (1) is the most portable and least likely to break, but the
-efficiencies gained in approach (2) make it more desirable.  There is
-a small risk of application fds wandering into our range, but we can
-minimize that by asserting on a "guard zone" and/or obstructing dup2().
-(We can also dup2(/dev/null) to "reserve" our fds, but that wastes
-resources.)
-*/
-
-#include "Common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <assert.h>
-#include <fnmatch.h>
-
-/*
- * Devices we intercept.
- *
- * Needed:
- *  /dev/alarm
- *  radio
- */
-typedef FakeDev* (*wsFileHook)(const char *path, int flags);
-
-typedef struct FakedPath {
-    const char *pathexpr;
-    wsFileHook hook;
-} FakedPath;
-
-FakedPath fakedpaths[] =
-{
-    { "/dev/graphics/fb0",      wsOpenDevFb },
-    { "/dev/hw3d",              NULL },
-    { "/dev/eac",               wsOpenDevAudio },
-    { "/dev/tty0",              wsOpenDevConsoleTty },
-    { "/dev/input/event0",      wsOpenDevEvent },
-    { "/dev/input/*",           NULL },
-    { "/dev/log/*",             wsOpenDevLog },
-    { "/sys/class/power_supply/*", wsOpenDevPower },
-    { "/sys/power/state",       wsOpenSysPower },
-    { "/sys/power/wake_lock",   wsOpenSysPower },
-    { "/sys/power/wake_unlock", wsOpenSysPower },
-    { "/sys/devices/platform/android-vibrator/enable",  wsOpenDevVibrator },
-    { "/sys/qemu_trace/*",      NULL },
-    { NULL,                     NULL }
-};
-
-
-/*
- * Generic drop-in for an unimplemented call.
- *
- * Returns -1, which conveniently is the same as MAP_FAILED for mmap.
- */
-static int notImplemented(FakeDev* dev, const char* callName)
-{
-    wsLog("WARNING: unimplemented %s() on '%s' %p\n",
-        callName, dev->debugName, dev->state);
-    errno = kNoHandlerError;
-    return -1;
-}
-
-/*
- * Default implementations.  We want to log as much information as we can
- * so that we can fill in the missing implementation.
- *
- * TODO: for some or all of these we will want to display the full arg list.
- */
-static int noClose(FakeDev* dev, ...)
-{
-    return 0;
-}
-static FakeDev* noDup(FakeDev* dev, ...)
-{
-    notImplemented(dev, "dup");
-    return NULL;
-}
-static int noRead(FakeDev* dev, ...)
-{
-    return notImplemented(dev, "read");
-}
-static int noReadv(FakeDev* dev, ...)
-{
-    return notImplemented(dev, "readv");
-}
-static int noWrite(FakeDev* dev, ...)
-{
-    return notImplemented(dev, "write");
-}
-static int noWritev(FakeDev* dev, ...)
-{
-    return notImplemented(dev, "writev");
-}
-static int noMmap(FakeDev* dev, ...)
-{
-    return notImplemented(dev, "mmap");
-}
-static int noIoctl(FakeDev* dev, ...)
-{
-    return notImplemented(dev, "ioctl");
-}
-
-
-/*
- * Create a new FakeDev entry.
- *
- * We mark the fd slot as "used" in the bitmap, but don't add it to the
- * table yet since the entry is not fully prepared.
- */
-FakeDev* wsCreateFakeDev(const char* debugName)
-{
-    FakeDev* newDev;
-    int cc;
-
-    assert(debugName != NULL);
-
-    newDev = (FakeDev*) calloc(1, sizeof(FakeDev));
-    if (newDev == NULL)
-        return NULL;
-
-    newDev->debugName = strdup(debugName);
-    newDev->state = NULL;
-
-    newDev->close = (Fake_close) noClose;
-    newDev->dup = (Fake_dup) noDup;
-    newDev->read = (Fake_read) noRead;
-    newDev->readv = (Fake_readv) noReadv;
-    newDev->write = (Fake_write) noWrite;
-    newDev->writev = (Fake_writev) noWritev;
-    newDev->mmap = (Fake_mmap) noMmap;
-    newDev->ioctl = (Fake_ioctl) noIoctl;
-
-    /*
-     * Allocate a new entry.  The bit vector map is really only used as a
-     * performance boost in the current implementation.
-     */
-    cc = pthread_mutex_lock(&gWrapSim.fakeFdLock); assert(cc == 0);
-    int newfd = wsAllocBit(gWrapSim.fakeFdMap);
-    cc = pthread_mutex_unlock(&gWrapSim.fakeFdLock); assert(cc == 0);
-
-    if (newfd < 0) {
-        wsLog("WARNING: ran out of 'fake' file descriptors\n");
-        free(newDev);
-        return NULL;
-    }
-    newDev->fd = newfd + kFakeFdBase;
-    newDev->otherFd = -1;
-    assert(gWrapSim.fakeFdList[newDev->fd - kFakeFdBase] == NULL);
-
-    return newDev;
-}
-
-/*
- * Create a new FakeDev entry, and open a file descriptor that actually
- * works.
- */
-FakeDev* wsCreateRealFakeDev(const char* debugName)
-{
-    FakeDev* newDev = wsCreateFakeDev(debugName);
-    if (newDev == NULL)
-        return newDev;
-    
-    int fds[2];
-
-    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
-        wsLog("socketpair() failed: %s\n", strerror(errno));
-        wsFreeFakeDev(newDev);
-        return NULL;
-    }
-
-    if (dup2(fds[0], newDev->fd) < 0) {
-        wsLog("dup2(%d,%d) failed: %s\n",
-            fds[0], newDev->fd, strerror(errno));
-        wsFreeFakeDev(newDev);
-        return NULL;
-    }
-    close(fds[0]);
-
-    /* okay to leave this one in the "normal" range; not visible to app */
-    newDev->otherFd = fds[1];
-
-    return newDev;
-}
-
-/*
- * Free fake device entry.
- */
-void wsFreeFakeDev(FakeDev* dev)
-{
-    if (dev == NULL)
-        return;
-
-    wsLog("## closing/freeing '%s' (%d/%d)\n",
-        dev->debugName, dev->fd, dev->otherFd);
-
-    /*
-     * If we assigned a file descriptor slot, free it up.
-     */
-    if (dev->fd >= 0) {
-        int cc;
-
-        gWrapSim.fakeFdList[dev->fd - kFakeFdBase] = NULL;
-
-        cc = pthread_mutex_lock(&gWrapSim.fakeFdLock); assert(cc == 0);
-        wsFreeBit(gWrapSim.fakeFdMap, dev->fd - kFakeFdBase);
-        cc = pthread_mutex_unlock(&gWrapSim.fakeFdLock); assert(cc == 0);
-    }
-    if (dev->otherFd >= 0)
-        close(dev->otherFd);
-
-    if (dev->debugName) free(dev->debugName);
-    free(dev);
-}
-
-/*
- * Map a file descriptor to a fake device.
- *
- * Returns NULL if there's no corresponding entry.
- */
-FakeDev* wsFakeDevFromFd(int fd)
-{
-    /* quick range test */
-    if (fd < kFakeFdBase || fd >= kFakeFdBase + kMaxFakeFdCount)
-        return NULL;
-
-    return gWrapSim.fakeFdList[fd - kFakeFdBase];
-}
-
-
-/*
- * Check to see if we're opening a device that we want to fake out.
- *
- * We return a file descriptor >= 0 on success, -1 if we're not interested,
- * or -2 if we explicitly want to pretend that the device doesn't exist.
- */
-int wsInterceptDeviceOpen(const char* pathName, int flags)
-{
-    FakedPath* p = fakedpaths;
-
-    while (p->pathexpr) {
-        if (fnmatch(p->pathexpr, pathName, 0) == 0) {
-            if (p->hook != NULL) {
-                FakeDev* dev = p->hook(pathName, flags);
-                if (dev != NULL) {
-                    /*
-                     * Now that the device entry is ready, add it to the list.
-                     */
-                    wsLog("## created fake dev %d: '%s' %p\n",
-                        dev->fd, dev->debugName, dev->state);
-                    gWrapSim.fakeFdList[dev->fd - kFakeFdBase] = dev;
-                    return dev->fd;
-                }
-            } else {
-                wsLog("## rejecting attempt to open %s\n", pathName);
-                errno = ENOENT;
-                return -2;
-            }
-            break;
-        }
-        p++;
-    }
-    return -1;
-}
-
-/*
- * Check to see if we're accessing a device that we want to fake out.
- * Returns 0 if the device can be (fake) opened with the given mode,
- * -1 if it can't, -2 if it can't and we don't want to allow fallback
- * to the host-device either.
- * TODO: actually check the mode.
- */
-int wsInterceptDeviceAccess(const char *pathName, int mode)
-{
-    FakedPath *p = fakedpaths;
-
-    while (p->pathexpr) {
-        if (fnmatch(p->pathexpr, pathName, 0) == 0) {
-            if (p->hook) {
-                return 0;
-            } else {
-                wsLog("## rejecting attempt to open %s\n", pathName);
-                errno = ENOENT;
-                return -2;
-            }
-            break;
-        }
-        p++;
-    }
-    errno = ENOENT;
-    return -1;
-}
diff --git a/simulator/wrapsim/FakeDev.h b/simulator/wrapsim/FakeDev.h
deleted file mode 100644
index 65f47ae..0000000
--- a/simulator/wrapsim/FakeDev.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Fake device support.
- */
-#ifndef _WRAPSIM_FAKEDEV_H
-#define _WRAPSIM_FAKEDEV_H
-
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <errno.h>
-
-typedef struct FakeDev FakeDev;
-
-typedef int      (*Fake_close)(FakeDev* dev, int);
-typedef FakeDev* (*Fake_dup)(FakeDev* dev, int);
-typedef ssize_t  (*Fake_read)(FakeDev* dev, int, void*, size_t);
-typedef ssize_t  (*Fake_readv)(FakeDev* dev, int, const struct iovec*, int);
-typedef ssize_t  (*Fake_write)(FakeDev* dev, int, const void*, size_t);
-typedef ssize_t  (*Fake_writev)(FakeDev* dev, int, const struct iovec*, int);
-typedef void*    (*Fake_mmap)(FakeDev* dev, void*, size_t, int, int, int, __off_t);
-typedef int      (*Fake_ioctl)(FakeDev* dev, int, int, void*);
-
-/*
- * An open fake device entry.
- */
-struct FakeDev {
-    /* string, for debugging; usually orig. device name */
-    char*   debugName;
-
-    /* state bucket */
-    void*   state;
-
-    /* the file descriptor we're associated with */
-    int     fd;
-
-    /* in some cases we use a pair; this is the other one */
-    int     otherFd;
-
-    /*
-     * Device functions we provide.
-     *
-     * All other file descriptor operations should fail, usually with EBADF.
-     */
-    Fake_close  close;
-    Fake_dup  dup;
-    Fake_read   read;
-    Fake_readv  readv;
-    Fake_write  write;
-    Fake_writev writev;
-    Fake_mmap   mmap;       // handles both mmap() and mmap64()
-    Fake_ioctl  ioctl;
-};
-
-/*
- * If a handler isn't defined for a syscall, we return EMLINK so that it's
- * obvious when the error is generated by us.
- */ 
-#define kNoHandlerError EMLINK
-
-/*
- * Fake file descriptors begin here.  This should be chosen such that no
- * real descriptor is ever at or above this value.
- */
-#define kFakeFdBase     512
-#define kMaxFakeFdCount 256
-
-/*
- * Create a new, completely fake device entry.
- */
-FakeDev* wsCreateFakeDev(const char* debugName);
-
-/*
- * Create a new, mostly fake device entry.
- */
-FakeDev* wsCreateRealFakeDev(const char* debugName);
-
-/*
- * Free a fake device entry.
- */
-void wsFreeFakeDev(FakeDev* dev);
-
-/*
- * Given a file descriptor, find the corresponding fake device.  Returns
- * NULL if the fd doesn't correspond to one of our entries.
- */
-FakeDev* wsFakeDevFromFd(int fd);
-
-/*
- * Check to see if this open() call is on a device we want to spoof.
- *
- * Returns a "fake" file descriptor on success, <0 on error.
- */
-int wsInterceptDeviceOpen(const char* pathName, int flags);
-
-/*
- * Check to see if this access() call is on a device we want to spoof.
- *
- * Returns 0 if the device can be fake-accessed, -1 if it can't, -2
- * if it can't and we don't want to allow fallback to the host-device.
- */
-int wsInterceptDeviceAccess(const char* pathName, int flags);
-
-/*
- * Devices.
- */
-FakeDev* wsOpenDevAudio(const char* pathName, int flags);
-FakeDev* wsOpenDevConsoleTty(const char* pathName, int flags);
-FakeDev* wsOpenDevEvent(const char* pathName, int flags);
-FakeDev* wsOpenDevFb(const char* pathName, int flags);
-FakeDev* wsOpenDevLog(const char* pathName, int flags);
-FakeDev* wsOpenDevPower(const char* pathName, int flags);
-FakeDev* wsOpenSysPower(const char* pathName, int flags);
-FakeDev* wsOpenDevVibrator(const char* pathName, int flags);
-
-/*
- * Performs key remapping and sends the event to the global input event device.
- */
-void wsSendSimKeyEvent(int key, int isDown);
-
-/*
- * Send a touch event to the global input event device.
- */
-void wsSendSimTouchEvent(int action, int x, int y);
-
-#endif /*_WRAPSIM_FAKEDEV_H*/
diff --git a/simulator/wrapsim/Globals.h b/simulator/wrapsim/Globals.h
deleted file mode 100644
index a8d834c..0000000
--- a/simulator/wrapsim/Globals.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Sim wrapper global state.
- */
-#ifndef _WRAPSIM_GLOBALS_H
-#define _WRAPSIM_GLOBALS_H
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <sys/time.h>
-#include <sys/vfs.h>
-#include <utime.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <pthread.h>
-
-/*
- * Type declarations for the functions we're replacing.
- *
- * For syscalls this matches the syscall definition, not the libc definition,
- * e.g. no varargs for open() or ioctl().
- */
-typedef int     (*Func_access)(const char*, int);
-typedef int     (*Func_open)(const char*, int, mode_t);
-typedef int     (*Func_open64)(const char*, int, mode_t);
-
-typedef int     (*Func_close)(int);
-typedef int     (*Func_dup)(int);
-typedef ssize_t (*Func_read)(int, void*, size_t);
-typedef ssize_t (*Func_readv)(int, const struct iovec*, int);
-typedef ssize_t (*Func_write)(int, const void*, size_t);
-typedef ssize_t (*Func_writev)(int, const struct iovec*, int);
-typedef void*   (*Func_mmap)(void*, size_t, int, int, int, __off_t);
-typedef void*   (*Func_mmap64)(void*, size_t, int, int, int, __off64_t);
-typedef int     (*Func_ioctl)(int, int, void*);
-
-typedef int     (*Func_chdir)(const char*);
-typedef int     (*Func_chmod)(const char*, mode_t);
-typedef int     (*Func_chown)(const char*, uid_t, uid_t);
-typedef int     (*Func_creat)(const char*, mode_t);
-typedef int     (*Func_execve)(const char*, char* const[], char* const[]);
-typedef char*   (*Func_getcwd)(char* buf, size_t size);
-typedef int     (*Func_lchown)(const char*, uid_t, uid_t);
-typedef int     (*Func_link)(const char*, const char*);
-typedef int     (*Func_lstat)(const char*, struct stat*);
-typedef int     (*Func_lstat64)(const char*, struct stat*);
-typedef int     (*Func___lxstat)(int version, const char*, struct stat*);
-typedef int     (*Func___lxstat64)(int version, const char*, struct stat*);
-typedef int     (*Func_mkdir)(const char*, mode_t mode);
-typedef ssize_t (*Func_readlink)(const char*, char*, size_t);
-typedef int     (*Func_rename)(const char*, const char*);
-typedef int     (*Func_rmdir)(const char*);
-typedef int     (*Func_stat)(const char*, struct stat*);
-typedef int     (*Func_stat64)(const char*, struct stat*);
-typedef int     (*Func___xstat)(int version, const char*, struct stat*);
-typedef int     (*Func___xstat64)(int version, const char*, struct stat*);
-typedef int     (*Func_statfs)(const char*, struct statfs*);
-typedef int     (*Func_statfs64)(const char*, struct statfs*);
-typedef int     (*Func_symlink)(const char*, const char*);
-typedef int     (*Func_unlink)(const char*);
-typedef int     (*Func_utime)(const char*, const struct utimbuf*);
-typedef int     (*Func_utimes)(const char*, const struct timeval []);
-
-typedef int     (*Func_execl)(const char*, const char*, ...);
-typedef int     (*Func_execle)(const char*, const char*, ...);
-typedef int     (*Func_execlp)(const char*, const char*, ...);
-typedef int     (*Func_execv)(const char*, char* const []);
-typedef int     (*Func_execvp)(const char*, char* const []);
-typedef FILE*   (*Func_fopen)(const char*, const char*);
-typedef FILE*   (*Func_fopen64)(const char*, const char*);
-typedef FILE*   (*Func_freopen)(const char*, const char*, FILE*);
-typedef int     (*Func_ftw)(const char*,
-                    int (*fn) (const char*, const struct stat*, int),
-                    int);
-typedef DIR*    (*Func_opendir)(const char* path);
-typedef void*   (*Func_dlopen)(const char*, int);
-
-typedef int     (*Func_setpriority)(int, int, int);
-//typedef int     (*Func_pipe)(int [2]);
-
-
-/*
- * Pointers to the actual implementations.
- */
-#ifndef CREATE_FUNC_STORAGE
-# define EXTERN_FUNC extern
-#else
-# define EXTERN_FUNC
-#endif
-EXTERN_FUNC Func_access _ws_access;
-EXTERN_FUNC Func_open _ws_open;
-EXTERN_FUNC Func_open64 _ws_open64;
-
-EXTERN_FUNC Func_close _ws_close;
-EXTERN_FUNC Func_dup _ws_dup;
-EXTERN_FUNC Func_read _ws_read;
-EXTERN_FUNC Func_readv _ws_readv;
-EXTERN_FUNC Func_write _ws_write;
-EXTERN_FUNC Func_writev _ws_writev;
-EXTERN_FUNC Func_mmap _ws_mmap;
-EXTERN_FUNC Func_mmap64 _ws_mmap64;
-EXTERN_FUNC Func_ioctl _ws_ioctl;
-
-EXTERN_FUNC Func_chdir _ws_chdir;
-EXTERN_FUNC Func_chmod _ws_chmod;
-EXTERN_FUNC Func_chown _ws_chown;
-EXTERN_FUNC Func_creat _ws_creat;
-EXTERN_FUNC Func_execve _ws_execve;
-EXTERN_FUNC Func_getcwd _ws_getcwd;
-EXTERN_FUNC Func_lchown _ws_lchown;
-EXTERN_FUNC Func_link _ws_link;
-EXTERN_FUNC Func_lstat _ws_lstat;
-EXTERN_FUNC Func_lstat64 _ws_lstat64;
-EXTERN_FUNC Func___lxstat _ws___lxstat;
-EXTERN_FUNC Func___lxstat64 _ws___lxstat64;
-EXTERN_FUNC Func_mkdir _ws_mkdir;
-EXTERN_FUNC Func_readlink _ws_readlink;
-EXTERN_FUNC Func_rename _ws_rename;
-EXTERN_FUNC Func_rmdir _ws_rmdir;
-EXTERN_FUNC Func_stat _ws_stat;
-EXTERN_FUNC Func_stat64 _ws_stat64;
-EXTERN_FUNC Func___xstat _ws___xstat;
-EXTERN_FUNC Func___xstat64 _ws___xstat64;
-EXTERN_FUNC Func_statfs _ws_statfs;
-EXTERN_FUNC Func_statfs64 _ws_statfs64;
-EXTERN_FUNC Func_symlink _ws_symlink;
-EXTERN_FUNC Func_unlink _ws_unlink;
-EXTERN_FUNC Func_utime _ws_utime;
-EXTERN_FUNC Func_utimes _ws_utimes;
-
-EXTERN_FUNC Func_execl _ws_execl;
-EXTERN_FUNC Func_execle _ws_execle;
-EXTERN_FUNC Func_execlp _ws_execlp;
-EXTERN_FUNC Func_execv _ws_execv;
-EXTERN_FUNC Func_execvp _ws_execvp;
-EXTERN_FUNC Func_fopen _ws_fopen;
-EXTERN_FUNC Func_fopen64 _ws_fopen64;
-EXTERN_FUNC Func_freopen _ws_freopen;
-EXTERN_FUNC Func_ftw _ws_ftw;
-EXTERN_FUNC Func_opendir _ws_opendir;
-EXTERN_FUNC Func_dlopen _ws_dlopen;
-
-EXTERN_FUNC Func_setpriority _ws_setpriority;
-//EXTERN_FUNC Func_pipe _ws_pipe;
-
-#define kMaxDisplays 4
-
-/*
- * Global values.  Must be initialized in initGlobals(), which is executed
- * the first time somebody calls dlopen on the wrapper lib.
- */
-struct WrapSimGlobals {
-    volatile int    initialized;
-
-    /* descriptor where we write log messages */
-    int         logFd;
-
-    /* socket for communicating with simulator front-end */
-    int         simulatorFd;
-
-    /* coordinate thread startup */
-    pthread_mutex_t startLock;
-    pthread_cond_t  startCond;
-    int             startReady;
-    int             simulatorInitFailed;
-
-    /* base directory for filename remapping */
-    char*       remapBaseDir;
-    int         remapBaseDirLen;
-
-    /*
-     * Display characteristics.
-     *
-     * TODO: this is retrieved from the simulator during initial config.
-     * It needs to be visible to whatever process holds the surfaceflinger,
-     * which may or may not be the initial process in multi-process mode.
-     * We probably want to get the display config via a query, performed at
-     * intercepted-ioctl time, rather than a push from the sim at startup.
-     */
-    struct {
-        int     width;
-        int     height;
-
-        int     shmemKey;
-        int     shmid;
-        void*   addr;
-        long    length;
-        int     semid;
-    } display[kMaxDisplays];
-    int     numDisplays;
-
-    /*
-     * Input device.
-     */
-    FakeDev*    keyInputDevice;
-    const char *keyMap;
-
-    /* fake file descriptor allocation map */
-    pthread_mutex_t fakeFdLock;
-    BitVector*  fakeFdMap;
-    FakeDev*    fakeFdList[kMaxFakeFdCount];
-
-    /* used for wsAtomicAdd */
-    pthread_mutex_t atomicLock;
-};
-
-extern struct WrapSimGlobals gWrapSim;
-
-#endif /*_WRAPSIM_GLOBALS_H*/
diff --git a/simulator/wrapsim/Init.c b/simulator/wrapsim/Init.c
deleted file mode 100644
index 3df0efe..0000000
--- a/simulator/wrapsim/Init.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Initialize the intercepts.
- */
-#include "Common.h"
-
-#define __USE_GNU       /* need RTLD_NEXT */
-#include <dlfcn.h>
-
-#include <stdlib.h>
-#include <pthread.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-
-/*
- * Global state.
- */
-struct WrapSimGlobals gWrapSim;
-pthread_once_t gWrapSimInitialized = PTHREAD_ONCE_INIT;
-
-/*
- * Initialize our global state.
- */
-static void initGlobals(void)
-{
-    memset(&gWrapSim, 0xdd, sizeof(gWrapSim));
-    gWrapSim.logFd = -1;
-    gWrapSim.keyMap = NULL;
-
-    /*
-     * Find the original version of functions we override.
-     */
-    _ws_access = dlsym(RTLD_NEXT, "access");
-    _ws_open = dlsym(RTLD_NEXT, "open");
-    _ws_open64 = dlsym(RTLD_NEXT, "open64");
-
-    _ws_close = dlsym(RTLD_NEXT, "close");
-    _ws_dup = dlsym(RTLD_NEXT, "dup");
-    _ws_read = dlsym(RTLD_NEXT, "read");
-    _ws_readv = dlsym(RTLD_NEXT, "readv");
-    _ws_write = dlsym(RTLD_NEXT, "write");
-    _ws_writev = dlsym(RTLD_NEXT, "writev");
-    _ws_mmap = dlsym(RTLD_NEXT, "mmap");
-    _ws_mmap64 = dlsym(RTLD_NEXT, "mmap64");
-    _ws_ioctl = dlsym(RTLD_NEXT, "ioctl");
-
-    _ws_chdir = dlsym(RTLD_NEXT, "chdir");
-    _ws_chmod = dlsym(RTLD_NEXT, "chmod");
-    _ws_chown = dlsym(RTLD_NEXT, "chown");
-    _ws_creat = dlsym(RTLD_NEXT, "creat");
-    _ws_execve = dlsym(RTLD_NEXT, "execve");
-    _ws_getcwd = dlsym(RTLD_NEXT, "getcwd");
-    _ws_lchown = dlsym(RTLD_NEXT, "lchown");
-    _ws_link = dlsym(RTLD_NEXT, "link");
-    _ws_lstat = dlsym(RTLD_NEXT, "lstat");
-    _ws_lstat64 = dlsym(RTLD_NEXT, "lstat64");
-    _ws___lxstat = dlsym(RTLD_NEXT, "__lxstat");
-    _ws___lxstat64 = dlsym(RTLD_NEXT, "__lxstat64");
-    _ws_mkdir = dlsym(RTLD_NEXT, "mkdir");
-    _ws_readlink = dlsym(RTLD_NEXT, "readlink");
-    _ws_rename = dlsym(RTLD_NEXT, "rename");
-    _ws_rmdir = dlsym(RTLD_NEXT, "rmdir");
-    _ws_stat = dlsym(RTLD_NEXT, "stat");
-    _ws_stat64 = dlsym(RTLD_NEXT, "stat64");
-    _ws___xstat = dlsym(RTLD_NEXT, "__xstat");
-    _ws___xstat64 = dlsym(RTLD_NEXT, "__xstat64");
-    _ws_statfs = dlsym(RTLD_NEXT, "statfs");
-    _ws_statfs64 = dlsym(RTLD_NEXT, "statfs64");
-    _ws_symlink = dlsym(RTLD_NEXT, "symlink");
-    _ws_unlink = dlsym(RTLD_NEXT, "unlink");
-    _ws_utime = dlsym(RTLD_NEXT, "utime");
-    _ws_utimes = dlsym(RTLD_NEXT, "utimes");
-
-    _ws_execl = dlsym(RTLD_NEXT, "execl");
-    _ws_execle = dlsym(RTLD_NEXT, "execle");
-    _ws_execlp = dlsym(RTLD_NEXT, "execlp");
-    _ws_execv = dlsym(RTLD_NEXT, "execv");
-    _ws_execvp = dlsym(RTLD_NEXT, "execvp");
-    _ws_fopen = dlsym(RTLD_NEXT, "fopen");
-    _ws_fopen64 = dlsym(RTLD_NEXT, "fopen64");
-    _ws_freopen = dlsym(RTLD_NEXT, "freopen");
-    _ws_ftw = dlsym(RTLD_NEXT, "ftw");
-    _ws_opendir = dlsym(RTLD_NEXT, "opendir");
-    _ws_dlopen = dlsym(RTLD_NEXT, "dlopen");
-
-    _ws_setpriority = dlsym(RTLD_NEXT, "setpriority");
-    //_ws_pipe = dlsym(RTLD_NEXT, "pipe");
-
-    const char* logFileName = getenv("WRAPSIM_LOG");
-    if (logFileName != NULL ){
-        gWrapSim.logFd = _ws_open(logFileName, O_WRONLY|O_APPEND|O_CREAT, 0664);
-    }
-
-    /* log messages now work; say hello */
-    wsLog("--- initializing sim wrapper ---\n");
-
-    gWrapSim.simulatorFd = -1;
-
-    pthread_mutex_init(&gWrapSim.startLock, NULL);
-    pthread_cond_init(&gWrapSim.startCond, NULL);
-    gWrapSim.startReady = 0;
-
-    pthread_mutex_init(&gWrapSim.fakeFdLock, NULL);
-    gWrapSim.fakeFdMap = wsAllocBitVector(kMaxFakeFdCount, 0);
-    memset(gWrapSim.fakeFdList, 0, sizeof(gWrapSim.fakeFdList));
-
-    pthread_mutex_init(&gWrapSim.atomicLock, NULL);
-
-    gWrapSim.numDisplays = 0;
-
-    gWrapSim.keyInputDevice = NULL;
-
-    /*
-     * Get target for remapped "/system" and "/data".
-     *
-     * The ANDROID_PRODUCT_OUT env var *must* be set for rewriting to work.
-     */
-    const char* outEnv = getenv("ANDROID_PRODUCT_OUT");
-    if (outEnv == NULL) {
-        gWrapSim.remapBaseDir = NULL;
-        wsLog("--- $ANDROID_PRODUCT_OUT not set, "
-                "filename remapping disabled\n");
-    } else {
-        /* grab string and append '/' -- note this never gets freed */
-        gWrapSim.remapBaseDirLen = strlen(outEnv);
-        gWrapSim.remapBaseDir = strdup(outEnv);
-        wsLog("--- name remap to %s\n", gWrapSim.remapBaseDir);
-    }
-
-    gWrapSim.initialized = 1;
-}
-
-/*
- * Creates a directory, or prints a log message if it fails.
- */
-static int createTargetDirectory(const char *path, mode_t mode)
-{
-    int ret;
-
-    ret = mkdir(path, mode);
-    if (ret == 0 || errno == EEXIST) {
-        return 0;
-    }
-    wsLog("--- could not create target directory %s: %s\n",
-            path, strerror(errno));
-    return ret;
-}
-
-/*
- * Any setup that would normally be done by init(8).
- * Note that since the syscall redirects have been installed
- * at this point, we are effectively operating within the
- * simulation context.
- */
-static void initGeneral(void)
-{
-    wsLog("--- preparing system\n");
-
-    /* Try to make sure that certain directories exist.
-     * If we fail to create them, the errors will show up in the log,
-     * but we keep going.
-     */
-    createTargetDirectory("/data", 0777);
-    createTargetDirectory("/data/dalvik-cache", 0777);
-}
-
-/*
- * Initialize all necessary state, and indicate that we're ready to go.
- */
-static void initOnce(void)
-{
-    initGlobals();
-    initGeneral();
-}
-
-/*
- * Shared object initializer.  glibc guarantees that this function is
- * called before dlopen() returns.  It may be called multiple times.
- */
-__attribute__((constructor))
-static void initialize(void)
-{
-    pthread_once(&gWrapSimInitialized, initOnce);
-}
-
-
diff --git a/simulator/wrapsim/Intercept.c b/simulator/wrapsim/Intercept.c
deleted file mode 100644
index 3d4edb2..0000000
--- a/simulator/wrapsim/Intercept.c
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Syscall and library intercepts.
- */
-
-/* don't remap open() to open64() */
-#undef _FILE_OFFSET_BITS
-
-#define CREATE_FUNC_STORAGE
-#include "Common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/uio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <utime.h>
-#include <limits.h>
-#include <ftw.h>
-#include <assert.h>
-
-
-#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
-#warning "big"
-#endif
-
-//#define CALLTRACE(format, ...)   wsLog(format, ##__VA_ARGS__)
-#define CALLTRACE(format, ...)   ((void)0)
-
-//#define CALLTRACEV(format, ...)  wsLog(format, ##__VA_ARGS__)
-#define CALLTRACEV(format, ...)  ((void)0)
-
-/*
-When opening certain files, we need to simulate the contents.  For example,
-we can pretend to open the frame buffer, and respond to ioctl()s by
-returning fake data or telling the front-end to render new data.
-
-We want to intercept specific files in /dev.  In some cases we want to
-intercept and reject, e.g. to indicate that a standard Linux device does
-not exist.
-
-Some things we're not going to intercept:
-  /etc/... (e.g. /etc/timezone) -- std. Linux version should be okay
-  /proc/... (e.g. /proc/stat) -- we're showing real pid, so real proc will work
-
-For the device drivers we need to intercept:
-
-  close(), ioctl(), mmap(), open()/open64(), read(), readv(), write(),
-  writev()
-
-May also need stat().  We don't need all fd calls, e.g. fchdir() is
-not likely to succeed on a device driver.  The expected uses of mmap()
-shouldn't require intercepting related calls like madvise() -- we will
-provide an actual mapping of the requested size.  In some cases we will
-want to return a "real" fd so the app can poll() or select() on it.
-
-
-We also need to consider:
-  getuid/setuid + variations -- fake out multi-user-id stuff
-
-
-We also want to translate filenames, effectively performing a "chroot"
-without all the baggage that comes with it.  The mapping looks like:
-
-  /system/... --> $ANDROID_PRODUCT_OUT/system/...
-  /data/... --> $ANDROID_PRODUCT_OUT/data/...
-
-Translating pathnames requires interception of additional system calls,
-substituting a new path.  Calls include:
-
-  access(), chdir(), chmod(), chown(), creat(), execve(), getcwd(),
-  lchown(), link(), lstat()/lstat64(), mkdir(), open()/open64(),
-  readlink(), rename(), rmdir(), stat()/stat64(), statfs/statfs64(),
-  symlink(), unlink(), utimes(),
-
-Possibly also mknod(), mount(), umount().
-
-The "at" family, notably openat(), should just work since the root comes
-from an open directory fd.
-
-We also need these libc calls, because LD_LIBRARY_PATH substitutes at
-the libc link level, not the syscall layer:
-
-  execl(), execlp(), execle(), execv(), execvp(), fopen(), ftw(), getwd(),
-  opendir(), dlopen()
-
-It is possible for the cwd to leak out.  Some possible leaks:
-  - /proc/[self]/exe
-  - /proc/[self]/cwd
-  - LD_LIBRARY_PATH (which may be awkward to work around)
-
-
-To provide a replacement for the dirent functions -- only required if we
-want to show "fake" directory contents -- we would need:
-
-  closedir(), dirfd() readdir(), rewinddir(), scandir(), seekdir(),
-  telldir()
-
-
-*/
-
-
-/*
- * ===========================================================================
- *      Filename remapping
- * ===========================================================================
- */
-
-/*
- * If appropriate, rewrite the path to point to a different location.
- *
- * Returns either "pathBuf" or "origPath" depending on whether or not we
- * chose to rewrite the path.  "origPath" must be a buffer capable of
- * holding an extended pathname; for best results use PATH_MAX.
- */
-static const char* rewritePath(const char* func, char* pathBuf,
-    const char* origPath)
-{
-    /*
-     * Rewrite paths that start with "/system/" or "/data/"
-     */
-    if (origPath[0] != '/')
-        goto skip_rewrite;
-    while (origPath[1] == '/') origPath++; // some apps like to use paths like '//data/data/....'
-    if (memcmp(origPath+1, "system", 6) == 0 &&
-        (origPath[7] == '/' || origPath[7] == '\0'))
-            goto do_rewrite;
-    if (memcmp(origPath+1, "data", 4) == 0 &&
-        (origPath[5] == '/' || origPath[5] == '\0'))
-            goto do_rewrite;
-
-skip_rewrite:
-    /* check to see if something is side-stepping the rewrite */
-    if (memcmp(origPath, gWrapSim.remapBaseDir, gWrapSim.remapBaseDirLen) == 0)
-    {
-        wsLog("NOTE: full path used: %s(%s)\n", func, origPath);
-    }
-
-    CALLTRACE("rewrite %s('%s') --> (not rewritten)\n", func, origPath);
-    return origPath;
-
-do_rewrite:
-    memcpy(pathBuf, gWrapSim.remapBaseDir, gWrapSim.remapBaseDirLen);
-    strcpy(pathBuf + gWrapSim.remapBaseDirLen, origPath);
-    CALLTRACE("rewrite %s('%s') --> '%s'\n", func, origPath, pathBuf);
-    return pathBuf;
-}
-
-/*
- * This works if the pathname is the first argument to the function, and
- * the function returns "int".
- */
-#define PASS_THROUGH_DECL(_fname, _rtype, ...)                              \
-    _rtype _fname( __VA_ARGS__ )
-#define PASS_THROUGH_BODY(_fname, _patharg, ...)                            \
-    {                                                                       \
-        CALLTRACEV("%s(%s)\n", __FUNCTION__, _patharg);                     \
-        char pathBuf[PATH_MAX];                                             \
-        return _ws_##_fname(rewritePath(#_fname, pathBuf, _patharg),        \
-            ##__VA_ARGS__);                                                 \
-    }
-
-
-PASS_THROUGH_DECL(chdir, int, const char* path)
-PASS_THROUGH_BODY(chdir, path)
-
-PASS_THROUGH_DECL(chmod, int, const char* path, mode_t mode)
-PASS_THROUGH_BODY(chmod, path, mode)
-
-PASS_THROUGH_DECL(chown, int, const char* path, uid_t owner, gid_t group)
-PASS_THROUGH_BODY(chown, path, owner, group)
-
-PASS_THROUGH_DECL(creat, int, const char* path, mode_t mode)
-PASS_THROUGH_BODY(creat, path, mode)
-
-PASS_THROUGH_DECL(execve, int, const char* path, char* const argv[],
-    char* const envp[])
-PASS_THROUGH_BODY(execve, path, argv, envp)
-
-PASS_THROUGH_DECL(lchown, int, const char* path, uid_t owner, gid_t group)
-PASS_THROUGH_BODY(lchown, path, owner, group)
-
-PASS_THROUGH_DECL(lstat, int, const char* path, struct stat* buf)
-PASS_THROUGH_BODY(lstat, path, buf)
-
-PASS_THROUGH_DECL(lstat64, int, const char* path, struct stat* buf)
-PASS_THROUGH_BODY(lstat64, path, buf)
-
-PASS_THROUGH_DECL(mkdir, int, const char* path, mode_t mode)
-PASS_THROUGH_BODY(mkdir, path, mode)
-
-PASS_THROUGH_DECL(readlink, ssize_t, const char* path, char* buf, size_t bufsiz)
-PASS_THROUGH_BODY(readlink, path, buf, bufsiz)
-
-PASS_THROUGH_DECL(rmdir, int, const char* path)
-PASS_THROUGH_BODY(rmdir, path)
-
-PASS_THROUGH_DECL(stat, int, const char* path, struct stat* buf)
-PASS_THROUGH_BODY(stat, path, buf)
-
-PASS_THROUGH_DECL(stat64, int, const char* path, struct stat* buf)
-PASS_THROUGH_BODY(stat64, path, buf)
-
-PASS_THROUGH_DECL(statfs, int, const char* path, struct statfs* buf)
-PASS_THROUGH_BODY(statfs, path, buf)
-
-PASS_THROUGH_DECL(statfs64, int, const char* path, struct statfs* buf)
-PASS_THROUGH_BODY(statfs64, path, buf)
-
-PASS_THROUGH_DECL(unlink, int, const char* path)
-PASS_THROUGH_BODY(unlink, path)
-
-PASS_THROUGH_DECL(utime, int, const char* path, const struct utimbuf* buf)
-PASS_THROUGH_BODY(utime, path, buf)
-
-PASS_THROUGH_DECL(utimes, int, const char* path, const struct timeval times[2])
-PASS_THROUGH_BODY(utimes, path, times)
-
-
-PASS_THROUGH_DECL(fopen, FILE*, const char* path, const char* mode)
-PASS_THROUGH_BODY(fopen, path, mode)
-
-PASS_THROUGH_DECL(fopen64, FILE*, const char* path, const char* mode)
-PASS_THROUGH_BODY(fopen64, path, mode)
-
-PASS_THROUGH_DECL(freopen, FILE*, const char* path, const char* mode,
-    FILE* stream)
-PASS_THROUGH_BODY(freopen, path, mode, stream)
-
-PASS_THROUGH_DECL(ftw, int, const char* dirpath,
-          int (*fn) (const char* fpath, const struct stat* sb, int typeflag),
-          int nopenfd)
-PASS_THROUGH_BODY(ftw, dirpath, fn, nopenfd)
-
-PASS_THROUGH_DECL(opendir, DIR*, const char* path)
-PASS_THROUGH_BODY(opendir, path)
-
-PASS_THROUGH_DECL(dlopen, void*, const char* path, int flag)
-PASS_THROUGH_BODY(dlopen, path, flag)
-
-/*
- * Opposite of path translation -- remove prefix.
- *
- * It looks like BSD allows you to pass a NULL value for "buf" to inspire
- * getcwd to allocate storage with malloc() (as an extension to the POSIX
- * definition, which doesn't specify this).  getcwd() is a system call
- * under Linux, so this doesn't work, but that doesn't stop gdb from
- * trying to use it anyway.
- */
-char* getcwd(char* buf, size_t size)
-{
-    CALLTRACEV("%s %p %d\n", __FUNCTION__, buf, size);
-
-    char* result = _ws_getcwd(buf, size);
-    if (buf != NULL && result != NULL) {
-        if (memcmp(buf, gWrapSim.remapBaseDir,
-                    gWrapSim.remapBaseDirLen) == 0)
-        {
-            memmove(buf, buf + gWrapSim.remapBaseDirLen,
-                strlen(buf + gWrapSim.remapBaseDirLen)+1);
-            CALLTRACE("rewrite getcwd() -> %s\n", result);
-        } else {
-            CALLTRACE("not rewriting getcwd(%s)\n", result);
-        }
-    }
-    return result;
-}
-
-/*
- * Need to tweak both pathnames.
- */
-int link(const char* oldPath, const char* newPath)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    char pathBuf1[PATH_MAX];
-    char pathBuf2[PATH_MAX];
-    return _ws_link(rewritePath("link-1", pathBuf1, oldPath),
-                    rewritePath("link-2", pathBuf2, newPath));
-}
-
-/*
- * Need to tweak both pathnames.
- */
-int rename(const char* oldPath, const char* newPath)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    char pathBuf1[PATH_MAX];
-    char pathBuf2[PATH_MAX];
-    return _ws_rename(rewritePath("rename-1", pathBuf1, oldPath),
-                      rewritePath("rename-2", pathBuf2, newPath));
-}
-
-/*
- * Need to tweak both pathnames.
- */
-int symlink(const char* oldPath, const char* newPath)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    char pathBuf1[PATH_MAX];
-    char pathBuf2[PATH_MAX];
-    return _ws_symlink(rewritePath("symlink-1", pathBuf1, oldPath),
-                       rewritePath("symlink-2", pathBuf2, newPath));
-}
-
-/*
- * glibc stat turns into this (32-bit).
- */
-int __xstat(int version, const char* path, struct stat* sbuf)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-    char pathBuf[PATH_MAX];
-    return _ws___xstat(version, rewritePath("__xstat", pathBuf, path),
-        sbuf);
-}
-
-/*
- * glibc stat turns into this (64-bit).
- */
-int __xstat64(int version, const char* path, struct stat* sbuf)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-    char pathBuf[PATH_MAX];
-    return _ws___xstat64(version, rewritePath("__xstat64", pathBuf, path),
-        sbuf);
-}
-
-/*
- * glibc lstat turns into this (32-bit).
- */
-int __lxstat(int version, const char* path, struct stat* sbuf)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-    char pathBuf[PATH_MAX];
-    return _ws___lxstat(version, rewritePath("__lxstat", pathBuf, path),
-        sbuf);
-}
-
-/*
- * glibc lstat turns into this (64-bit).
- */
-int __lxstat64(int version, const char* path, struct stat* sbuf)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-    char pathBuf[PATH_MAX];
-    return _ws___lxstat64(version, rewritePath("__lxstat64", pathBuf, path),
-        sbuf);
-}
-
-/*
- * Copy the argument list out of varargs for execl/execlp/execle.  This
- * leaves the argc value in _argc, and a NULL-terminated array of character
- * pointers in _argv.  We stop at the first NULL argument, so we shouldn't
- * end up copying "envp" out.
- *
- * We could use gcc __builtin_apply_args to just pass stuff through,
- * but that may not get along with the path rewriting.  It's unclear
- * whether we want to rewrite the first argument (i.e. the string that
- * becomes argv[0]); it only makes sense if the exec'ed program is also
- * getting remapped.
- */
-#define COPY_EXEC_ARGLIST(_first, _argc, _argv)                             \
-    int _argc = 0;                                                          \
-    {                                                                       \
-        va_list vargs;                                                      \
-        va_start(vargs, _first);                                            \
-        while (1) {                                                         \
-            _argc++;                                                        \
-            const char* val = va_arg(vargs, const char*);                   \
-            if (val == NULL)                                                \
-                break;                                                      \
-        }                                                                   \
-        va_end(vargs);                                                      \
-    }                                                                       \
-    const char* _argv[_argc+1];                                             \
-    _argv[0] = _first;                                                      \
-    {                                                                       \
-        va_list vargs;                                                      \
-        int i;                                                              \
-        va_start(vargs, _first);                                            \
-        for (i = 1; i < _argc; i++) {                                       \
-            _argv[i] = va_arg(vargs, const char*);                          \
-        }                                                                   \
-        va_end(vargs);                                                      \
-    }                                                                       \
-    _argv[_argc] = NULL;
-
-/*
- * Debug dump.
- */
-static void dumpExecArgs(const char* callName, const char* path,
-    int argc, const char* argv[], char* const envp[])
-{
-    int i;
-
-    CALLTRACE("Calling %s '%s' (envp=%p)\n", callName, path, envp);
-    for (i = 0; i <= argc; i++)
-        CALLTRACE("  %d: %s\n", i, argv[i]);
-}
-
-/*
- * Extract varargs, convert paths, hand off to execv.
- */
-int execl(const char* path, const char* arg, ...)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    char pathBuf[PATH_MAX];
-
-    COPY_EXEC_ARGLIST(arg, argc, argv);
-    dumpExecArgs("execl", path, argc, argv, NULL);
-    path = rewritePath("execl", pathBuf, path);
-    return _ws_execv(path, (char* const*) argv);
-}
-
-/*
- * Extract varargs, convert paths, hand off to execve.
- *
- * The execle prototype in the man page isn't valid C -- it shows the
- * "envp" argument after the "...".  We have to pull it out with the rest
- * of the varargs.
- */
-int execle(const char* path, const char* arg, ...)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    char pathBuf[PATH_MAX];
-
-    COPY_EXEC_ARGLIST(arg, argc, argv);
-
-    /* run through again and find envp */
-    char* const* envp;
-
-    va_list vargs;
-    va_start(vargs, arg);
-    while (1) {
-        const char* val = va_arg(vargs, const char*);
-        if (val == NULL) {
-            envp = va_arg(vargs, char* const*);
-            break;
-        }
-    }
-    va_end(vargs);
-
-    dumpExecArgs("execle", path, argc, argv, envp);
-    path = rewritePath("execl", pathBuf, path);
-
-    return _ws_execve(path, (char* const*) argv, envp);
-}
-
-/*
- * Extract varargs, convert paths, hand off to execvp.
- */
-int execlp(const char* file, const char* arg, ...)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    char pathBuf[PATH_MAX];
-
-    COPY_EXEC_ARGLIST(arg, argc, argv);
-    dumpExecArgs("execlp", file, argc, argv, NULL);
-    file = rewritePath("execlp", pathBuf, file);
-    return _ws_execvp(file, (char* const*) argv);
-}
-
-/*
- * Update path, forward to execv.
- */
-int execv(const char* path, char* const argv[])
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    char pathBuf[PATH_MAX];
-
-    path = rewritePath("execv", pathBuf, path);
-    return _ws_execv(path, argv);
-}
-
-/*
- * Shouldn't need to do anything unless they specified a full path to execvp.
- */
-int execvp(const char* file, char* const argv[])
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    char pathBuf[PATH_MAX];
-
-    file = rewritePath("execvp", pathBuf, file);
-    return _ws_execvp(file, argv);
-}
-
-
-/*
- * ===========================================================================
- *      Device fakery
- * ===========================================================================
- */
-
-/*
- * Need to do filesystem translation and show fake devices.
- */
-int access(const char* pathName, int mode)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    int status = wsInterceptDeviceAccess(pathName, mode);
-    if (status == 0)
-        return 0;
-    else if (status == -2)
-        return -1;          // errno already set
-    else {
-        char pathBuf[PATH_MAX];
-        return _ws_access(rewritePath("access", pathBuf, pathName), mode);
-    }
-}
-
-/*
- * Common handler for open().
- */
-int openCommon(const char* pathName, int flags, mode_t mode)
-{
-    char pathBuf[PATH_MAX];
-    int fd;
-
-    assert(gWrapSim.initialized);
-
-    fd = wsInterceptDeviceOpen(pathName, flags);
-    if (fd >= 0) {
-        return fd;
-    } else if (fd == -2) {
-        /* errno should be set */
-        return -1;
-    }
-
-    if ((flags & O_CREAT) != 0) {
-        fd = _ws_open(rewritePath("open", pathBuf, pathName), flags, mode);
-        CALLTRACE("open(%s, 0x%x, 0%o) = %d\n", pathName, flags, mode, fd);
-    } else {
-        fd = _ws_open(rewritePath("open", pathBuf, pathName), flags, 0);
-        CALLTRACE("open(%s, 0x%x) = %d\n", pathName, flags, fd);
-    }
-    return fd;
-}
-
-/*
- * Replacement open() and variants.
- *
- * We have to use the vararg decl for the standard call so it matches
- * the definition in fcntl.h.
- */
-int open(const char* pathName, int flags, ...)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    mode_t mode = 0;
-    if ((flags & O_CREAT) != 0) {
-        va_list args;
-
-        va_start(args, flags);
-        mode = va_arg(args, mode_t);
-        va_end(args);
-    }
-
-    return openCommon(pathName, flags, mode);
-}
-int __open(const char* pathName, int flags, mode_t mode)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    return openCommon(pathName, flags, mode);
-}
-
-/*
- * Common handler for open64().
- */
-int open64Common(const char* pathName, int flags, mode_t mode)
-{
-    char pathBuf[PATH_MAX];
-    int fd;
-
-    assert(gWrapSim.initialized);
-
-    fd = wsInterceptDeviceOpen(pathName, flags);
-    if (fd >= 0) {
-        return fd;
-    }
-
-    if ((flags & O_CREAT) != 0) {
-        fd = _ws_open64(rewritePath("open64", pathBuf, pathName), flags, mode);
-        CALLTRACE("open64(%s, 0x%x, 0%o) = %d\n", pathName, flags, mode, fd);
-    } else {
-        fd = _ws_open64(rewritePath("open64", pathBuf, pathName), flags, 0);
-        CALLTRACE("open64(%s, 0x%x) = %d\n", pathName, flags, fd);
-    }
-    return fd;
-}
-
-/*
- * Replacement open64() and variants.
- *
- * We have to use the vararg decl for the standard call so it matches
- * the definition in fcntl.h.
- */
-int open64(const char* pathName, int flags, ...)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    mode_t mode = 0;
-    if ((flags & O_CREAT) != 0) {
-        va_list args;
-
-        va_start(args, flags);
-        mode = va_arg(args, mode_t);
-        va_end(args);
-    }
-    return open64Common(pathName, flags, mode);
-}
-int __open64(const char* pathName, int flags, mode_t mode)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    return open64Common(pathName, flags, mode);
-}
-
-
-int dup(int fd)
-{
-    CALLTRACEV("%s(%d)\n", __FUNCTION__, fd);
-
-    FakeDev* dev = wsFakeDevFromFd(fd);
-    if (dev != NULL) {
-        FakeDev* newDev = dev->dup(dev, fd);
-        if (newDev != NULL) {
-            /*
-             * Now that the device entry is ready, add it to the list.
-             */
-            wsLog("## dup'ed fake dev %d: '%s' %p\n",
-                newDev->fd, newDev->debugName, newDev->state);
-            gWrapSim.fakeFdList[newDev->fd - kFakeFdBase] = newDev;
-            return newDev->fd;
-        }
-        return -1;
-    } else {
-        CALLTRACE("dup(%d)\n", fd);
-        return _ws_dup(fd);
-    }
-}
-
-
-/*
- * Close a file descriptor.
- */
-int close(int fd)
-{
-    CALLTRACEV("%s(%d)\n", __FUNCTION__, fd);
-
-    FakeDev* dev = wsFakeDevFromFd(fd);
-    if (dev != NULL) {
-        int result = dev->close(dev, fd);
-        wsFreeFakeDev(dev);
-        return result;
-    } else {
-        CALLTRACE("close(%d)\n", fd);
-        return _ws_close(fd);
-    }
-}
-
-/*
- * Map a region.
- */
-void* mmap(void* start, size_t length, int prot, int flags, int fd,
-    __off_t offset)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    FakeDev* dev = wsFakeDevFromFd(fd);
-    if (dev != NULL) {
-        return dev->mmap(dev, start, length, prot, flags, fd, offset);
-    } else {
-        CALLTRACE("mmap(%p, %d, %d, %d, %d, %d)\n",
-            start, (int) length, prot, flags, fd, (int) offset);
-        return _ws_mmap(start, length, prot, flags, fd, offset);
-    }
-}
-
-/*
- * Map a region.
- */
-void* mmap64(void* start, size_t length, int prot, int flags, int fd,
-    __off64_t offset)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    FakeDev* dev = wsFakeDevFromFd(fd);
-    if (dev != NULL) {
-        return dev->mmap(dev, start, length, prot, flags, fd, (__off_t) offset);
-    } else {
-        CALLTRACE("mmap64(%p, %d, %d, %d, %d, %d)\n",
-            start, (int) length, prot, flags, fd, (int) offset);
-        return _ws_mmap(start, length, prot, flags, fd, offset);
-    }
-}
-
-/*
- * The Linux headers show this with a vararg header, but as far as I can
- * tell the kernel always expects 3 args.
- */
-int ioctl(int fd, int request, ...)
-{
-    CALLTRACEV("%s(%d, %d, ...)\n", __FUNCTION__, fd, request);
-
-    FakeDev* dev = wsFakeDevFromFd(fd);
-    va_list args;
-    void* argp;
-
-    /* extract argp from varargs */
-    va_start(args, request);
-    argp = va_arg(args, void*);
-    va_end(args);
-
-    if (dev != NULL) {
-        return dev->ioctl(dev, fd, request, argp);
-    } else {
-        CALLTRACE("ioctl(%d, 0x%x, %p)\n", fd, request, argp);
-        return _ws_ioctl(fd, request, argp);
-    }
-}
-
-/*
- * Read data.
- */
-ssize_t read(int fd, void* buf, size_t count)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    FakeDev* dev = wsFakeDevFromFd(fd);
-    if (dev != NULL) {
-        return dev->read(dev, fd, buf, count);
-    } else {
-        CALLTRACE("read(%d, %p, %u)\n", fd, buf, count);
-        return _ws_read(fd, buf, count);
-    }
-}
-
-/*
- * Write data.
- */
-ssize_t write(int fd, const void* buf, size_t count)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    FakeDev* dev = wsFakeDevFromFd(fd);
-    if (dev != NULL) {
-        return dev->write(dev, fd, buf, count);
-    } else {
-        CALLTRACE("write(%d, %p, %u)\n", fd, buf, count);
-        return _ws_write(fd, buf, count);
-    }
-}
-
-/*
- * Read a data vector.
- */
-ssize_t readv(int fd, const struct iovec* vector, int count)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    FakeDev* dev = wsFakeDevFromFd(fd);
-    if (dev != NULL) {
-        return dev->readv(dev, fd, vector, count);
-    } else {
-        CALLTRACE("readv(%d, %p, %u)\n", fd, vector, count);
-        return _ws_readv(fd, vector, count);
-    }
-}
-
-/*
- * Write a data vector.
- */
-ssize_t writev(int fd, const struct iovec* vector, int count)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    FakeDev* dev = wsFakeDevFromFd(fd);
-    if (dev != NULL) {
-        return dev->writev(dev, fd, vector, count);
-    } else {
-        CALLTRACE("writev(%d, %p, %u)\n", fd, vector, count);
-        return _ws_writev(fd, vector, count);
-    }
-}
-
-/*
- * Set the scheduling priority.  The sim doesn't run as root, so we have
- * to fake this out.
- *
- * For now, do some basic verification of the which and who parameters,
- * but otherwise return success.  In the future we may want to track
- * these so getpriority works.
- */
-int setpriority(__priority_which_t which, id_t who, int what)
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    if (which != PRIO_PROCESS &&
-        which != PRIO_PGRP &&
-        which != PRIO_USER) {
-        return EINVAL;
-    }
-
-    if ((int)who < 0) {
-        return ESRCH;
-    }
-
-    return 0;
-}
-
-/*
- * Pretend to be running as root, so the Android framework
- * doesn't complain about permission problems all over the
- * place.
- */
-uid_t getuid(void)
-{
-    return 0;
-}
-
-#if 0
-/*
- * Create a pipe.  (Only needed for debugging an fd leak.)
- */
-int pipe(int filedes[2])
-{
-    CALLTRACEV("%s\n", __FUNCTION__);
-
-    int result = _ws_pipe(filedes);
-    if (result == 0)
-        CALLTRACE("pipe(%p) -> %d,%d\n", filedes, filedes[0], filedes[1]);
-    if (filedes[0] == 83)
-        abort();
-    return result;
-}
-#endif
diff --git a/simulator/wrapsim/LaunchWrapper.c b/simulator/wrapsim/LaunchWrapper.c
deleted file mode 100644
index c4f0efb..0000000
--- a/simulator/wrapsim/LaunchWrapper.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Launch the specified program and, if "-wait" was specified, wait for it
- * to exit.
- *
- * When in "wait mode", print a message indicating the exit status, then
- * wait for Ctrl-C before we exit.  This is useful if we were launched
- * with "xterm -e", because it lets us see the output before the xterm bails.
- *
- * We want to ignore signals while waiting, so Ctrl-C kills the child rather
- * than us, but we need to configure the signals *after* the fork() so we
- * don't block them for the child too.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <assert.h>
-
-/*
- * This is appended to $ANDROID_PRODUCT_OUT,
- * e.g. "/work/device/out/debug/host/linux-x8x/product/sim".
- */
-static const char* kWrapLib = "/system/lib/libwrapsim.so";
-
-
-/*
- * Configure LD_PRELOAD if possible.
- *
- * Returns newly-allocated storage with the preload path.
- */
-static char* configurePreload(void)
-{
-    const char* outEnv = getenv("ANDROID_PRODUCT_OUT");
-    const char* preloadEnv = getenv("LD_PRELOAD");
-    char* preload = NULL;
-
-    if (preloadEnv != NULL) {
-        /* TODO: append our stuff to existing LD_PRELOAD string */
-        fprintf(stderr,
-            "LW WARNING: LD_PRELOAD already set, not adding libwrapsim\n");
-    } else if (outEnv == NULL || *outEnv == '\0') {
-        fprintf(stderr, "LW WARNING: "
-            "$ANDROID_PRODUCT_OUT not in env, not setting LD_PRELOAD\n");
-    } else {
-        preload = (char*) malloc(strlen(outEnv) + strlen(kWrapLib) +1);
-        sprintf(preload, "%s%s", outEnv, kWrapLib);
-        setenv("LD_PRELOAD", preload, 1);
-        printf("LW: launching with LD_PRELOAD=%s\n", preload);
-    }
-
-    /* Let the process know that it's executing inside this LD_PRELOAD
-     * wrapper.
-     */
-    setenv("ANDROID_WRAPSIM", "1", 1);
-
-    return preload;
-}
-
-/*
- * Configure some environment variables that the runtime wants.
- *
- * Returns 0 if all goes well.
- */
-static int configureEnvironment()
-{
-    const char* outEnv = getenv("ANDROID_PRODUCT_OUT");
-    char pathBuf[PATH_MAX];
-    int outLen;
-
-    if (outEnv == NULL || *outEnv == '\0') {
-        fprintf(stderr, "LW WARNING: "
-            "$ANDROID_PRODUCT_OUT not in env, not configuring environment\n");
-        return 1;
-    }
-    outLen = strlen(outEnv);
-    assert(outLen + 64 < PATH_MAX);
-    memcpy(pathBuf, outEnv, outLen);
-    strcpy(pathBuf + outLen, "/system/lib");
-
-    /*
-     * Linux wants LD_LIBRARY_PATH
-     * Mac OS X wants DYLD_LIBRARY_PATH
-     * gdb under Mac OS X tramples on both of the above, so we added
-     * ANDROID_LIBRARY_PATH as a workaround.
-     *
-     * We're only supporting Linux now, so just set LD_LIBRARY_PATH.  Note
-     * this stomps the existing value, if any.
-     *
-     * If we only needed this for System.loadLibrary() we could do it later,
-     * but we need it to get the runtime started.
-     */
-    printf("LW: setting LD_LIBRARY_PATH=%s\n", pathBuf);
-    setenv("LD_LIBRARY_PATH", pathBuf, 1);
-
-    /*
-     * Trusted certificates are found, for some bizarre reason, through
-     * the JAVA_HOME environment variable.  We don't need to set this
-     * here, but it's convenient to do so.
-     */
-    strcpy(pathBuf /*+ outLen*/, "/system");
-    printf("LW: setting JAVA_HOME=%s\n", pathBuf);
-    setenv("JAVA_HOME", pathBuf, 1);
-
-    return 0;
-}
-
-/*
- * Redirect stdout/stderr to the specified file.  If "fileName" is NULL,
- * this returns successfully without doing anything.
- *
- * Returns 0 on success.
- */
-static int redirectStdio(const char* fileName)
-{
-    int fd;
-
-    if (fileName == NULL)
-        return 0;
-
-    printf("Redirecting stdio to append to '%s'\n", fileName);
-    fflush(stdout);
-    fflush(stderr);
-
-    fd = open(fileName, O_WRONLY | O_APPEND | O_CREAT, 0666);
-    if (fd < 0) {
-        fprintf(stderr, "ERROR: unable to open '%s' for writing\n",
-            fileName);
-        return 1;
-    }
-    dup2(fd, 1);
-    dup2(fd, 2);
-    close(fd);
-
-    return 0;
-}
-
-/*
- * Launch the requested process directly.
- *
- * On success this does not return (ever).
- */
-static int launch(char* argv[], const char* outputFile)
-{
-    (void) configurePreload();
-    (void) redirectStdio(outputFile);
-    execvp(argv[0], argv);
-    fprintf(stderr, "execvp %s failed: %s\n", argv[0], strerror(errno));
-    return 1;
-}
-
-/*
- * Launch in a sub-process and wait for it to finish.
- */
-static int launchWithWait(char* argv[], const char* outputFile)
-{
-    pid_t child;
-
-    child = fork();
-    if (child < 0) {
-        fprintf(stderr, "fork() failed: %s\n", strerror(errno));
-        return 1;
-    } else if (child == 0) {
-        /*
-         * This is the child, set up LD_PRELOAD if possible and launch.
-         */
-        (void) configurePreload();
-        (void) redirectStdio(outputFile);
-        execvp(argv[0], argv);
-        fprintf(stderr, "execvp %s failed: %s\n", argv[0], strerror(errno));
-        return 1;
-    } else {
-        pid_t result;
-        int status;
-
-        signal(SIGINT, SIG_IGN);
-        signal(SIGQUIT, SIG_IGN);
-
-        while (1) {
-            printf("LW: in pid %d (grp=%d), waiting on pid %d\n",
-                (int) getpid(), (int) getpgrp(), (int) child);
-            result = waitpid(child, &status, 0);
-            if (result < 0) {
-                if (errno == EINTR) {
-                    printf("Hiccup!\n");
-                    continue;
-                } else {
-                    fprintf(stderr, "waitpid failed: %s\n", strerror(errno));
-                    return 1;
-                }
-            } else if (result != child) {
-                fprintf(stderr, "bizarre: waitpid returned %d (wanted %d)\n",
-                    result, child);
-                return 1;
-            } else {
-                break;
-            }
-        }
-
-        printf("\n");
-        if (WIFEXITED(status)) {
-            printf("LW: process exited (status=%d)", WEXITSTATUS(status));
-        } else if (WIFSIGNALED(status)) {
-            printf("LW: process killed by signal %d", WTERMSIG(status));
-        } else {
-            printf("LW: process freaked out, status=0x%x\n", status);
-        }
-        if (WCOREDUMP(status)) {
-            printf(" (core dumped)");
-        }
-        printf("\n");
-
-        signal(SIGINT, SIG_DFL);
-        signal(SIGQUIT, SIG_DFL);
-
-        /*
-         * The underlying process may have changed process groups and pulled
-         * itself into the foreground.  Now that it's gone, pull ourselves
-         * back into the foreground.
-         */
-        signal(SIGTTOU, SIG_IGN);
-        if (tcsetpgrp(fileno(stdin), getpgrp()) != 0)
-            fprintf(stderr, "WARNING: tcsetpgrp failed\n");
-
-        printf("\nHit Ctrl-C or close window.\n");
-
-        while (1) {
-            sleep(10);
-        }
-
-        /* not reached */
-        return 0;
-    }
-}
-
-
-/*
- * All args are passed through.
- */
-int main(int argc, char** argv)
-{
-    int waitForChild = 0;
-    const char* outputFile = NULL;
-    int result;
-
-    /*
-     * Skip past the reference to ourselves, and check for args.
-     */
-    argv++;
-    argc--;
-    while (argc > 0) {
-        if (strcmp(argv[0], "-wait") == 0) {
-            waitForChild = 1;
-        } else if (strcmp(argv[0], "-output") == 0 && argc > 1) {
-            argv++;
-            argc--;
-            outputFile = argv[0];
-        } else {
-            /* no more args for us */
-            break;
-        }
-
-        argv++;
-        argc--;
-    }
-
-    if (argc == 0) {
-        fprintf(stderr,
-            "Usage: launch-wrapper [-wait] [-output filename] <cmd> [args...]\n");
-        result = 2;
-        goto bail;
-    }
-
-    /*
-     * Configure some environment variables.
-     */
-    if (configureEnvironment() != 0) {
-        result = 1;
-        goto bail;
-    }
-
-    /*
-     * Launch.
-     */
-    if (waitForChild)
-        result = launchWithWait(argv, outputFile);
-    else
-        result = launch(argv, outputFile);
-
-bail:
-    if (result != 0)
-        sleep(2);
-    return result;
-}
-
diff --git a/simulator/wrapsim/Log.c b/simulator/wrapsim/Log.c
deleted file mode 100644
index 7edb677..0000000
--- a/simulator/wrapsim/Log.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Debug-logging code.
- */
-#include "Common.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <time.h>
-
-/*
- * Write a message to our private log file.  This is a little awkward since
- * some or all of the system calls we want to use are being intercepted.
- */
-void wsLog(const char* format, ...)
-{
-#if defined(HAVE_LOCALTIME_R)
-    struct tm tmBuf;
-#endif
-    struct tm* ptm;
-    time_t now;
-    char timeBuf[32];
-    char prefixBuf[64];
-    int prefixLen;
-    char msgBuf[256];
-    int msgLen;
-
-    if (gWrapSim.logFd < 0)
-        return;
-
-    /*
-     * Create a prefix with a timestamp.
-     */
-    now = time(NULL);
-#if defined(HAVE_LOCALTIME_R)
-    ptm = localtime_r(&now, &tmBuf);
-#else
-    ptm = localtime(&now);
-#endif
-    //strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
-    strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S", ptm);
-
-    prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%s %5d ",
-        timeBuf, (int) getpid());
-
-    /*
-     * Format the message into a buffer.
-     */
-    va_list args;
-
-    va_start(args, format);
-    msgLen = vsnprintf(msgBuf, sizeof(msgBuf), format, args);
-    va_end(args);
-
-    /* if we overflowed, trim and annotate */
-    if (msgLen >= (int) sizeof(msgBuf)) {
-        msgBuf[sizeof(msgBuf)-2] = '!';
-        msgBuf[sizeof(msgBuf)-1] = '\n';
-        msgLen = sizeof(msgBuf);
-    }
-
-    /*
-     * Write the whole thing in one shot.  The log file was opened with
-     * O_APPEND so we don't have to worry about clashes.
-     */
-    struct iovec logVec[2];
-    logVec[0].iov_base = prefixBuf;
-    logVec[0].iov_len = prefixLen;
-    logVec[1].iov_base = msgBuf;
-    logVec[1].iov_len = msgLen;
-    (void) _ws_writev(gWrapSim.logFd, logVec, 2);
-}
-
diff --git a/simulator/wrapsim/Log.h b/simulator/wrapsim/Log.h
deleted file mode 100644
index 024ba44..0000000
--- a/simulator/wrapsim/Log.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Logging.
- */
-#ifndef _WRAPSIM_LOG_H
-#define _WRAPSIM_LOG_H
-
-
-/*
- * Log debug info.
- */
-void wsLog(const char* format, ...)
-    #if defined(__GNUC__)
-        __attribute__ ((format(printf, 1, 2)))
-    #endif
-    ;
-
-#endif /*_WRAPSIM_LOG_H*/
diff --git a/simulator/wrapsim/README.txt b/simulator/wrapsim/README.txt
deleted file mode 100644
index 364d96d..0000000
--- a/simulator/wrapsim/README.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-This shared library is used with LD_PRELOAD to wrap the Android runtime
-when used with the desktop simulator.
-
-Because LD_PRELOAD is part of the environment when gdb and valgrind are
-invoked, the wrapper can "see" activity from both of these (more so gdb
-than valgrind).  For this reason it needs to be very careful about which
-"open" calls are intercepted.
-
-It's also important that none of the intercepted system or library calls
-are invoked directly, or infinite recursion could result.
-
-Avoid creating dependencies on other libraries.
-
-
-To debug wrapsim, set WRAPSIM_LOG to a log file before launching, e.g.
-
-% WRAPSIM_LOG=/tmp/wraplog.txt simulator
-
-For more verbose logging, you can enable the verbose forms of CALLTRACE
-and CALLTRACEV in Intercept.c.
-
-To build, you will need to have the 32-bit libaudio2 development package
-installed. On Ubuntu Hardy, do something like:
-% sudo apt-get install lib32asound2-dev
diff --git a/simulator/wrapsim/SimMgr.c b/simulator/wrapsim/SimMgr.c
deleted file mode 100644
index 9b566cf..0000000
--- a/simulator/wrapsim/SimMgr.c
+++ /dev/null
@@ -1,988 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Simulator interactions.
- *
- * TODO: for multi-process we probably need to switch to a new process
- * group if we are the first process (could be runtime, could be gdb),
- * rather than wait for the simulator to tell us to switch.
- */
-#include "Common.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/sem.h>
-#include <sys/un.h>
-#include <signal.h>
-#include <assert.h>
-
-// fwd
-static int connectToSim(void);
-static void listenToSim(void);
-
-/*
- * Env var to restrict who tries to talk to the front end.
- */
-#define kWrapSimConnectedEnv    "WRAP_SIM_CONNECTED"
-
-
-/*
- * Signal the main thread that we're ready to continue.
- */
-static void signalMainThread(void)
-{
-    int cc;
-
-    cc = pthread_mutex_lock(&gWrapSim.startLock);
-    assert(cc == 0);
-
-    gWrapSim.startReady = 1;
-
-    cc = pthread_cond_signal(&gWrapSim.startCond);
-    assert(cc == 0);
-
-    cc = pthread_mutex_unlock(&gWrapSim.startLock);
-    assert(cc == 0);
-}
-
-
-/*
- * Entry point for the sim management thread.
- *
- * Once we have established a connection to the simulator and are ready
- * for other threads to send messages, we signal the main thread.
- */
-static void* simThreadEntry(void* arg)
-{
-    wsLog("--- sim manager thread started\n");
-
-    /*
-     * Establish a connection to the simulator front-end.  If we can't do
-     * that, we have no access to input or output devices, and we might
-     * as well give up.
-     */
-    if (connectToSim() != 0) {
-        signalMainThread();
-        return NULL;
-    }
-
-    /* success! */
-    wsLog("--- sim manager thread ready\n");
-    gWrapSim.simulatorInitFailed = 0;
-    signalMainThread();
-
-    listenToSim();
-
-    wsLog("--- sim manager thread exiting\n");
-
-    return NULL;
-}
-
-/*
- * If we think we're not yet connected to the sim, do so now.  We only
- * want to do this once per process *group*, so we control access with
- * an environment variable.
- */
-int wsSimConnect(void)
-{
-    /*
-     * If the environment variable hasn't been set, assume we're the first
-     * to get here, and should attach to the simulator.  We set the env
-     * var here whether or not we succeed in connecting to the sim.
-     *
-     * (For correctness we should wrap the getenv/setenv in a semaphore.)
-     */
-    if (getenv(kWrapSimConnectedEnv) == NULL) {
-        pthread_attr_t threadAttr;
-        pthread_t threadHandle;
-        int cc;
-
-        gWrapSim.simulatorInitFailed = 1;
-        setenv(kWrapSimConnectedEnv, "1", 1);
-
-        cc = pthread_mutex_lock(&gWrapSim.startLock);
-        assert(cc == 0);
-
-        pthread_attr_init(&threadAttr);
-        pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
-        cc = pthread_create(&threadHandle, &threadAttr, simThreadEntry, NULL);
-        if (cc != 0) {
-            wsLog("Unable to create new thread: %s\n", strerror(errno));
-            abort();
-        }
-
-        while (!gWrapSim.startReady) {
-            cc = pthread_cond_wait(&gWrapSim.startCond, &gWrapSim.startLock);
-            assert(cc == 0);
-        }
-
-        cc = pthread_mutex_unlock(&gWrapSim.startLock);
-        assert(cc == 0);
-
-        if (gWrapSim.simulatorInitFailed) {
-            wsLog("Simulator initialization failed, bailing\n");
-
-            /* this *should* be okay to do */
-            fprintf(stderr, "Fatal error:"
-                " unable to connect to sim front-end (not running?)\n");
-            abort();
-        }
-    }
-
-    wsLog("+++ continuing\n");
-    return 0;
-}
-
-
-/*
- * ===========================================================================
- *      Message / MessageStream
- * ===========================================================================
- */
-
-/*
- * This is a quick & dirty rewrite of the C++ Message and MessageStream
- * classes, ported to C, reduced in generality, with syscalls stubbed
- * where necessary.  I didn't fix the API to make it more sensible in C
- * (which lacks destructors), so some of this is a little fragile or
- * awkward.
- */
-
-/* values for message type byte; must match android::Message constants */
-typedef enum MessageType {
-    kTypeUnknown = 0,
-    kTypeRaw,           // chunk of raw data
-    kTypeConfig,        // send a name=value pair to peer
-    kTypeCommand,       // simple command w/arg
-    kTypeCommandExt,    // slightly more complicated command
-    kTypeLogBundle,     // multi-part log message
-} MessageType;
-
-/*
- * Reusable message object.
- */
-typedef struct Message {
-    MessageType     mType;
-    unsigned char*  mData;
-    int             mLength;
-} Message;
-
-/* magic init messages; must match android::MessageStream constants */
-enum {
-    kHelloMsg       = 0x4e303047,       // 'N00G'
-    kHelloAckMsg    = 0x31455221,       // '1ER!'
-};
-
-
-/*
- * Clear out a Message.
- */
-static void Message_clear(Message* msg)
-{
-    memset(msg, 0, sizeof(Message));
-}
-
-/*
- * Keep reading until we get all bytes or hit EOF/error.  "fd" is expected
- * to be in blocking mode.
- *
- * Returns 0 on success.
- */
-static int readAll(int fd, void* buf, size_t count)
-{
-    ssize_t actual;
-    ssize_t have;
-
-    have = 0;
-    while (have != (ssize_t) count) {
-        actual = _ws_read(fd, ((char*) buf) + have, count - have);
-        if (actual < 0) {
-            if (errno == EINTR)
-                continue;
-            wsLog("read %d failed: %s\n", fd, strerror(errno));
-        } else if (actual == 0) {
-            wsLog("early EOF on %d\n", fd);
-            return -1;
-        } else {
-            have += actual;
-        }
-
-        assert(have <= (ssize_t)count);
-    }
-
-    return 0;
-}
-
-#if 0
-/*
- * Keep writing until we put all bytes or hit an error.  "fd" is expected
- * to be in blocking mode.
- *
- * Returns 0 on success.
- */
-static int writeAll(int fd, const void* buf, size_t count)
-{
-    ssize_t actual;
-    ssize_t have;
-
-    have = 0;
-    while (have != count) {
-        actual = _ws_write(fd, ((const char*) buf) + have, count - have);
-        if (actual < 0) {
-            if (errno == EINTR)
-                continue;
-            wsLog("write %d failed: %s\n", fd, strerror(errno));
-        } else if (actual == 0) {
-            wsLog("wrote zero on %d\n", fd);
-            return -1;
-        } else {
-            have += actual;
-        }
-
-        assert(have <= count);
-    }
-
-    return 0;
-}
-#endif
-
-/*
- * Read a message from the specified file descriptor.
- *
- * The caller must Message_release(&msg).
- *
- * We guarantee 32-bit alignment for msg->mData.
- */
-static int Message_read(Message* msg, int fd)
-{
-    unsigned char header[4];
-
-    readAll(fd, header, 4);
-
-    msg->mType = (MessageType) header[2];
-    msg->mLength = header[0] | header[1] << 8;
-    msg->mLength -= 2;   // we already read two of them in the header
-
-    if (msg->mLength > 0) {
-        int actual;
-
-        /* Linux malloc guarantees at least 32-bit alignment */
-        msg->mData = (unsigned char*) malloc(msg->mLength);
-        if (msg->mData == NULL) {
-            wsLog("alloc %d failed\n", msg->mLength);
-            return -1;
-        }
-
-        if (readAll(fd, msg->mData, msg->mLength) != 0) {
-            wsLog("failed reading message body (wanted %d)\n", msg->mLength);
-            return -1;
-        }
-    } else {
-        msg->mData = NULL;
-    }
-
-    return 0;
-}
-
-/*
- * Write a message to the specified file descriptor.
- *
- * The caller must Message_release(&msg).
- */
-static int Message_write(Message* msg, int fd)
-{
-    struct iovec writeVec[2];
-    unsigned char header[4];
-    int len, numVecs;
-    ssize_t actual;
-
-    len = msg->mLength + 2;
-    header[0] = len & 0xff;
-    header[1] = (len >> 8) & 0xff;
-    header[2] = msg->mType;
-    header[3] = 0;
-    writeVec[0].iov_base = header;
-    writeVec[0].iov_len = 4;
-    numVecs = 1;
-
-    if (msg->mLength > 0) {
-        assert(msg->mData != NULL);
-        writeVec[1].iov_base = msg->mData;
-        writeVec[1].iov_len = msg->mLength;
-        numVecs++;
-    }
-
-    /* write it all in one shot; not worrying about partial writes for now */
-    actual = _ws_writev(fd, writeVec, numVecs);
-    if (actual != len+2) {
-        wsLog("failed writing message to fd %d: %d of %d %s\n",
-            fd, actual, len+2, strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Release storage associated with a Message.
- */
-static void Message_release(Message* msg)
-{
-    free(msg->mData);
-    msg->mData = NULL;
-}
-
-/*
- * Extract a name/value pair from a message.
- */
-static int getConfig(const Message* msg, const char** name, const char** val)
-{
-    if (msg->mLength < 2) {
-        wsLog("message len (%d) is too short\n", msg->mLength);
-        return -1;
-    }
-    const char* ptr = (const char*) msg->mData;
-
-    *name = (const char*) ptr;
-    *val = (const char*) (ptr + strlen((char*)ptr) +1);
-    return 0;
-}
-
-/*
- * Extract a command from a message.
- */
-static int getCommand(const Message* msg, int* pCmd, int* pArg)
-{
-    if (msg->mLength != sizeof(int) * 2) {
-        wsLog("message len (%d) is wrong for cmd (%d)\n",
-            msg->mLength, sizeof(int) * 2);
-        return -1;
-    }
-
-    /* this assumes 32-bit alignment on mData */
-    const int* ptr = (const int*) msg->mData;
-
-    *pCmd = ptr[0];
-    *pArg = ptr[1];
-
-    return 0;
-}
-
-/*
- * Extract an extended command from a message.
- */
-static int getCommandExt(const Message* msg, int* pCmd, int* pArg0,
-    int* pArg1, int* pArg2)
-{
-    if (msg->mLength != sizeof(int) * 4) {
-        wsLog("message len (%d) is wrong for cmd (%d)\n",
-            msg->mLength, sizeof(int) * 4);
-        return -1;
-    }
-
-    /* this assumes 32-bit alignment on mData */
-    const int* ptr = (const int*) msg->mData;
-
-    *pCmd = ptr[0];
-    *pArg0 = ptr[1];
-    *pArg1 = ptr[2];
-    *pArg2 = ptr[3];
-
-    return 0;
-}
-
-/*
- * Attach 8 bytes of data with "cmd" and "arg" to "msg".
- *
- * "msg->mData" will need to be freed by the caller.  (This approach made
- * more sense when C++ destructors were available, but it's just not worth
- * reworking it.)
- */
-static int setCommand(Message* msg, int cmd, int arg)
-{
-    Message_clear(msg);
-
-    msg->mLength = 8;
-    msg->mData = malloc(msg->mLength);
-    msg->mType = kTypeCommand;
-
-    /* assumes 32-bit alignment on malloc blocks */
-    int* pInt = (int*) msg->mData;
-    pInt[0] = cmd;
-    pInt[1] = arg;
-
-    return 0;
-}
-
-/*
- * Construct the full path.  The caller must free() the return value.
- */
-static char* makeFilename(const char* name)
-{
-    static const char* kBasePath = "/tmp/android-";
-    char* fileName;
-
-    assert(name != NULL && name[0] != '\0');
-
-    fileName = (char*) malloc(strlen(kBasePath) + strlen(name) + 1);
-    strcpy(fileName, kBasePath);
-    strcat(fileName, name);
-
-    return fileName;
-}
-
-/*
- * Attach to a SysV shared memory segment.
- */
-static int attachToShmem(int key, int* pShmid, void** pAddr, long* pLength)
-{
-    int shmid;
-
-    shmid = shmget(key, 0, 0);
-    if (shmid == -1) {
-        wsLog("ERROR: failed to find shmem key=%d\n", key);
-        return -1;
-    }
-
-    void* addr = shmat(shmid, NULL, 0);
-    if (addr == (void*) -1) {
-        wsLog("ERROR: could not attach to key=%d shmid=%d\n", key, shmid);
-        return -1;
-    }
-
-    struct shmid_ds shmids;
-    int cc;
-
-    cc = shmctl(shmid, IPC_STAT, &shmids);
-    if (cc != 0) {
-        wsLog("ERROR: could not IPC_STAT shmid=%d\n", shmid);
-        return -1;
-    }
-    *pLength = shmids.shm_segsz;
-
-    *pAddr = addr;
-    *pShmid = shmid;
-    return 0;
-}
-
-/*
- * Attach to a SysV semaphore.
- */
-static int attachToSem(int key, int* pSemid)
-{
-    int semid;
-
-    semid = semget(key, 0, 0);
-    if (semid == -1) {
-        wsLog("ERROR: failed to attach to semaphore key=%d\n", key);
-        return -1;
-    }
-
-    *pSemid = semid;
-    return 0;
-}
-
-/*
- * "Adjust" a semaphore.
- */
-static int adjustSem(int semid, int adj)
-{
-    const int wait = 1;
-    struct sembuf op;
-    int cc;
-
-    op.sem_num = 0;
-    op.sem_op = adj;
-    op.sem_flg = SEM_UNDO;
-    if (!wait)
-        op.sem_flg |= IPC_NOWAIT;
-
-    cc = semop(semid, &op, 1);
-    if (cc != 0) {
-        if (wait || errno != EAGAIN) {
-            wsLog("Warning:"
-                " semaphore adjust by %d failed for semid=%d (errno=%d)\n",
-                adj, semid, errno);
-        }
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Acquire the semaphore associated with a display.
- */
-void wsLockDisplay(int displayIdx)
-{
-    assert(displayIdx >= 0 && displayIdx < gWrapSim.numDisplays);
-    int semid = gWrapSim.display[displayIdx].semid;
-
-    (void) adjustSem(semid, -1);
-}
-
-/*
- * Acquire the semaphore associated with a display.
- */
-void wsUnlockDisplay(int displayIdx)
-{
-    assert(displayIdx >= 0 && displayIdx < gWrapSim.numDisplays);
-    int semid = gWrapSim.display[displayIdx].semid;
-
-    (void) adjustSem(semid, 1);
-}
-
-/*
- * Process the display config from the simulator
- *
- * Right now this is a blob of raw data that looks like this:
- *  +00 magic number
- *  +04 #of displays
- *  +08 display 0:
- *      +00 width
- *      +04 height
- *      +08 format
- *      +0c refresh rate
- *      +10 shmem key
- *  +1c display 1...
- */
-static int handleDisplayConfig(const int* pData, int length)
-{
-    int numDisplays;
-
-    if (length < 8) {
-        wsLog("Bad display config: length is %d\n", length);
-        return -1;
-    }
-    assert(*pData == kDisplayConfigMagic);
-
-    /*
-     * Pull out the #of displays.  If it looks valid, configure the runtime.
-     */
-    pData++;        // skip over magic
-    numDisplays = *pData++;
-
-    if (numDisplays <= 0 || numDisplays > kMaxDisplays) {
-        wsLog("Bizarre display count %d\n", numDisplays);
-        return -1;
-    }
-    if (length != 8 + numDisplays * kValuesPerDisplay * (int)sizeof(int)) {
-        wsLog("Bad display config: length is %d (expected %d)\n",
-            length, 8 + numDisplays * kValuesPerDisplay * (int)sizeof(int));
-        return -1;
-    }
-
-    /*
-     * Extract the config values.
-     *
-     * The runtime doesn't support multiple devices, so we don't either.
-     */
-    int i;
-    for (i = 0; i < numDisplays; i++) {
-        gWrapSim.display[i].width = pData[0];
-        gWrapSim.display[i].height = pData[1];
-        gWrapSim.display[i].shmemKey = pData[4];
-        /* format/refresh no longer needed */
-
-        void* addr;
-        int shmid, semid;
-        long length;
-        if (attachToShmem(gWrapSim.display[i].shmemKey, &shmid, &addr,
-                &length) != 0)
-        {
-            wsLog("Unable to connect to shared memory\n");
-            return -1;
-        }
-
-        if (attachToSem(gWrapSim.display[i].shmemKey, &semid) != 0) {
-            wsLog("Unable to attach to sempahore\n");
-            return -1;
-        }
-
-        gWrapSim.display[i].shmid = shmid;
-        gWrapSim.display[i].addr = addr;
-        gWrapSim.display[i].length = length;
-        gWrapSim.display[i].semid = semid;
-
-        wsLog("Display %d: width=%d height=%d\n",
-            i,
-            gWrapSim.display[i].width,
-            gWrapSim.display[i].height);
-        wsLog("  shmem=0x%08x addr=%p len=%ld semid=%d\n",
-            gWrapSim.display[i].shmemKey,
-            gWrapSim.display[i].addr,
-            gWrapSim.display[i].length,
-            gWrapSim.display[i].semid);
-
-        pData += kValuesPerDisplay;
-    }
-    gWrapSim.numDisplays = numDisplays;
-
-    return 0;
-}
-
-
-/*
- * Initialize our connection to the simulator, which will be listening on
- * a UNIX domain socket.
- *
- * On success, this configures gWrapSim.simulatorFd and returns 0.
- */
-static int openSimConnection(const char* name)
-{
-    int result = -1;
-    char* fileName = NULL;
-    int sock = -1;
-    int cc;
-
-    assert(gWrapSim.simulatorFd == -1);
-
-    fileName = makeFilename(name);
-
-    struct sockaddr_un addr;
-    
-    sock = socket(AF_UNIX, SOCK_STREAM, 0);
-    if (sock < 0) {
-        wsLog("UNIX domain socket create failed (errno=%d)\n", errno);
-        goto bail;
-    }
-
-    /* connect to socket; fails if file doesn't exist */
-    strcpy(addr.sun_path, fileName);    // max 108 bytes
-    addr.sun_family = AF_UNIX;
-    cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
-    if (cc < 0) {
-        // ENOENT means socket file doesn't exist
-        // ECONNREFUSED means socket exists but nobody is listening
-        wsLog("AF_UNIX connect failed for '%s': %s\n",
-            fileName, strerror(errno));
-        goto bail;
-    }
-
-    gWrapSim.simulatorFd = sock;
-    sock = -1;
-
-    result = 0;
-    wsLog("+++ connected to '%s'\n", fileName);
-
-bail:
-    if (sock >= 0)
-        _ws_close(sock);
-    free(fileName);
-    return result;
-}
-
-/*
- * Prepare communication with the front end.  We wait for a "hello" from
- * the other side, and respond in kind.
- */
-static int prepSimConnection(void)
-{
-    /* NOTE: this is endian-specific; we're x86 Linux only, so no problem */
-    static const unsigned int hello = kHelloMsg;
-    static const unsigned int helloAck = kHelloAckMsg;
-    Message msg;
-
-    if (Message_read(&msg, gWrapSim.simulatorFd) != 0) {
-        wsLog("hello read failed\n");
-        return -1;
-    }
-
-    if (memcmp(msg.mData, &hello, 4) != 0) {
-        wsLog("Got bad hello from peer\n");
-        return -1;
-    }
-
-    Message_release(&msg);
-
-    msg.mType = kTypeRaw;
-    msg.mData = (unsigned char*) &helloAck;
-    msg.mLength = 4;
-
-    if (Message_write(&msg, gWrapSim.simulatorFd) != 0) {
-        wsLog("hello ack write failed\n");
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Get the sim front-end configuration.  We loop here until the sim claims
- * to be done with us.
- */
-static int getSimConfig(void)
-{
-    Message msg;
-    int joinNewGroup, grabTerminal, done;
-    int result = -1;
-
-    joinNewGroup = grabTerminal = done = 0;
-    Message_clear(&msg);        // clear out msg->mData
-
-    wsLog("+++ awaiting hardware configuration\n");
-    while (!done) {
-        if (Message_read(&msg, gWrapSim.simulatorFd) != 0) {
-            wsLog("failed receiving config from parent\n");
-            goto bail;
-        }
-
-        if (msg.mType == kTypeCommand) {
-            int cmd, arg;
-
-            if (getCommand(&msg, &cmd, &arg) != 0)
-                goto bail;
-
-            switch (cmd) {
-            case kCommandGoAway:
-                wsLog("Simulator front-end is busy\n");
-                goto bail;
-            case kCommandNewPGroup:
-                joinNewGroup = 1;
-                grabTerminal = (arg != 0);
-                wsLog("Simulator wants us to be in a new pgrp (term=%d)\n",
-                    grabTerminal);
-                break;
-            case kCommandConfigDone:
-                done = 1;
-                break;
-            default:
-                wsLog("Got unexpected command %d/%d\n", cmd, arg);
-                break;
-            }
-        } else if (msg.mType == kTypeRaw) {
-            /* assumes 32-bit alignment and identical byte ordering */
-            int* pData = (int*) msg.mData;
-            if (msg.mLength >= 4 && *pData == kDisplayConfigMagic) {
-                if (handleDisplayConfig(pData, msg.mLength) != 0)
-                    goto bail;
-            }
-        } else if (msg.mType == kTypeConfig) {
-            const char* name = NULL;
-            const char* val = NULL;
-            getConfig(&msg, &name, &val);
-            if(strcmp(name, "keycharmap") == 0) {
-                free((void*)gWrapSim.keyMap);
-                gWrapSim.keyMap = strdup(val);
-            }
-        } else {
-            wsLog("Unexpected msg type %d during startup\n", msg.mType);
-            goto bail;
-        }
-
-        /* clear out the data field if necessary */
-        Message_release(&msg);
-    }
-
-    wsLog("Configuration received from simulator\n");
-
-    if (joinNewGroup) {
-        /* set pgid to pid */
-        pid_t pgid = getpid();
-        setpgid(0, pgid);
-
-        /*
-         * Put our pgrp in the foreground.
-         * tcsetpgrp() from background process causes us to get a SIGTTOU,
-         * which is mostly harmless but makes tcsetpgrp() fail with EINTR.
-         */
-        signal(SIGTTOU, SIG_IGN);
-        if (grabTerminal) {
-            if (tcsetpgrp(fileno(stdin), getpgrp()) != 0) {
-                wsLog("tcsetpgrp(%d, %d) failed (errno=%d)\n",
-                    fileno(stdin), getpgrp(), errno);
-            }
-            wsLog("Set pgrp %d as foreground\n", (int) getpgrp());
-        }
-    
-        /* tell the sim where we're at */
-        Message msg;
-        setCommand(&msg, kCommandNewPGroupCreated, pgid);
-        Message_write(&msg, gWrapSim.simulatorFd);
-        Message_release(&msg);
-    }
-
-    result = 0;
-
-bail:
-    /* make sure the data was freed */
-    Message_release(&msg);
-    //wsLog("bailing, result=%d\n", result);
-    return result;
-}
-
-/*
- * Connect to the simulator and exchange pleasantries.
- *
- * Returns 0 on success.
- */
-static int connectToSim(void)
-{
-    if (openSimConnection(kAndroidPipeName) != 0)
-        return -1;
-
-    if (prepSimConnection() != 0)
-        return -1;
-
-    if (getSimConfig() != 0)
-        return -1;
-
-    wsLog("+++ sim is ready to go\n");
-
-    return 0;
-}
-
-/*
- * Listen to the sim forever or until the front end shuts down, whichever
- * comes first.
- *
- * All we're really getting here are key events.
- */
-static void listenToSim(void)
-{
-    wsLog("--- listening for input events from front end\n");
-
-    while (1) {
-        Message msg;
-
-        Message_clear(&msg);
-        if (Message_read(&msg, gWrapSim.simulatorFd) != 0) {
-            wsLog("--- sim message read failed\n");
-            return;
-        }
-
-        if (msg.mType == kTypeCommand) {
-            int cmd, arg;
-
-            if (getCommand(&msg, &cmd, &arg) != 0) {
-                wsLog("bad command from sim?\n");
-                continue;
-            }
-
-            switch (cmd) {
-            case kCommandQuit:
-                wsLog("--- sim sent us a QUIT message\n");
-                return;
-            case kCommandKeyDown:
-                wsLog("KEY DOWN: %d\n", arg);
-                wsSendSimKeyEvent(arg, 1);
-                break;
-            case kCommandKeyUp:
-                wsLog("KEY UP: %d\n", arg);
-                wsSendSimKeyEvent(arg, 0);
-                break;
-            default:
-                wsLog("--- sim sent unrecognized command %d\n", cmd);
-                break;
-            }
-
-            Message_release(&msg);
-        } else if (msg.mType == kTypeCommandExt) {
-            int cmd, arg0, arg1, arg2;
-
-            if (getCommandExt(&msg, &cmd, &arg0, &arg1, &arg2) != 0) {
-                wsLog("bad ext-command from sim?\n");
-                continue;
-            }
-
-            switch (cmd) {
-            case kCommandTouch:
-                wsSendSimTouchEvent(arg0, arg1, arg2);
-                break;
-            }
-
-            Message_release(&msg);
-        } else {
-            wsLog("--- sim sent non-command message, type=%d\n", msg.mType);
-        }
-    }
-
-    assert(0);      // not reached
-}
-
-
-/*
- * Tell the simulator front-end that the display has been updated.
- */
-void wsPostDisplayUpdate(int displayIdx)
-{
-    if (gWrapSim.simulatorFd < 0) {
-        wsLog("Not posting display update -- sim not ready\n");
-        return;
-    }
-
-    Message msg;
-
-    setCommand(&msg, kCommandUpdateDisplay, displayIdx);
-    Message_write(&msg, gWrapSim.simulatorFd);
-    Message_release(&msg);
-}
-
-/*
- * Send a log message to the front-end.
- */
-void wsPostLogMessage(int logPrio, const char* tag, const char* message)
-{
-    if (gWrapSim.simulatorFd < 0) {
-        wsLog("Not posting log message -- sim not ready\n");
-        return;
-    }
-
-    time_t when = time(NULL);
-    int pid = (int) getpid();
-    int tagLen, messageLen, totalLen;
-
-    tagLen = strlen(tag) +1;
-    messageLen = strlen(message) +1;
-    totalLen = sizeof(int) * 3 + tagLen + messageLen;
-    unsigned char outBuf[totalLen];
-    unsigned char* cp = outBuf;
-
-    /* See Message::set/getLogBundle() in simulator/MessageStream.cpp. */
-    memcpy(cp, &when, sizeof(int));
-    cp += sizeof(int);
-    memcpy(cp, &logPrio, sizeof(int));
-    cp += sizeof(int);
-    memcpy(cp, &pid, sizeof(int));
-    cp += sizeof(int);
-    memcpy(cp, tag, tagLen);
-    cp += tagLen;
-    memcpy(cp, message, messageLen);
-    cp += messageLen;
-
-    assert(cp - outBuf == totalLen);
-
-    Message msg;
-    msg.mType = kTypeLogBundle;
-    msg.mData = outBuf;
-    msg.mLength = totalLen;
-    Message_write(&msg, gWrapSim.simulatorFd);
-
-    msg.mData = NULL;       // don't free
-    Message_release(&msg);
-}
-
-/*
- * Turn the vibrating notification device on or off.
- */
-void wsEnableVibration(int vibrateOn)
-{
-    if (gWrapSim.simulatorFd < 0) {
-        wsLog("Not posting vibrator update -- sim not ready\n");
-        return;
-    }
-
-    Message msg;
-
-    //wsLog("+++ sending vibrate:%d\n", vibrateOn);
-
-    setCommand(&msg, kCommandVibrate, vibrateOn);
-    Message_write(&msg, gWrapSim.simulatorFd);
-    Message_release(&msg);
-}
-
diff --git a/simulator/wrapsim/SimMgr.h b/simulator/wrapsim/SimMgr.h
deleted file mode 100644
index 378dfbc..0000000
--- a/simulator/wrapsim/SimMgr.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Simulator interactions.
- */
-#ifndef _WRAPSIM_SIMULATOR_H
-#define _WRAPSIM_SIMULATOR_H
-
-/*
- * Commands exchanged between simulator and runtime.
- *
- * NOTE: this is cloned from SimRuntime.h -- fix this.
- */
-typedef enum SimCommand {
-    kCommandUnknown = 0,
-
-    /* sent from sim to runtime */
-    kCommandGoAway,             // sim says: go away, I'm busy
-    kCommandConfigDone,         // sim says: done sending config
-    kCommandQuit,               // quit nicely
-    kCommandNewPGroup,          // process group management
-    kCommandKeyDown,            // key has been pressed
-    kCommandKeyUp,              // key has been released
-    kCommandTouch,              // finger touched/lifted/dragged
-
-    /* sent from runtime to sim */
-    kCommandNewPGroupCreated,   // send process group as argument
-    kCommandRuntimeReady,       // we're initialized and about to start
-    kCommandUpdateDisplay,      // display has been updated
-    kCommandVibrate,            // vibrate on or off
-} SimCommand;
-
-/*
- * Touch screen action; also clined from SimRuntime.h.
- */
-typedef enum TouchMode {
-    kTouchDown = 0,
-    kTouchUp = 1,
-    kTouchDrag = 2
-} TouchMode;
-
-
-/*
- * Some parameters for config exchange.
- */
-enum {
-    kDisplayConfigMagic = 0x44495350,
-    kValuesPerDisplay = 5,
-};
-
-/*
- * UNIX domain socket name.
- */
-#define kAndroidPipeName        "runtime"
-
-int wsSimConnect(void);
-
-/*
- * Display management.
- */
-void wsLockDisplay(int displayIdx);
-void wsUnlockDisplay(int displayIdx);
-void wsPostDisplayUpdate(int displayIdx);
-
-/*
- * Send a log message.
- */
-void wsPostLogMessage(int logPrio, const char* tag, const char* msg);
-
-/*
- * Change the state of the vibration device.
- */
-void wsEnableVibration(int vibrateOn);
-
-#endif /*_WRAPSIM_SIMULATOR_H*/
diff --git a/simulator/wrapsim/SysPower.c b/simulator/wrapsim/SysPower.c
deleted file mode 100644
index fa7ae0a..0000000
--- a/simulator/wrapsim/SysPower.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2009 The Android Open Source Project
- *
- * Magic entries in /sys/power/.
- */
-#include "Common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-/*
- * Map filename to device index.
- *
- * [ not using DeviceIndex -- would be useful if we need to return something
- * other than a static string ]
- */
-static const struct {
-    const char*     name;
-    //DeviceIndex     idx;
-    const char*     data;
-} gDeviceMap[] = {
-    { "state",
-        "mem\n" },
-    { "wake_lock",
-        "\n" },
-    { "wake_unlock",
-        "KeyEvents PowerManagerService radio-interface\n" },
-};
-
-/*
- * Power driver state.
- *
- * Right now we just ignore everything written.
- */
-typedef struct PowerState {
-    int         which;
-} PowerState;
-
-
-/*
- * Figure out who we are, based on "pathName".
- */
-static void configureInitialState(const char* pathName, PowerState* powerState)
-{
-    const char* cp = pathName + strlen("/sys/power/");
-    int i;
-
-    powerState->which = -1;
-    for (i = 0; i < (int) (sizeof(gDeviceMap) / sizeof(gDeviceMap[0])); i++) {
-        if (strcmp(cp, gDeviceMap[i].name) == 0) {
-            powerState->which = i;
-            break;
-        }
-    }
-
-    if (powerState->which == -1) {
-        wsLog("Warning: access to unknown power device '%s'\n", pathName);
-        return;
-    }
-}
-
-/*
- * Free up the state structure.
- */
-static void freeState(PowerState* powerState)
-{
-    free(powerState);
-}
-
-/*
- * Read data from the device.
- *
- * We don't try to keep track of how much was read -- existing clients just
- * try to read into a large buffer.
- */
-static ssize_t readPower(FakeDev* dev, int fd, void* buf, size_t count)
-{
-    PowerState* state = (PowerState*) dev->state;
-    int dataLen;
-
-    wsLog("%s: read %d\n", dev->debugName, count);
-
-    if (state->which < 0 ||
-        state->which >= (int) (sizeof(gDeviceMap)/sizeof(gDeviceMap[0])))
-    {
-        return 0;
-    }
-
-    const char* data = gDeviceMap[state->which].data;
-    size_t strLen = strlen(data);
-
-    while(strLen == 0)
-        sleep(10); // block forever
-
-    ssize_t copyCount = (strLen < count) ? strLen : count;
-    memcpy(buf, data, copyCount);
-    return copyCount;
-}
-
-/*
- * Ignore the request.
- */
-static ssize_t writePower(FakeDev* dev, int fd, const void* buf, size_t count)
-{
-    wsLog("%s: write %d bytes\n", dev->debugName, count);
-    return count;
-}
-
-/*
- * Free up our state before closing down the fake descriptor.
- */
-static int closePower(FakeDev* dev, int fd)
-{
-    freeState((PowerState*)dev->state);
-    dev->state = NULL;
-    return 0;
-}
-
-/*
- * Open a power device.
- */
-FakeDev* wsOpenSysPower(const char* pathName, int flags)
-{
-    FakeDev* newDev = wsCreateFakeDev(pathName);
-    if (newDev != NULL) {
-        newDev->read = readPower;
-        newDev->write = writePower;
-        newDev->ioctl = NULL;
-        newDev->close = closePower;
-
-        PowerState* powerState = calloc(1, sizeof(PowerState));
-
-        configureInitialState(pathName, powerState);
-        newDev->state = powerState;
-    }
-
-    return newDev;
-}
-
diff --git a/simulator/wrapsim/Util.c b/simulator/wrapsim/Util.c
deleted file mode 100644
index 33d903b..0000000
--- a/simulator/wrapsim/Util.c
+++ /dev/null
@@ -1,13 +0,0 @@
-
-#include "Common.h"
-
-int wsAtomicAdd(int *var, int val)
-{
-    int cc;
-    int ret;
-    cc = pthread_mutex_lock(&gWrapSim.atomicLock);
-    ret = *var;
-    *var = *var + val;
-    cc = pthread_mutex_unlock(&gWrapSim.atomicLock);
-    return ret;
-}
diff --git a/simulator/wrapsim/Util.h b/simulator/wrapsim/Util.h
deleted file mode 100644
index e470802..0000000
--- a/simulator/wrapsim/Util.h
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-int wsAtomicAdd(int *var, int val);
diff --git a/testrunner/adb_interface.py b/testrunner/adb_interface.py
index 3bd4396..ddc50d5 100755
--- a/testrunner/adb_interface.py
+++ b/testrunner/adb_interface.py
@@ -155,6 +155,7 @@
       return True
     elif "restarting adbd as root" in output:
       # device will disappear from adb, wait for it to come back
+      time.sleep(2)
       self.SendCommand("wait-for-device")
       return True
     else:
@@ -262,8 +263,10 @@
     inst_command_string = self._BuildInstrumentationCommand(
         package_name, runner_name, no_window_animation=no_window_animation,
         raw_mode=raw_mode, instrumentation_args=instrumentation_args)
-    command_string = "adb %s shell %s" % (self._target_arg, inst_command_string)
-    return command_string
+    return self.PreviewShellCommand(inst_command_string)
+
+  def PreviewShellCommand(self, cmd):
+    return "adb %s shell %s" % (self._target_arg, cmd)
 
   def _BuildInstrumentationCommand(
       self, package, runner_name, no_window_animation=False, profile=False,
diff --git a/testrunner/android_mk.py b/testrunner/android_mk.py
index 663aa5c..2c265ee 100644
--- a/testrunner/android_mk.py
+++ b/testrunner/android_mk.py
@@ -21,25 +21,26 @@
 development/ndk/docs/ANDROID-MK.txt
 """
 
+import os
 import re
 from sets import Set
 
+import logger
 
 class AndroidMK(object):
   """In memory representation of Android.mk file."""
 
   _RE_INCLUDE = re.compile(r'include\s+\$\((.+)\)')
+  _RE_VARIABLE_REF = re.compile(r'\$\((.+)\)')
   _VAR_DELIMITER = ":="
   FILENAME = "Android.mk"
   CERTIFICATE = "LOCAL_CERTIFICATE"
   PACKAGE_NAME = "LOCAL_PACKAGE_NAME"
 
-  def __init__(self, app_path=None):
+  def __init__(self):
     self._includes = Set() # variables included in makefile
     self._variables = {} # variables defined in makefile
-
-    if app_path:
-      self.ParseMK(app_path)
+    self._has_gtestlib = False
 
   def _ProcessMKLine(self, line):
     """Add a variable definition or include.
@@ -56,6 +57,9 @@
       parts = line.split(self._VAR_DELIMITER)
       if len(parts) > 1:
         self._variables[parts[0].strip()] = parts[1].strip()
+    # hack, look for explicit mention of libgtest_main
+    if line.find('libgtest_main') != -1:
+      self._has_gtestlib = True
 
   def GetVariable(self, identifier):
     """Retrieve makefile variable.
@@ -69,6 +73,38 @@
     # so None is returned if identifier not found
     return self._variables.get(identifier, None)
 
+  def GetExpandedVariable(self, identifier):
+    """Retrieve makefile variable.
+
+    If variable value refers to another variable, recursively expand it to
+    find its literal value
+
+    Args:
+      identifier: name of variable to retrieve
+    Returns:
+      value of specified identifier, None if identifier not found in makefile
+    """
+    # use dict.get(x) rather than dict[x] to avoid KeyError exception,
+    # so None is returned if identifier not found
+    return self.__RecursiveGetVariable(identifier, Set())
+
+  def __RecursiveGetVariable(self, identifier, visited_variables):
+    variable_value = self.GetVariable(identifier)
+    if not variable_value:
+      return None
+    if variable_value in visited_variables:
+      raise RuntimeError('recursive loop found for makefile variable %s'
+                         % variable_value)
+    m = self._RE_VARIABLE_REF.match(variable_value)
+    if m:
+      logger.SilentLog('Found variable ref %s for identifier %s'
+                       % (variable_value, identifier))
+      variable_ref = m.group(1)
+      visited_variables.add(variable_ref)
+      return self.__RecursiveGetVariable(variable_ref, visited_variables)
+    else:
+      return variable_value
+
   def HasInclude(self, identifier):
     """Check variable is included in makefile.
 
@@ -79,18 +115,57 @@
     """
     return identifier in self._includes
 
-  def ParseMK(self, app_path):
+  def HasJavaLibrary(self, library_name):
+    """Check if library is specified as a local java library in makefile.
+
+    Args:
+      library_name: name of library to check
+    Returns:
+      True if library_name is included in makefile, otherwise False
+    """
+    java_lib_string = self.GetExpandedVariable('LOCAL_JAVA_LIBRARIES')
+    if java_lib_string:
+      java_libs = java_lib_string.split(' ')
+      return library_name in java_libs
+    return False
+
+  def HasGTest(self):
+    """Check if makefile includes rule to build a native gtest.
+
+    Returns:
+      True if rule to build native test is in makefile, otherwise False
+    """
+    return self._has_gtestlib or self.HasInclude('BUILD_NATIVE_TEST')
+
+  def _ParseMK(self, mk_path):
     """Parse Android.mk at the specified path.
 
     Args:
-      app_path: path to folder containing Android.mk
+      mk_path: path to Android.mk
     Raises:
       IOError: Android.mk cannot be found at given path, or cannot be opened
           for reading
     """
-    self.app_path = app_path.rstrip("/")
-    self.mk_path = "%s/%s" % (self.app_path, self.FILENAME)
-    mk = open(self.mk_path)
+    mk = open(mk_path)
     for line in mk:
       self._ProcessMKLine(line)
     mk.close()
+
+
+def CreateAndroidMK(path, filename=AndroidMK.FILENAME):
+  """Factory method for creating a AndroidMK.
+
+  Args:
+    path: the directory of the make file
+    filename: the filename of the makefile
+
+  Return:
+    the AndroidMK or None if there was no file present
+  """
+  mk_path = os.path.join(path, filename)
+  if os.path.isfile(mk_path):
+    mk = AndroidMK()
+    mk._ParseMK(mk_path)
+    return mk
+  else:
+    return None
\ No newline at end of file
diff --git a/testrunner/coverage_targets.xml b/testrunner/coverage_targets.xml
index b239a87..406d5e5 100644
--- a/testrunner/coverage_targets.xml
+++ b/testrunner/coverage_targets.xml
@@ -104,6 +104,8 @@
         build_path="frameworks/base/packages/SettingsProvider" type="APPS" />
     <coverage_target name="TelephonyProvider"
         build_path="packages/providers/telephony" type="APPS" />
+    <coverage_target name="VoicemailProvider"
+        build_path="packages/providers/VoicemailProvider" type="APPS" />
 
     <!-- input methods -->
     <coverage_target name="LatinIME" build_path="packages/inputmethods/LatinIME"
diff --git a/testrunner/runtest.py b/testrunner/runtest.py
index 19102c6..6226350 100755
--- a/testrunner/runtest.py
+++ b/testrunner/runtest.py
@@ -35,6 +35,7 @@
 import os
 from sets import Set
 import sys
+import time
 
 # local imports
 import adb_interface
@@ -195,18 +196,21 @@
     Raises:
       AbortError: If a fatal error occurred when parsing the tests.
     """
-    core_test_path = os.path.join(self._root_path, self._CORE_TEST_PATH)
     try:
       known_tests = test_defs.TestDefinitions()
-      known_tests.Parse(core_test_path)
-      # read all <android root>/vendor/*/tests/testinfo/test_defs.xml paths
-      vendor_tests_pattern = os.path.join(self._root_path,
-                                          self._VENDOR_TEST_PATH)
-      test_file_paths = glob.glob(vendor_tests_pattern)
-      for test_file_path in test_file_paths:
-        known_tests.Parse(test_file_path)
-      if os.path.isfile(self._options.user_tests_file):
-        known_tests.Parse(self._options.user_tests_file)
+      # only read tests when not in path mode
+      if not self._options.test_path:
+        core_test_path = os.path.join(self._root_path, self._CORE_TEST_PATH)
+        if os.path.isfile(core_test_path):
+          known_tests.Parse(core_test_path)
+        # read all <android root>/vendor/*/tests/testinfo/test_defs.xml paths
+        vendor_tests_pattern = os.path.join(self._root_path,
+                                            self._VENDOR_TEST_PATH)
+        test_file_paths = glob.glob(vendor_tests_pattern)
+        for test_file_path in test_file_paths:
+          known_tests.Parse(test_file_path)
+        if os.path.isfile(self._options.user_tests_file):
+          known_tests.Parse(self._options.user_tests_file)
       return known_tests
     except errors.ParseError:
       raise errors.AbortError
@@ -261,7 +265,7 @@
 
       # mmm cannot be used from python, so perform a similar operation using
       # ONE_SHOT_MAKEFILE
-      cmd = 'ONE_SHOT_MAKEFILE="%s" make -j%s -C "%s" files %s' % (
+      cmd = 'ONE_SHOT_MAKEFILE="%s" make -j%s -C "%s" all_modules %s' % (
           target_build_string, self._options.make_jobs, self._root_path,
           extra_args_string)
       logger.Log(cmd)
@@ -385,6 +389,8 @@
           self._adb.SendShellCommand("\"echo %s >> /data/local.prop\""
                                      % self._DALVIK_VERIFIER_OFF_PROP)
           self._adb.SendCommand("reboot")
+          # wait for device to go offline
+          time.sleep(10)
           self._adb.SendCommand("wait-for-device", timeout_time=60,
                                 retry_count=3)
           self._adb.EnableAdbRoot()
diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml
index b9d006f..f80e5bb 100644
--- a/testrunner/test_defs.xml
+++ b/testrunner/test_defs.xml
@@ -439,6 +439,12 @@
     coverage_target="CalendarProvider"
     continuous="true" />
 
+<test name="voicemailprovider"
+    build_path="packages/providers/VoicemailProvider"
+    package="com.android.providers.voicemail.tests"
+    coverage_target="VoicemailProvider"
+    continuous="true" />
+
 <test name="contactsprov"
     build_path="packages/providers/ContactsProvider"
     package="com.android.providers.contacts.tests"
diff --git a/testrunner/test_defs/gtest.py b/testrunner/test_defs/gtest.py
new file mode 100644
index 0000000..7de674b
--- /dev/null
+++ b/testrunner/test_defs/gtest.py
@@ -0,0 +1,119 @@
+#!/usr/bin/python
+#
+#
+# Copyright 2011, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""TestSuite for running C/C++ Android tests using gtest framework."""
+
+# python imports
+import os
+import re
+
+# local imports
+import logger
+import run_command
+import test_suite
+
+
+class GTestSuite(test_suite.AbstractTestSuite):
+  """A test suite for running gtest on device."""
+
+  def __init__(self):
+    test_suite.AbstractTestSuite.__init__(self)
+    self._target_exec_path = None
+
+  def GetTargetExecPath(self):
+    """Get the target path to gtest executable."""
+    return self._target_exec_path
+
+  def SetTargetExecPath(self, path):
+    self._target_exec_path = path
+    return self
+
+  def Run(self, options, adb):
+    """Run the provided gtest test suite.
+
+    Args:
+      options: command line options
+      adb: adb interface
+    """
+    shell_cmd = adb.PreviewShellCommand(self.GetTargetExecPath())
+    logger.Log(shell_cmd)
+    if not options.preview:
+      # gtest will log to test results to stdout, so no need to do any
+      # extra processing
+      run_command.RunCommand(shell_cmd, return_output=False)
+
+
+class GTestFactory(test_suite.AbstractTestFactory):
+
+  def __init__(self, test_root_path, upstream_build_path=None):
+    test_suite.AbstractTestFactory.__init__(self, test_root_path,
+        upstream_build_path=upstream_build_path)
+
+  def CreateTests(self, sub_tests_path=None):
+    """Create tests found in sub_tests_path.
+
+    Looks for test files matching a pattern, and assumes each one is a separate
+    binary on target.
+
+    Test files must match one of the following pattern:
+      - test_*.[c|cc|cpp]
+      - *_test.[c|cc|cpp]
+      - *_unittest.[c|cc|cpp]
+
+    """
+    if not sub_tests_path:
+      sub_tests_path = self.GetTestRootPath()
+    test_file_list = []
+    if os.path.isfile(sub_tests_path):
+      self._EvaluateFile(test_file_list, os.path.basename(sub_tests_path))
+    else:
+      os.path.walk(sub_tests_path, self._CollectTestSources, test_file_list)
+    # TODO: obtain this from makefile instead of hardcoding
+    target_root_path = os.path.join('/data', 'nativetest')
+    test_suites = []
+    for test_file in test_file_list:
+      logger.SilentLog('Creating gtest suite for file %s' % test_file)
+      suite = GTestSuite()
+      suite.SetBuildPath(self.GetBuildPath())
+      suite.SetTargetExecPath(os.path.join(target_root_path, test_file))
+      test_suites.append(suite)
+    return test_suites
+
+  def _CollectTestSources(self, test_list, dirname, files):
+    """For each directory, find tests source file and add them to the list.
+
+    Test files must match one of the following pattern:
+      - test_*.[cc|cpp]
+      - *_test.[cc|cpp]
+      - *_unittest.[cc|cpp]
+
+    This method is a callback for os.path.walk.
+
+    Args:
+      test_list: Where new tests should be inserted.
+      dirname: Current directory.
+      files: List of files in the current directory.
+    """
+    for f in files:
+      self._EvaluateFile(test_list, f)
+
+  def _EvaluateFile(self, test_list, file):
+    (name, ext) = os.path.splitext(file)
+    if ext == ".cc" or ext == ".cpp" or ext == ".c":
+      if re.search("_test$|_test_$|_unittest$|_unittest_$|^test_", name):
+        logger.SilentLog("Found native test file %s" % file)
+        test_list.append(name)
diff --git a/testrunner/test_defs/instrumentation_test.py b/testrunner/test_defs/instrumentation_test.py
index 40d6bed..64182a4 100644
--- a/testrunner/test_defs/instrumentation_test.py
+++ b/testrunner/test_defs/instrumentation_test.py
@@ -17,7 +17,11 @@
 
 """TestSuite definition for Android instrumentation tests."""
 
+import os
+import re
+
 # local imports
+import android_manifest
 import coverage
 import errors
 import logger
@@ -193,3 +197,143 @@
       total_count+=1
     logger.Log("Tests run: %d, Failures: %d, Errors: %d" %
                (total_count, fail_count, error_count))
+
+
+class InstrumentationTestFactory(test_suite.AbstractTestFactory):
+  """A factory for creating InstrumentationTestSuites"""
+
+  def __init__(self, test_root_path, upstream_build_path=None):
+    test_suite.AbstractTestFactory.__init__(self, test_root_path,
+                                            upstream_build_path=upstream_build_path)
+
+  def CreateTests(self, sub_tests_path=None):
+    """Create tests found in test_path.
+
+    Will create a single InstrumentationTestSuite based on info found in
+    AndroidManifest.xml found at build_path. Will set additional filters if
+    test_path refers to a java package or java class.
+    """
+    tests = []
+    class_name_arg = None
+    java_package_name = None
+    if sub_tests_path:
+      # if path is java file, populate class name
+      if self._IsJavaFile(sub_tests_path):
+        class_name_arg = self._GetClassNameFromFile(sub_tests_path)
+        logger.SilentLog('Using java test class %s' % class_name_arg)
+      elif self._IsJavaPackage(sub_tests_path):
+        java_package_name = self._GetPackageNameFromDir(sub_tests_path)
+        logger.SilentLog('Using java package %s' % java_package_name)
+    try:
+      manifest_parser = android_manifest.AndroidManifest(app_path=
+                                                         self.GetTestsRootPath())
+      instrs = manifest_parser.GetInstrumentationNames()
+      if not instrs:
+        logger.Log('Could not find instrumentation declarations in %s at %s' %
+                   (android_manifest.AndroidManifest.FILENAME,
+                    self.GetBuildPath()))
+        return tests
+
+      for instr_name in manifest_parser.GetInstrumentationNames():
+        pkg_name = manifest_parser.GetPackageName()
+        if instr_name.find(".") < 0:
+          instr_name = "." + instr_name
+        logger.SilentLog('Found instrumentation %s/%s' % (pkg_name, instr_name))
+        suite = InstrumentationTestSuite()
+        suite.SetPackageName(pkg_name)
+        suite.SetBuildPath(self.GetBuildPath())
+        suite.SetRunnerName(instr_name)
+        suite.SetName(pkg_name)
+        suite.SetClassName(class_name_arg)
+        suite.SetJavaPackageFilter(java_package_name)
+        # this is a bit of a hack, assume if 'com.android.cts' is in
+        # package name, this is a cts test
+        # this logic can be removed altogether when cts tests no longer require
+        # custom build steps
+        if suite.GetPackageName().startswith('com.android.cts'):
+          suite.SetSuite('cts')
+        tests.append(suite)
+      return tests
+
+    except:
+      logger.Log('Could not find or parse %s at %s' %
+                 (android_manifest.AndroidManifest.FILENAME,
+                  self.GetBuildPath()))
+    return tests
+
+  def _IsJavaFile(self, path):
+    """Returns true if given file system path is a java file."""
+    return os.path.isfile(path) and self._IsJavaFileName(path)
+
+  def _IsJavaFileName(self, filename):
+    """Returns true if given file name is a java file name."""
+    return os.path.splitext(filename)[1] == '.java'
+
+  def _IsJavaPackage(self, path):
+    """Returns true if given file path is a java package.
+
+    Currently assumes if any java file exists in this directory, than it
+    represents a java package.
+
+    Args:
+      path: file system path of directory to check
+
+    Returns:
+      True if path is a java package
+    """
+    if not os.path.isdir(path):
+      return False
+    for file_name in os.listdir(path):
+      if self._IsJavaFileName(file_name):
+        return True
+    return False
+
+  def _GetClassNameFromFile(self, java_file_path):
+    """Gets the fully qualified java class name from path.
+
+    Args:
+      java_file_path: file system path of java file
+
+    Returns:
+      fully qualified java class name or None.
+    """
+    package_name = self._GetPackageNameFromFile(java_file_path)
+    if package_name:
+      filename = os.path.basename(java_file_path)
+      class_name = os.path.splitext(filename)[0]
+      return '%s.%s' % (package_name, class_name)
+    return None
+
+  def _GetPackageNameFromDir(self, path):
+    """Gets the java package name associated with given directory path.
+
+    Caveat: currently just parses defined java package name from first java
+    file found in directory.
+
+    Args:
+      path: file system path of directory
+
+    Returns:
+      the java package name or None
+    """
+    for filename in os.listdir(path):
+      if self._IsJavaFileName(filename):
+        return self._GetPackageNameFromFile(os.path.join(path, filename))
+
+  def _GetPackageNameFromFile(self, java_file_path):
+    """Gets the java package name associated with given java file path.
+
+    Args:
+      java_file_path: file system path of java file
+
+    Returns:
+      the java package name or None
+    """
+    logger.SilentLog('Looking for java package name in %s' % java_file_path)
+    re_package = re.compile(r'package\s+(.*);')
+    file_handle = open(java_file_path, 'r')
+    for line in file_handle:
+      match = re_package.match(line)
+      if match:
+        return match.group(1)
+    return None
diff --git a/testrunner/test_defs/test_suite.py b/testrunner/test_defs/test_suite.py
index 102a738..20f9629 100644
--- a/testrunner/test_defs/test_suite.py
+++ b/testrunner/test_defs/test_suite.py
@@ -105,3 +105,41 @@
       adb: asdb_interface to device under test
     """
     raise NotImplementedError
+
+class AbstractTestFactory(object):
+  """generic test suite factory."""
+
+  def __init__(self, test_root_path, upstream_build_path=None):
+    """Creates a test suite factory.
+
+    Args:
+      test_root_path: the filesystem path to the tests build directory
+      upstream_build_path: optional filesystem path for the directory
+      to build when running tests. If unspecified, will use test_root_path
+    """
+    self._test_root_path = test_root_path
+    if upstream_build_path:
+      self._build_path = upstream_build_path
+    else:
+      self._build_path = self._test_root_path
+
+  def GetBuildPath(self):
+    return self._build_path
+
+  def GetTestsRootPath(self):
+    return self._test_root_path
+
+  def CreateTests(self, sub_tests_path=None):
+    """Creates the tests at given test_path.
+
+    Subclasses must implement this.
+
+    Args:
+      sub_tests_path: the child path of test_root_path containing the tests to
+        run. If unspecified will be set to test_root_path.
+
+    Returns:
+      an array of AbstractTestSuite, or empty AbstractTestSuite if no tests
+      were defined
+    """
+    raise NotImplementedError
diff --git a/testrunner/test_defs/test_walker.py b/testrunner/test_defs/test_walker.py
index e34dafc..de93c80 100755
--- a/testrunner/test_defs/test_walker.py
+++ b/testrunner/test_defs/test_walker.py
@@ -19,27 +19,31 @@
 
 # python imports
 import os
-import re
 
 # local imports
 import android_build
-import android_manifest
 import android_mk
+import gtest
 import instrumentation_test
 import logger
 
 
 class TestWalker(object):
-  """Finds instrumentation tests from filesystem."""
+  """Finds Android tests from filesystem."""
 
   def FindTests(self, path):
-    """Gets list of Android instrumentation tests found at given path.
+    """Gets list of Android tests found at given path.
 
-    Tests are created from the <instrumentation> tags found in
-    AndroidManifest.xml files relative to the given path.
+    Tests are created from info found in Android.mk and AndroidManifest.xml
+    files relative to the given path.
+
+    Currently supported tests are:
+    - Android application tests run via instrumentation
+    - native C/C++ tests using GTest framework. (note Android.mk must follow
+      expected GTest template)
 
     FindTests will first scan sub-folders of path for tests. If none are found,
-    it will scan the file system upwards until a AndroidManifest.xml is found
+    it will scan the file system upwards until a valid test Android.mk is found
     or the Android build root is reached.
 
     Some sample values for path:
@@ -55,6 +59,8 @@
     the instrumentation in ApiDemos/tests, with the java package filter set
     to com.example.android.apis.
 
+    TODO: add GTest examples
+
     Args:
       path: file system path to search
 
@@ -110,204 +116,143 @@
     # return string with common build_path removed
     return path[build_path_len:]
 
-  def _FindSubTests(self, path, tests, build_path=None):
+  def _FindSubTests(self, path, tests, upstream_build_path=None):
     """Recursively finds all tests within given path.
 
     Args:
       path: absolute file system path to check
       tests: current list of found tests
-      build_path: the parent directory where Android.mk that builds sub-folders
-        was found
+      upstream_build_path: the parent directory where Android.mk that builds
+        sub-folders was found
 
     Returns:
       updated list of tests
     """
     if not os.path.isdir(path):
       return tests
-    filenames = os.listdir(path)
-    if filenames.count(android_manifest.AndroidManifest.FILENAME):
-      # found a manifest! now parse it to find the test definition(s)
-      manifest = android_manifest.AndroidManifest(app_path=path)
-      if not build_path:
+    android_mk_parser = android_mk.CreateAndroidMK(path)
+    if android_mk_parser:
+      if not upstream_build_path:
         # haven't found a parent makefile which builds this dir. Use current
         # dir as build path
-        tests.extend(self._CreateSuitesFromManifest(
-            manifest, self._MakePathRelativeToBuild(path)))
+        tests.extend(self._CreateSuites(
+            android_mk_parser, path, self._MakePathRelativeToBuild(path)))
       else:
-        tests.extend(self._CreateSuitesFromManifest(manifest, build_path))
-    # Try to build as much of original path as possible, so
-    # keep track of upper-most parent directory where Android.mk was found that
-    # has rule to build sub-directory makefiles
-    # this is also necessary in case of overlapping tests
-    # ie if a test exists at 'foo' directory  and 'foo/sub', attempting to
-    # build both 'foo' and 'foo/sub' will fail.
-    if filenames.count(android_mk.AndroidMK.FILENAME):
-      android_mk_parser = android_mk.AndroidMK(app_path=path)
+        tests.extend(self._CreateSuites(android_mk_parser, path,
+                                        upstream_build_path))
+      # Try to build as much of original path as possible, so
+      # keep track of upper-most parent directory where Android.mk was found
+      # that has rule to build sub-directory makefiles.
+      # this is also necessary in case of overlapping tests
+      # ie if a test exists at 'foo' directory  and 'foo/sub', attempting to
+      # build both 'foo' and 'foo/sub' will fail.
+
       if android_mk_parser.HasInclude('call all-makefiles-under,$(LOCAL_PATH)'):
-        # found rule to build sub-directories. The parent path can be used, 
+        # found rule to build sub-directories. The parent path can be used,
         # or if not set, use current path
-        if not build_path:
-          build_path = self._MakePathRelativeToBuild(path)
+        if not upstream_build_path:
+          upstream_build_path = self._MakePathRelativeToBuild(path)
       else:
-        build_path = None
-    for filename in filenames:
-      self._FindSubTests(os.path.join(path, filename), tests, build_path)
+        upstream_build_path = None
+    for filename in os.listdir(path):
+      self._FindSubTests(os.path.join(path, filename), tests,
+                         upstream_build_path)
     return tests
 
   def _FindUpstreamTests(self, path):
     """Find tests defined upward from given path.
 
     Args:
-      path: the location to start searching. If it points to a java class file
-        or java package dir, the appropriate test suite filters will be set
+      path: the location to start searching.
 
     Returns:
       list of test_suite.AbstractTestSuite found, may be empty
     """
-    class_name_arg = None
-    package_name = None
-    # if path is java file, populate class name
-    if self._IsJavaFile(path):
-      class_name_arg = self._GetClassNameFromFile(path)
-      logger.SilentLog('Using java test class %s' % class_name_arg)
-    elif self._IsJavaPackage(path):
-      package_name = self._GetPackageNameFromDir(path)
-      logger.SilentLog('Using java package %s' % package_name)
-    manifest = self._FindUpstreamManifest(path)
-    if manifest:
-      logger.SilentLog('Found AndroidManifest at %s' % manifest.GetAppPath())
-      build_path = self._MakePathRelativeToBuild(manifest.GetAppPath())
-      return self._CreateSuitesFromManifest(manifest,
-                                            build_path,
-                                            class_name=class_name_arg,
-                                            java_package_name=package_name)
+    factory = self._FindUpstreamTestFactory(path)
+    if factory:
+      return factory.CreateTests(sub_tests_path=path)
+    else:
+      return []
 
-  def _IsJavaFile(self, path):
-    """Returns true if given file system path is a java file."""
-    return os.path.isfile(path) and self._IsJavaFileName(path)
+  def _GetTestFactory(self, android_mk_parser, path, upstream_build_path=None):
+    """Get the test factory for given makefile.
 
-  def _IsJavaFileName(self, filename):
-    """Returns true if given file name is a java file name."""
-    return os.path.splitext(filename)[1] == '.java'
-
-  def _IsJavaPackage(self, path):
-    """Returns true if given file path is a java package.
-
-    Currently assumes if any java file exists in this directory, than it
-    represents a java package.
+    If given path is a valid tests build path, will return the TestFactory
+    for creating tests.
 
     Args:
-      path: file system path of directory to check
+      android_mk_parser: the android mk to evaluate
+      path: the filesystem path of the makefile
+      upstream_build_path: optional filesystem path for the directory
+      to build when running tests. If unspecified, will use path
 
     Returns:
-      True if path is a java package
+      the TestFactory or None if path is not a valid tests build path
     """
-    if not os.path.isdir(path):
-      return False
-    for file_name in os.listdir(path):
-      if self._IsJavaFileName(file_name):
-        return True
-    return False
+    if android_mk_parser.HasGTest():
+      return gtest.GTestFactory(path, upstream_build_path=upstream_build_path)
+    elif android_mk_parser.HasJavaLibrary('android.test.runner'):
+      return instrumentation_test.InstrumentationTestFactory(path,
+          upstream_build_path=upstream_build_path)
+    else:
+      # somewhat unusual, but will continue searching
+      logger.SilentLog('Found makefile at %s, but did not detect any tests.'
+                       % path)
 
-  def _GetClassNameFromFile(self, java_file_path):
-    """Gets the fully qualified java class name from path.
-
-    Args:
-      java_file_path: file system path of java file
-
-    Returns:
-      fully qualified java class name or None.
-    """
-    package_name = self._GetPackageNameFromFile(java_file_path)
-    if package_name:
-      filename = os.path.basename(java_file_path)
-      class_name = os.path.splitext(filename)[0]
-      return '%s.%s' % (package_name, class_name)
     return None
 
-  def _GetPackageNameFromDir(self, path):
-    """Gets the java package name associated with given directory path.
+  def _GetTestFactoryForPath(self, path):
+    """Get the test factory for given path.
 
-    Caveat: currently just parses defined java package name from first java
-    file found in directory.
+    If given path is a valid tests build path, will return the TestFactory
+    for creating tests.
 
     Args:
-      path: file system path of directory
+      path: the filesystem path to evaluate
 
     Returns:
-      the java package name or None
+      the TestFactory or None if path is not a valid tests build path
     """
-    for filename in os.listdir(path):
-      if self._IsJavaFileName(filename):
-        return self._GetPackageNameFromFile(os.path.join(path, filename))
+    android_mk_parser = android_mk.CreateAndroidMK(path)
+    if android_mk_parser:
+      return self._GetTestFactory(android_mk_parser, path)
+    else:
+      return None
 
-  def _GetPackageNameFromFile(self, java_file_path):
-    """Gets the java package name associated with given java file path.
-
-    Args:
-      java_file_path: file system path of java file
-
-    Returns:
-      the java package name or None
-    """
-    logger.SilentLog('Looking for java package name in %s' % java_file_path)
-    re_package = re.compile(r'package\s+(.*);')
-    file_handle = open(java_file_path, 'r')
-    for line in file_handle:
-      match = re_package.match(line)
-      if match:
-        return match.group(1)
-    return None
-
-  def _FindUpstreamManifest(self, path):
-    """Recursively searches filesystem upwards for a AndroidManifest file.
+  def _FindUpstreamTestFactory(self, path):
+    """Recursively searches filesystem upwards for a test factory.
 
     Args:
       path: file system path to search
 
     Returns:
-      the AndroidManifest found or None
+      the TestFactory found or None
     """
-    if (os.path.isdir(path) and
-        os.listdir(path).count(android_manifest.AndroidManifest.FILENAME)):
-      return android_manifest.AndroidManifest(app_path=path)
+    factory = self._GetTestFactoryForPath(path)
+    if factory:
+      return factory
     dirpath = os.path.dirname(path)
     if self._IsPathInBuildTree(path):
-      return self._FindUpstreamManifest(dirpath)
-    logger.Log('AndroidManifest.xml not found')
+      return self._FindUpstreamTestFactory(dirpath)
+    logger.Log('A tests Android.mk was not found')
     return None
 
-  def _CreateSuitesFromManifest(self, manifest, build_path, class_name=None,
-                                java_package_name=None):
-    """Creates TestSuites from a AndroidManifest.
+  def _CreateSuites(self, android_mk_parser, path, upstream_build_path):
+    """Creates TestSuites from a AndroidMK.
 
     Args:
-      manifest: the AndroidManifest
-      build_path: the build path to use for test
-      class_name: optionally, the class filter for the suite
-      java_package_name: optionally, the java package filter for the suite
+      android_mk_parser: the AndroidMK
+      path: absolute file system path of the makefile to evaluate
+      upstream_build_path: the build path to use for test. This can be
+        different than the 'path', in cases where an upstream makefile
+        is being used.
 
     Returns:
       the list of tests created
     """
-    tests = []
-    for instr_name in manifest.GetInstrumentationNames():
-      pkg_name = manifest.GetPackageName()
-      if instr_name.find(".") < 0:
-        instr_name = "." + instr_name
-      logger.SilentLog('Found instrumentation %s/%s' % (pkg_name, instr_name))
-      suite = instrumentation_test.InstrumentationTestSuite()
-      suite.SetPackageName(pkg_name)
-      suite.SetBuildPath(build_path)
-      suite.SetRunnerName(instr_name)
-      suite.SetName(pkg_name)
-      suite.SetClassName(class_name)
-      suite.SetJavaPackageFilter(java_package_name)
-      # this is a bit of a hack, assume if 'com.android.cts' is in
-      # package name, this is a cts test
-      # this logic can be removed altogether when cts tests no longer require
-      # custom build steps
-      if suite.GetPackageName().startswith('com.android.cts'):
-        suite.SetSuite('cts')
-      tests.append(suite)
-    return tests
+    factory = self._GetTestFactory(android_mk_parser, path,
+                                   upstream_build_path=upstream_build_path)
+    if factory:
+      return factory.CreateTests(path)
+    else:
+      return []
diff --git a/testrunner/tests/Android_gtestlib.mk b/testrunner/tests/Android_gtestlib.mk
new file mode 100644
index 0000000..79ecec6
--- /dev/null
+++ b/testrunner/tests/Android_gtestlib.mk
@@ -0,0 +1,52 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build the unit tests.
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Build the unit tests.
+test_src_files := $(call find-subdir-files, *.cpp)
+
+shared_libraries := \
+        libz \
+        liblog \
+        libcutils \
+        libutils \
+        libstlport
+
+static_libraries := \
+        libgtest \
+        libgtest_main
+
+c_includes := \
+    external/zlib \
+    external/icu4c/common \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport
+
+module_tags := eng tests
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+    $(eval include $(BUILD_EXECUTABLE)) \
+)
diff --git a/testrunner/tests/Android_java.mk b/testrunner/tests/Android_java.mk
new file mode 100644
index 0000000..ff9138a
--- /dev/null
+++ b/testrunner/tests/Android_java.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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)
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+LOCAL_JAVA_LIBRARIES := foo android.test.runner
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := ApiDemosTests
+LOCAL_INSTRUMENTATION_FOR := ApiDemos
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/testrunner/tests/Android_native.mk b/testrunner/tests/Android_native.mk
new file mode 100644
index 0000000..6273ccb
--- /dev/null
+++ b/testrunner/tests/Android_native.mk
@@ -0,0 +1,21 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 $(CLEAR_VARS)
+test_module := foo
+LOCAL_MODULE := $(test_module)
+recursive_var := $(recursive_var)
+LOCAL_MODULE_TAGS := tags
+LOCAL_SRC_FILES := src
+include $(BUILD_NATIVE_TEST)
diff --git a/testrunner/tests/android_mk_tests.py b/testrunner/tests/android_mk_tests.py
new file mode 100755
index 0000000..ff1f289
--- /dev/null
+++ b/testrunner/tests/android_mk_tests.py
@@ -0,0 +1,90 @@
+#!/usr/bin/python
+#
+#
+# Copyright 2011, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+import unittest
+sys.path.append('../..')
+
+from testrunner import android_mk
+
+
+class AndroidMKTest(unittest.TestCase):
+  """Unit tests for AndroidMK."""
+
+  def testHasGTest(self):
+    """Test for AndroidMK.HasGTest."""
+    mk_parser = android_mk.CreateAndroidMK(path='.',
+                                           filename='Android_native.mk')
+    self.assertTrue(mk_parser.HasGTest())
+
+  def testHasGTest_lib(self):
+    """Test for AndroidMK.HasGTest."""
+    mk_parser = android_mk.CreateAndroidMK(path='.',
+                                           filename='Android_gtestlib.mk')
+    self.assertTrue(mk_parser.HasGTest())
+
+  def testHasGTest_false(self):
+    """Negative test for AndroidMK.HasGTest."""
+    mk_parser = android_mk.CreateAndroidMK(path='.', filename='Android_java.mk')
+    self.assertFalse(mk_parser.HasGTest())
+
+  def testHasJavaLibrary(self):
+    """Test for AndroidMK.HasJavaLibrary."""
+    mk_parser = android_mk.CreateAndroidMK(path='.',
+                                           filename='Android_java.mk')
+    self.assertTrue(mk_parser.HasJavaLibrary('android.test.runner'))
+
+  def testHasJavaLibrary_missing(self):
+    """Negative test for AndroidMK.HasJavaLibrary.
+
+    Test behavior when LOCAL_JAVA_LIBARIES rule is not present in makefile.
+    """
+    mk_parser = android_mk.CreateAndroidMK(path='.',
+                                           filename='Android_native.mk')
+    self.assertFalse(mk_parser.HasJavaLibrary('android.test.runner'))
+
+  def testHasJavaLibrary_false(self):
+    """Negative test for AndroidMK.HasJavaLibrary.
+
+    Test behavior when LOCAL_JAVA_LIBARIES rule is present, but does not list
+    given library.
+    """
+    mk_parser = android_mk.CreateAndroidMK(path='.', filename='Android_java.mk')
+    self.assertFalse(mk_parser.HasJavaLibrary('doesntexist'))
+
+  def testGetExpandedVariable(self):
+    """Test for AndroidMK.GetExpandedVariable.
+    """
+    mk_parser = android_mk.CreateAndroidMK(path='.',
+                                           filename='Android_native.mk')
+    self.assertEquals('foo', mk_parser.GetExpandedVariable('LOCAL_MODULE'))
+
+  def testGetExpandedVariable_loop(self):
+    """Test for AndroidMK.GetExpandedVariable where variable expansion loops
+    """
+    mk_parser = android_mk.CreateAndroidMK(path='.',
+                                           filename='Android_native.mk')
+    try:
+      mk_parser.GetExpandedVariable('recursive_var')
+      self.assertTrue(False)
+    except RuntimeError:
+      # expected
+      pass
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/a3dconvert/Android.mk b/tools/a3dconvert/Android.mk
index 7bc634e..2b09fbf 100644
--- a/tools/a3dconvert/Android.mk
+++ b/tools/a3dconvert/Android.mk
@@ -29,12 +29,19 @@
     ColladaGeometry.cpp \
     ColladaLoader.cpp
 
+# Needed to maintain libRS dependencies
+intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,HOST,)
+librs_generated_headers := \
+    $(intermediates)/rsgApiStructs.h \
+    $(intermediates)/rsgApiFuncDecl.h
+LOCAL_GENERATED_SOURCES := $(librs_generated_headers)
 
 LOCAL_C_INCLUDES += external/collada/include
 LOCAL_C_INCLUDES += external/collada/include/1.4
 LOCAL_C_INCLUDES += frameworks/base/libs/rs
+LOCAL_C_INCLUDES += $(intermediates)
 
 LOCAL_LDLIBS := -lpthread
-LOCAL_STATIC_LIBRARIES += libRSserialize libutils libcutils
+LOCAL_STATIC_LIBRARIES += libRS libutils libcutils
 LOCAL_STATIC_LIBRARIES += colladadom libtinyxml libpcrecpp libpcre
 include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/a3dconvert/ColladaGeometry.h b/tools/a3dconvert/ColladaGeometry.h
index 5774997..a89fa69 100644
--- a/tools/a3dconvert/ColladaGeometry.h
+++ b/tools/a3dconvert/ColladaGeometry.h
@@ -27,8 +27,8 @@
     ColladaGeometry();
     bool init(domGeometryRef geometry);
 
-    Mesh *getMesh(Context *rsc) {
-        return mConvertedMesh.getMesh(rsc);
+    SimpleMesh *getMesh() {
+        return &mConvertedMesh;
     }
 
 private:
diff --git a/tools/a3dconvert/ColladaLoader.cpp b/tools/a3dconvert/ColladaLoader.cpp
index 8a74748..32d6250 100644
--- a/tools/a3dconvert/ColladaLoader.cpp
+++ b/tools/a3dconvert/ColladaLoader.cpp
@@ -17,8 +17,6 @@
 #include "ColladaLoader.h"
 #include "ColladaConditioner.h"
 #include "ColladaGeometry.h"
-#include "rsContext.h"
-#include "rsFileA3D.h"
 
 #include <dae.h>
 #include <dom/domCOLLADA.h>
@@ -64,22 +62,8 @@
     return convertSuceeded;
 }
 
-bool ColladaLoader::convertToA3D(const char *a3dFile) {
-    if (mGeometries.size() == 0) {
-        return false;
-    }
-    // Now write all this stuff out
-    Context rsc;
-    FileA3D file(&rsc);
-
-    for (uint32_t i = 0; i < mGeometries.size(); i++) {
-        Mesh *exportedMesh = mGeometries[i]->getMesh(&rsc);
-        file.appendToFile(exportedMesh);
-        delete exportedMesh;
-    }
-
-    file.writeFile(a3dFile);
-    return true;
+SimpleMesh *ColladaLoader::getMesh(uint32_t meshIndex) {
+    return mGeometries[meshIndex]->getMesh();
 }
 
 bool ColladaLoader::convertAllGeometry(domLibrary_geometries *allGeometry) {
diff --git a/tools/a3dconvert/ColladaLoader.h b/tools/a3dconvert/ColladaLoader.h
index aa66e7d..3d7bb7d 100644
--- a/tools/a3dconvert/ColladaLoader.h
+++ b/tools/a3dconvert/ColladaLoader.h
@@ -22,14 +22,20 @@
 class domLibrary_geometries;
 class domGeometry;
 class ColladaGeometry;
+class SimpleMesh;
 
-class ColladaLoader {
+#include "GeometryLoader.h"
+
+class ColladaLoader : public GeometryLoader {
 public:
     ColladaLoader();
-    ~ColladaLoader();
+    virtual ~ColladaLoader();
 
-    bool init(const char *colladaFile);
-    bool convertToA3D(const char *a3dFile);
+    virtual bool init(const char *colladaFile);
+    virtual SimpleMesh *getMesh(uint32_t meshIndex);
+    virtual uint32_t getNumMeshes() const {
+        return mGeometries.size();
+    }
 
 private:
     void clearGeometry();
diff --git a/tools/a3dconvert/GeometryLoader.h b/tools/a3dconvert/GeometryLoader.h
new file mode 100644
index 0000000..e0aca7a
--- /dev/null
+++ b/tools/a3dconvert/GeometryLoader.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 _GEOMETRY_LOADER_H_
+#define _GEOMETRY_LOADER_H_
+
+#include "SimpleMesh.h"
+
+class GeometryLoader {
+public:
+    virtual ~GeometryLoader() {
+    }
+    virtual bool init(const char *file) = 0;
+    virtual uint32_t getNumMeshes() const = 0;
+    virtual SimpleMesh *getMesh(uint32_t meshIndex) = 0;
+};
+
+#endif _GEOMETRY_LOADER_H_
diff --git a/tools/a3dconvert/ObjLoader.cpp b/tools/a3dconvert/ObjLoader.cpp
index 4465f4f..19b6e0b 100644
--- a/tools/a3dconvert/ObjLoader.cpp
+++ b/tools/a3dconvert/ObjLoader.cpp
@@ -228,24 +228,6 @@
     return true;
 }
 
-bool ObjLoader::convertToA3D(const char *a3dFile) {
-    if (!getNumMeshes()) {
-        return false;
-    }
-    // Now write all this stuff out
-    Context rsc;
-    FileA3D file(&rsc);
-
-    for (uint32_t i = 0; i < getNumMeshes(); i ++) {
-        Mesh *exportedMesh = getMesh(&rsc, i);
-        file.appendToFile(exportedMesh);
-        delete exportedMesh;
-    }
-
-    file.writeFile(a3dFile);
-    return true;
-}
-
 void ObjLoader::reIndexGeometry() {
     // We want to know where each vertex lands
     mVertexRemap.resize(mObjPositions.size() / mPositionsStride);
diff --git a/tools/a3dconvert/ObjLoader.h b/tools/a3dconvert/ObjLoader.h
index 210b35f..a3eee04 100644
--- a/tools/a3dconvert/ObjLoader.h
+++ b/tools/a3dconvert/ObjLoader.h
@@ -22,28 +22,28 @@
 #include <iostream>
 #include <fstream>
 
-#include "SimpleMesh.h"
-#include <rsContext.h>
+#include "GeometryLoader.h"
 
 using namespace android;
 using namespace android::renderscript;
 
 #define MAX_INDEX 0xffffffff
 
-class ObjLoader {
+class ObjLoader : public GeometryLoader {
 public:
     ObjLoader();
-    bool init(const char *objFile);
-    bool convertToA3D(const char *a3dFile);
-private:
-
-    Mesh *getMesh(Context *rsc, uint32_t meshIndex) {
-        return mMeshes[meshIndex].getMesh(rsc);
+    virtual ~ObjLoader() {
     }
-    uint32_t getNumMeshes() const {
+    virtual bool init(const char *objFile);
+
+    virtual SimpleMesh *getMesh(uint32_t meshIndex) {
+        return &mMeshes[meshIndex];
+    }
+    virtual uint32_t getNumMeshes() const {
         return mMeshes.size();
     }
 
+private:
     // .obj has a global list of vertex data
     std::vector<float> mObjPositions;
     std::vector<float> mObjNormals;
diff --git a/tools/a3dconvert/SimpleMesh.h b/tools/a3dconvert/SimpleMesh.h
index 57e1a7c..15205cb 100644
--- a/tools/a3dconvert/SimpleMesh.h
+++ b/tools/a3dconvert/SimpleMesh.h
@@ -19,6 +19,7 @@
 
 #include <rsContext.h>
 #include <rsMesh.h>
+#include <string>
 using namespace android;
 using namespace android::renderscript;
 
@@ -68,7 +69,7 @@
     }
 
     // Generates a renderscript mesh that could be used for a3d serialization
-    Mesh *getMesh(Context *rsc) {
+    Mesh *getRsMesh(Context *rsc) {
         if (mChannels.size() == 0) {
             return NULL;
         }
@@ -89,7 +90,7 @@
         Type *vertexDataType = Type::getType(rsc, vertexDataElem, numVerts, 0, 0, false, false);
         vertexDataType->compute();
 
-        Allocation *vertexAlloc = new Allocation(rsc, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT);
+        Allocation *vertexAlloc = Allocation::createAllocation(rsc, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT);
 
         uint32_t vertexSize = vertexDataElem->getSizeBytes()/sizeof(float);
         // Fill this allocation with some data
@@ -113,26 +114,19 @@
         // Now lets write index data
         const Element *indexElem = Element::create(rsc, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
 
-        Mesh *mesh = new Mesh(rsc);
+        Mesh *mesh = new Mesh(rsc, 1, mTriangleLists.size());
         mesh->setName(mName.c_str());
-        mesh->mVertexBufferCount = 1;
-        mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[1];
-        mesh->mVertexBuffers[0].set(vertexAlloc);
-
-        mesh->mPrimitivesCount = mTriangleLists.size();
-        mesh->mPrimitives = new Mesh::Primitive_t *[mesh->mPrimitivesCount];
+        mesh->setVertexBuffer(vertexAlloc, 0);
 
         // load all primitives
-        for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) {
-            Mesh::Primitive_t *prim = new Mesh::Primitive_t;
-            mesh->mPrimitives[pCount] = prim;
+        for (uint32_t pCount = 0; pCount < mTriangleLists.size(); pCount ++) {
 
             uint32_t numIndicies = mTriangleLists[pCount].size();
             Type *indexType = Type::getType(rsc, indexElem, numIndicies, 0, 0, false, false );
 
             indexType->compute();
 
-            Allocation *indexAlloc = new Allocation(rsc, indexType, RS_ALLOCATION_USAGE_SCRIPT);
+            Allocation *indexAlloc = Allocation::createAllocation(rsc, indexType, RS_ALLOCATION_USAGE_SCRIPT);
             uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
             const std::vector<uint32_t> &indexList = mTriangleLists[pCount];
             uint32_t numTries = numIndicies / 3;
@@ -143,8 +137,7 @@
                 indexPtr[i * 3 + 2] = (uint16_t)indexList[i * 3 + 2];
             }
             indexAlloc->setName(mTriangleListNames[pCount].c_str());
-            prim->mIndexBuffer.set(indexAlloc);
-            prim->mPrimitive = RS_PRIMITIVE_TRIANGLE;
+            mesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, pCount);
         }
 
         return mesh;
diff --git a/tools/a3dconvert/a3dconvert.cpp b/tools/a3dconvert/a3dconvert.cpp
index 33f5733..6094473 100644
--- a/tools/a3dconvert/a3dconvert.cpp
+++ b/tools/a3dconvert/a3dconvert.cpp
@@ -19,6 +19,69 @@
 
 #include "ColladaLoader.h"
 #include "ObjLoader.h"
+#include <rsContext.h>
+#include <rsFileA3D.h>
+
+bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) {
+    void * ptr = malloc(alloc->mHal.state.type->getSizeBytes());
+    if (!ptr) {
+        return false;
+    }
+
+    alloc->mHal.drvState.mallocPtr = ptr;
+    if (forceZero) {
+        memset(ptr, 0, alloc->mHal.state.type->getSizeBytes());
+    }
+    return true;
+}
+
+void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) {
+    if (alloc->mHal.drvState.mallocPtr) {
+        free(alloc->mHal.drvState.mallocPtr);
+        alloc->mHal.drvState.mallocPtr = NULL;
+    }
+}
+
+// We only care to implement allocation memory initialization and destruction
+// because we need no other renderscript hal features for serialization
+static RsdHalFunctions FunctionTable = {
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL },
+    {
+        rsdAllocationInit,
+        rsdAllocationDestroy,
+        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+    },
+    { NULL, NULL, NULL }, { NULL, NULL, NULL }, { NULL, NULL, NULL },
+    { NULL, NULL, NULL }, { NULL, NULL, NULL }, { NULL, NULL },
+    { NULL, NULL, NULL},
+};
+
+// No-op initizlizer for rs context hal since we only
+bool rsdHalInit(Context *rsc, uint32_t version_major, uint32_t version_minor) {
+    rsc->mHal.funcs = FunctionTable;
+    return true;
+}
+
+bool convertToA3D(GeometryLoader *loader, const char *a3dFile) {
+    if (!loader->getNumMeshes()) {
+        return false;
+    }
+    // Now write all this stuff out
+    Context *rsc = Context::createContextLite();
+    rsdHalInit(rsc, 0, 0);
+    FileA3D file(rsc);
+
+    for (uint32_t i = 0; i < loader->getNumMeshes(); i ++) {
+        Mesh *exportedMesh = loader->getMesh(i)->getRsMesh(rsc);
+        file.appendToFile(exportedMesh);
+        delete exportedMesh;
+    }
+
+    file.writeFile(a3dFile);
+    delete rsc;
+    return true;
+}
 
 int main (int argc, char * const argv[]) {
     const char *objExt = ".obj";
@@ -42,24 +105,24 @@
         return 1;
     }
 
+    GeometryLoader *loader = NULL;
     std::string ext = filename.substr(dotPos);
     if (ext == daeExt) {
-        ColladaLoader converter;
-        isSuccessful = converter.init(argv[1]);
-        if (isSuccessful) {
-            isSuccessful = converter.convertToA3D(argv[2]);
-        }
+        loader = new ColladaLoader();
     } else if (ext == objExt) {
-        ObjLoader objConv;
-        isSuccessful = objConv.init(argv[1]);
-        if (isSuccessful) {
-            isSuccessful = objConv.convertToA3D(argv[2]);
-        }
+        loader = new ObjLoader();
     } else {
         printf("Invalid input. Currently .obj and .dae (collada) input files are accepted\n");
         return 1;
     }
 
+    isSuccessful = loader->init(argv[1]);
+    if (isSuccessful) {
+        isSuccessful = convertToA3D(loader, argv[2]);
+    }
+
+    delete loader;
+
     if(isSuccessful) {
         printf("---All done---\n");
     } else {
diff --git a/tools/emulator/skins/WSVGA/arrow_down.png b/tools/emulator/skins/WSVGA/arrow_down.png
new file mode 100755
index 0000000..b9fde22
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/arrow_down.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/arrow_left.png b/tools/emulator/skins/WSVGA/arrow_left.png
new file mode 100755
index 0000000..281b192
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/arrow_left.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/arrow_right.png b/tools/emulator/skins/WSVGA/arrow_right.png
new file mode 100755
index 0000000..4cbc65d
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/arrow_right.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/arrow_up.png b/tools/emulator/skins/WSVGA/arrow_up.png
new file mode 100755
index 0000000..29c7121
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/arrow_up.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/background_land.png b/tools/emulator/skins/WSVGA/background_land.png
new file mode 100644
index 0000000..109c747
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/background_land.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/background_port.png b/tools/emulator/skins/WSVGA/background_port.png
new file mode 100644
index 0000000..5bb2580
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/background_port.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/button.png b/tools/emulator/skins/WSVGA/button.png
new file mode 100755
index 0000000..8281d20
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/button.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/controls.png b/tools/emulator/skins/WSVGA/controls.png
new file mode 100755
index 0000000..04b85e2
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/controls.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/hardware.ini b/tools/emulator/skins/WSVGA/hardware.ini
new file mode 100755
index 0000000..c777f9e
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/hardware.ini
@@ -0,0 +1,6 @@
+# skin-specific hardware values
+hw.lcd.density=160
+vm.heapSize=48
+hw.ramSize=512
+hw.keyboard.lid=no
+
diff --git a/tools/emulator/skins/WSVGA/key.png b/tools/emulator/skins/WSVGA/key.png
new file mode 100755
index 0000000..40b03bf
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/key.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/keyboard.png b/tools/emulator/skins/WSVGA/keyboard.png
new file mode 100755
index 0000000..ca49dcf
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/keyboard.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/layout b/tools/emulator/skins/WSVGA/layout
new file mode 100755
index 0000000..140ecd7
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/layout
@@ -0,0 +1,88 @@
+parts {
+    portrait {
+        background {
+            image   background_port.png
+        }
+    }
+    landscape {
+        background {
+            image   background_land.png
+        }
+    }
+
+    device {
+        display {
+            width   1024
+            height  600
+            x       0
+            y       0
+        }
+    }
+    
+}
+
+layouts {
+
+    landscape {
+        width     1076
+        height    654
+        color     0xe0e0e0
+        event     EV_SW:0:1
+
+        part1 {
+            name    portrait
+            x       1400
+            y       0
+        }
+
+        part2 {
+            name    landscape
+            x       0
+            y       0
+        }
+
+        part3 {
+            name      device
+            x         26
+            y         29
+        }
+    }
+
+    portrait {
+        width     654
+        height    1076
+        color     0xe0e0e0
+        event     EV_SW:0:0
+
+        dpad-rotation 3
+        
+        part1 {
+            name    portrait
+            x       0
+            y       0
+        }
+
+        part2 {
+            name    landscape
+            x       1400
+            y       0
+        }
+
+        part3 {
+            name    device
+            x       29
+            y       1050
+            rotation  3
+        }
+    }
+
+}
+
+keyboard {
+    charmap qwerty2
+}
+
+network {
+    speed  full
+    delay  none
+}
diff --git a/tools/emulator/skins/WSVGA/select.png b/tools/emulator/skins/WSVGA/select.png
new file mode 100755
index 0000000..f4a65d3
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/select.png
Binary files differ
diff --git a/tools/emulator/skins/WSVGA/spacebar.png b/tools/emulator/skins/WSVGA/spacebar.png
new file mode 100755
index 0000000..aa459bd
--- /dev/null
+++ b/tools/emulator/skins/WSVGA/spacebar.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/hardware.ini b/tools/emulator/skins/WXGA/hardware.ini
index 130592f..c777f9e 100755
--- a/tools/emulator/skins/WXGA/hardware.ini
+++ b/tools/emulator/skins/WXGA/hardware.ini
@@ -1,6 +1,6 @@
 # skin-specific hardware values
 hw.lcd.density=160
 vm.heapSize=48
-hw.ramSize=256
+hw.ramSize=512
 hw.keyboard.lid=no
 
diff --git a/tools/emulator/system/gps/Android.mk b/tools/emulator/system/gps/Android.mk
index 41bdc64..9daf4d6 100644
--- a/tools/emulator/system/gps/Android.mk
+++ b/tools/emulator/system/gps/Android.mk
@@ -22,18 +22,20 @@
 
 LOCAL_PATH := $(call my-dir)
 
-ifneq ($(TARGET_PRODUCT),sim)
-# HAL module implemenation, not prelinked and stored in
+# HAL module implemenation stored in
 # hw/<GPS_HARDWARE_MODULE_ID>.<ro.hardware>.so
 include $(CLEAR_VARS)
-LOCAL_PRELINK_MODULE := false
+
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
 LOCAL_CFLAGS += -DQEMU_HARDWARE
 LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware
 LOCAL_SRC_FILES := gps_qemu.c
+ifeq ($(TARGET_PRODUCT),vbox_x86)
+LOCAL_MODULE := gps.vbox_x86
+else
 LOCAL_MODULE := gps.goldfish
+endif
 LOCAL_MODULE_TAGS := debug
 include $(BUILD_SHARED_LIBRARY)
-endif
 
 endif # BUILD_EMULATOR_GPS_MODULE
diff --git a/tools/emulator/system/lights/Android.mk b/tools/emulator/system/lights/Android.mk
index c7aa83c..f0f76dc 100644
--- a/tools/emulator/system/lights/Android.mk
+++ b/tools/emulator/system/lights/Android.mk
@@ -14,7 +14,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-ifneq ($(TARGET_PRODUCT),sim)
 # HAL module implemenation, not prelinked and stored in
 # hw/<LIGHTS_HARDWARE_MODULE_ID>.<ro.hardware>.so
 include $(CLEAR_VARS)
@@ -26,4 +25,3 @@
 LOCAL_MODULE_TAGS := debug
 LOCAL_CFLAGS += -DLIGHT_BACKLIGHT
 include $(BUILD_SHARED_LIBRARY)
-endif
diff --git a/tools/emulator/system/qemu-props/Android.mk b/tools/emulator/system/qemu-props/Android.mk
index 1bdbf68..1b2932f 100644
--- a/tools/emulator/system/qemu-props/Android.mk
+++ b/tools/emulator/system/qemu-props/Android.mk
@@ -25,8 +25,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-ifneq ($(TARGET_PRODUCT),sim)
-
 # The 'qemu-props' program is run from /system/etc/init.goldfish.rc
 # to setup various system properties sent by the emulator program.
 #
@@ -39,6 +37,4 @@
 LOCAL_MODULE_TAGS := debug
 include $(BUILD_EXECUTABLE)
 
-endif # TARGET_PRODUCT != sim
-
 endif # BUILD_EMULATOR_QEMU_PROPS
diff --git a/tools/emulator/system/sensors/Android.mk b/tools/emulator/system/sensors/Android.mk
index 9b0e83d..4ae048b 100644
--- a/tools/emulator/system/sensors/Android.mk
+++ b/tools/emulator/system/sensors/Android.mk
@@ -23,14 +23,18 @@
 LOCAL_PATH := $(call my-dir)
 
 ifneq ($(TARGET_PRODUCT),sim)
-# HAL module implemenation, not prelinked and stored in
+# HAL module implemenation stored in
 # hw/<SENSORS_HARDWARE_MODULE_ID>.<ro.hardware>.so
 include $(CLEAR_VARS)
-LOCAL_PRELINK_MODULE := false
+
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
 LOCAL_SHARED_LIBRARIES := liblog libcutils
 LOCAL_SRC_FILES := sensors_qemu.c
+ifeq ($(TARGET_PRODUCT),vbox_x86)
+LOCAL_MODULE := sensors.vbox_x86
+else
 LOCAL_MODULE := sensors.goldfish
+endif
 LOCAL_MODULE_TAGS := debug
 include $(BUILD_SHARED_LIBRARY)
 endif
diff --git a/tools/emulator/test-apps/ConnectivityTest/Android.mk b/tools/emulator/test-apps/ConnectivityTest/Android.mk
new file mode 100644
index 0000000..097d118
--- /dev/null
+++ b/tools/emulator/test-apps/ConnectivityTest/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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_MODULE_TAGS := optional
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := ConnectivityTest
+
+LOCAL_SDK_VERSION := 4
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml b/tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml
new file mode 100644
index 0000000..80f65cf
--- /dev/null
+++ b/tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.android.emulator.connectivity.test"
+      android:versionCode="1"
+      android:versionName="1.0">
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-sdk android:minSdkVersion="4" />
+    <instrumentation android:targetPackage="com.android.emulator.connectivity.test" android:name="android.test.InstrumentationTestRunner" />
+    <application  android:label="Connectivity Test">
+        <uses-library android:name="android.test.runner" />
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java b/tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java
new file mode 100644
index 0000000..9931eb8
--- /dev/null
+++ b/tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.emulator.connectivity.test;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+/**
+ * Network connectivity testcases.
+ */
+public class ConnectivityTest extends AndroidTestCase {
+
+    private ConnectivityManager connectivity;
+
+    //Connection attempt will be made to google.com
+    private static final String  URL_NAME = "http://www.google.com";
+
+    @Override
+    protected void setUp() throws Exception {
+        connectivity = (ConnectivityManager) getContext().
+            getSystemService(Context.CONNECTIVITY_SERVICE);
+        assertNotNull(connectivity);
+    }
+
+    /**
+     * Test that there is an active network
+     */
+    public void testActiveConnectivity() {
+        NetworkInfo networkInfo = connectivity.getActiveNetworkInfo();
+        Log.d("ConnectivityTest", "validating active networks.");
+        assertNotNull(networkInfo);
+        assertEquals( NetworkInfo.State.CONNECTED, networkInfo.getState());
+    }
+
+    /**
+     * Test that a connection can be made over the active network
+     */
+    public void testConnectionCreation() throws IOException {
+        URL url = new URL(URL_NAME);
+        Log.d("ConnectivityTest", "creating HTTP connection to google.com.");
+        URLConnection connection = url.openConnection();
+        connection.connect();
+    }
+
+}
diff --git a/tools/glesv2debugger/.classpath b/tools/glesv2debugger/.classpath
new file mode 100755
index 0000000..4ba3585
--- /dev/null
+++ b/tools/glesv2debugger/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="lib" path="lib/sdklib.jar"/>
+	<classpathentry kind="lib" path="lib/liblzf.jar"/>
+	<classpathentry kind="lib" path="lib/host-libprotobuf-java-2.3.0-lite.jar"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="test"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/tools/glesv2debugger/.gitignore b/tools/glesv2debugger/.gitignore
new file mode 100644
index 0000000..574bfc7
--- /dev/null
+++ b/tools/glesv2debugger/.gitignore
@@ -0,0 +1,4 @@
+lib/*.jar
+bin/*
+.settings/*
+
diff --git a/tools/glesv2debugger/.project b/tools/glesv2debugger/.project
new file mode 100755
index 0000000..0c974ca
--- /dev/null
+++ b/tools/glesv2debugger/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>GLESv2DebuggerClient</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/tools/glesv2debugger/META-INF/MANIFEST.MF b/tools/glesv2debugger/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..cf42bdb
--- /dev/null
+++ b/tools/glesv2debugger/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: GLESv2DebuggerClient
+Bundle-SymbolicName: GLESv2DebuggerClient; singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: com.android.glesv2debugger.Activator
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.junit
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ClassPath: lib/host-libprotobuf-java-2.3.0-lite.jar,
+ lib/liblzf.jar,
+ lib/sdklib.jar,
+ .
diff --git a/tools/glesv2debugger/README.android b/tools/glesv2debugger/README.android
new file mode 100644
index 0000000..ae95463
--- /dev/null
+++ b/tools/glesv2debugger/README.android
@@ -0,0 +1,20 @@
+The following is taken from slide 3 & 4 of https://docs.google.com/a/google.com/present/edit?id=0AcZLV3icFYi0ZGZxa3NqZndfMGRqa2tiOXB4&authkey=CMfb8ukI&hl=en
+The spec doc is at https://docs.google.com/a/google.com/document/d/1dsASXCF9Suq8KOGcxwB2mAwgdRlrFj4QhMxkfaRJlA0/edit?hl=en&authkey=CPj4tKkO#
+
+
+Building and Running
+
+Debugger server is linked into EGL, code is in framework/base/opengl/libs/GLES2_dbg and already included in latest master builds, no action needed.
+Use development/tools/glesv2debugger/setup.sh to build and copy the jars: libprotobuf-java-2.3.0-lite, liblzf, sdklib into development/tools/glesv2debugger/lib
+Install Eclipse SDK for Eclipse: Eclipse->Help->Install New Software. Select "All Available Sites" in the "Work with:" drop down, then find "Eclipse SDK". (If Eclipse reports dependency conflicts, try install updates first)
+Debugger client is an Eclipse plug-in, code is at development/tools/glesv2debugger, built in Eclipse
+Optional: build glsl_compiler and copy to plug-in working directory; this is used for shader syntax check
+
+
+"Attaching" to a Process
+
+adb shell setprop debug.egl.debug_proc <process name> before running process. ie: com.example.android.apis
+EGL checks /proc/<proc_id>/cmdline for match during init and sets debug functions in eglMakeCurrent
+EGL will bind to socket and wait for incoming connection, so need to adb forward tcp:5039 tcp:5039. Port can be overridden by adb shell setprop debug.egl.debug_port <port>
+If create socket failed, EGL will try to open /data/local/tmp/dump.gles2dbg for write, and exit when 8MB is written. The relevant properties are ...debug_forceUseFile, ...debug_maxFileSize, and ...debug_filePath
+Now manually start the process on device; on host, open development/tools/glesv2debugger/.project and run/debug as Eclipse application, then Window->Show View->Other->Debug->OpenGL ES 2.0 Debugger, then Connect or Open File
diff --git a/tools/glesv2debugger/build.properties b/tools/glesv2debugger/build.properties
new file mode 100644
index 0000000..39d82d2
--- /dev/null
+++ b/tools/glesv2debugger/build.properties
@@ -0,0 +1,11 @@
+source.. = src/,\

+           test/

+output.. = bin/

+bin.includes = plugin.xml,\

+               META-INF/,\

+               .,\

+               icons/,\
+               contexts.xml,\
+               lib/host-libprotobuf-java-2.3.0-lite.jar,\
+               lib/liblzf.jar,\
+               lib/sdklib.jar
diff --git a/tools/glesv2debugger/contexts.xml b/tools/glesv2debugger/contexts.xml
new file mode 100644
index 0000000..02e26e4
--- /dev/null
+++ b/tools/glesv2debugger/contexts.xml
@@ -0,0 +1,12 @@
+<contexts>
+	<context id="viewer" title="Sample View">
+		<description>This is the context help for the sample view with a table viewer. It was generated by a PDE template.</description>
+		<topic href="/PLUGINS_ROOT/org.eclipse.platform.doc.isv/guide/ua_help_context.htm" label="Context-sensitive help">
+			<enablement>
+				<with variable="platform">
+	            	<test property="org.eclipse.core.runtime.isBundleInstalled" args="org.eclipse.platform.doc.isv"/>
+	     		</with>
+			</enablement>
+		</topic>
+	</context>
+</contexts>
diff --git a/tools/glesv2debugger/generate_GLEnum_java.py b/tools/glesv2debugger/generate_GLEnum_java.py
new file mode 100755
index 0000000..cf543c8
--- /dev/null
+++ b/tools/glesv2debugger/generate_GLEnum_java.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+#
+# Copyright 2011, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+if __name__ == "__main__":
+    externs = []
+    lines = open("../../../frameworks/base/opengl/libs/enums.in").readlines()
+    output = open("src/com/android/glesv2debugger/GLEnum.java", "w")
+    i = 0
+    output.write(
+"""/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+// auto generated by generate_GLEnum_java.py"
+
+package com.android.glesv2debugger;
+
+public enum GLEnum {
+""")
+    
+    index = 0
+    for line in lines:
+        value = line[line.find("(") + 1: line.find(",")]
+        name = line[line.find(",") + 1: line.find(")")]    
+        output.write("    %s(%s),\n" % (name, value))
+
+    output.write("""    ;
+
+    public final int value;
+    GLEnum(final int value) {
+        this.value = value;
+    }
+
+    private static final java.util.HashMap<Integer, GLEnum> reverseMap = new java.util.HashMap<Integer, GLEnum>();
+    static {
+        for (GLEnum e : GLEnum.values())
+        reverseMap.put(e.value, e);
+    }
+
+    public static GLEnum valueOf(final int value) {
+        return reverseMap.get(value);
+    }
+}""")
+
+
diff --git a/tools/glesv2debugger/generate_MessageFormatter_java.py b/tools/glesv2debugger/generate_MessageFormatter_java.py
new file mode 100755
index 0000000..dfbf2ea
--- /dev/null
+++ b/tools/glesv2debugger/generate_MessageFormatter_java.py
@@ -0,0 +1,281 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+#
+# Copyright 2011, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+import sys
+
+def RemoveAnnotation(line):
+    if line.find(":") >= 0:
+        annotation = line[line.find(":"): line.find(" ", line.find(":"))]
+        return line.replace(annotation, "*")
+    else:
+        return line
+        
+if __name__ == "__main__":
+    externs = []
+    lines = open("../../../frameworks/base/opengl/libs/GLES2_dbg/gl2_api_annotated.in").readlines()
+    output = open("src/com/android/glesv2debugger/MessageFormatter.java", "w")
+    
+    i = 0
+    output.write(
+"""/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+// auto generated by generate_MessageFormatter_java.py"
+
+package com.android.glesv2debugger;
+
+import java.nio.ByteBuffer;
+
+public class MessageFormatter {
+
+    static String formatFloats(int count, final ByteBuffer data) {
+        if (data.remaining() == 0)
+            return "{}";
+        data.order(SampleView.targetByteOrder);
+        String ret = "{";
+        for (int i = 0; i < count; i++) {
+            ret += Float.intBitsToFloat(data.getInt());
+            if (i < count - 1)
+                ret += ", ";
+        }
+        return ret + "}";
+    }
+
+    static String formatInts(int count, final ByteBuffer data) {
+        if (data.remaining() == 0)
+            return "{}";
+        data.order(SampleView.targetByteOrder);
+        String ret = "{";
+        for (int i = 0; i < count; i++) {
+            ret += data.getInt();
+            if (i < count - 1)
+                ret += ", ";
+        }
+        return ret + "}";
+    }
+
+    static String formatUInts(int count, final ByteBuffer data) {
+        if (data.remaining() == 0)
+            return "{}";
+        data.order(SampleView.targetByteOrder);
+        String ret = "{";
+        for (int i = 0; i < count; i++) {
+            long bits = data.getInt() & 0xffffffff;
+            ret += bits;
+            if (i < count - 1)
+                ret += ", ";
+        }
+        return ret + "}";
+    }
+
+    static String formatMatrix(int columns, int count, final ByteBuffer data) {
+        if (data.remaining() == 0)
+            return "{}";
+        data.order(SampleView.targetByteOrder);
+        String ret = "{";
+        for (int i = 0; i < count; i++) {
+            ret += Float.intBitsToFloat(data.getInt());
+            if (i < count - 1)
+                ret += ", ";
+            if (i % columns == columns - 1)
+                ret += "\\n                                             ";
+        }
+        return ret + "}";
+    }
+
+    public static String format(final DebuggerMessage.Message msg,
+                                final boolean code) {
+        String str;
+        switch (msg.getFunction()) {
+""")
+    #in source code these turn into program_%d etc.
+    nameReplaces = ["program", "shader", "texture", "buffer", "framebuffer", "renderbuffer"]
+    for line in lines:
+        if line.find("API_ENTRY(") >= 0: # a function prototype
+            returnType = line[0: line.find(" API_ENTRY(")].replace("const ", "")
+            functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
+            parameterList = line[line.find(")(") + 2: line.find(") {")]
+
+            parameters = parameterList.split(',')
+            paramIndex = 0
+
+            formatString = "%s"
+            formatArgs = ""
+            if returnType != "void":
+                if returnType == "GLenum":
+                    formatArgs += '\
+                    (code ? "%s" : GLEnum.valueOf(msg.getRet()))\n' % (functionName)
+                elif returnType.find("*") >= 0:
+                    formatArgs += '\
+                    (code ? "%s" : "0x" + Integer.toHexString(msg.getRet()))\n' % (functionName)
+                else:
+                    formatArgs += '\
+                    (code ? "%s" : msg.getRet())\n' % (functionName)
+            else:
+                formatArgs += '\
+                    (code ? "%s" : "void")\n' % (functionName)
+
+            formatString += "("
+
+            if parameterList == "void":
+                parameters = []
+            inout = ""
+
+            paramNames = []
+
+            for parameter in parameters:
+                parameter = parameter.replace("const","")
+                parameter = parameter.strip()
+                paramType = parameter.split(' ')[0]
+                paramName = parameter.split(' ')[1]
+                annotation = ""
+
+                formatString += "%s%s"
+                formatArgs += '\
+                    , (code ? "/*%s*/ " : "%s=")\n' % (paramName, paramName)
+                if parameter.find(":") >= 0:
+                    assert inout == "" # only one parameter should be annotated
+                    inout = paramType.split(":")[2]
+                    annotation = paramType.split(":")[1]
+                    paramType = paramType.split(":")[0]
+                    count = 1
+                    countArg = ""
+                    if annotation.find("*") >= 0: # [1,n] * param
+                        count = int(annotation.split("*")[0])
+                        countArg = annotation.split("*")[1]
+                        assert countArg in paramNames
+                    elif annotation in paramNames:
+                        count = 1
+                        countArg = annotation
+                    elif annotation == "GLstring":
+                        annotation = annotation
+                    else:
+                        count = int(annotation)
+                    dataFormatter = ""
+                    if paramType == "GLfloat":
+                        dataFormatter = "formatFloats"
+                    elif paramType == "GLint":
+                        dataFormatter = "formatInts"
+                    elif paramType == "GLuint":
+                        dataFormatter = "formatUInts"
+                    elif annotation == "GLstring":
+                        assert paramType == "GLchar"
+                    elif paramType.find("void") >= 0:
+                        assert 1
+                    else:
+                        assert 0
+                    if functionName.find("Matrix") >= 0:
+                        columns = int(functionName[functionName.find("fv") - 1: functionName.find("fv")])
+                        assert columns * columns == count
+                        assert countArg != ""
+                        assert paramType == "GLfloat"
+                        formatArgs += '\
+                    , (code ? "(GLfloat [])" : "") + formatMatrix(%d, %d * msg.getArg%d(), msg.getData().asReadOnlyByteBuffer())' % (
+                        columns, count, paramNames.index(countArg))
+                    elif annotation == "GLstring":
+                        formatArgs += '\
+                    , (code ? "\\"" : "") + msg.getData().toStringUtf8() + (code ? "\\"" : "")'
+                    elif paramType.find("void") >= 0:
+                        formatArgs += '\
+                    , (code ? "arg%d" : "0x" + Integer.toHexString(msg.getArg%d()))' % (paramIndex, paramIndex)
+                    elif countArg == "":
+                        formatArgs += '\
+                    , (code ? "(%s [])" : "") + %s(%d, msg.getData().asReadOnlyByteBuffer())' % (
+                        paramType, dataFormatter, count)
+                    else:
+                        formatArgs += '\
+                    , (code ? "(%s [])" : "") +  %s(%d * msg.getArg%d(), msg.getData().asReadOnlyByteBuffer())' % (
+                        paramType, dataFormatter, count, paramNames.index(countArg))
+                else:
+                    if paramType == "GLfloat" or paramType == "GLclampf":
+                        formatArgs += "\
+                    , Float.intBitsToFloat(msg.getArg%d())" % (paramIndex)
+                    elif paramType == "GLenum": 
+                        formatArgs += "\
+                    , GLEnum.valueOf(msg.getArg%d())" % (paramIndex)
+                    elif paramType.find("*") >= 0:
+                        formatArgs += '\
+                    , (code ? "arg%d" : "0x" + Integer.toHexString(msg.getArg%d()))' % (paramIndex, paramIndex)
+                    elif paramName in nameReplaces:
+                        formatArgs += '\
+                    , (code ? "%s_" : "") + msg.getArg%d()' % (paramName, paramIndex)
+                    else:
+                        formatArgs += "\
+                    , msg.getArg%d()" % (paramIndex)
+                if paramIndex < len(parameters) - 1:
+                    formatString += ", "
+                    formatArgs += '\n'
+                paramNames.append(paramName)
+                paramIndex += 1  
+
+                
+            formatString += ")"
+             
+            output.write("            case %s:\n" % (functionName))
+            if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")):
+                sys.stderr.write(line)
+                output.write("                // FIXME: this function uses pointers, debugger may send data in msg.data\n")
+            output.write('\
+                str = String.format("%s",\n%s);\n\
+                break;\n' % (formatString, formatArgs))
+
+
+    output.write("""            default:
+                str = msg.toString();
+        }
+        return str;
+    }
+}""")
+
+'''    print """/*
+package GLESv2Debugger;
+
+public class MessageFormatterCustom {
+
+    public static String format(final DebuggerMessage.Message msg) {
+        String str;
+        switch (msg.getFunction()) {"""
+
+    for extern in externs:
+        print "        case %s" % (extern)
+        print "            // TODO:"
+
+print """        default:
+            str = msg.toString();
+        }
+        return str;
+    }
+}
+*/"""    '''
+        
+        
diff --git a/tools/glesv2debugger/generate_MessageParser_java.py b/tools/glesv2debugger/generate_MessageParser_java.py
new file mode 100755
index 0000000..b6e8282
--- /dev/null
+++ b/tools/glesv2debugger/generate_MessageParser_java.py
@@ -0,0 +1,304 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+#
+# Copyright 2011, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+import sys
+
+def RemoveAnnotation(line):
+    if line.find(":") >= 0:
+        annotation = line[line.find(":"): line.find(" ", line.find(":"))]
+        return line.replace(annotation, "*")
+    else:
+        return line
+
+if __name__ == "__main__":
+    externs = []
+    lines = open("../../../frameworks/base/opengl/libs/GLES2_dbg/gl2_api_annotated.in").readlines()
+    output = open("src/com/android/glesv2debugger/MessageParser.java", "w")
+
+    i = 0
+    output.write("""\
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+// auto generated by generate_MessageParser_java.py,
+//  which also prints skeleton code for MessageParserEx.java
+
+package com.android.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.google.protobuf.ByteString;
+
+import java.nio.ByteBuffer;
+
+public abstract class MessageParser {
+
+    String args;
+
+    String[] getList()
+    {
+        String arg = args;
+        args = args.substring(args.lastIndexOf('}') + 1);
+        final int comma = args.indexOf(',');
+        if (comma >= 0)
+            args = args.substring(comma + 1).trim();
+        else
+            args = null;
+
+        final int comment = arg.indexOf('=');
+        if (comment >= 0)
+            arg = arg.substring(comment + 1);
+        arg = arg.trim();
+        assert arg.charAt(0) == '{';
+        arg = arg.substring(1, arg.lastIndexOf('}')).trim();
+        return arg.split("\\s*,\\s*");
+    }
+
+    ByteString parseFloats(int count) {
+        ByteBuffer buffer = ByteBuffer.allocate(count * 4);
+        buffer.order(SampleView.targetByteOrder);
+        String [] arg = getList();
+        for (int i = 0; i < count; i++)
+            buffer.putFloat(Float.parseFloat(arg[i].trim()));
+        buffer.rewind();
+        return ByteString.copyFrom(buffer);
+    }
+
+    ByteString parseInts(int count) {
+        ByteBuffer buffer = ByteBuffer.allocate(count * 4);
+        buffer.order(SampleView.targetByteOrder);
+        String [] arg = getList();
+        for (int i = 0; i < count; i++)
+            buffer.putInt(Integer.parseInt(arg[i].trim()));
+        buffer.rewind();
+        return ByteString.copyFrom(buffer);
+    }
+
+    ByteString parseUInts(int count) {
+        ByteBuffer buffer = ByteBuffer.allocate(count * 4);
+        buffer.order(SampleView.targetByteOrder);
+        String [] arg = getList();
+        for (int i = 0; i < count; i++)
+            buffer.putInt((int)(Long.parseLong(arg[i].trim()) & 0xffffffff));
+        buffer.rewind();
+        return ByteString.copyFrom(buffer);
+    }
+
+    ByteString parseMatrix(int columns, int count) {
+        return parseFloats(columns * columns * count);
+    }
+
+    ByteString parseString() {
+        // TODO: escape sequence and proper string literal
+        String arg = args.substring(args.indexOf('"') + 1, args.lastIndexOf('"'));
+        args = args.substring(args.lastIndexOf('"'));
+        int comma = args.indexOf(',');
+        if (comma >= 0)
+            args = args.substring(comma + 1).trim();
+        else
+            args = null;
+        return ByteString.copyFromUtf8(arg);
+    }
+
+    String getArgument()
+    {
+        final int comma = args.indexOf(',');
+        String arg = null;
+        if (comma >= 0)
+        {
+            arg = args.substring(0, comma);
+            args = args.substring(comma + 1);
+        }
+        else
+        {
+            arg = args;
+            args = null;
+        }
+        final int comment = arg.indexOf('=');
+        if (comment >= 0)
+            arg = arg.substring(comment + 1);
+        return arg.trim();
+    }
+
+    int parseArgument()
+    {
+        String arg = getArgument();
+        if (arg.startsWith("GL_"))
+            return GLEnum.valueOf(arg).value;
+        else if (arg.toLowerCase().startsWith("0x"))
+            return Integer.parseInt(arg.substring(2), 16);
+        else
+            return Integer.parseInt(arg);
+    }
+
+    int parseFloat()
+    {
+        String arg = getArgument();
+        return Float.floatToRawIntBits(Float.parseFloat(arg));
+    }
+
+    public void parse(final Message.Builder builder, String string) {
+        int lparen = string.indexOf("("), rparen = string.lastIndexOf(")");
+        String s = string.substring(0, lparen).trim();
+        args = string.substring(lparen + 1, rparen);
+        String[] t = s.split(" ");
+        Function function = Function.valueOf(t[t.length - 1]);
+        builder.setFunction(function);
+        switch (function) {
+""")
+
+    abstractParsers = ""
+
+    for line in lines:
+        if line.find("API_ENTRY(") >= 0: # a function prototype
+            returnType = line[0: line.find(" API_ENTRY(")].replace("const ", "")
+            functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
+            parameterList = line[line.find(")(") + 2: line.find(") {")]
+
+            parameters = parameterList.split(',')
+            paramIndex = 0
+
+            #if returnType != "void":
+            #else:
+
+            if parameterList == "void":
+                parameters = []
+            inout = ""
+
+            paramNames = []
+            abstract = False
+            argumentSetters = ""
+            output.write("\
+            case %s:\n" % (functionName))
+
+            for parameter in parameters:
+                parameter = parameter.replace("const","")
+                parameter = parameter.strip()
+                paramType = parameter.split(' ')[0]
+                paramName = parameter.split(' ')[1]
+                annotation = ""
+
+                argumentParser = ""
+
+                if parameter.find(":") >= 0:
+                    dataSetter = ""
+                    assert inout == "" # only one parameter should be annotated
+                    inout = paramType.split(":")[2]
+                    annotation = paramType.split(":")[1]
+                    paramType = paramType.split(":")[0]
+                    count = 1
+                    countArg = ""
+                    if annotation.find("*") >= 0: # [1,n] * param
+                        count = int(annotation.split("*")[0])
+                        countArg = annotation.split("*")[1]
+                        assert countArg in paramNames
+                    elif annotation in paramNames:
+                        count = 1
+                        countArg = annotation
+                    elif annotation == "GLstring":
+                        annotation = annotation
+                    else:
+                        count = int(annotation)
+
+                    if paramType == "GLfloat":
+                        argumentParser = "parseFloats"
+                    elif paramType == "GLint":
+                        argumentParser = "parseInts"
+                    elif paramType == "GLuint":
+                        argumentParser = "parseUInts"
+                    elif annotation == "GLstring":
+                        assert paramType == 'GLchar'
+                    elif paramType.find("void") >= 0:
+                        assert 1
+                    else:
+                        assert 0
+
+                    if functionName.find('Matrix') >= 0:
+                        columns = int(functionName[functionName.find("fv") - 1: functionName.find("fv")])
+                        assert columns * columns == count
+                        assert countArg != ""
+                        assert paramType == "GLfloat"
+                        dataSetter = "builder.setData(parseMatrix(%d, builder.getArg%d()));" % (
+                            columns, paramNames.index(countArg))
+                    elif annotation == "GLstring":
+                        dataSetter = "builder.setData(parseString());"
+                    elif paramType.find("void") >= 0:
+                        dataSetter = "// TODO"
+                        abstract = True
+                    elif countArg == "":
+                        dataSetter = "builder.setData(%s(%d));" % (argumentParser, count)
+                    else:
+                        dataSetter = "builder.setData(%s(%d * builder.getArg%d()));" % (
+                            argumentParser, count, paramNames.index(countArg))
+                    argumentSetters += "\
+                %s // %s %s\n" % (dataSetter, paramType, paramName)
+                else:
+                    if paramType == "GLfloat" or paramType == "GLclampf":
+                        argumentSetters += "\
+                builder.setArg%d(parseFloat()); // %s %s\n" % (
+                    paramIndex, paramType, paramName)
+                    elif paramType.find("*") >= 0:
+                        argumentSetters += "\
+                // TODO: %s %s\n" % (paramType, paramName)
+                        abstract = True
+                    else:
+                        argumentSetters += "\
+                builder.setArg%d(parseArgument()); // %s %s\n" % (
+                    paramIndex, paramType, paramName)
+                paramNames.append(paramName)
+                paramIndex += 1
+
+            if not abstract:
+                output.write("%s" % argumentSetters)
+            else:
+                output.write("\
+                parse_%s(builder);\n" % functionName)
+                abstractParsers += "\
+    abstract void parse_%s(Message.Builder builder);\n" % functionName
+                print """\
+    @Override
+    void parse_%s(Message.Builder builder) {
+%s    }
+""" % (functionName, argumentSetters) # print skeleton code for MessageParserEx
+
+            output.write("\
+                break;\n")
+    output.write("""\
+            default:
+                assert false;
+        }
+    }
+""")
+    output.write(abstractParsers)
+    output.write("\
+}""")
diff --git a/tools/glesv2debugger/icons/sample.gif b/tools/glesv2debugger/icons/sample.gif
new file mode 100644
index 0000000..34fb3c9
--- /dev/null
+++ b/tools/glesv2debugger/icons/sample.gif
Binary files differ
diff --git a/tools/glesv2debugger/plugin.xml b/tools/glesv2debugger/plugin.xml
new file mode 100644
index 0000000..f1512a5
--- /dev/null
+++ b/tools/glesv2debugger/plugin.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<?eclipse version="3.4"?>

+<plugin>

+

+   <extension

+         point="org.eclipse.ui.views">

+      <view

+            name="OpenGL ES 2.0 Debugger"

+            icon="icons/sample.gif"

+            category="org.eclipse.debug.ui"

+            class="com.android.glesv2debugger.SampleView"

+            id="glesv2debuggerclient.views.SampleView">

+      </view>

+   </extension>

+   <extension

+         point="org.eclipse.ui.perspectiveExtensions">

+      <perspectiveExtension

+            targetID="org.eclipse.jdt.ui.JavaPerspective">

+         <view

+               ratio="0.5"

+               relative="org.eclipse.ui.views.TaskList"

+               relationship="right"

+               id="glesv2debuggerclient.views.SampleView">

+         </view>

+      </perspectiveExtension>

+   </extension>

+   <extension

+         point="org.eclipse.help.contexts">

+      <contexts

+            file="contexts.xml">

+      </contexts>

+   </extension>

+

+</plugin>

diff --git a/tools/glesv2debugger/setup.sh b/tools/glesv2debugger/setup.sh
new file mode 100755
index 0000000..839019d
--- /dev/null
+++ b/tools/glesv2debugger/setup.sh
@@ -0,0 +1,35 @@
+source ../../../build/envsetup.sh
+pushd ../../../
+
+# need lunch before building jars
+if [ -z "$TARGET_PRODUCT" ]; then
+    lunch
+fi
+
+pushd external/liblzf/
+mm
+popd
+
+pushd external/protobuf/
+mm
+popd
+
+pushd sdk/sdkmanager/libs/sdklib
+mm
+popd
+
+# glsl_compiler is optional
+# make glsl_compiler -j3
+
+popd
+
+mkdir -p lib
+cp "$ANDROID_HOST_OUT/framework/host-libprotobuf-java-2.3.0-lite.jar" lib/
+cp "$ANDROID_HOST_OUT/framework/liblzf.jar" lib/
+cp "$ANDROID_HOST_OUT/framework/sdklib.jar" lib/
+
+# optional; usually for linux
+#cp "$ANDROID_HOST_OUT/bin/glsl_compiler" ~/
+
+# optional; usually for mac, need to replace eclipse.app with actual path
+#cp "$ANDROID_HOST_OUT/bin/glsl_compiler" eclipse.app/Contents/MacOS
diff --git a/tools/glesv2debugger/src/META-INF/MANIFEST.MF b/tools/glesv2debugger/src/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..212b27a
--- /dev/null
+++ b/tools/glesv2debugger/src/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0

+Created-By: 1.6.0_22 (Sun Microsystems Inc.)

+

diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/Activator.java b/tools/glesv2debugger/src/com/android/glesv2debugger/Activator.java
new file mode 100644
index 0000000..6083c0f
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/Activator.java
@@ -0,0 +1,83 @@
+/*

+ ** Copyright 2011, The Android Open Source Project

+ **

+ ** Licensed under the Apache License, Version 2.0 (the "License");

+ ** you may not use this file except in compliance with the License.

+ ** You may obtain a copy of the License at

+ **

+ **     http://www.apache.org/licenses/LICENSE-2.0

+ **

+ ** Unless required by applicable law or agreed to in writing, software

+ ** distributed under the License is distributed on an "AS IS" BASIS,

+ ** WITHOUT 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.glesv2debugger;

+

+import org.eclipse.jface.resource.ImageDescriptor;

+import org.eclipse.ui.plugin.AbstractUIPlugin;

+import org.osgi.framework.BundleContext;

+

+/**

+ * The activator class controls the plug-in life cycle

+ */

+public class Activator extends AbstractUIPlugin {

+

+    // The plug-in ID

+    public static final String PLUGIN_ID = "GLESv2DebuggerClient"; //$NON-NLS-1$

+

+    // The shared instance

+    private static Activator plugin;

+

+    /**

+     * The constructor

+     */

+    public Activator() {

+    }

+

+    /*

+     * (non-Javadoc)

+     * @see

+     * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext

+     * )

+     */

+    @Override

+    public void start(BundleContext context) throws Exception {

+        super.start(context);

+        plugin = this;

+    }

+

+    /*

+     * (non-Javadoc)

+     * @see

+     * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext

+     * )

+     */

+    @Override

+    public void stop(BundleContext context) throws Exception {

+        plugin = null;

+        super.stop(context);

+    }

+

+    /**

+     * Returns the shared instance

+     * 

+     * @return the shared instance

+     */

+    public static Activator getDefault() {

+        return plugin;

+    }

+

+    /**

+     * Returns an image descriptor for the image file at the given plug-in

+     * relative path

+     * 

+     * @param path the path

+     * @return the image descriptor

+     */

+    public static ImageDescriptor getImageDescriptor(String path) {

+        return imageDescriptorFromPlugin(PLUGIN_ID, path);

+    }

+}

diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/BreakpointOption.java b/tools/glesv2debugger/src/com/android/glesv2debugger/BreakpointOption.java
new file mode 100644
index 0000000..e8405f9
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/BreakpointOption.java
@@ -0,0 +1,191 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.android.glesv2debugger.DebuggerMessage.Message.Prop;
+import com.android.glesv2debugger.DebuggerMessage.Message.Type;
+
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Shell;
+
+import java.io.IOException;
+
+public class BreakpointOption extends ScrolledComposite implements SelectionListener,
+        ProcessMessage {
+
+    SampleView sampleView;
+    Button[] buttonsBreak = new Button[Function.values().length];
+    /** cache of buttonsBreak[Function.getNumber()].getSelection */
+    boolean[] breakpoints = new boolean[Function.values().length];
+
+    BreakpointOption(SampleView sampleView, Composite parent) {
+        super(parent, SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL);
+        this.sampleView = sampleView;
+
+        Composite composite = new Composite(this, 0);
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 4;
+        composite.setLayout(layout);
+        this.setLayout(new FillLayout());
+
+        for (int i = 0; i < Function.values().length; i++) {
+            Group group = new Group(composite, 0);
+            group.setLayout(new RowLayout());
+            group.setText(Function.values()[i].toString());
+            Button btn = new Button(group, SWT.CHECK);
+            btn.addSelectionListener(this);
+            btn.setText("Break");
+            btn.setSelection(false);
+            breakpoints[Function.values()[i].getNumber()] = btn.getSelection();
+            buttonsBreak[Function.values()[i].getNumber()] = btn;
+        }
+
+        Point size = composite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+        composite.setSize(size);
+        this.setContent(composite);
+        this.setExpandHorizontal(true);
+        this.setExpandVertical(true);
+        this.setMinSize(size);
+        this.layout();
+    }
+
+    void setBreakpoint(final int contextId, final Function function, final boolean enabled) {
+        Message.Builder builder = Message.newBuilder();
+        builder.setContextId(contextId);
+        builder.setType(Type.Response);
+        builder.setExpectResponse(false);
+        builder.setFunction(Function.SETPROP);
+        builder.setProp(Prop.ExpectResponse);
+        builder.setArg0(function.getNumber());
+        builder.setArg1(enabled ? 1 : 0);
+        sampleView.messageQueue.addCommand(builder.build());
+        breakpoints[function.getNumber()] = enabled;
+    }
+
+    @Override
+    public void widgetSelected(SelectionEvent e) {
+        Button btn = (Button) e.widget;
+        Group group = (Group) btn.getParent();
+        int contextId = 0;
+        if (sampleView.current != null)
+            contextId = sampleView.current.contextId;
+        setBreakpoint(contextId, Function.valueOf(group.getText()), btn.getSelection());
+    }
+
+    @Override
+    public void widgetDefaultSelected(SelectionEvent e) {
+    }
+
+    private Function lastFunction = Function.NEG;
+
+    public boolean processMessage(final MessageQueue queue, final Message msg) throws IOException {
+        if (!breakpoints[msg.getFunction().getNumber()])
+            return false;
+        // use DefaultProcessMessage just to register the GL call
+        // but do not send response
+        final int contextId = msg.getContextId();
+        if (msg.getType() == Type.BeforeCall || msg.getType() == Type.AfterCall)
+            queue.defaultProcessMessage(msg, true, false);
+        final Message.Builder builder = Message.newBuilder();
+        builder.setContextId(contextId);
+        builder.setType(Type.Response);
+        builder.setExpectResponse(true);
+        final Shell shell = sampleView.getViewSite().getShell();
+        final boolean send[] = new boolean[1];
+        shell.getDisplay().syncExec(new Runnable() {
+            @Override
+            public void run() {
+                String call = MessageFormatter.format(msg, false);
+                call = call.substring(0, call.indexOf("(")) + ' ' +
+                        msg.getFunction() + call.substring(call.indexOf("("));
+                if (msg.hasData() && msg.getFunction() == Function.glShaderSource)
+                {
+                    int index = call.indexOf("string=") + 7;
+                    String ptr = call.substring(index, call.indexOf(',', index));
+                    call = call.replace(ptr, '"' + msg.getData().toStringUtf8() + '"');
+                }
+                if (msg.getType() == Type.AfterCall)
+                {
+                    call = "skip " + call;
+                    builder.setFunction(Function.SKIP);
+                }
+                else if (msg.getType() == Type.BeforeCall)
+                {
+                    call = "continue " + call;
+                    builder.setFunction(Function.CONTINUE);
+                }
+                else
+                {
+                    assert msg.getType() == Type.AfterGeneratedCall;
+                    assert msg.getFunction() == lastFunction;
+                    call = "skip " + call;
+                    builder.setFunction(Function.SKIP);
+                }
+                InputDialog inputDialog = new InputDialog(shell,
+                            msg.getFunction().toString() + " " + msg.getType().toString(),
+                        "(s)kip, (c)continue, (r)emove bp or glFunction(...)",
+                            call, null);
+                if (Window.OK == inputDialog.open())
+                {
+                    String s = inputDialog.getValue().substring(0, 1).toLowerCase();
+                    if (s.startsWith("s"))
+                    {
+                        builder.setFunction(Function.SKIP);
+                        // AfterCall is skipped, so push BeforeCall to complete
+                        if (queue.getPartialMessage(contextId) != null)
+                            queue.completePartialMessage(contextId);
+                    }
+                    else if (s.startsWith("c"))
+                        builder.setFunction(Function.CONTINUE);
+                    else if (s.startsWith("r"))
+                    {
+                        Button btn = buttonsBreak[msg.getFunction().getNumber()];
+                        btn.setSelection(false);
+                        setBreakpoint(msg.getContextId(), msg.getFunction(), false);
+                        builder.setExpectResponse(false);
+                    }
+                    else
+                    {
+                        MessageParserEx.instance.parse(builder, inputDialog.getValue());
+                        lastFunction = builder.getFunction();
+                        builder.setExpectResponse(true);
+                        // AfterCall is skipped, so push BeforeCall to complete
+                        if (queue.getPartialMessage(contextId) != null)
+                            queue.completePartialMessage(contextId);
+                    }
+                }
+                // else defaults to continue BeforeCall and skip AfterCall
+            }
+        });
+        queue.sendMessage(builder.build());
+        return true;
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/CodeGen.java b/tools/glesv2debugger/src/com/android/glesv2debugger/CodeGen.java
new file mode 100644
index 0000000..28f3a54
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/CodeGen.java
@@ -0,0 +1,1236 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.android.sdklib.util.SparseIntArray;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.swt.widgets.Shell;
+
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.ByteBuffer;
+
+public class CodeGen implements IRunnableWithProgress {
+    private FileWriter codeFile, makeFile, namesHeaderFile, namesSourceFile;
+    private PrintWriter code, make, namesHeader, namesSource;
+    private FileOutputStream dataOut;
+    private SparseIntArray bufferNames,
+            framebufferNames, programNames, textureNames, shaderNames, renderbufferNames;
+
+    /** return true if msg was a texture upload */
+    private boolean codeGenTextureUpload(final Message msg, final boolean replaceCopy) {
+        String s = null;
+        switch (msg.getFunction()) {
+            case glCompressedTexImage2D:
+                s = MessageFormatter.format(msg, true).replace("arg7", "texData");
+                break;
+            case glCompressedTexSubImage2D:
+            case glTexImage2D:
+            case glTexSubImage2D:
+                s = MessageFormatter.format(msg, true).replace("arg8", "texData");
+                break;
+            case glCopyTexImage2D:
+                if (!replaceCopy) {
+                    code.write(MessageFormatter.format(msg, true));
+                    code.write(";CHKERR;\n");
+                    return true;
+                }
+                assert msg.getArg2() == msg.getPixelFormat(); // TODO
+                s = "//" + MessageFormatter.format(msg, true) + "\n";
+                s += String.format("glTexImage2D(%s, %d, %s, %d, %d, %d, %s, %s, texData);CHKERR;",
+                        GLEnum.valueOf(msg.getArg0()), msg.getArg1(),
+                        GLEnum.valueOf(msg.getArg2()), msg.getArg5(), msg.getArg6(),
+                        msg.getArg7(), GLEnum.valueOf(msg.getPixelFormat()),
+                        GLEnum.valueOf(msg.getPixelType()));
+                break;
+            case glCopyTexSubImage2D:
+                if (!replaceCopy) {
+                    code.write(MessageFormatter.format(msg, true));
+                    code.write(";CHKERR;\n");
+                    return true;
+                }
+                // FIXME: check the texture format & type, and convert
+                s = "//" + MessageFormatter.format(msg, true) + "\n";
+                s += String.format(
+                        "glTexSubImage2D(%s, %d, %d, %d, %d, %d, %s, %s, texData);CHKERR;",
+                        GLEnum.valueOf(msg.getArg0()), msg.getArg1(), msg.getArg2(),
+                        msg.getArg3(), msg.getArg6(), msg.getArg7(),
+                        GLEnum.valueOf(msg.getPixelFormat()), GLEnum.valueOf(msg.getPixelType()));
+                break;
+            default:
+                return false;
+        }
+
+        if (msg.hasData()) {
+            final byte[] data = MessageProcessor.lzfDecompressChunks(msg.getData());
+            try {
+                code.write("{\n");
+                code.format("    void * texData = malloc(%d);CHKERR;\n", data.length);
+                code.format("    FILE * texFile = fopen(\"/sdcard/frame_data.bin\", \"rb\");CHKERR;\n");
+                code.format("    assert(texFile);CHKERR;\n");
+                code.format("    fseek(texFile, %d, SEEK_SET);CHKERR;\n", dataOut.getChannel()
+                        .position());
+                dataOut.write(data);
+                code.format("    fread(texData, %d, 1, texFile);CHKERR;\n", data.length);
+                code.format("    fclose(texFile);CHKERR;\n");
+                code.format("    " + s + ";\n");
+                code.format("    free(texData);CHKERR;\n");
+                code.format("}\n");
+            } catch (IOException e) {
+                e.printStackTrace();
+                assert false;
+            }
+        } else
+            code.write(s.replace("texData", "NULL") + ";\n");
+        return true;
+    }
+
+    private void codeGenServerState(final GLServerState serverState) {
+        code.write("// CodeGenServerState\n");
+        for (int i = 0; i < serverState.enableDisables.size(); i++) {
+            final GLEnum key = GLEnum.valueOf(serverState.enableDisables.keyAt(i));
+            if (serverState.enableDisables.valueAt(i) == 0)
+                code.format("glDisable(%s);CHKERR;\n", key);
+            else
+                code.format("glEnable(%s);CHKERR;\n", key);
+        }
+        for (int i = 0; i < serverState.lastSetter.size(); i++) {
+            final Function key = Function.valueOf(serverState.lastSetter.keyAt(i));
+            final Message msg = serverState.lastSetter.valueAt(i);
+            if (msg == null) {
+                code.format("// %s is default\n", key);
+                continue;
+            }
+            final String s = MessageFormatter.format(msg, true);
+            code.write(s);
+            code.write(";\n");
+        }
+        // TODO: stencil and integers
+    }
+
+    private void codeGenServerShader(final GLServerShader serverShader) {
+        code.write("// CodeGenServerShader\n");
+        for (int i = 0; i < serverShader.shaders.size(); i++) {
+            final int name = serverShader.shaders.keyAt(i);
+            final GLShader shader = serverShader.shaders.valueAt(i);
+            final String id = "shader_" + name;
+            if (shaderNames.indexOfKey(name) < 0) {
+                namesSource.format("GLuint %s = 0;\n", id);
+                namesHeader.format("extern GLuint %s;\n", id);
+            }
+            code.format("%s = glCreateShader(%s);CHKERR;\n", id, shader.type);
+            shaderNames.put(name, name);
+
+            if (shader.source != null) {
+                final String src = shader.source.replace("\r", "").replace("\n", "\\n\\\n")
+                        .replace("\"", "\\\"");
+                code.format("glShaderSource(%s, 1, (const GLchar *[]){\"%s\"}, NULL);CHKERR;\n",
+                                id, src);
+                code.format("glCompileShader(%s);CHKERR;\n", id);
+            }
+        }
+
+        for (int i = 0; i < serverShader.programs.size(); i++) {
+            final int name = serverShader.programs.keyAt(i);
+            final GLProgram program = serverShader.programs.valueAt(i);
+            final String id = "program_" + name;
+            if (programNames.indexOfKey(name) < 0) {
+                namesSource.format("GLuint %s = 0;\n", id);
+                namesHeader.format("extern GLuint %s;\n", id);
+            }
+            code.format("%s = glCreateProgram();CHKERR;\n", id);
+            programNames.put(name, name);
+            code.format("glAttachShader(%s, shader_%d);CHKERR;\n", id,
+                    program.vert);
+            code.format("glAttachShader(%s, shader_%d);CHKERR;\n", id,
+                    program.frag);
+            code.format("glLinkProgram(%s);CHKERR;\n", id);
+            if (serverShader.current == program)
+                code.format("glUseProgram(%s);CHKERR;\n", id);
+        }
+    }
+
+    private void codeGenServerTexture(final GLServerTexture serverTexture, final boolean replaceCopy) {
+        code.write("// CodeGenServerTexture\n");
+        for (int i = 0; i < serverTexture.textures.size(); i++) {
+            final int name = serverTexture.textures.keyAt(i);
+            final GLTexture tex = serverTexture.textures.valueAt(i);
+            final String id = "texture_" + name;
+            if (textureNames.indexOfKey(name) < 0) {
+                namesHeader.format("extern GLuint %s;\n", id);
+                namesSource.format("GLuint %s = 0;\n", id);
+            }
+            code.format("%s = 0;\n", id);
+            textureNames.put(name, name);
+
+            if (name == 0)
+                continue;
+            code.format("glGenTextures(1, &%s);CHKERR;\n", id);
+            String s = String.format("glBindTexture(%s, texture_%d);CHKERR;\n", tex.target,
+                    tex.name);
+            code.write(s);
+            for (final Message msg : tex.contentChanges) {
+                if (codeGenTextureUpload(msg, replaceCopy))
+                    continue;
+                switch (msg.getFunction()) {
+                    case glGenerateMipmap:
+                        s = MessageFormatter.format(msg, true);
+                        break;
+                    default:
+                        assert false;
+                }
+                code.write(s + ";\n");
+            }
+            code.format("glTexParameteriv(%s, GL_TEXTURE_WRAP_S, (GLint[]){%s});CHKERR;\n",
+                    tex.target, tex.wrapS);
+            code.format("glTexParameteriv(%s, GL_TEXTURE_WRAP_T, (GLint[]){%s});CHKERR;\n",
+                    tex.target, tex.wrapT);
+            code.format("glTexParameteriv(%s, GL_TEXTURE_MIN_FILTER, (GLint[]){%s});CHKERR;\n",
+                    tex.target, tex.min);
+            code.format("glTexParameteriv(%s, GL_TEXTURE_MAG_FILTER, (GLint[]){%s});CHKERR;\n",
+                    tex.target, tex.mag);
+        }
+        for (int i = 0; i < serverTexture.tmu2D.length; i++) {
+            code.format("glActiveTexture(%s);CHKERR;\n",
+                    GLEnum.valueOf(GLEnum.GL_TEXTURE0.value + i));
+            code.format("glBindTexture(GL_TEXTURE_2D, texture_%d);CHKERR;\n",
+                    serverTexture.tmu2D[i]);
+        }
+        for (int i = 0; i < serverTexture.tmuCube.length; i++) {
+            code.format("glActiveTexture(%s);CHKERR;\n",
+                    GLEnum.valueOf(GLEnum.GL_TEXTURE0.value + i));
+            code.format("glBindTexture(GL_TEXTURE_CUBE_MAP, texture_%d);CHKERR;\n",
+                    serverTexture.tmuCube[i]);
+        }
+        code.format("glActiveTexture(%s);CHKERR;\n", serverTexture.activeTexture);
+        if (serverTexture.tex2D == null)
+            code.format("glBindTexture(GL_TEXTURE_2D, 0);CHKERR;\n");
+        else
+            code.format("glBindTexture(GL_TEXTURE_2D, texture_%d);CHKERR;\n",
+                    serverTexture.tex2D.name);
+        if (serverTexture.texCube == null)
+            code.format("glBindTexture(GL_TEXTURE_CUBE_MAP, 0);CHKERR;\n");
+        else
+            code.format("glBindTexture(GL_TEXTURE_CUBE_MAP, texture_%d);CHKERR;\n",
+                    serverTexture.texCube.name);
+    }
+
+    private void codeGenBufferData(final ByteBuffer buffer, final String call) {
+        ByteBuffer bfr = buffer;
+        if (buffer.isReadOnly()) {
+            bfr = ByteBuffer.allocate(buffer.capacity());
+            bfr.put(buffer);
+        }
+        final byte[] data = bfr.array();
+        try {
+            code.write("{\n");
+            code.format("    void * bufferData = malloc(%d);\n", data.length);
+            code.format("    FILE * bufferFile = fopen(\"/sdcard/frame_data.bin\", \"rb\");\n");
+            code.format("    assert(bufferFile);\n");
+            code.format("    fseek(bufferFile, %d, SEEK_SET);\n", dataOut.getChannel()
+                    .position());
+            dataOut.write(data);
+            code.format("    fread(bufferData, %d, 1, bufferFile);\n", data.length);
+            code.format("    fclose(bufferFile);\n");
+            code.format("    " + call + ";CHKERR;\n");
+            code.format("    free(bufferData);\n");
+            code.format("}\n");
+        } catch (IOException e) {
+            e.printStackTrace();
+            assert false;
+        }
+    }
+
+    private void codeGenServerVertex(final GLServerVertex v) {
+        code.write("// CodeGenServerVertex\n");
+        for (int i = 0; i < v.buffers.size(); i++) {
+            final int name = v.buffers.keyAt(i);
+            final String id = "buffer_" + name;
+            final GLBuffer buffer = v.buffers.valueAt(i);
+            if (bufferNames.indexOfKey(name) < 0) {
+                namesHeader.format("extern GLuint %s;\n", id);
+                namesSource.format("GLuint %s = 0;\n", id);
+            }
+            code.format("%s = 0;\n", id);
+            bufferNames.put(name, name);
+            if (name == 0)
+                continue;
+            code.format("glGenBuffers(1, &%s);CHKERR;\n", id);
+            if (buffer.target != null) {
+                code.format("glBindBuffer(%s, %s);CHKERR;\n", buffer.target, id);
+                if (buffer.data != null) {
+                    String s = String.format("glBufferData(%s, %d, bufferData, %s)", buffer.target,
+                            buffer.data.capacity(), buffer.usage);
+                    codeGenBufferData(buffer.data, s);
+                }
+            }
+        }
+        // TODO: use MAX_VERTEX_ATTRIBS
+        for (int i = 0; i < v.defaultAttribs.length; i++)
+            code.format("glVertexAttrib4f(%d, %f, %f, %f, %f);CHKERR;\n", i,
+                    v.defaultAttribs[i][0],
+                    v.defaultAttribs[i][1], v.defaultAttribs[i][2], v.defaultAttribs[i][3]);
+        for (int i = 0; i < v.attribPointers.length; i++) {
+            final GLAttribPointer att = v.attribPointers[i];
+            if (att.type == null)
+                continue;
+            if (att.buffer != null)
+                code.format("glBindBuffer(GL_ARRAY_BUFFER, buffer_%d);CHKERR;\n", att.buffer.name);
+            else
+                code.format("glBindBuffer(GL_ARRAY_BUFFER, 0);CHKERR;\n");
+            code.format("glVertexAttribPointer(%d, %d, %s, %b, %d, (const GLvoid *)%d);CHKERR;\n",
+                    i, att.size, att.type, att.normalized, att.stride, att.ptr);
+        }
+        if (v.attribBuffer != null)
+            code.format("glBindBuffer(GL_ARRAY_BUFFER, buffer_%d);CHKERR;\n", v.attribBuffer.name);
+        else
+            code.write("glBindBuffer(GL_ARRAY_BUFFER, 0);CHKERR;\n");
+        if (v.indexBuffer != null)
+            code.format("glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_%d);CHKERR;\n",
+                    v.indexBuffer.name);
+        else
+            code.write("glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);CHKERR;\n");
+    }
+
+    private void codeGenGenNames(final Message msg) {
+        final ByteBuffer names = msg.getData().asReadOnlyByteBuffer();
+        names.order(SampleView.targetByteOrder);
+        SparseIntArray namesArray = null;
+        for (int i = 0; i < msg.getArg0(); i++) {
+            String id = "";
+            final int name = names.getInt();
+            switch (msg.getFunction()) {
+                case glGenBuffers:
+                    id = "buffer";
+                    namesArray = bufferNames;
+                    break;
+                case glGenFramebuffers:
+                    id = "framebuffer";
+                    namesArray = framebufferNames;
+                    break;
+                case glGenRenderbuffers:
+                    id = "renderbuffer";
+                    namesArray = renderbufferNames;
+                    break;
+                case glGenTextures:
+                    id = "texture";
+                    namesArray = textureNames;
+                    break;
+                default:
+                    assert false;
+            }
+            id += "_" + name;
+            if (namesArray.indexOfKey(name) < 0) {
+                namesHeader.format("extern GLuint %s;\n", id);
+                namesSource.format("GLuint %s = 0;\n", id);
+            }
+            code.format("%s = 0;\n", id);
+            namesArray.put(name, name);
+            code.format("%s(1, &%s);CHKERR;\n", msg.getFunction(), id);
+        }
+    }
+
+    private void codeGenDeleteNames(final Message msg) {
+        final ByteBuffer names = msg.getData().asReadOnlyByteBuffer();
+        names.order(SampleView.targetByteOrder);
+        SparseIntArray namesArray = null;
+        for (int i = 0; i < msg.getArg0(); i++) {
+            String id = null;
+            final int name = names.getInt();
+            switch (msg.getFunction()) {
+                case glDeleteBuffers:
+                    id = "buffer";
+                    namesArray = bufferNames;
+                    break;
+                case glDeleteFramebuffers:
+                    id = "framebuffer";
+                    namesArray = framebufferNames;
+                    break;
+                case glDeleteRenderbuffers:
+                    id = "renderbuffer";
+                    namesArray = renderbufferNames;
+                    break;
+                case glDeleteTextures:
+                    id = "texture";
+                    namesArray = textureNames;
+                    break;
+                default:
+                    assert false;
+            }
+            id += "_" + name;
+            code.format("%s = 0;\n", id);
+            namesArray.put(name, 0);
+            code.format("%s(1, &%s);CHKERR;\n", msg.getFunction(), id);
+        }
+    }
+
+    private void codeGenBindNames(final Message msg) {
+        String id = null;
+        SparseIntArray namesArray = null;
+        final int name = msg.getArg1();
+        switch (msg.getFunction()) {
+            case glBindBuffer:
+                id = "buffer";
+                namesArray = bufferNames;
+                break;
+            case glBindFramebuffer:
+                id = "framebuffer";
+                namesArray = framebufferNames;
+                break;
+            case glBindRenderbuffer:
+                id = "renderbuffer";
+                namesArray = renderbufferNames;
+                break;
+            case glBindTexture:
+                id = "texture";
+                namesArray = textureNames;
+                break;
+            default:
+                assert false;
+        }
+        id += "_" + name;
+        if (namesArray.indexOfKey(name) < 0) {
+            namesHeader.format("extern GLuint %s;\n", id);
+            namesSource.format("GLuint %s = 0;\n", id);
+        } else if (namesArray.get(name) != name)
+            code.format("%s = %d;\n", id, name); // name was deleted
+        namesArray.put(name, name);
+        code.write(MessageFormatter.format(msg, true));
+        code.write(";CHKERR;\n");
+    }
+
+    private void codeGenDrawArrays(final GLServerVertex v, final MessageData msgData)
+            throws IOException {
+        final int maxAttrib = msgData.msg.getArg7();
+        if (maxAttrib < 1) {
+            code.write("// no vertex data\n");
+            return;
+        }
+        final byte[] data = msgData.msg.getData().toByteArray();
+        final GLEnum mode = GLEnum.valueOf(msgData.msg.getArg0());
+        final int first = msgData.msg.getArg1(), count = msgData.msg.getArg2();
+        int attribDataStride = 0;
+        for (int i = 0; i < maxAttrib; i++) {
+            final GLAttribPointer att = v.attribPointers[i];
+            if (!att.enabled)
+                continue;
+            if (att.buffer != null)
+                continue;
+            attribDataStride += att.elemSize;
+        }
+        assert attribDataStride * count == data.length;
+        code.write("{\n");
+        if (attribDataStride > 0) {
+            code.format("    FILE * attribFile = fopen(\"/sdcard/frame_data.bin\", \"rb\");CHKERR;\n");
+            code.format("    assert(attribFile);CHKERR;\n");
+            code.format("    fseek(attribFile, %d, SEEK_SET);CHKERR;\n", dataOut.getChannel()
+                    .position());
+            dataOut.write(data);
+            code.format("    char * const attribData = (char *)malloc(%d);\n", first
+                    * attribDataStride + data.length);
+            code.format("    assert(attribData);\n");
+            code.format("    fread(attribData + %d, %d, 1, attribFile);\n",
+                    first * attribDataStride, data.length);
+            code.format("    fclose(attribFile);\n");
+            code.format("    glBindBuffer(GL_ARRAY_BUFFER, 0);CHKERR;\n");
+            int attribDataOffset = 0;
+            for (int i = 0; i < maxAttrib; i++) {
+                final GLAttribPointer att = v.attribPointers[i];
+                if (!att.enabled)
+                    continue;
+                if (att.buffer != null)
+                    continue;
+                code.format(
+                        "    glVertexAttribPointer(%d, %d, %s, %b, %d, attribData + %d);CHKERR;\n",
+                        i, att.size, att.type, att.normalized,
+                        attribDataStride, attribDataOffset);
+                attribDataOffset += att.elemSize;
+            }
+            if (v.attribBuffer != null)
+                code.format("    glBindBuffer(GL_ARRAY_BUFFER, %d);CHKERR;\n",
+                        v.attribBuffer.name);
+        }
+        code.format("    glDrawArrays(%s, %d, %d);CHKERR;\n", mode, first, count);
+        if (attribDataStride > 0)
+            code.format("    free(attribData);CHKERR;\n");
+        code.write("};\n");
+    }
+
+    private void codeGenDrawElements(final GLServerVertex v, final MessageData msgData)
+            throws IOException {
+        final int maxAttrib = msgData.msg.getArg7();
+        if (maxAttrib < 1) {
+            code.write("// no vertex data\n");
+            return;
+        }
+        final GLEnum mode = GLEnum.valueOf(msgData.msg.getArg0());
+        final int count = msgData.msg.getArg1();
+        final GLEnum type = GLEnum.valueOf(msgData.msg.getArg2());
+        String typeName = "GLubyte";
+        if (type == GLEnum.GL_UNSIGNED_SHORT)
+            typeName = "GLushort";
+        int attribDataStride = 0;
+        for (int i = 0; i < maxAttrib; i++) {
+            final GLAttribPointer att = v.attribPointers[i];
+            if (!att.enabled)
+                continue;
+            if (att.buffer != null)
+                continue;
+            attribDataStride += att.elemSize;
+        }
+        code.write("{\n");
+        if (v.indexBuffer == null || attribDataStride > 0) {
+            // need to load user pointer indices and/or attributes
+            final byte[] element = new byte[attribDataStride];
+            final ByteBuffer data = msgData.msg.getData().asReadOnlyByteBuffer();
+            data.order(SampleView.targetByteOrder);
+            final ByteBuffer indexData = ByteBuffer.allocate(count * GLServerVertex.typeSize(type));
+            indexData.order(SampleView.targetByteOrder);
+            final ByteBuffer attribData = ByteBuffer.allocate(count * attribDataStride);
+            attribData.order(SampleView.targetByteOrder);
+            int maxIndex = -1;
+            ByteBuffer indexSrc = data;
+            if (v.indexBuffer != null) {
+                indexSrc = v.indexBuffer.data;
+                indexSrc.position(msgData.msg.getArg3());
+            }
+            indexSrc.order(SampleView.targetByteOrder);
+            for (int i = 0; i < count; i++) {
+                int index = -1;
+                if (type == GLEnum.GL_UNSIGNED_BYTE) {
+                    byte idx = indexSrc.get();
+                    index = idx & 0xff;
+                    indexData.put(idx);
+                } else if (type == GLEnum.GL_UNSIGNED_SHORT) {
+                    short idx = indexSrc.getShort();
+                    index = idx & 0xffff;
+                    indexData.putShort(idx);
+                } else
+                    assert false;
+                data.get(element);
+                attribData.put(element);
+                if (index > maxIndex)
+                    maxIndex = index;
+            }
+            code.format("    FILE * attribFile = fopen(\"/sdcard/frame_data.bin\", \"rb\");CHKERR;\n");
+            code.format("    assert(attribFile);CHKERR;\n");
+            code.format("    fseek(attribFile, 0x%X, SEEK_SET);CHKERR;\n",
+                    dataOut.getChannel().position());
+            dataOut.write(indexData.array());
+            code.format("    %s * const indexData = (%s *)malloc(%d);\n", typeName, typeName,
+                    indexData.capacity());
+            code.format("    assert(indexData);\n");
+            code.format("    fread(indexData, %d, 1, attribFile);\n", indexData.capacity());
+            if (attribDataStride > 0) {
+                code.format("    glBindBuffer(GL_ARRAY_BUFFER, 0);CHKERR;\n");
+                for (int i = 0; i < maxAttrib; i++) {
+                    final GLAttribPointer att = v.attribPointers[i];
+                    if (!att.enabled)
+                        continue;
+                    if (att.buffer != null)
+                        continue;
+                    code.format("    char * const attrib%d = (char *)malloc(%d);\n",
+                            i, att.elemSize * (maxIndex + 1));
+                    code.format("    assert(attrib%d);\n", i);
+                    code.format(
+                            "    glVertexAttribPointer(%d, %d, %s, %b, %d, attrib%d);CHKERR;\n",
+                            i, att.size, att.type, att.normalized, att.elemSize, i);
+                }
+                dataOut.write(attribData.array());
+                code.format("    for (%s i = 0; i < %d; i++) {\n", typeName, count);
+                for (int i = 0; i < maxAttrib; i++) {
+                    final GLAttribPointer att = v.attribPointers[i];
+                    if (!att.enabled)
+                        continue;
+                    if (att.buffer != null)
+                        continue;
+                    code.format(
+                            "        fread(attrib%d + indexData[i] * %d, %d, 1, attribFile);\n",
+                            i, att.elemSize, att.elemSize);
+                }
+                code.format("    }\n");
+                if (v.attribBuffer != null)
+                    code.format("    glBindBuffer(GL_ARRAY_BUFFER, %d);CHKERR;\n",
+                            v.attribBuffer.name);
+            }
+            code.format("    fclose(attribFile);\n");
+        }
+        if (v.indexBuffer != null)
+            code.format("    glDrawElements(%s, %d, %s, (const void *)%d);CHKERR;\n",
+                    mode, count, type, msgData.msg.getArg3());
+        else {
+            code.format("    glDrawElements(%s, %d, %s, indexData);CHKERR;\n",
+                    mode, count, type);
+            code.format("    free(indexData);\n");
+        }
+        for (int i = 0; i < maxAttrib; i++) {
+            final GLAttribPointer att = v.attribPointers[i];
+            if (!att.enabled)
+                continue;
+            if (att.buffer != null)
+                continue;
+            code.format("    free(attrib%d);\n", i);
+        }
+        code.write("};\n");
+    }
+
+    private void codeGenDraw(final GLServerVertex v, final MessageData msgData)
+            throws IOException {
+        final int maxAttrib = msgData.msg.getArg7();
+        if (maxAttrib < 1) {
+            code.write("// no vertex data\n");
+            return;
+        }
+        final int count = msgData.attribs[0].length / 4;
+        final GLEnum mode = GLEnum.valueOf(msgData.msg.getArg0());
+        final ByteBuffer attribData = ByteBuffer.allocate(maxAttrib * count * 16);
+        attribData.order(SampleView.targetByteOrder);
+        for (int i = 0; i < count; i++)
+            for (int j = 0; j < maxAttrib; j++)
+                for (int k = 0; k < 4; k++)
+                    attribData.putFloat(msgData.attribs[j][i * 4 + k]);
+        assert attribData.remaining() == 0;
+        code.write("{\n");
+        code.format("    FILE * attribFile = fopen(\"/sdcard/frame_data.bin\", \"rb\");CHKERR;\n");
+        code.format("    assert(attribFile);CHKERR;\n");
+        code.format("    fseek(attribFile, 0x%X, SEEK_SET);CHKERR;\n",
+                dataOut.getChannel().position());
+        dataOut.write(attribData.array());
+        code.format("    char * const attribData = (char *)malloc(%d);\n", attribData.capacity());
+        code.format("    assert(attribData);\n");
+        code.format("    fread(attribData, %d, 1, attribFile);\n", attribData.capacity());
+        code.format("    fclose(attribFile);\n");
+        code.format("    glBindBuffer(GL_ARRAY_BUFFER, 0);CHKERR;\n");
+        for (int i = 0; i < maxAttrib; i++) {
+            final GLAttribPointer att = v.attribPointers[i];
+            assert msgData.attribs[i].length == count * 4;
+            code.format(
+                    "    glVertexAttribPointer(%d, %d, GL_FLOAT, GL_FALSE, %d, attribData + %d);CHKERR;\n",
+                        i, att.size, maxAttrib * 16, i * 16);
+        }
+        code.format("    glDrawArrays(%s, 0, %d);CHKERR;\n", mode, count);
+        code.format("    free(attribData);\n");
+        if (v.attribBuffer != null)
+            code.format("    glBindBuffer(GL_ARRAY_BUFFER, %d);CHKERR;\n",
+                        v.attribBuffer.name);
+        code.write("};\n");
+    }
+
+    private void codeGenFunction(final Context ctx, final MessageData msgData)
+            throws IOException {
+        final Message msg = msgData.msg;
+        String call = MessageFormatter.format(msg, true);
+        switch (msg.getFunction()) {
+            case glActiveTexture:
+            case glAttachShader:
+            case glBindAttribLocation:
+                break;
+            case glBindBuffer:
+            case glBindFramebuffer:
+            case glBindRenderbuffer:
+            case glBindTexture:
+                codeGenBindNames(msg);
+                return;
+            case glBlendColor:
+            case glBlendEquation:
+            case glBlendEquationSeparate:
+            case glBlendFunc:
+            case glBlendFuncSeparate:
+                break;
+            case glBufferData:
+                call = MessageFormatter.format(msg, true).replace("arg2", "bufferData");
+                codeGenBufferData(msg.getData().asReadOnlyByteBuffer(), call);
+                return;
+            case glBufferSubData:
+                call = MessageFormatter.format(msg, true).replace("arg3", "bufferData");
+                codeGenBufferData(msg.getData().asReadOnlyByteBuffer(), call);
+                return;
+            case glCheckFramebufferStatus:
+            case glClear:
+            case glClearColor:
+            case glClearDepthf:
+            case glClearStencil:
+            case glColorMask:
+            case glCompileShader:
+                break;
+            case glCompressedTexImage2D:
+            case glCompressedTexSubImage2D:
+            case glCopyTexImage2D:
+            case glCopyTexSubImage2D:
+                codeGenTextureUpload(msg, false);
+                return;
+            case glCreateProgram:
+                namesHeader.format("extern GLuint program_%d;\n", msg.getRet());
+                namesSource.format("GLuint program_%d = 0;\n", msg.getRet());
+                code.format("program_%d = glCreateProgram();CHKERR;\n", msg.getRet());
+                return;
+            case glCreateShader:
+                namesHeader.format("extern GLuint shader_%d;\n", msg.getRet());
+                namesSource.format("GLuint shader_%d = 0;\n", msg.getRet());
+                code.format("shader_%d = %s;\n", msg.getRet(), call);
+                return;
+            case glCullFace:
+                break;
+            case glDeleteBuffers:
+            case glDeleteFramebuffers:
+            case glDeleteProgram:
+                programNames.put(msg.getArg0(), 0);
+                break;
+            case glDeleteRenderbuffers:
+                codeGenDeleteNames(msg);
+                return;
+            case glDeleteShader:
+                shaderNames.put(msg.getArg0(), 0);
+                return;
+            case glDeleteTextures:
+                codeGenDeleteNames(msg);
+                return;
+            case glDepthFunc:
+            case glDepthMask:
+            case glDepthRangef:
+            case glDetachShader:
+            case glDisable:
+            case glDisableVertexAttribArray:
+                break;
+            case glDrawArrays:
+                // CodeGenDraw(ctx.serverVertex, msgData);
+                codeGenDrawArrays(ctx.serverVertex, msgData);
+                return;
+            case glDrawElements:
+                // CodeGenDraw(ctx.serverVertex, msgData);
+                codeGenDrawElements(ctx.serverVertex, msgData);
+                return;
+            case glEnable:
+            case glEnableVertexAttribArray:
+            case glFinish:
+            case glFlush:
+            case glFramebufferRenderbuffer:
+            case glFramebufferTexture2D:
+            case glFrontFace:
+                break;
+            case glGenBuffers:
+                codeGenGenNames(msg);
+                return;
+            case glGenerateMipmap:
+                break;
+            case glGenFramebuffers:
+            case glGenRenderbuffers:
+            case glGenTextures:
+                codeGenGenNames(msg);
+                return;
+            case glGetActiveAttrib:
+            case glGetActiveUniform:
+            case glGetAttachedShaders:
+                break;
+            case glGetAttribLocation:
+                call = String.format("assert(%d == %s)", msg.getRet(), call);
+                break;
+            case glGetBooleanv:
+            case glGetBufferParameteriv:
+                return; // TODO
+            case glGetError:
+                code.write("CHKERR;\n");
+                return;
+            case glGetFloatv:
+            case glGetFramebufferAttachmentParameteriv:
+            case glGetIntegerv:
+            case glGetProgramiv:
+            case glGetProgramInfoLog:
+            case glGetRenderbufferParameteriv:
+            case glGetShaderiv:
+            case glGetShaderInfoLog:
+            case glGetShaderPrecisionFormat:
+            case glGetShaderSource:
+            case glGetString:
+            case glGetTexParameterfv:
+            case glGetTexParameteriv:
+            case glGetUniformfv:
+            case glGetUniformiv:
+                return;
+            case glGetUniformLocation:
+                call = String.format("assert(%d == %s)", msg.getRet(), call);
+                break;
+            case glGetVertexAttribfv:
+            case glGetVertexAttribiv:
+            case glGetVertexAttribPointerv:
+                return; // TODO
+            case glHint:
+            case glIsBuffer:
+            case glIsEnabled:
+            case glIsFramebuffer:
+            case glIsProgram:
+            case glIsRenderbuffer:
+            case glIsShader:
+            case glIsTexture:
+            case glLineWidth:
+            case glLinkProgram:
+            case glPixelStorei:
+            case glPolygonOffset:
+                break;
+            case glReadPixels:
+                return; // TODO
+            case glReleaseShaderCompiler:
+            case glRenderbufferStorage:
+            case glSampleCoverage:
+            case glScissor:
+                break;
+            case glShaderBinary:
+                return; // TODO
+            case glShaderSource:
+                call = String.format(
+                        "glShaderSource(shader_%d, 1, (const char * []){\"%s\"}, NULL)",
+                        msg.getArg0(),
+                        msg.getData().toStringUtf8().replace("\r", "").replace("\n", "\\n\\\n")
+                                .replace("\"", "\\\"")
+                                );
+                break;
+            case glStencilFunc:
+            case glStencilFuncSeparate:
+            case glStencilMask:
+            case glStencilMaskSeparate:
+            case glStencilOp:
+            case glStencilOpSeparate:
+                break;
+            case glTexImage2D:
+                codeGenTextureUpload(msg, false);
+                return;
+            case glTexParameterf:
+                break;
+            case glTexParameterfv:
+                return; // TODO
+            case glTexParameteri:
+                break;
+            case glTexParameteriv:
+                return; // TODO
+            case glTexSubImage2D:
+                codeGenTextureUpload(msg, false);
+                return;
+            case glUniform1f:
+            case glUniform1fv:
+            case glUniform1i:
+            case glUniform1iv:
+            case glUniform2f:
+            case glUniform2fv:
+            case glUniform2i:
+            case glUniform2iv:
+            case glUniform3f:
+            case glUniform3fv:
+            case glUniform3i:
+            case glUniform3iv:
+            case glUniform4f:
+            case glUniform4fv:
+            case glUniform4i:
+            case glUniform4iv:
+            case glUniformMatrix2fv:
+            case glUniformMatrix3fv:
+            case glUniformMatrix4fv:
+            case glUseProgram:
+            case glValidateProgram:
+            case glVertexAttrib1f:
+            case glVertexAttrib1fv:
+            case glVertexAttrib2f:
+            case glVertexAttrib2fv:
+            case glVertexAttrib3f:
+            case glVertexAttrib3fv:
+            case glVertexAttrib4f:
+            case glVertexAttrib4fv:
+                break;
+            case glVertexAttribPointer:
+                // if it's user pointer, then CodeGenDrawArrays/Elements will
+                // replace it with loaded data just before the draw
+                call = call.replace("arg5", "(const void *)0x" +
+                        Integer.toHexString(msg.getArg5()));
+                break;
+            case glViewport:
+                break;
+            case eglSwapBuffers:
+                return;
+            default:
+                assert false;
+                return;
+        }
+        if (call.indexOf("glEnable(/*cap*/ GL_TEXTURE_2D)") >= 0)
+            return;
+        else if (call.indexOf("glDisable(/*cap*/ GL_TEXTURE_2D)") >= 0)
+            return;
+        else if (call.indexOf("glActiveTexture(/*texture*/ GL_TEXTURE_2D)") >= 0)
+            return;
+        code.write(call + ";CHKERR;\n");
+    }
+
+    private void codeGenSetup(final Context ctx) {
+        try {
+            codeFile = new FileWriter("frame_setup.cpp", false);
+            code = new PrintWriter(codeFile);
+            dataOut = new FileOutputStream("frame_data.bin", false);
+            namesHeaderFile = new FileWriter("frame_names.h", false);
+            namesHeader = new PrintWriter(namesHeaderFile);
+            namesSourceFile = new FileWriter("frame_names.cpp", false);
+            namesSource = new PrintWriter(namesSourceFile);
+        } catch (IOException e) {
+            e.printStackTrace();
+            assert false;
+        }
+        bufferNames = new SparseIntArray();
+        framebufferNames = new SparseIntArray();
+        programNames = new SparseIntArray();
+        textureNames = new SparseIntArray();
+        shaderNames = new SparseIntArray();
+        renderbufferNames = new SparseIntArray();
+
+        namesHeader.write("#include <stdlib.h>\n");
+        namesHeader.write("#include <stdio.h>\n");
+        namesHeader.write("#include <assert.h>\n");
+        namesHeader.write("#include <GLES2/gl2.h>\n");
+        namesHeader.write("#include <GLES2/gl2ext.h>\n");
+        namesHeader.write("#define CHKERR assert(GL_NO_ERROR == glGetError());/**/\n");
+        namesHeader.write("void FrameSetup();\n");
+        namesHeader.write("extern const unsigned int FrameCount;\n");
+        namesHeader.write("extern const GLuint program_0;\n");
+
+        namesSource.write("/*\n" + 
+        " * Copyright (C) 2011 The Android Open Source Project\n" + 
+        " *\n" + 
+        " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" + 
+        " * you may not use this file except in compliance with the License.\n" + 
+        " * You may obtain a copy of the License at\n" + 
+        " *\n" + 
+        " *      http://www.apache.org/licenses/LICENSE-2.0\n" + 
+        " *\n" + 
+        " * Unless required by applicable law or agreed to in writing, software\n" + 
+        " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" + 
+        " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" + 
+        " * See the License for the specific language governing permissions and\n" + 
+        " * limitations under the License.\n" + 
+        " */\n" + 
+        "\n" + 
+        "#include <stdlib.h>\n" + 
+        "#include <stdio.h>\n" + 
+        "\n" + 
+        "#include <EGL/egl.h>\n" + 
+        "#include <GLES2/gl2.h>\n" + 
+        "#include <GLES2/gl2ext.h>\n" + 
+        "\n" + 
+        "#include <ui/FramebufferNativeWindow.h>\n" + 
+        "#include <ui/EGLUtils.h>\n" + 
+        "\n" + 
+        "#include <private/ui/android_natives_priv.h>\n" + 
+        "\n" + 
+        "#include <surfaceflinger/Surface.h>\n" + 
+        "#include <surfaceflinger/ISurface.h>\n" + 
+        "#include <surfaceflinger/SurfaceComposerClient.h>\n" + 
+        "\n" + 
+        "using namespace android;\n" + 
+        "\n" + 
+        "static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE)\n" + 
+        "{\n" + 
+        "    if (returnVal != EGL_TRUE) {\n" + 
+        "        fprintf(stderr, \"%s() returned %d\\n\", op, returnVal);\n" + 
+        "    }\n" + 
+        "\n" + 
+        "    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error\n" + 
+        "            = eglGetError()) {\n" + 
+        "        fprintf(stderr, \"after %s() eglError %s (0x%x)\\n\", op, EGLUtils::strerror(error),\n" + 
+        "                error);\n" + 
+        "    }\n" + 
+        "}\n" + 
+        "\n" + 
+        "static EGLDisplay dpy;\n" + 
+        "static EGLSurface surface;\n" + 
+        "\n" + 
+        "#include \"frame_names.h\"\n" + 
+        "const GLuint program_0 = 0;\n" + 
+        "int main(int argc, char** argv)\n" + 
+        "{\n" + 
+        "    EGLBoolean returnValue;\n" + 
+        "    EGLConfig myConfig = {0};\n" + 
+        "\n" + 
+        "    EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };\n" + 
+        "    EGLint majorVersion;\n" + 
+        "    EGLint minorVersion;\n" + 
+        "    EGLContext context;\n" + 
+        "    EGLint w, h;\n" + 
+        "\n" + 
+        "\n" + 
+        "    checkEglError(\"<init>\");\n" + 
+        "    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);\n" + 
+        "    checkEglError(\"eglGetDisplay\");\n" + 
+        "    if (dpy == EGL_NO_DISPLAY) {\n" + 
+        "        printf(\"eglGetDisplay returned EGL_NO_DISPLAY.\\n\");\n" + 
+        "        return 0;\n" + 
+        "    }\n" + 
+        "\n" + 
+        "    returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);\n" + 
+        "    checkEglError(\"eglInitialize\", returnValue);\n" + 
+        "    if (returnValue != EGL_TRUE) {\n" + 
+        "        printf(\"eglInitialize failed\\n\");\n" + 
+        "        return 0;\n" + 
+        "    }\n" + 
+        "\n" + 
+        "    sp<SurfaceComposerClient> spClient;\n" + 
+        "    sp<SurfaceControl> spControl;\n" + 
+        "    sp<Surface> spSurface;\n" + 
+        "\n" + 
+        "    // create a client to surfaceflinger\n" + 
+        "    spClient = new SurfaceComposerClient();\n" + 
+        "\n" + 
+        "    spControl = spClient->createSurface(getpid(), 0, 1280, 752, PIXEL_FORMAT_RGBX_8888);\n" + 
+        "    spClient->openTransaction();\n" + 
+        "    spControl->setLayer(350000);\n" + 
+        "    spControl->show();\n" + 
+        "    spClient->closeTransaction();\n" + 
+        "\n" + 
+        "    spSurface = spControl->getSurface();\n" + 
+        "    EGLNativeWindowType window = spSurface.get();\n" + 
+        "\n" + 
+        "    printf(\"window=%p\\n\", window);\n" + 
+        "    EGLint attrib_list[] = {\n" + 
+        "        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,\n" + 
+        "        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,\n" + 
+        "        EGL_BUFFER_SIZE, 32,\n" + 
+        "        EGL_RED_SIZE, 8,\n" + 
+        "        EGL_GREEN_SIZE, 8,\n" + 
+        "        EGL_BLUE_SIZE, 8,\n" + 
+        "        EGL_NONE\n" + 
+        "    };\n" + 
+        "\n" + 
+        "    EGLConfig configs[12] = {0};\n" + 
+        "    int num_config = -1;\n" + 
+        "    eglChooseConfig(dpy, attrib_list, configs, sizeof(configs) / sizeof(*configs), &num_config);\n" + 
+        "    printf(\"eglChooseConfig %d \\n\", num_config);\n" + 
+        "\n" + 
+        "    surface = eglCreateWindowSurface(dpy, configs[0], window, NULL);\n" + 
+        "    checkEglError(\"eglCreateWindowSurface\");\n" + 
+        "    if (surface == EGL_NO_SURFACE) {\n" + 
+        "        printf(\"gelCreateWindowSurface failed.\\n\");\n" + 
+        "        return 0;\n" + 
+        "    }\n" + 
+        "\n" + 
+        "    context = eglCreateContext(dpy, configs[0], EGL_NO_CONTEXT, context_attribs);\n" + 
+        "    checkEglError(\"eglCreateContext\");\n" + 
+        "    if (context == EGL_NO_CONTEXT) {\n" + 
+        "        printf(\"eglCreateContext failed\\n\");\n" + 
+        "        return 0;\n" + 
+        "    }\n" + 
+        "    printf(\"context=%p \\n\", context);\n" + 
+        "\n" + 
+        "    returnValue = eglMakeCurrent(dpy, surface, surface, context);\n" + 
+        "    checkEglError(\"eglMakeCurrent\", returnValue);\n" + 
+        "    if (returnValue != EGL_TRUE) {\n" + 
+        "        return 0;\n" + 
+        "    }\n" + 
+        "\n" + 
+        "    glClearColor(1,1,1,1);\n" + 
+        "    glClear(GL_COLOR_BUFFER_BIT);\n" + 
+        "\n" + 
+        "    FrameSetup();\n" + 
+        "    while (true)\n" + 
+        "        for (unsigned int i = 0; i < FrameCount; i++) {\n" + 
+        "            Frames[i]();\n" + 
+        "            eglSwapBuffers(dpy, surface);\n" + 
+        "            printf(\"press ENTER after Frame%d \\n\", i);\n" + 
+        "            getchar();\n" + 
+        "        }\n" + 
+        "\n" + 
+        "    return 0;\n" + 
+        "}");
+
+        code.write("#include \"frame_names.h\"\n");
+        code.write("void FrameSetup(){\n");
+
+        codeGenServerState(ctx.serverState);
+        codeGenServerShader(ctx.serverShader);
+        codeGenServerTexture(ctx.serverTexture, true);
+        codeGenServerVertex(ctx.serverVertex);
+
+        code.write("}\n");
+
+        try {
+            codeFile.close();
+            makeFile = new FileWriter("Android.mk", false);
+            make = new PrintWriter(makeFile);
+            make.write("LOCAL_PATH:= $(call my-dir)\n" +
+                    "include $(CLEAR_VARS)\n" +
+                    "LOCAL_SRC_FILES := \\\n");
+        } catch (IOException e) {
+            e.printStackTrace();
+            assert false;
+        }
+    }
+
+    private void codeGenCleanup() {
+        make.write("    frame_setup.cpp \\\n");
+        make.write("    frame_names.cpp \\\n");
+        make.write("#\n");
+        make.write(
+                "LOCAL_SHARED_LIBRARIES := \\\n" + 
+                "    libcutils \\\n" + 
+                "    libutils \\\n" + 
+                "    libEGL \\\n" + 
+                "    libGLESv2 \\\n" + 
+                "    libui \\\n" + 
+                "    libhardware \\\n" + 
+                "    libgui\n" + 
+                "\n" + 
+                "LOCAL_MODULE:= gles2dbg\n" + 
+                "\n" + 
+                "LOCAL_MODULE_TAGS := optional\n" + 
+                "\n" + 
+                "LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -O0 -g -DDEBUG -UNDEBUG\n" + 
+                "\n" + 
+                "include $(BUILD_EXECUTABLE)");
+        try {
+            dataOut.flush();
+            dataOut.close();
+            codeFile.close();
+            makeFile.close();
+            namesHeaderFile.close();
+            namesSourceFile.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+            assert false;
+        }
+        dataOut = null;
+        code = null;
+        codeFile = null;
+        make = null;
+        makeFile = null;
+
+        bufferNames = null;
+        framebufferNames = null;
+        programNames = null;
+        textureNames = null;
+        shaderNames = null;
+        renderbufferNames = null;
+    }
+
+    private DebugContext dbgCtx;
+    private int count;
+    private IProgressMonitor progress;
+
+    @Override
+    public void run(IProgressMonitor monitor) {
+        progress.beginTask("CodeGenFrames", count + 2);
+        Context ctx = dbgCtx.getFrame(0).startContext.clone();
+        codeGenSetup(ctx);
+        progress.worked(1);
+        for (int i = 0; i < count; i++) {
+            try {
+                codeFile = new FileWriter("frame" + i + ".cpp", false);
+                code = new PrintWriter(codeFile);
+            } catch (IOException e1) {
+                e1.printStackTrace();
+                assert false;
+            }
+            make.format("    frame%d.cpp \\\n", i);
+
+            code.write("#include \"frame_names.h\"\n");
+            code.format("void Frame%d(){\n", i);
+            final Frame frame = dbgCtx.getFrame(i);
+            for (int j = 0; j < frame.size(); j++) {
+                final MessageData msgData = frame.get(j);
+                code.format("/* frame function %d: %s %s*/\n", j, msgData.msg.getFunction(),
+                        MessageFormatter.format(msgData.msg, false));
+                ctx.processMessage(msgData.msg);
+                try {
+                    codeGenFunction(ctx, msgData);
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    assert false;
+                }
+            }
+            code.write("}\n");
+            try {
+                codeFile.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+                assert false;
+            }
+            progress.worked(1);
+        }
+        for (int i = 0; i < count; i++)
+            namesHeader.format("void Frame%d();\n", i);
+        namesHeader.format("extern void (* Frames[%d])();\n", count);
+        namesSource.format("void (* Frames[%d])() = {\n", count);
+        for (int i = 0; i < count; i++) {
+            namesSource.format("    Frame%d,\n", i);
+        }
+        namesSource.write("};\n");
+        namesSource.format("const unsigned int FrameCount = %d;\n", count);
+        codeGenCleanup();
+        progress.worked(1);
+    }
+
+    void codeGenFrames(final DebugContext dbgCtx, int count, final Shell shell) {
+        this.dbgCtx = dbgCtx;
+        this.count = count;
+        ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
+        this.progress = dialog.getProgressMonitor();
+        try {
+            dialog.run(false, true, this);
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+            assert false;
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        this.dbgCtx = null;
+        this.count = 0;
+        progress = null;
+    }
+
+    void codeGenFrame(final Frame frame) {
+        Context ctx = frame.startContext.clone();
+        codeGenSetup(ctx);
+        try {
+            codeFile = new FileWriter("frame0.cpp", false);
+            code = new PrintWriter(codeFile);
+        } catch (IOException e1) {
+            e1.printStackTrace();
+            assert false;
+        }
+        make.format("    frame0.cpp \\\n");
+        code.write("#include \"frame_names.h\"\n");
+        code.format("void Frame0(){\n");
+        for (int i = 0; i < frame.size(); i++) {
+            final MessageData msgData = frame.get(i);
+            code.format("/* frame function %d: %s %s*/\n", i, msgData.msg.getFunction(),
+                    MessageFormatter.format(msgData.msg, false));
+            ctx.processMessage(msgData.msg);
+            try {
+                codeGenFunction(ctx, msgData);
+            } catch (IOException e) {
+                e.printStackTrace();
+                assert false;
+            }
+        }
+        code.write("}\n");
+        namesHeader.write("void Frame0();\n");
+        namesHeader.write("extern void (* Frames[1])();\n");
+        namesSource.write("void (* Frames[1])() = {Frame0};\n");
+        namesSource.write("const unsigned int FrameCount = 1;\n");
+        codeGenCleanup();
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java b/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java
new file mode 100644
index 0000000..122695b
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java
@@ -0,0 +1,532 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.DataType;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.android.glesv2debugger.DebuggerMessage.Message.Prop;
+import com.android.sdklib.util.SparseArray;
+import com.android.sdklib.util.SparseIntArray;
+import com.google.protobuf.ByteString;
+
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+class Frame {
+    public final long filePosition;
+    private int callsCount;
+
+    final Context startContext;
+    private ArrayList<MessageData> calls = new ArrayList<MessageData>();
+
+    Frame(final Context context, final long filePosition) {
+        this.startContext = context.clone();
+        this.filePosition = filePosition;
+    }
+
+    void add(final MessageData msgData) {
+        calls.add(msgData);
+    }
+
+    void increaseCallsCount() {
+        callsCount++;
+    }
+
+    Context computeContext(final MessageData call) {
+        Context ctx = startContext.clone();
+        for (int i = 0; i < calls.size(); i++)
+            if (call == calls.get(i))
+                return ctx;
+            else
+                ctx.processMessage(calls.get(i).msg);
+        assert false;
+        return ctx;
+    }
+
+    int size() {
+        return callsCount;
+    }
+
+    MessageData get(final int i) {
+        return calls.get(i);
+    }
+
+    ArrayList<MessageData> get() {
+        return calls;
+    }
+
+    void unload() {
+        if (calls == null)
+            return;
+        calls.clear();
+        calls = null;
+    }
+
+    void load(final RandomAccessFile file) {
+        if (calls != null && calls.size() == callsCount)
+            return;
+        try {
+            Context ctx = startContext.clone();
+            calls = new ArrayList<MessageData>(callsCount);
+            final long oriPosition = file.getFilePointer();
+            file.seek(filePosition);
+            for (int i = 0; i < callsCount; i++) {
+                int len = file.readInt();
+                if (SampleView.targetByteOrder == ByteOrder.LITTLE_ENDIAN)
+                    len = Integer.reverseBytes(len);
+                final byte[] data = new byte[len];
+                file.read(data);
+                Message msg = Message.parseFrom(data);
+                ctx.processMessage(msg);
+                final MessageData msgData = new MessageData(Display.getCurrent(), msg, ctx);
+                calls.add(msgData);
+            }
+            file.seek(oriPosition);
+        } catch (IOException e) {
+            e.printStackTrace();
+            assert false;
+        }
+    }
+}
+
+class DebugContext {
+    boolean uiUpdate = false;
+    final int contextId;
+    Context currentContext;
+    private ArrayList<Frame> frames = new ArrayList<Frame>(128);
+    private Frame lastFrame;
+    private Frame loadedFrame;
+    private RandomAccessFile file;
+
+    DebugContext(final int contextId) {
+        this.contextId = contextId;
+        currentContext = new Context(contextId);
+        try {
+            file = new RandomAccessFile("0x" + Integer.toHexString(contextId) +
+                    ".gles2dbg", "rw");
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+            assert false;
+        }
+    }
+
+    /** write message to file; if frame not null, then increase its call count */
+    void saveMessage(final Message msg, final RandomAccessFile file, Frame frame) {
+        synchronized (file) {
+            if (frame != null)
+                frame.increaseCallsCount();
+            final byte[] data = msg.toByteArray();
+            final ByteBuffer len = ByteBuffer.allocate(4);
+            len.order(SampleView.targetByteOrder);
+            len.putInt(data.length);
+            try {
+                if (SampleView.targetByteOrder == ByteOrder.BIG_ENDIAN)
+                    file.writeInt(data.length);
+                else
+                    file.writeInt(Integer.reverseBytes(data.length));
+                file.write(data);
+            } catch (IOException e) {
+                e.printStackTrace();
+                assert false;
+            }
+        }
+    }
+
+    /**
+     * Caches new Message, and formats into MessageData for current frame; this
+     * function is called exactly once for each new Message
+     */
+    void processMessage(final Message newMsg) {
+        Message msg = newMsg;
+        if (msg.getFunction() == Function.SETPROP) {
+            // GL impl. consts should have been sent before any GL call messages
+            assert frames.size() == 0;
+            assert lastFrame == null;
+            assert msg.getProp() == Prop.GLConstant;
+            switch (GLEnum.valueOf(msg.getArg0())) {
+                case GL_MAX_VERTEX_ATTRIBS:
+                    currentContext.serverVertex = new GLServerVertex(msg.getArg1());
+                    break;
+                case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+                    currentContext.serverTexture = new GLServerTexture(currentContext,
+                            msg.getArg1());
+                    break;
+                default:
+                    assert false;
+                    return;
+            }
+            saveMessage(msg, file, null);
+            return;
+        }
+
+        if (lastFrame == null) {
+            // first real message after the GL impl. consts
+            synchronized (file) {
+                try {
+                    lastFrame = new Frame(currentContext, file.getFilePointer());
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    assert false;
+                }
+            }
+            synchronized (frames) {
+                frames.add(lastFrame);
+            }
+            assert loadedFrame == null;
+            loadedFrame = lastFrame;
+        }
+        currentContext.processMessage(msg);
+        if (msg.hasDataType() && msg.getDataType() == DataType.ReferencedImage) {
+            // decode referenced image so it doesn't rely on context later on
+            final byte[] referenced = MessageProcessor.lzfDecompressChunks(msg.getData());
+            currentContext.readPixelRef = MessageProcessor.decodeReferencedImage(
+                        currentContext.readPixelRef, referenced);
+            final byte[] decoded = MessageProcessor.lzfCompressChunks(
+                        currentContext.readPixelRef, referenced.length);
+            msg = msg.toBuilder().setDataType(DataType.NonreferencedImage)
+                        .setData(ByteString.copyFrom(decoded)).build();
+        }
+        saveMessage(msg, file, lastFrame);
+        if (loadedFrame == lastFrame) {
+            // frame selected for view, so format MessageData
+            final MessageData msgData = new MessageData(Display.getCurrent(), msg, currentContext);
+            lastFrame.add(msgData);
+            uiUpdate = true;
+        }
+        if (msg.getFunction() != Function.eglSwapBuffers)
+            return;
+        synchronized (frames) {
+            if (loadedFrame != lastFrame)
+                lastFrame.unload();
+            try {
+                frames.add(lastFrame = new Frame(currentContext, file.getFilePointer()));
+                // file.getChannel().force(false);
+                uiUpdate = true;
+            } catch (IOException e) {
+                e.printStackTrace();
+                assert false;
+            }
+        }
+        return;
+    }
+
+    Frame getFrame(int index) {
+        synchronized (frames) {
+            Frame newFrame = frames.get(index);
+            if (loadedFrame != null && loadedFrame != lastFrame && newFrame != loadedFrame) {
+                loadedFrame.unload();
+                uiUpdate = true;
+            }
+            loadedFrame = newFrame;
+            synchronized (file) {
+                loadedFrame.load(file);
+            }
+            return loadedFrame;
+        }
+    }
+
+    int frameCount() {
+        synchronized (frames) {
+            return frames.size();
+        }
+    }
+}
+
+/** aggregate of GL states */
+public class Context implements Cloneable {
+    public final int contextId;
+    public ArrayList<Context> shares = new ArrayList<Context>(); // self too
+    public GLServerVertex serverVertex;
+    public GLServerShader serverShader = new GLServerShader(this);
+    public GLServerState serverState = new GLServerState(this);
+    public GLServerTexture serverTexture;
+
+    byte[] readPixelRef = new byte[0];
+
+    public Context(int contextId) {
+        this.contextId = contextId;
+        shares.add(this);
+    }
+
+    @Override
+    public Context clone() {
+        try {
+            Context copy = (Context) super.clone();
+            // FIXME: context sharing list clone
+            copy.shares = new ArrayList<Context>(1);
+            copy.shares.add(copy);
+            if (serverVertex != null)
+                copy.serverVertex = serverVertex.clone();
+            copy.serverShader = serverShader.clone(copy);
+            copy.serverState = serverState.clone();
+            if (serverTexture != null)
+                copy.serverTexture = serverTexture.clone(copy);
+            // don't need to clone readPixelsRef, since referenced images
+            // are decoded when they are encountered
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            assert false;
+            return null;
+        }
+    }
+
+    /** mainly updating states */
+    public void processMessage(Message msg) {
+        if (serverVertex.process(msg))
+            return;
+        if (serverShader.processMessage(msg))
+            return;
+        if (serverState.processMessage(msg))
+            return;
+        if (serverTexture.processMessage(msg))
+            return;
+    }
+}
+
+class ContextViewProvider extends LabelProvider implements ITreeContentProvider,
+        ISelectionChangedListener {
+    Context context;
+    final SampleView sampleView;
+
+    ContextViewProvider(final SampleView sampleView) {
+        this.sampleView = sampleView;
+    }
+
+    @Override
+    public void dispose() {
+    }
+
+    @Override
+    public String getText(Object obj) {
+        if (obj == null)
+            return "null";
+        if (obj instanceof Entry) {
+            Entry entry = (Entry) obj;
+            String objStr = "null (or default)";
+            if (entry.obj != null) {
+                objStr = entry.obj.toString();
+                if (entry.obj instanceof Message)
+                    objStr = MessageFormatter.format((Message) entry.obj, false);
+            }
+            return entry.name + " = " + objStr;
+        }
+        return obj.toString();
+    }
+
+    @Override
+    public Image getImage(Object obj) {
+        if (!(obj instanceof Entry))
+            return null;
+        final Entry entry = (Entry) obj;
+        if (!(entry.obj instanceof Message))
+            return null;
+        final Message msg = (Message) entry.obj;
+        switch (msg.getFunction()) {
+            case glTexImage2D:
+            case glTexSubImage2D:
+            case glCopyTexImage2D:
+            case glCopyTexSubImage2D: {
+                entry.image = new MessageData(Display.getCurrent(), msg, null).getImage();
+                if (entry.image == null)
+                    return null;
+                return new Image(Display.getCurrent(), entry.image.getImageData().scaledTo(96, 96));
+            }
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public void selectionChanged(SelectionChangedEvent event) {
+        StructuredSelection selection = (StructuredSelection) event
+                .getSelection();
+        if (null == selection)
+            return;
+        final Object obj = selection.getFirstElement();
+        if (!(obj instanceof Entry))
+            return;
+        final Entry entry = (Entry) obj;
+        if (entry.image == null)
+            return;
+        sampleView.tabFolder.setSelection(sampleView.tabItemImage);
+        sampleView.canvas.setBackgroundImage(entry.image);
+        sampleView.canvas.redraw();
+    }
+
+    @Override
+    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        context = (Context) newInput;
+    }
+
+    class Entry {
+        String name;
+        Object obj;
+        Image image;
+
+        Entry(String name, Object obj) {
+            this.name = name;
+            this.obj = obj;
+        }
+    }
+
+    @Override
+    public Object[] getElements(Object inputElement) {
+        if (inputElement != context)
+            return null;
+        return getChildren(new Entry("Context", inputElement));
+    }
+
+    @Override
+    public Object[] getChildren(Object parentElement) {
+        if (!(parentElement instanceof Entry))
+            return null;
+        Entry entry = (Entry) parentElement;
+        ArrayList<Object> children = new ArrayList<Object>();
+        if (entry.obj == context.serverState.enableDisables) {
+            for (int i = 0; i < context.serverState.enableDisables.size(); i++) {
+                final int key = context.serverState.enableDisables.keyAt(i);
+                final int value = context.serverState.enableDisables.valueAt(i);
+                children.add(GLEnum.valueOf(key).name() + " = " + value);
+            }
+        } else if (entry.obj == context.serverState.integers) {
+            for (int i = 0; i < context.serverState.integers.size(); i++) {
+                final int key = context.serverState.integers.keyAt(i);
+                final Message val = context.serverState.integers.valueAt(i);
+                if (val != null)
+                    children.add(GLEnum.valueOf(key).name() + " : " +
+                            MessageFormatter.format(val, false));
+                else
+                    children.add(GLEnum.valueOf(key).name() + " : default");
+            }
+        } else if (entry.obj == context.serverState.lastSetter) {
+            for (int i = 0; i < context.serverState.lastSetter.size(); i++) {
+                final int key = context.serverState.lastSetter.keyAt(i);
+                final Message msg = context.serverState.lastSetter.valueAt(i);
+                if (msg == null)
+                    children.add(Function.valueOf(key).name() + " : default");
+                else
+                    children.add(Function.valueOf(key).name() + " : "
+                            + MessageFormatter.format(msg, false));
+            }
+        } else if (entry.obj instanceof SparseArray) {
+            SparseArray<?> sa = (SparseArray<?>) entry.obj;
+            for (int i = 0; i < sa.size(); i++)
+                children.add(new Entry("[" + sa.keyAt(i) + "]", sa.valueAt(i)));
+        } else if (entry.obj instanceof Map) {
+            Set<?> set = ((Map<?, ?>) entry.obj).entrySet();
+            for (Object o : set) {
+                Map.Entry e = (Map.Entry) o;
+                children.add(new Entry(e.getKey().toString(), e.getValue()));
+            }
+        } else if (entry.obj instanceof SparseIntArray) {
+            SparseIntArray sa = (SparseIntArray) entry.obj;
+            for (int i = 0; i < sa.size(); i++)
+                children.add("[" + sa.keyAt(i) + "] = " + sa.valueAt(i));
+        } else if (entry.obj instanceof Collection) {
+            Collection<?> collection = (Collection<?>) entry.obj;
+            for (Object o : collection)
+                children.add(new Entry("[?]", o));
+        } else if (entry.obj.getClass().isArray()) {
+            for (int i = 0; i < Array.getLength(entry.obj); i++)
+                children.add(new Entry("[" + i + "]", Array.get(entry.obj, i)));
+        } else {
+            Field[] fields = entry.obj.getClass().getFields();
+            for (Field f : fields) {
+                try {
+                    children.add(new Entry(f.getName(), f.get(entry.obj)));
+                } catch (IllegalArgumentException e) {
+                    e.printStackTrace();
+                } catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return children.toArray();
+    }
+
+    @Override
+    public Object getParent(Object element) {
+        return null;
+    }
+
+    @Override
+    public boolean hasChildren(Object element) {
+        if (element == null)
+            return false;
+        if (!(element instanceof Entry))
+            return false;
+        Object obj = ((Entry) element).obj;
+        if (obj == null)
+            return false;
+        if (obj instanceof SparseArray)
+            return ((SparseArray<?>) obj).size() > 0;
+        else if (obj instanceof SparseIntArray)
+            return ((SparseIntArray) obj).size() > 0;
+        else if (obj instanceof Collection)
+            return ((Collection<?>) obj).size() > 0;
+        else if (obj instanceof Map)
+            return ((Map<?, ?>) obj).size() > 0;
+        else if (obj.getClass().isArray())
+            return Array.getLength(obj) > 0;
+        else if (obj instanceof Message)
+            return false;
+        else if (isPrimitive(obj))
+            return false;
+        else if (obj.getClass().equals(String.class))
+            return false;
+        else if (obj.getClass().equals(Message.class))
+            return false;
+        else if (obj instanceof GLEnum)
+            return false;
+        return obj.getClass().getFields().length > 0;
+    }
+
+    static boolean isPrimitive(final Object obj) {
+        final Class<? extends Object> c = obj.getClass();
+        if (c.isPrimitive())
+            return true;
+        if (c == Integer.class)
+            return true;
+        if (c == Boolean.class)
+            return true;
+        if (c == Float.class)
+            return true;
+        if (c == Short.class)
+            return true;
+        return false;
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/DebuggerMessage.java b/tools/glesv2debugger/src/com/android/glesv2debugger/DebuggerMessage.java
new file mode 100644
index 0000000..94133f5
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/DebuggerMessage.java
@@ -0,0 +1,1713 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: debugger_message.proto
+
+package com.android.glesv2debugger;
+
+public final class DebuggerMessage {
+  private DebuggerMessage() {}
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistryLite registry) {
+  }
+  public static final class Message extends
+      com.google.protobuf.GeneratedMessageLite {
+    // Use Message.newBuilder() to construct.
+    private Message() {
+      initFields();
+    }
+    private Message(boolean noInit) {}
+    
+    private static final Message defaultInstance;
+    public static Message getDefaultInstance() {
+      return defaultInstance;
+    }
+    
+    public Message getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+    
+    public enum Function
+        implements com.google.protobuf.Internal.EnumLite {
+      glActiveTexture(0, 0),
+      glAttachShader(1, 1),
+      glBindAttribLocation(2, 2),
+      glBindBuffer(3, 3),
+      glBindFramebuffer(4, 4),
+      glBindRenderbuffer(5, 5),
+      glBindTexture(6, 6),
+      glBlendColor(7, 7),
+      glBlendEquation(8, 8),
+      glBlendEquationSeparate(9, 9),
+      glBlendFunc(10, 10),
+      glBlendFuncSeparate(11, 11),
+      glBufferData(12, 12),
+      glBufferSubData(13, 13),
+      glCheckFramebufferStatus(14, 14),
+      glClear(15, 15),
+      glClearColor(16, 16),
+      glClearDepthf(17, 17),
+      glClearStencil(18, 18),
+      glColorMask(19, 19),
+      glCompileShader(20, 20),
+      glCompressedTexImage2D(21, 21),
+      glCompressedTexSubImage2D(22, 22),
+      glCopyTexImage2D(23, 23),
+      glCopyTexSubImage2D(24, 24),
+      glCreateProgram(25, 25),
+      glCreateShader(26, 26),
+      glCullFace(27, 27),
+      glDeleteBuffers(28, 28),
+      glDeleteFramebuffers(29, 29),
+      glDeleteProgram(30, 30),
+      glDeleteRenderbuffers(31, 31),
+      glDeleteShader(32, 32),
+      glDeleteTextures(33, 33),
+      glDepthFunc(34, 34),
+      glDepthMask(35, 35),
+      glDepthRangef(36, 36),
+      glDetachShader(37, 37),
+      glDisable(38, 38),
+      glDisableVertexAttribArray(39, 39),
+      glDrawArrays(40, 40),
+      glDrawElements(41, 41),
+      glEnable(42, 42),
+      glEnableVertexAttribArray(43, 43),
+      glFinish(44, 44),
+      glFlush(45, 45),
+      glFramebufferRenderbuffer(46, 46),
+      glFramebufferTexture2D(47, 47),
+      glFrontFace(48, 48),
+      glGenBuffers(49, 49),
+      glGenerateMipmap(50, 50),
+      glGenFramebuffers(51, 51),
+      glGenRenderbuffers(52, 52),
+      glGenTextures(53, 53),
+      glGetActiveAttrib(54, 54),
+      glGetActiveUniform(55, 55),
+      glGetAttachedShaders(56, 56),
+      glGetAttribLocation(57, 57),
+      glGetBooleanv(58, 58),
+      glGetBufferParameteriv(59, 59),
+      glGetError(60, 60),
+      glGetFloatv(61, 61),
+      glGetFramebufferAttachmentParameteriv(62, 62),
+      glGetIntegerv(63, 63),
+      glGetProgramiv(64, 64),
+      glGetProgramInfoLog(65, 65),
+      glGetRenderbufferParameteriv(66, 66),
+      glGetShaderiv(67, 67),
+      glGetShaderInfoLog(68, 68),
+      glGetShaderPrecisionFormat(69, 69),
+      glGetShaderSource(70, 70),
+      glGetString(71, 71),
+      glGetTexParameterfv(72, 72),
+      glGetTexParameteriv(73, 73),
+      glGetUniformfv(74, 74),
+      glGetUniformiv(75, 75),
+      glGetUniformLocation(76, 76),
+      glGetVertexAttribfv(77, 77),
+      glGetVertexAttribiv(78, 78),
+      glGetVertexAttribPointerv(79, 79),
+      glHint(80, 80),
+      glIsBuffer(81, 81),
+      glIsEnabled(82, 82),
+      glIsFramebuffer(83, 83),
+      glIsProgram(84, 84),
+      glIsRenderbuffer(85, 85),
+      glIsShader(86, 86),
+      glIsTexture(87, 87),
+      glLineWidth(88, 88),
+      glLinkProgram(89, 89),
+      glPixelStorei(90, 90),
+      glPolygonOffset(91, 91),
+      glReadPixels(92, 92),
+      glReleaseShaderCompiler(93, 93),
+      glRenderbufferStorage(94, 94),
+      glSampleCoverage(95, 95),
+      glScissor(96, 96),
+      glShaderBinary(97, 97),
+      glShaderSource(98, 98),
+      glStencilFunc(99, 99),
+      glStencilFuncSeparate(100, 100),
+      glStencilMask(101, 101),
+      glStencilMaskSeparate(102, 102),
+      glStencilOp(103, 103),
+      glStencilOpSeparate(104, 104),
+      glTexImage2D(105, 105),
+      glTexParameterf(106, 106),
+      glTexParameterfv(107, 107),
+      glTexParameteri(108, 108),
+      glTexParameteriv(109, 109),
+      glTexSubImage2D(110, 110),
+      glUniform1f(111, 111),
+      glUniform1fv(112, 112),
+      glUniform1i(113, 113),
+      glUniform1iv(114, 114),
+      glUniform2f(115, 115),
+      glUniform2fv(116, 116),
+      glUniform2i(117, 117),
+      glUniform2iv(118, 118),
+      glUniform3f(119, 119),
+      glUniform3fv(120, 120),
+      glUniform3i(121, 121),
+      glUniform3iv(122, 122),
+      glUniform4f(123, 123),
+      glUniform4fv(124, 124),
+      glUniform4i(125, 125),
+      glUniform4iv(126, 126),
+      glUniformMatrix2fv(127, 127),
+      glUniformMatrix3fv(128, 128),
+      glUniformMatrix4fv(129, 129),
+      glUseProgram(130, 130),
+      glValidateProgram(131, 131),
+      glVertexAttrib1f(132, 132),
+      glVertexAttrib1fv(133, 133),
+      glVertexAttrib2f(134, 134),
+      glVertexAttrib2fv(135, 135),
+      glVertexAttrib3f(136, 136),
+      glVertexAttrib3fv(137, 137),
+      glVertexAttrib4f(138, 138),
+      glVertexAttrib4fv(139, 139),
+      glVertexAttribPointer(140, 140),
+      glViewport(141, 141),
+      eglGetDisplay(142, 142),
+      eglInitialize(143, 143),
+      eglTerminate(144, 144),
+      eglGetConfigs(145, 145),
+      eglChooseConfig(146, 146),
+      eglGetConfigAttrib(147, 147),
+      eglCreateWindowSurface(148, 148),
+      eglCreatePixmapSurface(149, 149),
+      eglCreatePbufferSurface(150, 150),
+      eglDestroySurface(151, 151),
+      eglQuerySurface(152, 152),
+      eglCreateContext(153, 153),
+      eglDestroyContext(154, 154),
+      eglMakeCurrent(155, 155),
+      eglGetCurrentContext(156, 156),
+      eglGetCurrentSurface(157, 157),
+      eglGetCurrentDisplay(158, 158),
+      eglQueryContext(159, 159),
+      eglWaitGL(160, 160),
+      eglWaitNative(161, 161),
+      eglSwapBuffers(162, 162),
+      eglCopyBuffers(163, 163),
+      eglGetError(164, 164),
+      eglQueryString(165, 165),
+      eglGetProcAddress(166, 166),
+      eglSurfaceAttrib(167, 167),
+      eglBindTexImage(168, 168),
+      eglReleaseTexImage(169, 169),
+      eglSwapInterval(170, 170),
+      eglBindAPI(171, 171),
+      eglQueryAPI(172, 172),
+      eglWaitClient(173, 173),
+      eglReleaseThread(174, 174),
+      eglCreatePbufferFromClientBuffer(175, 175),
+      eglLockSurfaceKHR(176, 176),
+      eglUnlockSurfaceKHR(177, 177),
+      eglCreateImageKHR(178, 178),
+      eglDestroyImageKHR(179, 179),
+      eglCreateSyncKHR(180, 180),
+      eglDestroySyncKHR(181, 181),
+      eglClientWaitSyncKHR(182, 182),
+      eglGetSyncAttribKHR(183, 183),
+      eglSetSwapRectangleANDROID(184, 184),
+      eglGetRenderBufferANDROID(185, 185),
+      ACK(186, 186),
+      NEG(187, 187),
+      CONTINUE(188, 188),
+      SKIP(189, 189),
+      SETPROP(190, 190),
+      ;
+      
+      
+      public final int getNumber() { return value; }
+      
+      public static Function valueOf(int value) {
+        switch (value) {
+          case 0: return glActiveTexture;
+          case 1: return glAttachShader;
+          case 2: return glBindAttribLocation;
+          case 3: return glBindBuffer;
+          case 4: return glBindFramebuffer;
+          case 5: return glBindRenderbuffer;
+          case 6: return glBindTexture;
+          case 7: return glBlendColor;
+          case 8: return glBlendEquation;
+          case 9: return glBlendEquationSeparate;
+          case 10: return glBlendFunc;
+          case 11: return glBlendFuncSeparate;
+          case 12: return glBufferData;
+          case 13: return glBufferSubData;
+          case 14: return glCheckFramebufferStatus;
+          case 15: return glClear;
+          case 16: return glClearColor;
+          case 17: return glClearDepthf;
+          case 18: return glClearStencil;
+          case 19: return glColorMask;
+          case 20: return glCompileShader;
+          case 21: return glCompressedTexImage2D;
+          case 22: return glCompressedTexSubImage2D;
+          case 23: return glCopyTexImage2D;
+          case 24: return glCopyTexSubImage2D;
+          case 25: return glCreateProgram;
+          case 26: return glCreateShader;
+          case 27: return glCullFace;
+          case 28: return glDeleteBuffers;
+          case 29: return glDeleteFramebuffers;
+          case 30: return glDeleteProgram;
+          case 31: return glDeleteRenderbuffers;
+          case 32: return glDeleteShader;
+          case 33: return glDeleteTextures;
+          case 34: return glDepthFunc;
+          case 35: return glDepthMask;
+          case 36: return glDepthRangef;
+          case 37: return glDetachShader;
+          case 38: return glDisable;
+          case 39: return glDisableVertexAttribArray;
+          case 40: return glDrawArrays;
+          case 41: return glDrawElements;
+          case 42: return glEnable;
+          case 43: return glEnableVertexAttribArray;
+          case 44: return glFinish;
+          case 45: return glFlush;
+          case 46: return glFramebufferRenderbuffer;
+          case 47: return glFramebufferTexture2D;
+          case 48: return glFrontFace;
+          case 49: return glGenBuffers;
+          case 50: return glGenerateMipmap;
+          case 51: return glGenFramebuffers;
+          case 52: return glGenRenderbuffers;
+          case 53: return glGenTextures;
+          case 54: return glGetActiveAttrib;
+          case 55: return glGetActiveUniform;
+          case 56: return glGetAttachedShaders;
+          case 57: return glGetAttribLocation;
+          case 58: return glGetBooleanv;
+          case 59: return glGetBufferParameteriv;
+          case 60: return glGetError;
+          case 61: return glGetFloatv;
+          case 62: return glGetFramebufferAttachmentParameteriv;
+          case 63: return glGetIntegerv;
+          case 64: return glGetProgramiv;
+          case 65: return glGetProgramInfoLog;
+          case 66: return glGetRenderbufferParameteriv;
+          case 67: return glGetShaderiv;
+          case 68: return glGetShaderInfoLog;
+          case 69: return glGetShaderPrecisionFormat;
+          case 70: return glGetShaderSource;
+          case 71: return glGetString;
+          case 72: return glGetTexParameterfv;
+          case 73: return glGetTexParameteriv;
+          case 74: return glGetUniformfv;
+          case 75: return glGetUniformiv;
+          case 76: return glGetUniformLocation;
+          case 77: return glGetVertexAttribfv;
+          case 78: return glGetVertexAttribiv;
+          case 79: return glGetVertexAttribPointerv;
+          case 80: return glHint;
+          case 81: return glIsBuffer;
+          case 82: return glIsEnabled;
+          case 83: return glIsFramebuffer;
+          case 84: return glIsProgram;
+          case 85: return glIsRenderbuffer;
+          case 86: return glIsShader;
+          case 87: return glIsTexture;
+          case 88: return glLineWidth;
+          case 89: return glLinkProgram;
+          case 90: return glPixelStorei;
+          case 91: return glPolygonOffset;
+          case 92: return glReadPixels;
+          case 93: return glReleaseShaderCompiler;
+          case 94: return glRenderbufferStorage;
+          case 95: return glSampleCoverage;
+          case 96: return glScissor;
+          case 97: return glShaderBinary;
+          case 98: return glShaderSource;
+          case 99: return glStencilFunc;
+          case 100: return glStencilFuncSeparate;
+          case 101: return glStencilMask;
+          case 102: return glStencilMaskSeparate;
+          case 103: return glStencilOp;
+          case 104: return glStencilOpSeparate;
+          case 105: return glTexImage2D;
+          case 106: return glTexParameterf;
+          case 107: return glTexParameterfv;
+          case 108: return glTexParameteri;
+          case 109: return glTexParameteriv;
+          case 110: return glTexSubImage2D;
+          case 111: return glUniform1f;
+          case 112: return glUniform1fv;
+          case 113: return glUniform1i;
+          case 114: return glUniform1iv;
+          case 115: return glUniform2f;
+          case 116: return glUniform2fv;
+          case 117: return glUniform2i;
+          case 118: return glUniform2iv;
+          case 119: return glUniform3f;
+          case 120: return glUniform3fv;
+          case 121: return glUniform3i;
+          case 122: return glUniform3iv;
+          case 123: return glUniform4f;
+          case 124: return glUniform4fv;
+          case 125: return glUniform4i;
+          case 126: return glUniform4iv;
+          case 127: return glUniformMatrix2fv;
+          case 128: return glUniformMatrix3fv;
+          case 129: return glUniformMatrix4fv;
+          case 130: return glUseProgram;
+          case 131: return glValidateProgram;
+          case 132: return glVertexAttrib1f;
+          case 133: return glVertexAttrib1fv;
+          case 134: return glVertexAttrib2f;
+          case 135: return glVertexAttrib2fv;
+          case 136: return glVertexAttrib3f;
+          case 137: return glVertexAttrib3fv;
+          case 138: return glVertexAttrib4f;
+          case 139: return glVertexAttrib4fv;
+          case 140: return glVertexAttribPointer;
+          case 141: return glViewport;
+          case 142: return eglGetDisplay;
+          case 143: return eglInitialize;
+          case 144: return eglTerminate;
+          case 145: return eglGetConfigs;
+          case 146: return eglChooseConfig;
+          case 147: return eglGetConfigAttrib;
+          case 148: return eglCreateWindowSurface;
+          case 149: return eglCreatePixmapSurface;
+          case 150: return eglCreatePbufferSurface;
+          case 151: return eglDestroySurface;
+          case 152: return eglQuerySurface;
+          case 153: return eglCreateContext;
+          case 154: return eglDestroyContext;
+          case 155: return eglMakeCurrent;
+          case 156: return eglGetCurrentContext;
+          case 157: return eglGetCurrentSurface;
+          case 158: return eglGetCurrentDisplay;
+          case 159: return eglQueryContext;
+          case 160: return eglWaitGL;
+          case 161: return eglWaitNative;
+          case 162: return eglSwapBuffers;
+          case 163: return eglCopyBuffers;
+          case 164: return eglGetError;
+          case 165: return eglQueryString;
+          case 166: return eglGetProcAddress;
+          case 167: return eglSurfaceAttrib;
+          case 168: return eglBindTexImage;
+          case 169: return eglReleaseTexImage;
+          case 170: return eglSwapInterval;
+          case 171: return eglBindAPI;
+          case 172: return eglQueryAPI;
+          case 173: return eglWaitClient;
+          case 174: return eglReleaseThread;
+          case 175: return eglCreatePbufferFromClientBuffer;
+          case 176: return eglLockSurfaceKHR;
+          case 177: return eglUnlockSurfaceKHR;
+          case 178: return eglCreateImageKHR;
+          case 179: return eglDestroyImageKHR;
+          case 180: return eglCreateSyncKHR;
+          case 181: return eglDestroySyncKHR;
+          case 182: return eglClientWaitSyncKHR;
+          case 183: return eglGetSyncAttribKHR;
+          case 184: return eglSetSwapRectangleANDROID;
+          case 185: return eglGetRenderBufferANDROID;
+          case 186: return ACK;
+          case 187: return NEG;
+          case 188: return CONTINUE;
+          case 189: return SKIP;
+          case 190: return SETPROP;
+          default: return null;
+        }
+      }
+      
+      public static com.google.protobuf.Internal.EnumLiteMap<Function>
+          internalGetValueMap() {
+        return internalValueMap;
+      }
+      private static com.google.protobuf.Internal.EnumLiteMap<Function>
+          internalValueMap =
+            new com.google.protobuf.Internal.EnumLiteMap<Function>() {
+              public Function findValueByNumber(int number) {
+                return Function.valueOf(number)
+      ;        }
+            };
+      
+      private final int index;
+      private final int value;
+      private Function(int index, int value) {
+        this.index = index;
+        this.value = value;
+      }
+      
+      // @@protoc_insertion_point(enum_scope:com.android.glesv2debugger.Message.Function)
+    }
+    
+    public enum Type
+        implements com.google.protobuf.Internal.EnumLite {
+      BeforeCall(0, 0),
+      AfterCall(1, 1),
+      AfterGeneratedCall(2, 2),
+      Response(3, 3),
+      CompleteCall(4, 4),
+      ;
+      
+      
+      public final int getNumber() { return value; }
+      
+      public static Type valueOf(int value) {
+        switch (value) {
+          case 0: return BeforeCall;
+          case 1: return AfterCall;
+          case 2: return AfterGeneratedCall;
+          case 3: return Response;
+          case 4: return CompleteCall;
+          default: return null;
+        }
+      }
+      
+      public static com.google.protobuf.Internal.EnumLiteMap<Type>
+          internalGetValueMap() {
+        return internalValueMap;
+      }
+      private static com.google.protobuf.Internal.EnumLiteMap<Type>
+          internalValueMap =
+            new com.google.protobuf.Internal.EnumLiteMap<Type>() {
+              public Type findValueByNumber(int number) {
+                return Type.valueOf(number)
+      ;        }
+            };
+      
+      private final int index;
+      private final int value;
+      private Type(int index, int value) {
+        this.index = index;
+        this.value = value;
+      }
+      
+      // @@protoc_insertion_point(enum_scope:com.android.glesv2debugger.Message.Type)
+    }
+    
+    public enum DataType
+        implements com.google.protobuf.Internal.EnumLite {
+      ReferencedImage(0, 0),
+      NonreferencedImage(1, 1),
+      ;
+      
+      
+      public final int getNumber() { return value; }
+      
+      public static DataType valueOf(int value) {
+        switch (value) {
+          case 0: return ReferencedImage;
+          case 1: return NonreferencedImage;
+          default: return null;
+        }
+      }
+      
+      public static com.google.protobuf.Internal.EnumLiteMap<DataType>
+          internalGetValueMap() {
+        return internalValueMap;
+      }
+      private static com.google.protobuf.Internal.EnumLiteMap<DataType>
+          internalValueMap =
+            new com.google.protobuf.Internal.EnumLiteMap<DataType>() {
+              public DataType findValueByNumber(int number) {
+                return DataType.valueOf(number)
+      ;        }
+            };
+      
+      private final int index;
+      private final int value;
+      private DataType(int index, int value) {
+        this.index = index;
+        this.value = value;
+      }
+      
+      // @@protoc_insertion_point(enum_scope:com.android.glesv2debugger.Message.DataType)
+    }
+    
+    public enum Prop
+        implements com.google.protobuf.Internal.EnumLite {
+      CaptureDraw(0, 0),
+      TimeMode(1, 1),
+      ExpectResponse(2, 2),
+      CaptureSwap(3, 3),
+      GLConstant(4, 4),
+      ;
+      
+      
+      public final int getNumber() { return value; }
+      
+      public static Prop valueOf(int value) {
+        switch (value) {
+          case 0: return CaptureDraw;
+          case 1: return TimeMode;
+          case 2: return ExpectResponse;
+          case 3: return CaptureSwap;
+          case 4: return GLConstant;
+          default: return null;
+        }
+      }
+      
+      public static com.google.protobuf.Internal.EnumLiteMap<Prop>
+          internalGetValueMap() {
+        return internalValueMap;
+      }
+      private static com.google.protobuf.Internal.EnumLiteMap<Prop>
+          internalValueMap =
+            new com.google.protobuf.Internal.EnumLiteMap<Prop>() {
+              public Prop findValueByNumber(int number) {
+                return Prop.valueOf(number)
+      ;        }
+            };
+      
+      private final int index;
+      private final int value;
+      private Prop(int index, int value) {
+        this.index = index;
+        this.value = value;
+      }
+      
+      // @@protoc_insertion_point(enum_scope:com.android.glesv2debugger.Message.Prop)
+    }
+    
+    // required int32 context_id = 1;
+    public static final int CONTEXT_ID_FIELD_NUMBER = 1;
+    private boolean hasContextId;
+    private int contextId_ = 0;
+    public boolean hasContextId() { return hasContextId; }
+    public int getContextId() { return contextId_; }
+    
+    // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
+    public static final int FUNCTION_FIELD_NUMBER = 2;
+    private boolean hasFunction;
+    private com.android.glesv2debugger.DebuggerMessage.Message.Function function_;
+    public boolean hasFunction() { return hasFunction; }
+    public com.android.glesv2debugger.DebuggerMessage.Message.Function getFunction() { return function_; }
+    
+    // required .com.android.glesv2debugger.Message.Type type = 3;
+    public static final int TYPE_FIELD_NUMBER = 3;
+    private boolean hasType;
+    private com.android.glesv2debugger.DebuggerMessage.Message.Type type_;
+    public boolean hasType() { return hasType; }
+    public com.android.glesv2debugger.DebuggerMessage.Message.Type getType() { return type_; }
+    
+    // required bool expect_response = 4;
+    public static final int EXPECT_RESPONSE_FIELD_NUMBER = 4;
+    private boolean hasExpectResponse;
+    private boolean expectResponse_ = false;
+    public boolean hasExpectResponse() { return hasExpectResponse; }
+    public boolean getExpectResponse() { return expectResponse_; }
+    
+    // optional int32 ret = 5;
+    public static final int RET_FIELD_NUMBER = 5;
+    private boolean hasRet;
+    private int ret_ = 0;
+    public boolean hasRet() { return hasRet; }
+    public int getRet() { return ret_; }
+    
+    // optional int32 arg0 = 6;
+    public static final int ARG0_FIELD_NUMBER = 6;
+    private boolean hasArg0;
+    private int arg0_ = 0;
+    public boolean hasArg0() { return hasArg0; }
+    public int getArg0() { return arg0_; }
+    
+    // optional int32 arg1 = 7;
+    public static final int ARG1_FIELD_NUMBER = 7;
+    private boolean hasArg1;
+    private int arg1_ = 0;
+    public boolean hasArg1() { return hasArg1; }
+    public int getArg1() { return arg1_; }
+    
+    // optional int32 arg2 = 8;
+    public static final int ARG2_FIELD_NUMBER = 8;
+    private boolean hasArg2;
+    private int arg2_ = 0;
+    public boolean hasArg2() { return hasArg2; }
+    public int getArg2() { return arg2_; }
+    
+    // optional int32 arg3 = 9;
+    public static final int ARG3_FIELD_NUMBER = 9;
+    private boolean hasArg3;
+    private int arg3_ = 0;
+    public boolean hasArg3() { return hasArg3; }
+    public int getArg3() { return arg3_; }
+    
+    // optional int32 arg4 = 16;
+    public static final int ARG4_FIELD_NUMBER = 16;
+    private boolean hasArg4;
+    private int arg4_ = 0;
+    public boolean hasArg4() { return hasArg4; }
+    public int getArg4() { return arg4_; }
+    
+    // optional int32 arg5 = 17;
+    public static final int ARG5_FIELD_NUMBER = 17;
+    private boolean hasArg5;
+    private int arg5_ = 0;
+    public boolean hasArg5() { return hasArg5; }
+    public int getArg5() { return arg5_; }
+    
+    // optional int32 arg6 = 18;
+    public static final int ARG6_FIELD_NUMBER = 18;
+    private boolean hasArg6;
+    private int arg6_ = 0;
+    public boolean hasArg6() { return hasArg6; }
+    public int getArg6() { return arg6_; }
+    
+    // optional int32 arg7 = 19;
+    public static final int ARG7_FIELD_NUMBER = 19;
+    private boolean hasArg7;
+    private int arg7_ = 0;
+    public boolean hasArg7() { return hasArg7; }
+    public int getArg7() { return arg7_; }
+    
+    // optional int32 arg8 = 20;
+    public static final int ARG8_FIELD_NUMBER = 20;
+    private boolean hasArg8;
+    private int arg8_ = 0;
+    public boolean hasArg8() { return hasArg8; }
+    public int getArg8() { return arg8_; }
+    
+    // optional bytes data = 10;
+    public static final int DATA_FIELD_NUMBER = 10;
+    private boolean hasData;
+    private com.google.protobuf.ByteString data_ = com.google.protobuf.ByteString.EMPTY;
+    public boolean hasData() { return hasData; }
+    public com.google.protobuf.ByteString getData() { return data_; }
+    
+    // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+    public static final int DATA_TYPE_FIELD_NUMBER = 23;
+    private boolean hasDataType;
+    private com.android.glesv2debugger.DebuggerMessage.Message.DataType dataType_;
+    public boolean hasDataType() { return hasDataType; }
+    public com.android.glesv2debugger.DebuggerMessage.Message.DataType getDataType() { return dataType_; }
+    
+    // optional int32 pixel_format = 24;
+    public static final int PIXEL_FORMAT_FIELD_NUMBER = 24;
+    private boolean hasPixelFormat;
+    private int pixelFormat_ = 0;
+    public boolean hasPixelFormat() { return hasPixelFormat; }
+    public int getPixelFormat() { return pixelFormat_; }
+    
+    // optional int32 pixel_type = 25;
+    public static final int PIXEL_TYPE_FIELD_NUMBER = 25;
+    private boolean hasPixelType;
+    private int pixelType_ = 0;
+    public boolean hasPixelType() { return hasPixelType; }
+    public int getPixelType() { return pixelType_; }
+    
+    // optional int32 image_width = 26;
+    public static final int IMAGE_WIDTH_FIELD_NUMBER = 26;
+    private boolean hasImageWidth;
+    private int imageWidth_ = 0;
+    public boolean hasImageWidth() { return hasImageWidth; }
+    public int getImageWidth() { return imageWidth_; }
+    
+    // optional int32 image_height = 27;
+    public static final int IMAGE_HEIGHT_FIELD_NUMBER = 27;
+    private boolean hasImageHeight;
+    private int imageHeight_ = 0;
+    public boolean hasImageHeight() { return hasImageHeight; }
+    public int getImageHeight() { return imageHeight_; }
+    
+    // optional float time = 11;
+    public static final int TIME_FIELD_NUMBER = 11;
+    private boolean hasTime;
+    private float time_ = 0F;
+    public boolean hasTime() { return hasTime; }
+    public float getTime() { return time_; }
+    
+    // optional .com.android.glesv2debugger.Message.Prop prop = 21;
+    public static final int PROP_FIELD_NUMBER = 21;
+    private boolean hasProp;
+    private com.android.glesv2debugger.DebuggerMessage.Message.Prop prop_;
+    public boolean hasProp() { return hasProp; }
+    public com.android.glesv2debugger.DebuggerMessage.Message.Prop getProp() { return prop_; }
+    
+    // optional float clock = 22;
+    public static final int CLOCK_FIELD_NUMBER = 22;
+    private boolean hasClock;
+    private float clock_ = 0F;
+    public boolean hasClock() { return hasClock; }
+    public float getClock() { return clock_; }
+    
+    private void initFields() {
+      function_ = com.android.glesv2debugger.DebuggerMessage.Message.Function.NEG;
+      type_ = com.android.glesv2debugger.DebuggerMessage.Message.Type.BeforeCall;
+      dataType_ = com.android.glesv2debugger.DebuggerMessage.Message.DataType.ReferencedImage;
+      prop_ = com.android.glesv2debugger.DebuggerMessage.Message.Prop.CaptureDraw;
+    }
+    public final boolean isInitialized() {
+      if (!hasContextId) return false;
+      if (!hasFunction) return false;
+      if (!hasType) return false;
+      if (!hasExpectResponse) return false;
+      return true;
+    }
+    
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      getSerializedSize();
+      if (hasContextId()) {
+        output.writeInt32(1, getContextId());
+      }
+      if (hasFunction()) {
+        output.writeEnum(2, getFunction().getNumber());
+      }
+      if (hasType()) {
+        output.writeEnum(3, getType().getNumber());
+      }
+      if (hasExpectResponse()) {
+        output.writeBool(4, getExpectResponse());
+      }
+      if (hasRet()) {
+        output.writeInt32(5, getRet());
+      }
+      if (hasArg0()) {
+        output.writeInt32(6, getArg0());
+      }
+      if (hasArg1()) {
+        output.writeInt32(7, getArg1());
+      }
+      if (hasArg2()) {
+        output.writeInt32(8, getArg2());
+      }
+      if (hasArg3()) {
+        output.writeInt32(9, getArg3());
+      }
+      if (hasData()) {
+        output.writeBytes(10, getData());
+      }
+      if (hasTime()) {
+        output.writeFloat(11, getTime());
+      }
+      if (hasArg4()) {
+        output.writeInt32(16, getArg4());
+      }
+      if (hasArg5()) {
+        output.writeInt32(17, getArg5());
+      }
+      if (hasArg6()) {
+        output.writeInt32(18, getArg6());
+      }
+      if (hasArg7()) {
+        output.writeInt32(19, getArg7());
+      }
+      if (hasArg8()) {
+        output.writeInt32(20, getArg8());
+      }
+      if (hasProp()) {
+        output.writeEnum(21, getProp().getNumber());
+      }
+      if (hasClock()) {
+        output.writeFloat(22, getClock());
+      }
+      if (hasDataType()) {
+        output.writeEnum(23, getDataType().getNumber());
+      }
+      if (hasPixelFormat()) {
+        output.writeInt32(24, getPixelFormat());
+      }
+      if (hasPixelType()) {
+        output.writeInt32(25, getPixelType());
+      }
+      if (hasImageWidth()) {
+        output.writeInt32(26, getImageWidth());
+      }
+      if (hasImageHeight()) {
+        output.writeInt32(27, getImageHeight());
+      }
+    }
+    
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+    
+      size = 0;
+      if (hasContextId()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(1, getContextId());
+      }
+      if (hasFunction()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeEnumSize(2, getFunction().getNumber());
+      }
+      if (hasType()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeEnumSize(3, getType().getNumber());
+      }
+      if (hasExpectResponse()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(4, getExpectResponse());
+      }
+      if (hasRet()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(5, getRet());
+      }
+      if (hasArg0()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(6, getArg0());
+      }
+      if (hasArg1()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(7, getArg1());
+      }
+      if (hasArg2()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(8, getArg2());
+      }
+      if (hasArg3()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(9, getArg3());
+      }
+      if (hasData()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(10, getData());
+      }
+      if (hasTime()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeFloatSize(11, getTime());
+      }
+      if (hasArg4()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(16, getArg4());
+      }
+      if (hasArg5()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(17, getArg5());
+      }
+      if (hasArg6()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(18, getArg6());
+      }
+      if (hasArg7()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(19, getArg7());
+      }
+      if (hasArg8()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(20, getArg8());
+      }
+      if (hasProp()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeEnumSize(21, getProp().getNumber());
+      }
+      if (hasClock()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeFloatSize(22, getClock());
+      }
+      if (hasDataType()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeEnumSize(23, getDataType().getNumber());
+      }
+      if (hasPixelFormat()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(24, getPixelFormat());
+      }
+      if (hasPixelType()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(25, getPixelType());
+      }
+      if (hasImageWidth()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(26, getImageWidth());
+      }
+      if (hasImageHeight()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(27, getImageHeight());
+      }
+      memoizedSerializedSize = size;
+      return size;
+    }
+    
+    public static com.android.glesv2debugger.DebuggerMessage.Message parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return newBuilder().mergeFrom(data).buildParsed();
+    }
+    public static com.android.glesv2debugger.DebuggerMessage.Message parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return newBuilder().mergeFrom(data, extensionRegistry)
+               .buildParsed();
+    }
+    public static com.android.glesv2debugger.DebuggerMessage.Message parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return newBuilder().mergeFrom(data).buildParsed();
+    }
+    public static com.android.glesv2debugger.DebuggerMessage.Message parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return newBuilder().mergeFrom(data, extensionRegistry)
+               .buildParsed();
+    }
+    public static com.android.glesv2debugger.DebuggerMessage.Message parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return newBuilder().mergeFrom(input).buildParsed();
+    }
+    public static com.android.glesv2debugger.DebuggerMessage.Message parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return newBuilder().mergeFrom(input, extensionRegistry)
+               .buildParsed();
+    }
+    public static com.android.glesv2debugger.DebuggerMessage.Message parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      Builder builder = newBuilder();
+      if (builder.mergeDelimitedFrom(input)) {
+        return builder.buildParsed();
+      } else {
+        return null;
+      }
+    }
+    public static com.android.glesv2debugger.DebuggerMessage.Message parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      Builder builder = newBuilder();
+      if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+        return builder.buildParsed();
+      } else {
+        return null;
+      }
+    }
+    public static com.android.glesv2debugger.DebuggerMessage.Message parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return newBuilder().mergeFrom(input).buildParsed();
+    }
+    public static com.android.glesv2debugger.DebuggerMessage.Message parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return newBuilder().mergeFrom(input, extensionRegistry)
+               .buildParsed();
+    }
+    
+    public static Builder newBuilder() { return Builder.create(); }
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder(com.android.glesv2debugger.DebuggerMessage.Message prototype) {
+      return newBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() { return newBuilder(this); }
+    
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessageLite.Builder<
+          com.android.glesv2debugger.DebuggerMessage.Message, Builder> {
+      private com.android.glesv2debugger.DebuggerMessage.Message result;
+      
+      // Construct using com.android.glesv2debugger.DebuggerMessage.Message.newBuilder()
+      private Builder() {}
+      
+      private static Builder create() {
+        Builder builder = new Builder();
+        builder.result = new com.android.glesv2debugger.DebuggerMessage.Message();
+        return builder;
+      }
+      
+      protected com.android.glesv2debugger.DebuggerMessage.Message internalGetResult() {
+        return result;
+      }
+      
+      public Builder clear() {
+        if (result == null) {
+          throw new IllegalStateException(
+            "Cannot call clear() after build().");
+        }
+        result = new com.android.glesv2debugger.DebuggerMessage.Message();
+        return this;
+      }
+      
+      public Builder clone() {
+        return create().mergeFrom(result);
+      }
+      
+      public com.android.glesv2debugger.DebuggerMessage.Message getDefaultInstanceForType() {
+        return com.android.glesv2debugger.DebuggerMessage.Message.getDefaultInstance();
+      }
+      
+      public boolean isInitialized() {
+        return result.isInitialized();
+      }
+      public com.android.glesv2debugger.DebuggerMessage.Message build() {
+        if (result != null && !isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return buildPartial();
+      }
+      
+      private com.android.glesv2debugger.DebuggerMessage.Message buildParsed()
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        if (!isInitialized()) {
+          throw newUninitializedMessageException(
+            result).asInvalidProtocolBufferException();
+        }
+        return buildPartial();
+      }
+      
+      public com.android.glesv2debugger.DebuggerMessage.Message buildPartial() {
+        if (result == null) {
+          throw new IllegalStateException(
+            "build() has already been called on this Builder.");
+        }
+        com.android.glesv2debugger.DebuggerMessage.Message returnMe = result;
+        result = null;
+        return returnMe;
+      }
+      
+      public Builder mergeFrom(com.android.glesv2debugger.DebuggerMessage.Message other) {
+        if (other == com.android.glesv2debugger.DebuggerMessage.Message.getDefaultInstance()) return this;
+        if (other.hasContextId()) {
+          setContextId(other.getContextId());
+        }
+        if (other.hasFunction()) {
+          setFunction(other.getFunction());
+        }
+        if (other.hasType()) {
+          setType(other.getType());
+        }
+        if (other.hasExpectResponse()) {
+          setExpectResponse(other.getExpectResponse());
+        }
+        if (other.hasRet()) {
+          setRet(other.getRet());
+        }
+        if (other.hasArg0()) {
+          setArg0(other.getArg0());
+        }
+        if (other.hasArg1()) {
+          setArg1(other.getArg1());
+        }
+        if (other.hasArg2()) {
+          setArg2(other.getArg2());
+        }
+        if (other.hasArg3()) {
+          setArg3(other.getArg3());
+        }
+        if (other.hasArg4()) {
+          setArg4(other.getArg4());
+        }
+        if (other.hasArg5()) {
+          setArg5(other.getArg5());
+        }
+        if (other.hasArg6()) {
+          setArg6(other.getArg6());
+        }
+        if (other.hasArg7()) {
+          setArg7(other.getArg7());
+        }
+        if (other.hasArg8()) {
+          setArg8(other.getArg8());
+        }
+        if (other.hasData()) {
+          setData(other.getData());
+        }
+        if (other.hasDataType()) {
+          setDataType(other.getDataType());
+        }
+        if (other.hasPixelFormat()) {
+          setPixelFormat(other.getPixelFormat());
+        }
+        if (other.hasPixelType()) {
+          setPixelType(other.getPixelType());
+        }
+        if (other.hasImageWidth()) {
+          setImageWidth(other.getImageWidth());
+        }
+        if (other.hasImageHeight()) {
+          setImageHeight(other.getImageHeight());
+        }
+        if (other.hasTime()) {
+          setTime(other.getTime());
+        }
+        if (other.hasProp()) {
+          setProp(other.getProp());
+        }
+        if (other.hasClock()) {
+          setClock(other.getClock());
+        }
+        return this;
+      }
+      
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        while (true) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              return this;
+            default: {
+              if (!parseUnknownField(input, extensionRegistry, tag)) {
+                return this;
+              }
+              break;
+            }
+            case 8: {
+              setContextId(input.readInt32());
+              break;
+            }
+            case 16: {
+              int rawValue = input.readEnum();
+              com.android.glesv2debugger.DebuggerMessage.Message.Function value = com.android.glesv2debugger.DebuggerMessage.Message.Function.valueOf(rawValue);
+              if (value != null) {
+                setFunction(value);
+              }
+              break;
+            }
+            case 24: {
+              int rawValue = input.readEnum();
+              com.android.glesv2debugger.DebuggerMessage.Message.Type value = com.android.glesv2debugger.DebuggerMessage.Message.Type.valueOf(rawValue);
+              if (value != null) {
+                setType(value);
+              }
+              break;
+            }
+            case 32: {
+              setExpectResponse(input.readBool());
+              break;
+            }
+            case 40: {
+              setRet(input.readInt32());
+              break;
+            }
+            case 48: {
+              setArg0(input.readInt32());
+              break;
+            }
+            case 56: {
+              setArg1(input.readInt32());
+              break;
+            }
+            case 64: {
+              setArg2(input.readInt32());
+              break;
+            }
+            case 72: {
+              setArg3(input.readInt32());
+              break;
+            }
+            case 82: {
+              setData(input.readBytes());
+              break;
+            }
+            case 93: {
+              setTime(input.readFloat());
+              break;
+            }
+            case 128: {
+              setArg4(input.readInt32());
+              break;
+            }
+            case 136: {
+              setArg5(input.readInt32());
+              break;
+            }
+            case 144: {
+              setArg6(input.readInt32());
+              break;
+            }
+            case 152: {
+              setArg7(input.readInt32());
+              break;
+            }
+            case 160: {
+              setArg8(input.readInt32());
+              break;
+            }
+            case 168: {
+              int rawValue = input.readEnum();
+              com.android.glesv2debugger.DebuggerMessage.Message.Prop value = com.android.glesv2debugger.DebuggerMessage.Message.Prop.valueOf(rawValue);
+              if (value != null) {
+                setProp(value);
+              }
+              break;
+            }
+            case 181: {
+              setClock(input.readFloat());
+              break;
+            }
+            case 184: {
+              int rawValue = input.readEnum();
+              com.android.glesv2debugger.DebuggerMessage.Message.DataType value = com.android.glesv2debugger.DebuggerMessage.Message.DataType.valueOf(rawValue);
+              if (value != null) {
+                setDataType(value);
+              }
+              break;
+            }
+            case 192: {
+              setPixelFormat(input.readInt32());
+              break;
+            }
+            case 200: {
+              setPixelType(input.readInt32());
+              break;
+            }
+            case 208: {
+              setImageWidth(input.readInt32());
+              break;
+            }
+            case 216: {
+              setImageHeight(input.readInt32());
+              break;
+            }
+          }
+        }
+      }
+      
+      
+      // required int32 context_id = 1;
+      public boolean hasContextId() {
+        return result.hasContextId();
+      }
+      public int getContextId() {
+        return result.getContextId();
+      }
+      public Builder setContextId(int value) {
+        result.hasContextId = true;
+        result.contextId_ = value;
+        return this;
+      }
+      public Builder clearContextId() {
+        result.hasContextId = false;
+        result.contextId_ = 0;
+        return this;
+      }
+      
+      // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
+      public boolean hasFunction() {
+        return result.hasFunction();
+      }
+      public com.android.glesv2debugger.DebuggerMessage.Message.Function getFunction() {
+        return result.getFunction();
+      }
+      public Builder setFunction(com.android.glesv2debugger.DebuggerMessage.Message.Function value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        result.hasFunction = true;
+        result.function_ = value;
+        return this;
+      }
+      public Builder clearFunction() {
+        result.hasFunction = false;
+        result.function_ = com.android.glesv2debugger.DebuggerMessage.Message.Function.NEG;
+        return this;
+      }
+      
+      // required .com.android.glesv2debugger.Message.Type type = 3;
+      public boolean hasType() {
+        return result.hasType();
+      }
+      public com.android.glesv2debugger.DebuggerMessage.Message.Type getType() {
+        return result.getType();
+      }
+      public Builder setType(com.android.glesv2debugger.DebuggerMessage.Message.Type value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        result.hasType = true;
+        result.type_ = value;
+        return this;
+      }
+      public Builder clearType() {
+        result.hasType = false;
+        result.type_ = com.android.glesv2debugger.DebuggerMessage.Message.Type.BeforeCall;
+        return this;
+      }
+      
+      // required bool expect_response = 4;
+      public boolean hasExpectResponse() {
+        return result.hasExpectResponse();
+      }
+      public boolean getExpectResponse() {
+        return result.getExpectResponse();
+      }
+      public Builder setExpectResponse(boolean value) {
+        result.hasExpectResponse = true;
+        result.expectResponse_ = value;
+        return this;
+      }
+      public Builder clearExpectResponse() {
+        result.hasExpectResponse = false;
+        result.expectResponse_ = false;
+        return this;
+      }
+      
+      // optional int32 ret = 5;
+      public boolean hasRet() {
+        return result.hasRet();
+      }
+      public int getRet() {
+        return result.getRet();
+      }
+      public Builder setRet(int value) {
+        result.hasRet = true;
+        result.ret_ = value;
+        return this;
+      }
+      public Builder clearRet() {
+        result.hasRet = false;
+        result.ret_ = 0;
+        return this;
+      }
+      
+      // optional int32 arg0 = 6;
+      public boolean hasArg0() {
+        return result.hasArg0();
+      }
+      public int getArg0() {
+        return result.getArg0();
+      }
+      public Builder setArg0(int value) {
+        result.hasArg0 = true;
+        result.arg0_ = value;
+        return this;
+      }
+      public Builder clearArg0() {
+        result.hasArg0 = false;
+        result.arg0_ = 0;
+        return this;
+      }
+      
+      // optional int32 arg1 = 7;
+      public boolean hasArg1() {
+        return result.hasArg1();
+      }
+      public int getArg1() {
+        return result.getArg1();
+      }
+      public Builder setArg1(int value) {
+        result.hasArg1 = true;
+        result.arg1_ = value;
+        return this;
+      }
+      public Builder clearArg1() {
+        result.hasArg1 = false;
+        result.arg1_ = 0;
+        return this;
+      }
+      
+      // optional int32 arg2 = 8;
+      public boolean hasArg2() {
+        return result.hasArg2();
+      }
+      public int getArg2() {
+        return result.getArg2();
+      }
+      public Builder setArg2(int value) {
+        result.hasArg2 = true;
+        result.arg2_ = value;
+        return this;
+      }
+      public Builder clearArg2() {
+        result.hasArg2 = false;
+        result.arg2_ = 0;
+        return this;
+      }
+      
+      // optional int32 arg3 = 9;
+      public boolean hasArg3() {
+        return result.hasArg3();
+      }
+      public int getArg3() {
+        return result.getArg3();
+      }
+      public Builder setArg3(int value) {
+        result.hasArg3 = true;
+        result.arg3_ = value;
+        return this;
+      }
+      public Builder clearArg3() {
+        result.hasArg3 = false;
+        result.arg3_ = 0;
+        return this;
+      }
+      
+      // optional int32 arg4 = 16;
+      public boolean hasArg4() {
+        return result.hasArg4();
+      }
+      public int getArg4() {
+        return result.getArg4();
+      }
+      public Builder setArg4(int value) {
+        result.hasArg4 = true;
+        result.arg4_ = value;
+        return this;
+      }
+      public Builder clearArg4() {
+        result.hasArg4 = false;
+        result.arg4_ = 0;
+        return this;
+      }
+      
+      // optional int32 arg5 = 17;
+      public boolean hasArg5() {
+        return result.hasArg5();
+      }
+      public int getArg5() {
+        return result.getArg5();
+      }
+      public Builder setArg5(int value) {
+        result.hasArg5 = true;
+        result.arg5_ = value;
+        return this;
+      }
+      public Builder clearArg5() {
+        result.hasArg5 = false;
+        result.arg5_ = 0;
+        return this;
+      }
+      
+      // optional int32 arg6 = 18;
+      public boolean hasArg6() {
+        return result.hasArg6();
+      }
+      public int getArg6() {
+        return result.getArg6();
+      }
+      public Builder setArg6(int value) {
+        result.hasArg6 = true;
+        result.arg6_ = value;
+        return this;
+      }
+      public Builder clearArg6() {
+        result.hasArg6 = false;
+        result.arg6_ = 0;
+        return this;
+      }
+      
+      // optional int32 arg7 = 19;
+      public boolean hasArg7() {
+        return result.hasArg7();
+      }
+      public int getArg7() {
+        return result.getArg7();
+      }
+      public Builder setArg7(int value) {
+        result.hasArg7 = true;
+        result.arg7_ = value;
+        return this;
+      }
+      public Builder clearArg7() {
+        result.hasArg7 = false;
+        result.arg7_ = 0;
+        return this;
+      }
+      
+      // optional int32 arg8 = 20;
+      public boolean hasArg8() {
+        return result.hasArg8();
+      }
+      public int getArg8() {
+        return result.getArg8();
+      }
+      public Builder setArg8(int value) {
+        result.hasArg8 = true;
+        result.arg8_ = value;
+        return this;
+      }
+      public Builder clearArg8() {
+        result.hasArg8 = false;
+        result.arg8_ = 0;
+        return this;
+      }
+      
+      // optional bytes data = 10;
+      public boolean hasData() {
+        return result.hasData();
+      }
+      public com.google.protobuf.ByteString getData() {
+        return result.getData();
+      }
+      public Builder setData(com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  result.hasData = true;
+        result.data_ = value;
+        return this;
+      }
+      public Builder clearData() {
+        result.hasData = false;
+        result.data_ = getDefaultInstance().getData();
+        return this;
+      }
+      
+      // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+      public boolean hasDataType() {
+        return result.hasDataType();
+      }
+      public com.android.glesv2debugger.DebuggerMessage.Message.DataType getDataType() {
+        return result.getDataType();
+      }
+      public Builder setDataType(com.android.glesv2debugger.DebuggerMessage.Message.DataType value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        result.hasDataType = true;
+        result.dataType_ = value;
+        return this;
+      }
+      public Builder clearDataType() {
+        result.hasDataType = false;
+        result.dataType_ = com.android.glesv2debugger.DebuggerMessage.Message.DataType.ReferencedImage;
+        return this;
+      }
+      
+      // optional int32 pixel_format = 24;
+      public boolean hasPixelFormat() {
+        return result.hasPixelFormat();
+      }
+      public int getPixelFormat() {
+        return result.getPixelFormat();
+      }
+      public Builder setPixelFormat(int value) {
+        result.hasPixelFormat = true;
+        result.pixelFormat_ = value;
+        return this;
+      }
+      public Builder clearPixelFormat() {
+        result.hasPixelFormat = false;
+        result.pixelFormat_ = 0;
+        return this;
+      }
+      
+      // optional int32 pixel_type = 25;
+      public boolean hasPixelType() {
+        return result.hasPixelType();
+      }
+      public int getPixelType() {
+        return result.getPixelType();
+      }
+      public Builder setPixelType(int value) {
+        result.hasPixelType = true;
+        result.pixelType_ = value;
+        return this;
+      }
+      public Builder clearPixelType() {
+        result.hasPixelType = false;
+        result.pixelType_ = 0;
+        return this;
+      }
+      
+      // optional int32 image_width = 26;
+      public boolean hasImageWidth() {
+        return result.hasImageWidth();
+      }
+      public int getImageWidth() {
+        return result.getImageWidth();
+      }
+      public Builder setImageWidth(int value) {
+        result.hasImageWidth = true;
+        result.imageWidth_ = value;
+        return this;
+      }
+      public Builder clearImageWidth() {
+        result.hasImageWidth = false;
+        result.imageWidth_ = 0;
+        return this;
+      }
+      
+      // optional int32 image_height = 27;
+      public boolean hasImageHeight() {
+        return result.hasImageHeight();
+      }
+      public int getImageHeight() {
+        return result.getImageHeight();
+      }
+      public Builder setImageHeight(int value) {
+        result.hasImageHeight = true;
+        result.imageHeight_ = value;
+        return this;
+      }
+      public Builder clearImageHeight() {
+        result.hasImageHeight = false;
+        result.imageHeight_ = 0;
+        return this;
+      }
+      
+      // optional float time = 11;
+      public boolean hasTime() {
+        return result.hasTime();
+      }
+      public float getTime() {
+        return result.getTime();
+      }
+      public Builder setTime(float value) {
+        result.hasTime = true;
+        result.time_ = value;
+        return this;
+      }
+      public Builder clearTime() {
+        result.hasTime = false;
+        result.time_ = 0F;
+        return this;
+      }
+      
+      // optional .com.android.glesv2debugger.Message.Prop prop = 21;
+      public boolean hasProp() {
+        return result.hasProp();
+      }
+      public com.android.glesv2debugger.DebuggerMessage.Message.Prop getProp() {
+        return result.getProp();
+      }
+      public Builder setProp(com.android.glesv2debugger.DebuggerMessage.Message.Prop value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        result.hasProp = true;
+        result.prop_ = value;
+        return this;
+      }
+      public Builder clearProp() {
+        result.hasProp = false;
+        result.prop_ = com.android.glesv2debugger.DebuggerMessage.Message.Prop.CaptureDraw;
+        return this;
+      }
+      
+      // optional float clock = 22;
+      public boolean hasClock() {
+        return result.hasClock();
+      }
+      public float getClock() {
+        return result.getClock();
+      }
+      public Builder setClock(float value) {
+        result.hasClock = true;
+        result.clock_ = value;
+        return this;
+      }
+      public Builder clearClock() {
+        result.hasClock = false;
+        result.clock_ = 0F;
+        return this;
+      }
+      
+      // @@protoc_insertion_point(builder_scope:com.android.glesv2debugger.Message)
+    }
+    
+    static {
+      defaultInstance = new Message(true);
+      com.android.glesv2debugger.DebuggerMessage.internalForceInit();
+      defaultInstance.initFields();
+    }
+    
+    // @@protoc_insertion_point(class_scope:com.android.glesv2debugger.Message)
+  }
+  
+  
+  static {
+  }
+  
+  public static void internalForceInit() {}
+  
+  // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLEnum.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLEnum.java
new file mode 100644
index 0000000..898c6e9
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLEnum.java
@@ -0,0 +1,632 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+// auto generated by generate_GLEnum_java.py"
+
+package com.android.glesv2debugger;
+
+public enum GLEnum {
+    GL_POINTS(0x0000),
+    GL_LINES(0x0001),
+    GL_LINE_LOOP(0x0002),
+    GL_LINE_STRIP(0x0003),
+    GL_TRIANGLES(0x0004),
+    GL_TRIANGLE_STRIP(0x0005),
+    GL_TRIANGLE_FAN(0x0006),
+    GL_ADD(0x0104),
+    GL_NEVER(0x0200),
+    GL_LESS(0x0201),
+    GL_EQUAL(0x0202),
+    GL_LEQUAL(0x0203),
+    GL_GREATER(0x0204),
+    GL_NOTEQUAL(0x0205),
+    GL_GEQUAL(0x0206),
+    GL_ALWAYS(0x0207),
+    GL_SRC_COLOR(0x0300),
+    GL_ONE_MINUS_SRC_COLOR(0x0301),
+    GL_SRC_ALPHA(0x0302),
+    GL_ONE_MINUS_SRC_ALPHA(0x0303),
+    GL_DST_ALPHA(0x0304),
+    GL_ONE_MINUS_DST_ALPHA(0x0305),
+    GL_DST_COLOR(0x0306),
+    GL_ONE_MINUS_DST_COLOR(0x0307),
+    GL_SRC_ALPHA_SATURATE(0x0308),
+    GL_FRONT(0x0404),
+    GL_BACK(0x0405),
+    GL_FRONT_AND_BACK(0x0408),
+    GL_INVALID_ENUM(0x0500),
+    GL_INVALID_VALUE(0x0501),
+    GL_INVALID_OPERATION(0x0502),
+    GL_STACK_OVERFLOW(0x0503),
+    GL_STACK_UNDERFLOW(0x0504),
+    GL_OUT_OF_MEMORY(0x0505),
+    GL_INVALID_FRAMEBUFFER_OPERATION(0x0506),
+    GL_EXP(0x0800),
+    GL_EXP2(0x0801),
+    GL_CW(0x0900),
+    GL_CCW(0x0901),
+    GL_CURRENT_COLOR(0x0B00),
+    GL_CURRENT_NORMAL(0x0B02),
+    GL_CURRENT_TEXTURE_COORDS(0x0B03),
+    GL_POINT_SMOOTH(0x0B10),
+    GL_POINT_SIZE(0x0B11),
+    GL_SMOOTH_POINT_SIZE_RANGE(0x0B12),
+    GL_LINE_SMOOTH(0x0B20),
+    GL_LINE_WIDTH(0x0B21),
+    GL_SMOOTH_LINE_WIDTH_RANGE(0x0B22),
+    GL_CULL_FACE(0x0B44),
+    GL_CULL_FACE_MODE(0x0B45),
+    GL_FRONT_FACE(0x0B46),
+    GL_LIGHTING(0x0B50),
+    GL_LIGHT_MODEL_TWO_SIDE(0x0B52),
+    GL_LIGHT_MODEL_AMBIENT(0x0B53),
+    GL_SHADE_MODEL(0x0B54),
+    GL_COLOR_MATERIAL(0x0B57),
+    GL_FOG(0x0B60),
+    GL_FOG_DENSITY(0x0B62),
+    GL_FOG_START(0x0B63),
+    GL_FOG_END(0x0B64),
+    GL_FOG_MODE(0x0B65),
+    GL_FOG_COLOR(0x0B66),
+    GL_DEPTH_RANGE(0x0B70),
+    GL_DEPTH_TEST(0x0B71),
+    GL_DEPTH_WRITEMASK(0x0B72),
+    GL_DEPTH_CLEAR_VALUE(0x0B73),
+    GL_DEPTH_FUNC(0x0B74),
+    GL_STENCIL_TEST(0x0B90),
+    GL_STENCIL_CLEAR_VALUE(0x0B91),
+    GL_STENCIL_FUNC(0x0B92),
+    GL_STENCIL_VALUE_MASK(0x0B93),
+    GL_STENCIL_FAIL(0x0B94),
+    GL_STENCIL_PASS_DEPTH_FAIL(0x0B95),
+    GL_STENCIL_PASS_DEPTH_PASS(0x0B96),
+    GL_STENCIL_REF(0x0B97),
+    GL_STENCIL_WRITEMASK(0x0B98),
+    GL_MATRIX_MODE(0x0BA0),
+    GL_NORMALIZE(0x0BA1),
+    GL_VIEWPORT(0x0BA2),
+    GL_MODELVIEW_STACK_DEPTH(0x0BA3),
+    GL_PROJECTION_STACK_DEPTH(0x0BA4),
+    GL_TEXTURE_STACK_DEPTH(0x0BA5),
+    GL_MODELVIEW_MATRIX(0x0BA6),
+    GL_PROJECTION_MATRIX(0x0BA7),
+    GL_TEXTURE_MATRIX(0x0BA8),
+    GL_ALPHA_TEST(0x0BC0),
+    GL_ALPHA_TEST_FUNC(0x0BC1),
+    GL_ALPHA_TEST_REF(0x0BC2),
+    GL_DITHER(0x0BD0),
+    GL_BLEND_DST(0x0BE0),
+    GL_BLEND_SRC(0x0BE1),
+    GL_BLEND(0x0BE2),
+    GL_LOGIC_OP_MODE(0x0BF0),
+    GL_COLOR_LOGIC_OP(0x0BF2),
+    GL_SCISSOR_BOX(0x0C10),
+    GL_SCISSOR_TEST(0x0C11),
+    GL_COLOR_CLEAR_VALUE(0x0C22),
+    GL_COLOR_WRITEMASK(0x0C23),
+    GL_PERSPECTIVE_CORRECTION_HINT(0x0C50),
+    GL_POINT_SMOOTH_HINT(0x0C51),
+    GL_LINE_SMOOTH_HINT(0x0C52),
+    GL_FOG_HINT(0x0C54),
+    GL_UNPACK_ALIGNMENT(0x0CF5),
+    GL_PACK_ALIGNMENT(0x0D05),
+    GL_ALPHA_SCALE(0x0D1C),
+    GL_MAX_LIGHTS(0x0D31),
+    GL_MAX_CLIP_PLANES(0x0D32),
+    GL_MAX_TEXTURE_SIZE(0x0D33),
+    GL_MAX_MODELVIEW_STACK_DEPTH(0x0D36),
+    GL_MAX_PROJECTION_STACK_DEPTH(0x0D38),
+    GL_MAX_TEXTURE_STACK_DEPTH(0x0D39),
+    GL_MAX_VIEWPORT_DIMS(0x0D3A),
+    GL_SUBPIXEL_BITS(0x0D50),
+    GL_RED_BITS(0x0D52),
+    GL_GREEN_BITS(0x0D53),
+    GL_BLUE_BITS(0x0D54),
+    GL_ALPHA_BITS(0x0D55),
+    GL_DEPTH_BITS(0x0D56),
+    GL_STENCIL_BITS(0x0D57),
+    GL_TEXTURE_2D(0x0DE1),
+    GL_DONT_CARE(0x1100),
+    GL_FASTEST(0x1101),
+    GL_NICEST(0x1102),
+    GL_AMBIENT(0x1200),
+    GL_DIFFUSE(0x1201),
+    GL_SPECULAR(0x1202),
+    GL_POSITION(0x1203),
+    GL_SPOT_DIRECTION(0x1204),
+    GL_SPOT_EXPONENT(0x1205),
+    GL_SPOT_CUTOFF(0x1206),
+    GL_CONSTANT_ATTENUATION(0x1207),
+    GL_LINEAR_ATTENUATION(0x1208),
+    GL_QUADRATIC_ATTENUATION(0x1209),
+    GL_BYTE(0x1400),
+    GL_UNSIGNED_BYTE(0x1401),
+    GL_SHORT(0x1402),
+    GL_UNSIGNED_SHORT(0x1403),
+    GL_INT(0x1404),
+    GL_UNSIGNED_INT(0x1405),
+    GL_FLOAT(0x1406),
+    GL_FIXED(0x140C),
+    GL_CLEAR(0x1500),
+    GL_AND(0x1501),
+    GL_AND_REVERSE(0x1502),
+    GL_COPY(0x1503),
+    GL_AND_INVERTED(0x1504),
+    GL_NOOP(0x1505),
+    GL_XOR(0x1506),
+    GL_OR(0x1507),
+    GL_NOR(0x1508),
+    GL_EQUIV(0x1509),
+    GL_INVERT(0x150A),
+    GL_OR_REVERSE(0x150B),
+    GL_COPY_INVERTED(0x150C),
+    GL_OR_INVERTED(0x150D),
+    GL_NAND(0x150E),
+    GL_SET(0x150F),
+    GL_EMISSION(0x1600),
+    GL_SHININESS(0x1601),
+    GL_AMBIENT_AND_DIFFUSE(0x1602),
+    GL_MODELVIEW(0x1700),
+    GL_PROJECTION(0x1701),
+    GL_TEXTURE(0x1702),
+    GL_COLOR_EXT(0x1800),
+    GL_DEPTH_EXT(0x1801),
+    GL_STENCIL_EXT(0x1802),
+    GL_STENCIL_INDEX(0x1901),
+    GL_DEPTH_COMPONENT(0x1902),
+    GL_ALPHA(0x1906),
+    GL_RGB(0x1907),
+    GL_RGBA(0x1908),
+    GL_LUMINANCE(0x1909),
+    GL_LUMINANCE_ALPHA(0x190A),
+    GL_FLAT(0x1D00),
+    GL_SMOOTH(0x1D01),
+    GL_KEEP(0x1E00),
+    GL_REPLACE(0x1E01),
+    GL_INCR(0x1E02),
+    GL_DECR(0x1E03),
+    GL_VENDOR(0x1F00),
+    GL_RENDERER(0x1F01),
+    GL_VERSION(0x1F02),
+    GL_EXTENSIONS(0x1F03),
+    GL_MODULATE(0x2100),
+    GL_DECAL(0x2101),
+    GL_TEXTURE_ENV_MODE(0x2200),
+    GL_TEXTURE_ENV_COLOR(0x2201),
+    GL_TEXTURE_ENV(0x2300),
+    GL_TEXTURE_GEN_MODE(0x2500),
+    GL_NEAREST(0x2600),
+    GL_LINEAR(0x2601),
+    GL_NEAREST_MIPMAP_NEAREST(0x2700),
+    GL_LINEAR_MIPMAP_NEAREST(0x2701),
+    GL_NEAREST_MIPMAP_LINEAR(0x2702),
+    GL_LINEAR_MIPMAP_LINEAR(0x2703),
+    GL_TEXTURE_MAG_FILTER(0x2800),
+    GL_TEXTURE_MIN_FILTER(0x2801),
+    GL_TEXTURE_WRAP_S(0x2802),
+    GL_TEXTURE_WRAP_T(0x2803),
+    GL_REPEAT(0x2901),
+    GL_POLYGON_OFFSET_UNITS(0x2A00),
+    GL_CLIP_PLANE0(0x3000),
+    GL_CLIP_PLANE1(0x3001),
+    GL_CLIP_PLANE2(0x3002),
+    GL_CLIP_PLANE3(0x3003),
+    GL_CLIP_PLANE4(0x3004),
+    GL_CLIP_PLANE5(0x3005),
+    GL_LIGHT0(0x4000),
+    GL_LIGHT1(0x4001),
+    GL_LIGHT2(0x4002),
+    GL_LIGHT3(0x4003),
+    GL_LIGHT4(0x4004),
+    GL_LIGHT5(0x4005),
+    GL_LIGHT6(0x4006),
+    GL_LIGHT7(0x4007),
+    GL_COVERAGE_BUFFER_BIT_NV(0x8000),
+    GL_CONSTANT_COLOR(0x8001),
+    GL_ONE_MINUS_CONSTANT_COLOR(0x8002),
+    GL_CONSTANT_ALPHA(0x8003),
+    GL_ONE_MINUS_CONSTANT_ALPHA(0x8004),
+    GL_BLEND_COLOR(0x8005),
+    GL_FUNC_ADD(0x8006),
+    GL_MIN_EXT(0x8007),
+    GL_MAX_EXT(0x8008),
+    GL_BLEND_EQUATION_RGB(0x8009),
+    GL_FUNC_SUBTRACT(0x800A),
+    GL_FUNC_REVERSE_SUBTRACT(0x800B),
+    GL_UNSIGNED_SHORT_4_4_4_4(0x8033),
+    GL_UNSIGNED_SHORT_5_5_5_1(0x8034),
+    GL_POLYGON_OFFSET_FILL(0x8037),
+    GL_POLYGON_OFFSET_FACTOR(0x8038),
+    GL_RESCALE_NORMAL(0x803A),
+    GL_RGB8(0x8051),
+    GL_RGBA4(0x8056),
+    GL_RGB5_A1(0x8057),
+    GL_RGBA8(0x8058),
+    GL_TEXTURE_BINDING_2D(0x8069),
+    GL_TEXTURE_BINDING_3D(0x806A),
+    GL_TEXTURE_3D(0x806F),
+    GL_TEXTURE_WRAP_R(0x8072),
+    GL_MAX_3D_TEXTURE_SIZE(0x8073),
+    GL_VERTEX_ARRAY(0x8074),
+    GL_NORMAL_ARRAY(0x8075),
+    GL_COLOR_ARRAY(0x8076),
+    GL_TEXTURE_COORD_ARRAY(0x8078),
+    GL_VERTEX_ARRAY_SIZE(0x807A),
+    GL_VERTEX_ARRAY_TYPE(0x807B),
+    GL_VERTEX_ARRAY_STRIDE(0x807C),
+    GL_NORMAL_ARRAY_TYPE(0x807E),
+    GL_NORMAL_ARRAY_STRIDE(0x807F),
+    GL_COLOR_ARRAY_SIZE(0x8081),
+    GL_COLOR_ARRAY_TYPE(0x8082),
+    GL_COLOR_ARRAY_STRIDE(0x8083),
+    GL_TEXTURE_COORD_ARRAY_SIZE(0x8088),
+    GL_TEXTURE_COORD_ARRAY_TYPE(0x8089),
+    GL_TEXTURE_COORD_ARRAY_STRIDE(0x808A),
+    GL_VERTEX_ARRAY_POINTER(0x808E),
+    GL_NORMAL_ARRAY_POINTER(0x808F),
+    GL_COLOR_ARRAY_POINTER(0x8090),
+    GL_TEXTURE_COORD_ARRAY_POINTER(0x8092),
+    GL_MULTISAMPLE(0x809D),
+    GL_SAMPLE_ALPHA_TO_COVERAGE(0x809E),
+    GL_SAMPLE_ALPHA_TO_ONE(0x809F),
+    GL_SAMPLE_COVERAGE(0x80A0),
+    GL_SAMPLE_BUFFERS(0x80A8),
+    GL_SAMPLES(0x80A9),
+    GL_SAMPLE_COVERAGE_VALUE(0x80AA),
+    GL_SAMPLE_COVERAGE_INVERT(0x80AB),
+    GL_BLEND_DST_RGB(0x80C8),
+    GL_BLEND_SRC_RGB(0x80C9),
+    GL_BLEND_DST_ALPHA(0x80CA),
+    GL_BLEND_SRC_ALPHA(0x80CB),
+    GL_BGRA_EXT(0x80E1),
+    GL_POINT_SIZE_MIN(0x8126),
+    GL_POINT_SIZE_MAX(0x8127),
+    GL_POINT_FADE_THRESHOLD_SIZE(0x8128),
+    GL_POINT_DISTANCE_ATTENUATION(0x8129),
+    GL_CLAMP_TO_EDGE(0x812F),
+    GL_GENERATE_MIPMAP(0x8191),
+    GL_GENERATE_MIPMAP_HINT(0x8192),
+    GL_DEPTH_COMPONENT16(0x81A5),
+    GL_DEPTH_COMPONENT24(0x81A6),
+    GL_DEPTH_COMPONENT32(0x81A7),
+    GL_UNSIGNED_SHORT_5_6_5(0x8363),
+    GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT(0x8365),
+    GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT(0x8366),
+    GL_UNSIGNED_INT_2_10_10_10_REV_EXT(0x8368),
+    GL_MIRRORED_REPEAT(0x8370),
+    GL_COMPRESSED_RGB_S3TC_DXT1_EXT(0x83F0),
+    GL_COMPRESSED_RGBA_S3TC_DXT1_EXT(0x83F1),
+    GL_ALIASED_POINT_SIZE_RANGE(0x846D),
+    GL_ALIASED_LINE_WIDTH_RANGE(0x846E),
+    GL_TEXTURE0(0x84C0),
+    GL_TEXTURE1(0x84C1),
+    GL_TEXTURE2(0x84C2),
+    GL_TEXTURE3(0x84C3),
+    GL_TEXTURE4(0x84C4),
+    GL_TEXTURE5(0x84C5),
+    GL_TEXTURE6(0x84C6),
+    GL_TEXTURE7(0x84C7),
+    GL_TEXTURE8(0x84C8),
+    GL_TEXTURE9(0x84C9),
+    GL_TEXTURE10(0x84CA),
+    GL_TEXTURE11(0x84CB),
+    GL_TEXTURE12(0x84CC),
+    GL_TEXTURE13(0x84CD),
+    GL_TEXTURE14(0x84CE),
+    GL_TEXTURE15(0x84CF),
+    GL_TEXTURE16(0x84D0),
+    GL_TEXTURE17(0x84D1),
+    GL_TEXTURE18(0x84D2),
+    GL_TEXTURE19(0x84D3),
+    GL_TEXTURE20(0x84D4),
+    GL_TEXTURE21(0x84D5),
+    GL_TEXTURE22(0x84D6),
+    GL_TEXTURE23(0x84D7),
+    GL_TEXTURE24(0x84D8),
+    GL_TEXTURE25(0x84D9),
+    GL_TEXTURE26(0x84DA),
+    GL_TEXTURE27(0x84DB),
+    GL_TEXTURE28(0x84DC),
+    GL_TEXTURE29(0x84DD),
+    GL_TEXTURE30(0x84DE),
+    GL_TEXTURE31(0x84DF),
+    GL_ACTIVE_TEXTURE(0x84E0),
+    GL_CLIENT_ACTIVE_TEXTURE(0x84E1),
+    GL_MAX_TEXTURE_UNITS(0x84E2),
+    GL_SUBTRACT(0x84E7),
+    GL_MAX_RENDERBUFFER_SIZE(0x84E8),
+    GL_ALL_COMPLETED_NV(0x84F2),
+    GL_FENCE_STATUS_NV(0x84F3),
+    GL_FENCE_CONDITION_NV(0x84F4),
+    GL_DEPTH_STENCIL(0x84F9),
+    GL_UNSIGNED_INT_24_8(0x84FA),
+    GL_MAX_TEXTURE_LOD_BIAS_EXT(0x84FD),
+    GL_TEXTURE_MAX_ANISOTROPY_EXT(0x84FE),
+    GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT(0x84FF),
+    GL_TEXTURE_FILTER_CONTROL_EXT(0x8500),
+    GL_TEXTURE_LOD_BIAS_EXT(0x8501),
+    GL_INCR_WRAP(0x8507),
+    GL_DECR_WRAP(0x8508),
+    GL_NORMAL_MAP(0x8511),
+    GL_REFLECTION_MAP(0x8512),
+    GL_TEXTURE_CUBE_MAP(0x8513),
+    GL_TEXTURE_BINDING_CUBE_MAP(0x8514),
+    GL_TEXTURE_CUBE_MAP_POSITIVE_X(0x8515),
+    GL_TEXTURE_CUBE_MAP_NEGATIVE_X(0x8516),
+    GL_TEXTURE_CUBE_MAP_POSITIVE_Y(0x8517),
+    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y(0x8518),
+    GL_TEXTURE_CUBE_MAP_POSITIVE_Z(0x8519),
+    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z(0x851A),
+    GL_MAX_CUBE_MAP_TEXTURE_SIZE(0x851C),
+    GL_COMBINE(0x8570),
+    GL_COMBINE_RGB(0x8571),
+    GL_COMBINE_ALPHA(0x8572),
+    GL_RGB_SCALE(0x8573),
+    GL_ADD_SIGNED(0x8574),
+    GL_INTERPOLATE(0x8575),
+    GL_CONSTANT(0x8576),
+    GL_PRIMARY_COLOR(0x8577),
+    GL_PREVIOUS(0x8578),
+    GL_SRC0_RGB(0x8580),
+    GL_SRC1_RGB(0x8581),
+    GL_SRC2_RGB(0x8582),
+    GL_SRC0_ALPHA(0x8588),
+    GL_SRC1_ALPHA(0x8589),
+    GL_SRC2_ALPHA(0x858A),
+    GL_OPERAND0_RGB(0x8590),
+    GL_OPERAND1_RGB(0x8591),
+    GL_OPERAND2_RGB(0x8592),
+    GL_OPERAND0_ALPHA(0x8598),
+    GL_OPERAND1_ALPHA(0x8599),
+    GL_OPERAND2_ALPHA(0x859A),
+    GL_VERTEX_ARRAY_BINDING(0x85B5),
+    GL_VERTEX_ATTRIB_ARRAY_ENABLED(0x8622),
+    GL_VERTEX_ATTRIB_ARRAY_SIZE(0x8623),
+    GL_VERTEX_ATTRIB_ARRAY_STRIDE(0x8624),
+    GL_VERTEX_ATTRIB_ARRAY_TYPE(0x8625),
+    GL_CURRENT_VERTEX_ATTRIB(0x8626),
+    GL_VERTEX_ATTRIB_ARRAY_POINTER(0x8645),
+    GL_NUM_COMPRESSED_TEXTURE_FORMATS(0x86A2),
+    GL_COMPRESSED_TEXTURE_FORMATS(0x86A3),
+    GL_MAX_VERTEX_UNITS(0x86A4),
+    GL_WEIGHT_ARRAY_TYPE(0x86A9),
+    GL_WEIGHT_ARRAY_STRIDE(0x86AA),
+    GL_WEIGHT_ARRAY_SIZE(0x86AB),
+    GL_WEIGHT_ARRAY_POINTER(0x86AC),
+    GL_WEIGHT_ARRAY(0x86AD),
+    GL_DOT3_RGB(0x86AE),
+    GL_DOT3_RGBA(0x86AF),
+    GL_Z400_BINARY_AMD(0x8740),
+    GL_PROGRAM_BINARY_LENGTH(0x8741),
+    GL_BUFFER_SIZE(0x8764),
+    GL_BUFFER_USAGE(0x8765),
+    GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD(0x87EE),
+    GL_3DC_X_AMD(0x87F9),
+    GL_3DC_XY_AMD(0x87FA),
+    GL_NUM_PROGRAM_BINARY_FORMATS(0x87FE),
+    GL_PROGRAM_BINARY_FORMATS(0x87FF),
+    GL_STENCIL_BACK_FUNC(0x8800),
+    GL_STENCIL_BACK_FAIL(0x8801),
+    GL_STENCIL_BACK_PASS_DEPTH_FAIL(0x8802),
+    GL_STENCIL_BACK_PASS_DEPTH_PASS(0x8803),
+    GL_WRITEONLY_RENDERING_QCOM(0x8823),
+    GL_BLEND_EQUATION_ALPHA(0x883D),
+    GL_MATRIX_PALETTE(0x8840),
+    GL_MAX_PALETTE_MATRICES(0x8842),
+    GL_CURRENT_PALETTE_MATRIX(0x8843),
+    GL_MATRIX_INDEX_ARRAY(0x8844),
+    GL_MATRIX_INDEX_ARRAY_SIZE(0x8846),
+    GL_MATRIX_INDEX_ARRAY_TYPE(0x8847),
+    GL_MATRIX_INDEX_ARRAY_STRIDE(0x8848),
+    GL_MATRIX_INDEX_ARRAY_POINTER(0x8849),
+    GL_POINT_SPRITE(0x8861),
+    GL_COORD_REPLACE(0x8862),
+    GL_MAX_VERTEX_ATTRIBS(0x8869),
+    GL_VERTEX_ATTRIB_ARRAY_NORMALIZED(0x886A),
+    GL_MAX_TEXTURE_IMAGE_UNITS(0x8872),
+    GL_ARRAY_BUFFER(0x8892),
+    GL_ELEMENT_ARRAY_BUFFER(0x8893),
+    GL_ARRAY_BUFFER_BINDING(0x8894),
+    GL_ELEMENT_ARRAY_BUFFER_BINDING(0x8895),
+    GL_VERTEX_ARRAY_BUFFER_BINDING(0x8896),
+    GL_NORMAL_ARRAY_BUFFER_BINDING(0x8897),
+    GL_COLOR_ARRAY_BUFFER_BINDING(0x8898),
+    GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING(0x889A),
+    GL_WEIGHT_ARRAY_BUFFER_BINDING(0x889E),
+    GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING(0x889F),
+    GL_WRITE_ONLY(0x88B9),
+    GL_BUFFER_ACCESS(0x88BB),
+    GL_BUFFER_MAPPED(0x88BC),
+    GL_BUFFER_MAP_POINTER(0x88BD),
+    GL_STREAM_DRAW(0x88E0),
+    GL_STATIC_DRAW(0x88E4),
+    GL_DYNAMIC_DRAW(0x88E8),
+    GL_DEPTH24_STENCIL8(0x88F0),
+    GL_POINT_SIZE_ARRAY_TYPE(0x898A),
+    GL_POINT_SIZE_ARRAY_STRIDE(0x898B),
+    GL_POINT_SIZE_ARRAY_POINTER(0x898C),
+    GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS(0x898D),
+    GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS(0x898E),
+    GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS(0x898F),
+    GL_FRAGMENT_SHADER(0x8B30),
+    GL_VERTEX_SHADER(0x8B31),
+    GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS(0x8B4C),
+    GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS(0x8B4D),
+    GL_SHADER_TYPE(0x8B4F),
+    GL_FLOAT_VEC2(0x8B50),
+    GL_FLOAT_VEC3(0x8B51),
+    GL_FLOAT_VEC4(0x8B52),
+    GL_INT_VEC2(0x8B53),
+    GL_INT_VEC3(0x8B54),
+    GL_INT_VEC4(0x8B55),
+    GL_BOOL(0x8B56),
+    GL_BOOL_VEC2(0x8B57),
+    GL_BOOL_VEC3(0x8B58),
+    GL_BOOL_VEC4(0x8B59),
+    GL_FLOAT_MAT2(0x8B5A),
+    GL_FLOAT_MAT3(0x8B5B),
+    GL_FLOAT_MAT4(0x8B5C),
+    GL_SAMPLER_2D(0x8B5E),
+    GL_SAMPLER_3D(0x8B5F),
+    GL_SAMPLER_CUBE(0x8B60),
+    GL_DELETE_STATUS(0x8B80),
+    GL_COMPILE_STATUS(0x8B81),
+    GL_LINK_STATUS(0x8B82),
+    GL_VALIDATE_STATUS(0x8B83),
+    GL_INFO_LOG_LENGTH(0x8B84),
+    GL_ATTACHED_SHADERS(0x8B85),
+    GL_ACTIVE_UNIFORMS(0x8B86),
+    GL_ACTIVE_UNIFORM_MAX_LENGTH(0x8B87),
+    GL_SHADER_SOURCE_LENGTH(0x8B88),
+    GL_ACTIVE_ATTRIBUTES(0x8B89),
+    GL_ACTIVE_ATTRIBUTE_MAX_LENGTH(0x8B8A),
+    GL_FRAGMENT_SHADER_DERIVATIVE_HINT(0x8B8B),
+    GL_SHADING_LANGUAGE_VERSION(0x8B8C),
+    GL_CURRENT_PROGRAM(0x8B8D),
+    GL_PALETTE4_RGB8(0x8B90),
+    GL_PALETTE4_RGBA8(0x8B91),
+    GL_PALETTE4_R5_G6_B5(0x8B92),
+    GL_PALETTE4_RGBA4(0x8B93),
+    GL_PALETTE4_RGB5_A1(0x8B94),
+    GL_PALETTE8_RGB8(0x8B95),
+    GL_PALETTE8_RGBA8(0x8B96),
+    GL_PALETTE8_R5_G6_B5(0x8B97),
+    GL_PALETTE8_RGBA4(0x8B98),
+    GL_PALETTE8_RGB5_A1(0x8B99),
+    GL_IMPLEMENTATION_COLOR_READ_TYPE(0x8B9A),
+    GL_IMPLEMENTATION_COLOR_READ_FORMAT(0x8B9B),
+    GL_POINT_SIZE_ARRAY(0x8B9C),
+    GL_TEXTURE_CROP_RECT(0x8B9D),
+    GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING(0x8B9E),
+    GL_POINT_SIZE_ARRAY_BUFFER_BINDING(0x8B9F),
+    GL_COUNTER_TYPE_AMD(0x8BC0),
+    GL_COUNTER_RANGE_AMD(0x8BC1),
+    GL_UNSIGNED_INT64_AMD(0x8BC2),
+    GL_PERCENTAGE_AMD(0x8BC3),
+    GL_PERFMON_RESULT_AVAILABLE_AMD(0x8BC4),
+    GL_PERFMON_RESULT_SIZE_AMD(0x8BC5),
+    GL_PERFMON_RESULT_AMD(0x8BC6),
+    GL_TEXTURE_WIDTH_QCOM(0x8BD2),
+    GL_TEXTURE_HEIGHT_QCOM(0x8BD3),
+    GL_TEXTURE_DEPTH_QCOM(0x8BD4),
+    GL_TEXTURE_INTERNAL_FORMAT_QCOM(0x8BD5),
+    GL_TEXTURE_FORMAT_QCOM(0x8BD6),
+    GL_TEXTURE_TYPE_QCOM(0x8BD7),
+    GL_TEXTURE_IMAGE_VALID_QCOM(0x8BD8),
+    GL_TEXTURE_NUM_LEVELS_QCOM(0x8BD9),
+    GL_TEXTURE_TARGET_QCOM(0x8BDA),
+    GL_TEXTURE_OBJECT_VALID_QCOM(0x8BDB),
+    GL_STATE_RESTORE(0x8BDC),
+    GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG(0x8C00),
+    GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG(0x8C01),
+    GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG(0x8C02),
+    GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG(0x8C03),
+    GL_MODULATE_COLOR_IMG(0x8C04),
+    GL_RECIP_ADD_SIGNED_ALPHA_IMG(0x8C05),
+    GL_TEXTURE_ALPHA_MODULATE_IMG(0x8C06),
+    GL_FACTOR_ALPHA_MODULATE_IMG(0x8C07),
+    GL_FRAGMENT_ALPHA_MODULATE_IMG(0x8C08),
+    GL_ADD_BLEND_IMG(0x8C09),
+    GL_SGX_BINARY_IMG(0x8C0A),
+    GL_ATC_RGB_AMD(0x8C92),
+    GL_ATC_RGBA_EXPLICIT_ALPHA_AMD(0x8C93),
+    GL_STENCIL_BACK_REF(0x8CA3),
+    GL_STENCIL_BACK_VALUE_MASK(0x8CA4),
+    GL_STENCIL_BACK_WRITEMASK(0x8CA5),
+    GL_FRAMEBUFFER_BINDING(0x8CA6),
+    GL_RENDERBUFFER_BINDING(0x8CA7),
+    GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE(0x8CD0),
+    GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME(0x8CD1),
+    GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL(0x8CD2),
+    GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE(0x8CD3),
+    GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET(0x8CD4),
+    GL_FRAMEBUFFER_COMPLETE(0x8CD5),
+    GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT(0x8CD6),
+    GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT(0x8CD7),
+    GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS(0x8CD9),
+    GL_FRAMEBUFFER_INCOMPLETE_FORMATS(0x8CDA),
+    GL_FRAMEBUFFER_UNSUPPORTED(0x8CDD),
+    GL_COLOR_ATTACHMENT0(0x8CE0),
+    GL_DEPTH_ATTACHMENT(0x8D00),
+    GL_STENCIL_ATTACHMENT(0x8D20),
+    GL_FRAMEBUFFER(0x8D40),
+    GL_RENDERBUFFER(0x8D41),
+    GL_RENDERBUFFER_WIDTH(0x8D42),
+    GL_RENDERBUFFER_HEIGHT(0x8D43),
+    GL_RENDERBUFFER_INTERNAL_FORMAT(0x8D44),
+    GL_STENCIL_INDEX1(0x8D46),
+    GL_STENCIL_INDEX4(0x8D47),
+    GL_STENCIL_INDEX8(0x8D48),
+    GL_RENDERBUFFER_RED_SIZE(0x8D50),
+    GL_RENDERBUFFER_GREEN_SIZE(0x8D51),
+    GL_RENDERBUFFER_BLUE_SIZE(0x8D52),
+    GL_RENDERBUFFER_ALPHA_SIZE(0x8D53),
+    GL_RENDERBUFFER_DEPTH_SIZE(0x8D54),
+    GL_RENDERBUFFER_STENCIL_SIZE(0x8D55),
+    GL_TEXTURE_GEN_STR(0x8D60),
+    GL_HALF_FLOAT(0x8D61),
+    GL_RGB565(0x8D62),
+    GL_ETC1_RGB8(0x8D64),
+    GL_TEXTURE_EXTERNAL(0x8D65),
+    GL_SAMPLER_EXTERNAL(0x8D66),
+    GL_TEXTURE_BINDING_EXTERNAL(0x8D67),
+    GL_REQUIRED_TEXTURE_IMAGE_UNITS(0x8D68),
+    GL_LOW_FLOAT(0x8DF0),
+    GL_MEDIUM_FLOAT(0x8DF1),
+    GL_HIGH_FLOAT(0x8DF2),
+    GL_LOW_INT(0x8DF3),
+    GL_MEDIUM_INT(0x8DF4),
+    GL_HIGH_INT(0x8DF5),
+    GL_UNSIGNED_INT_10_10_10_2(0x8DF6),
+    GL_INT_10_10_10_2(0x8DF7),
+    GL_SHADER_BINARY_FORMATS(0x8DF8),
+    GL_NUM_SHADER_BINARY_FORMATS(0x8DF9),
+    GL_SHADER_COMPILER(0x8DFA),
+    GL_MAX_VERTEX_UNIFORM_VECTORS(0x8DFB),
+    GL_MAX_VARYING_VECTORS(0x8DFC),
+    GL_MAX_FRAGMENT_UNIFORM_VECTORS(0x8DFD),
+    GL_DEPTH_COMPONENT16_NONLINEAR_NV(0x8E2C),
+    GL_COVERAGE_COMPONENT_NV(0x8ED0),
+    GL_COVERAGE_COMPONENT4_NV(0x8ED1),
+    GL_COVERAGE_ATTACHMENT_NV(0x8ED2),
+    GL_COVERAGE_BUFFERS_NV(0x8ED3),
+    GL_COVERAGE_SAMPLES_NV(0x8ED4),
+    GL_COVERAGE_ALL_FRAGMENTS_NV(0x8ED5),
+    GL_COVERAGE_EDGE_FRAGMENTS_NV(0x8ED6),
+    GL_COVERAGE_AUTOMATIC_NV(0x8ED7),
+    GL_PERFMON_GLOBAL_MODE_QCOM(0x8FA0),
+    GL_SGX_PROGRAM_BINARY_IMG(0x9130),
+    GL_RENDERBUFFER_SAMPLES_IMG(0x9133),
+    GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG(0x9134),
+    GL_MAX_SAMPLES_IMG(0x9135),
+    GL_TEXTURE_SAMPLES_IMG(0x9136),
+    ;
+
+    public final int value;
+    GLEnum(final int value) {
+        this.value = value;
+    }
+
+    private static final java.util.HashMap<Integer, GLEnum> reverseMap = new java.util.HashMap<Integer, GLEnum>();
+    static {
+        for (GLEnum e : GLEnum.values())
+        reverseMap.put(e.value, e);
+    }
+
+    public static GLEnum valueOf(final int value) {
+        return reverseMap.get(value);
+    }
+}
\ No newline at end of file
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java
new file mode 100644
index 0000000..f13c465
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java
@@ -0,0 +1,259 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.sdklib.util.SparseArray;
+
+import java.util.ArrayList;
+
+class GLShader implements Cloneable {
+    public final int name;
+    GLServerShader context; // the context this was created in
+    public final GLEnum type;
+    public boolean delete;
+    public ArrayList<Integer> programs = new ArrayList<Integer>();
+    public String source, originalSource;
+
+    GLShader(final int name, final GLServerShader context, final GLEnum type) {
+        this.name = name;
+        this.context = context;
+        this.type = type;
+    }
+
+    /** deep copy */
+    public GLShader clone(final GLServerShader copyContext) {
+        try {
+            GLShader shader = (GLShader) super.clone();
+            shader.programs = (ArrayList<Integer>) programs.clone();
+            shader.context = copyContext;
+            return shader;
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            assert false;
+            return null;
+        }
+    }
+}
+
+class GLProgram implements Cloneable {
+    public final int name;
+    GLServerShader context; // the context this was created in
+    public boolean delete;
+    public int vert, frag;
+
+    GLProgram(final int name, final GLServerShader context) {
+        this.name = name;
+        this.context = context;
+    }
+
+    /** deep copy */
+    public GLProgram clone(final GLServerShader copyContext) {
+        try {
+            GLProgram copy = (GLProgram) super.clone();
+            copy.context = copyContext;
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            assert false;
+            return null;
+        }
+    }
+}
+
+public class GLServerShader implements Cloneable {
+    Context context;
+    public SparseArray<GLShader> shaders = new SparseArray<GLShader>();
+    public SparseArray<GLProgram> programs = new SparseArray<GLProgram>();
+    public GLProgram current = null;
+    boolean uiUpdate = false;
+
+    GLServerShader(Context context) {
+        this.context = context;
+    }
+
+    /** deep copy */
+    public GLServerShader clone(final Context copyContext) {
+        try {
+            GLServerShader copy = (GLServerShader) super.clone();
+            copy.context = copyContext;
+
+            copy.shaders = new SparseArray<GLShader>(shaders.size());
+            for (int i = 0; i < shaders.size(); i++)
+                copy.shaders.append(shaders.keyAt(i), shaders.valueAt(i).clone(copy));
+
+            copy.programs = new SparseArray<GLProgram>(programs.size());
+            for (int i = 0; i < programs.size(); i++)
+                copy.programs.append(programs.keyAt(i), programs.valueAt(i).clone(copy));
+
+            if (current != null)
+                copy.current = copy.programs.get(current.name);
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            assert false;
+            return null;
+        }
+    }
+
+    /** returns true if processed */
+    public boolean processMessage(final Message msg) {
+        boolean oldUiUpdate = uiUpdate;
+        uiUpdate = true;
+        switch (msg.getFunction()) {
+            case glAttachShader:
+                glAttachShader(msg);
+                return true;
+            case glCreateProgram:
+                glCreateProgram(msg);
+                return true;
+            case glCreateShader:
+                glCreateShader(msg);
+                return true;
+            case glDeleteProgram:
+                glDeleteProgram(msg);
+                return true;
+            case glDeleteShader:
+                glDeleteShader(msg);
+                return true;
+            case glDetachShader:
+                glDetachShader(msg);
+                return true;
+            case glShaderSource:
+                glShaderSource(msg);
+                return true;
+            case glUseProgram:
+                glUseProgram(msg);
+                return true;
+            default:
+                uiUpdate = oldUiUpdate;
+                return false;
+        }
+    }
+
+    GLShader getShader(int name) {
+        if (name == 0)
+            return null;
+        for (Context ctx : context.shares) {
+            GLShader shader = ctx.serverShader.shaders.get(name);
+            if (shader != null)
+                return shader;
+        }
+        assert false;
+        return null;
+    }
+
+    GLProgram getProgram(int name) {
+        if (name == 0)
+            return null;
+        for (Context ctx : context.shares) {
+            GLProgram program = ctx.serverShader.programs.get(name);
+            if (program != null)
+                return program;
+        }
+        assert false;
+        return null;
+    }
+
+    // void API_ENTRY(glAttachShader)(GLuint program, GLuint shader)
+    void glAttachShader(final Message msg) {
+        GLProgram program = getProgram(msg.getArg0());
+        assert program != null;
+        GLShader shader = getShader(msg.getArg1());
+        assert program != null;
+        if (GLEnum.GL_VERTEX_SHADER == shader.type)
+            program.vert = shader.name;
+        else
+            program.frag = shader.name;
+        shader.programs.add(program.name);
+    }
+
+    // GLuint API_ENTRY(glCreateProgram)(void)
+    void glCreateProgram(final Message msg) {
+        programs.put(msg.getRet(), new GLProgram(msg.getRet(), this));
+    }
+
+    // GLuint API_ENTRY(glCreateShader)(GLenum type)
+    void glCreateShader(final Message msg) {
+        shaders.put(msg.getRet(),
+                new GLShader(msg.getRet(), this, GLEnum.valueOf(msg.getArg0())));
+    }
+
+    // void API_ENTRY(glDeleteProgram)
+    void glDeleteProgram(final Message msg) {
+        if (msg.getArg0() == 0)
+            return;
+        GLProgram program = getProgram(msg.getArg0());
+        program.delete = true;
+        for (Context ctx : context.shares)
+            if (ctx.serverShader.current == program)
+                return;
+        glDetachShader(program, getShader(program.vert));
+        glDetachShader(program, getShader(program.frag));
+        programs.remove(program.name);
+    }
+
+    // void API_ENTRY(glDeleteShader)(GLuint shader)
+    void glDeleteShader(final Message msg) {
+        if (msg.getArg0() == 0)
+            return;
+        GLShader shader = getShader(msg.getArg0());
+        shader.delete = true;
+        if (shader.programs.size() == 0)
+            shaders.remove(shader.name);
+    }
+
+    // void API_ENTRY(glDetachShader)(GLuint program, GLuint shader)
+    void glDetachShader(final Message msg) {
+        glDetachShader(getProgram(msg.getArg0()), getShader(msg.getArg1()));
+    }
+
+    void glDetachShader(final GLProgram program, final GLShader shader) {
+        if (program == null)
+            return;
+        if (program.vert == shader.name)
+            program.vert = 0;
+        else if (program.frag == shader.name)
+            program.frag = 0;
+        else
+            return;
+        shader.programs.remove(new Integer(program.name));
+        if (shader.delete && shader.programs.size() == 0)
+            shaders.remove(shader.name);
+    }
+
+    // void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const
+    // GLchar** string, const GLint* length)
+    void glShaderSource(final Message msg) {
+        if (!msg.hasData())
+            return; // TODO: distinguish between generated calls
+        GLShader shader = getShader(msg.getArg0());
+        shader.source = shader.originalSource = msg.getData().toStringUtf8();
+    }
+
+    // void API_ENTRY(glUseProgram)(GLuint program)
+    void glUseProgram(final Message msg) {
+        GLProgram oldCurrent = current;
+        current = getProgram(msg.getArg0());
+        if (null != oldCurrent && oldCurrent.delete && oldCurrent != current) {
+            for (Context ctx : context.shares)
+                if (ctx.serverShader.current == oldCurrent)
+                    return;
+            oldCurrent.context.programs.remove(new Integer(oldCurrent.name));
+        }
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerState.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerState.java
new file mode 100644
index 0000000..addf277
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerState.java
@@ -0,0 +1,271 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.android.sdklib.util.SparseArray;
+import com.android.sdklib.util.SparseIntArray;
+
+class GLStencilState implements Cloneable {
+    public int ref, mask;
+    public GLEnum func;
+    public GLEnum sf, df, dp; // operation
+
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+}
+
+public class GLServerState implements Cloneable {
+    final Context context;
+    public GLStencilState front = new GLStencilState(), back = new GLStencilState();
+    public SparseIntArray enableDisables;
+
+    /** integer states set via a GL function and GLEnum; keyed by GLEnum.value */
+    public SparseArray<Message> integers;
+
+    /** states set only via a GL function; keyed by Function.getNumber() */
+    public SparseArray<Message> lastSetter;
+
+    GLServerState(final Context context) {
+        this.context = context;
+        enableDisables = new SparseIntArray();
+        enableDisables.put(GLEnum.GL_BLEND.value, 0);
+        enableDisables.put(GLEnum.GL_DITHER.value, 1);
+        enableDisables.put(GLEnum.GL_DEPTH_TEST.value, 0);
+        enableDisables.put(GLEnum.GL_STENCIL_TEST.value, 0);
+        enableDisables.put(GLEnum.GL_SCISSOR_TEST.value, 0);
+        enableDisables.put(GLEnum.GL_SAMPLE_COVERAGE.value, 0);
+        enableDisables.put(GLEnum.GL_SAMPLE_ALPHA_TO_COVERAGE.value, 0);
+        enableDisables.put(GLEnum.GL_POLYGON_OFFSET_FILL.value, 0);
+        enableDisables.put(GLEnum.GL_CULL_FACE.value, 0);
+        // enableDisables.put(GLEnum.GL_TEXTURE_2D.value, 1);
+
+        lastSetter = new SparseArray<Message>();
+        lastSetter.put(Function.glBlendColor.getNumber(), null);
+        // glBlendEquation overwrites glBlendEquationSeparate
+        lastSetter.put(Function.glBlendEquationSeparate.getNumber(), null);
+        // glBlendFunc overwrites glBlendFuncSeparate
+        lastSetter.put(Function.glBlendFuncSeparate.getNumber(), null);
+        lastSetter.put(Function.glClearColor.getNumber(), null);
+        lastSetter.put(Function.glClearDepthf.getNumber(), null);
+        lastSetter.put(Function.glClearStencil.getNumber(), null);
+        lastSetter.put(Function.glColorMask.getNumber(), null);
+        lastSetter.put(Function.glCullFace.getNumber(), null);
+        lastSetter.put(Function.glDepthMask.getNumber(), null);
+        lastSetter.put(Function.glDepthFunc.getNumber(), null);
+        lastSetter.put(Function.glDepthRangef.getNumber(), null);
+        lastSetter.put(Function.glFrontFace.getNumber(), null);
+        lastSetter.put(Function.glLineWidth.getNumber(), null);
+        lastSetter.put(Function.glPolygonOffset.getNumber(), null);
+        lastSetter.put(Function.glSampleCoverage.getNumber(), null);
+        lastSetter.put(Function.glScissor.getNumber(), null);
+        lastSetter.put(Function.glStencilMaskSeparate.getNumber(), null);
+        lastSetter.put(Function.glViewport.getNumber(), null);
+
+        integers = new SparseArray<Message>();
+        integers.put(GLEnum.GL_PACK_ALIGNMENT.value, null);
+        integers.put(GLEnum.GL_UNPACK_ALIGNMENT.value, null);
+    }
+
+    /** returns true if processed */
+    public boolean processMessage(final Message msg) {
+        switch (msg.getFunction()) {
+            case glBlendColor:
+            case glBlendEquation:
+            case glBlendEquationSeparate:
+            case glBlendFunc:
+            case glBlendFuncSeparate:
+            case glClearColor:
+            case glClearDepthf:
+            case glClearStencil:
+            case glColorMask:
+            case glCullFace:
+            case glDepthMask:
+            case glDepthFunc:
+            case glDepthRangef:
+                return setter(msg);
+            case glDisable:
+                return enableDisable(false, msg);
+            case glEnable:
+                return enableDisable(true, msg);
+            case glFrontFace:
+            case glLineWidth:
+                return setter(msg);
+            case glPixelStorei:
+                if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_PACK_ALIGNMENT)
+                    integers.put(msg.getArg0(), msg);
+                else if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_UNPACK_ALIGNMENT)
+                    integers.put(msg.getArg0(), msg);
+                else
+                    assert false;
+                return true;
+            case glPolygonOffset:
+            case glSampleCoverage:
+            case glScissor:
+                return setter(msg);
+            case glStencilFunc: {
+                Message.Builder builder = msg.toBuilder();
+                builder.setArg2(msg.getArg1());
+                builder.setArg1(msg.getArg0());
+                builder.setArg0(GLEnum.GL_FRONT_AND_BACK.value);
+                return glStencilFuncSeparate(builder.build());
+            }
+            case glStencilFuncSeparate:
+                return glStencilFuncSeparate(msg);
+            case glStencilMask:
+            case glStencilMaskSeparate:
+                return setter(msg);
+            case glStencilOp: {
+                Message.Builder builder = msg.toBuilder();
+                builder.setArg3(msg.getArg2());
+                builder.setArg2(msg.getArg1());
+                builder.setArg1(msg.getArg0());
+                builder.setArg0(GLEnum.GL_FRONT_AND_BACK.value);
+                return glStencilOpSeparate(builder.build());
+            }
+            case glStencilOpSeparate:
+                return glStencilOpSeparate(msg);
+            case glViewport:
+                return setter(msg);
+            default:
+                return false;
+        }
+    }
+
+    boolean setter(final Message msg) {
+        switch (msg.getFunction()) {
+            case glBlendFunc:
+                lastSetter.put(Function.glBlendFuncSeparate.getNumber(), msg);
+                break;
+            case glBlendEquation:
+                lastSetter.put(Function.glBlendEquationSeparate.getNumber(), msg);
+                break;
+            case glStencilMask:
+                lastSetter.put(Function.glStencilMaskSeparate.getNumber(), msg);
+                break;
+            default:
+                lastSetter.put(msg.getFunction().getNumber(), msg);
+                break;
+        }
+        return true;
+    }
+
+    boolean enableDisable(boolean enable, final Message msg) {
+        int index = enableDisables.indexOfKey(msg.getArg0());
+        if (index < 0) {
+            System.out.print("invalid glDisable/Enable: ");
+            System.out.println(MessageFormatter.format(msg, false));
+            return true;
+        }
+        if ((enableDisables.valueAt(index) != 0) == enable)
+            return true; // TODO: redundant
+        enableDisables.put(msg.getArg0(), enable ? 1 : 0);
+        return true;
+    }
+
+    // void StencilFuncSeparate( enum face, enum func, int ref, uint mask )
+    boolean glStencilFuncSeparate(final Message msg) {
+        GLEnum ff = front.func, bf = back.func;
+        int fr = front.ref, br = back.ref;
+        int fm = front.mask, bm = back.mask;
+        final GLEnum face = GLEnum.valueOf(msg.getArg0());
+        if (face == GLEnum.GL_FRONT || face == GLEnum.GL_FRONT_AND_BACK) {
+            ff = GLEnum.valueOf(msg.getArg1());
+            fr = msg.getArg2();
+            fm = msg.getArg3();
+        }
+        if (face == GLEnum.GL_BACK || face == GLEnum.GL_FRONT_AND_BACK) {
+            bf = GLEnum.valueOf(msg.getArg1());
+            br = msg.getArg2();
+            bm = msg.getArg3();
+        }
+        if (ff == front.func && fr == front.ref && fm == front.mask)
+            if (bf == back.func && br == back.ref && bm == back.mask)
+                return true; // TODO: redundant
+        front.func = ff;
+        front.ref = fr;
+        front.mask = fm;
+        back.func = bf;
+        back.ref = br;
+        back.mask = bm;
+        return true;
+    }
+
+    // void StencilOpSeparate( enum face, enum sfail, enum dpfail, enum dppass )
+    boolean glStencilOpSeparate(final Message msg) {
+        GLEnum fsf = front.sf, fdf = front.df, fdp = front.dp;
+        GLEnum bsf = back.sf, bdf = back.df, bdp = back.dp;
+        final GLEnum face = GLEnum.valueOf(msg.getArg0());
+        if (face == GLEnum.GL_FRONT || face == GLEnum.GL_FRONT_AND_BACK) {
+            fsf = GLEnum.valueOf(msg.getArg1());
+            fdf = GLEnum.valueOf(msg.getArg2());
+            fdp = GLEnum.valueOf(msg.getArg3());
+        }
+        if (face == GLEnum.GL_BACK || face == GLEnum.GL_FRONT_AND_BACK) {
+            bsf = GLEnum.valueOf(msg.getArg1());
+            bdf = GLEnum.valueOf(msg.getArg2());
+            bdp = GLEnum.valueOf(msg.getArg3());
+        }
+        if (fsf == front.sf && fdf == front.df && fdp == front.dp)
+            if (bsf == back.sf && bdf == back.df && bdp == back.dp)
+                return true; // TODO: redundant
+        front.sf = fsf;
+        front.df = fdf;
+        front.dp = fdp;
+        back.sf = bsf;
+        back.df = bdf;
+        back.dp = bdp;
+        return true;
+    }
+
+    /** deep copy */
+    @Override
+    public GLServerState clone() {
+        try {
+            GLServerState newState = (GLServerState) super.clone();
+            newState.front = (GLStencilState) front.clone();
+            newState.back = (GLStencilState) back.clone();
+
+            newState.enableDisables = new SparseIntArray(enableDisables.size());
+            for (int i = 0; i < enableDisables.size(); i++)
+                newState.enableDisables.append(enableDisables.keyAt(i),
+                        enableDisables.valueAt(i));
+
+            newState.integers = new SparseArray<Message>(integers.size());
+            for (int i = 0; i < integers.size(); i++)
+                newState.integers.append(integers.keyAt(i), integers.valueAt(i));
+
+            newState.lastSetter = new SparseArray<Message>(lastSetter.size());
+            for (int i = 0; i < lastSetter.size(); i++)
+                newState.lastSetter.append(lastSetter.keyAt(i), lastSetter.valueAt(i));
+
+            return newState;
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            assert false;
+            return null;
+        }
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerTexture.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerTexture.java
new file mode 100644
index 0000000..27676dd
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerTexture.java
@@ -0,0 +1,235 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.sdklib.util.SparseArray;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+class GLTexture implements Cloneable {
+    public final int name;
+    public final GLEnum target;
+    public ArrayList<Message> contentChanges = new ArrayList<Message>();
+    public GLEnum wrapS = GLEnum.GL_REPEAT, wrapT = GLEnum.GL_REPEAT;
+    public GLEnum min = GLEnum.GL_NEAREST_MIPMAP_LINEAR;
+    public GLEnum mag = GLEnum.GL_LINEAR;
+    public GLEnum format;
+    public int width, height;
+
+    GLTexture(final int name, final GLEnum target) {
+        this.name = name;
+        this.target = target;
+    }
+
+    @Override
+    public GLTexture clone() {
+        try {
+            GLTexture copy = (GLTexture) super.clone();
+            copy.contentChanges = (ArrayList<Message>) contentChanges.clone();
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            assert false;
+            return null;
+        }
+    }
+
+    boolean processMessage(final Message msg) {
+        switch (msg.getFunction()) {
+            case glCompressedTexImage2D:
+            case glCopyTexImage2D:
+            case glTexImage2D:
+                if (msg.getArg1() == 0) { // level 0
+                    format = GLEnum.valueOf(msg.getArg2());
+                    width = msg.getArg3();
+                    height = msg.getArg4();
+                }
+                //$FALL-THROUGH$
+            case glCompressedTexSubImage2D:
+            case glCopyTexSubImage2D:
+            case glTexSubImage2D:
+            case glGenerateMipmap:
+                contentChanges.add(msg);
+                break;
+            default:
+                assert false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s %s %d*%d %d change(s)", target, format, width, height,
+                contentChanges.size());
+    }
+}
+
+public class GLServerTexture implements Cloneable {
+    Context context;
+
+    public GLEnum activeTexture = GLEnum.GL_TEXTURE0;
+    public int[] tmu2D;
+    public int[] tmuCube;
+    public SparseArray<GLTexture> textures = new SparseArray<GLTexture>();
+    public GLTexture tex2D = null, texCube = null;
+
+    GLServerTexture(final Context context, final int MAX_COMBINED_TEXTURE_IMAGE_UNITS) {
+        this.context = context;
+        textures.append(0, null);
+        tmu2D = new int[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+        tmuCube = new int[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+    }
+
+    public GLServerTexture clone(final Context copyContext) {
+        try {
+            GLServerTexture copy = (GLServerTexture) super.clone();
+            copy.context = copyContext;
+
+            copy.tmu2D = tmu2D.clone();
+            copy.tmuCube = tmuCube.clone();
+
+            copy.textures = new SparseArray<GLTexture>(textures.size());
+            for (int i = 0; i < textures.size(); i++)
+                if (textures.valueAt(i) != null)
+                    copy.textures.append(textures.keyAt(i), textures.valueAt(i).clone());
+                else
+                    copy.textures.append(textures.keyAt(i), null);
+
+            if (tex2D != null)
+                copy.tex2D = copy.textures.get(tex2D.name);
+            if (texCube != null)
+                copy.texCube = copy.textures.get(texCube.name);
+
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            assert false;
+            return null;
+        }
+    }
+
+    public boolean processMessage(final Message msg) {
+        switch (msg.getFunction()) {
+            case glActiveTexture:
+                activeTexture = GLEnum.valueOf(msg.getArg0());
+                return true;
+            case glBindTexture:
+                return bindTexture(msg.getArg0(), msg.getArg1());
+            case glCompressedTexImage2D:
+            case glCompressedTexSubImage2D:
+            case glCopyTexImage2D:
+            case glCopyTexSubImage2D:
+            case glTexImage2D:
+            case glTexSubImage2D:
+                switch (GLEnum.valueOf(msg.getArg0())) {
+                    case GL_TEXTURE_2D:
+                        if (tex2D != null)
+                            return tex2D.processMessage(msg);
+                        return true;
+                    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+                    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+                    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+                    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+                    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+                    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+                        if (texCube != null)
+                            return texCube.processMessage(msg);
+                        return true;
+                    default:
+                        return true;
+                }
+            case glDeleteTextures: {
+                final ByteBuffer names = msg.getData().asReadOnlyByteBuffer();
+                names.order(SampleView.targetByteOrder);
+                for (int i = 0; i < msg.getArg0(); i++) {
+                    final int name = names.getInt();
+                    if (tex2D != null && tex2D.name == name)
+                        bindTexture(GLEnum.GL_TEXTURE_2D.value, 0);
+                    if (texCube != null && texCube.name == name)
+                        bindTexture(GLEnum.GL_TEXTURE_CUBE_MAP.value, 0);
+                    if (name != 0)
+                        textures.remove(name);
+                }
+                return true;
+            }
+            case glGenerateMipmap:
+                if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_TEXTURE_2D && tex2D != null)
+                    return tex2D.processMessage(msg);
+                else if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_TEXTURE_CUBE_MAP
+                        && texCube != null)
+                    return texCube.processMessage(msg);
+                return true;
+            case glTexParameteri:
+                return texParameter(msg.getArg0(), msg.getArg1(), msg.getArg2());
+            case glTexParameterf:
+                return texParameter(msg.getArg0(), msg.getArg1(),
+                        (int) Float.intBitsToFloat(msg.getArg2()));
+            default:
+                return false;
+        }
+    }
+
+    boolean bindTexture(final int target, final int name) {
+        final int index = activeTexture.value - GLEnum.GL_TEXTURE0.value;
+        if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_2D) {
+            tex2D = textures.get(name);
+            if (name != 0 && tex2D == null)
+                textures.put(name, tex2D = new GLTexture(name,
+                        GLEnum.GL_TEXTURE_2D));
+            if (index >= 0 && index < tmu2D.length)
+                tmu2D[index] = name;
+        } else if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_CUBE_MAP) {
+            texCube = textures.get(name);
+            if (name != 0 && texCube == null)
+                textures.put(name, texCube = new GLTexture(name,
+                        GLEnum.GL_TEXTURE_CUBE_MAP));
+            if (index >= 0 && index < tmu2D.length)
+                tmu2D[index] = name;
+        } else
+            assert false;
+        return true;
+    }
+
+    boolean texParameter(final int target, final int pname, final int param) {
+        GLTexture tex = null;
+        if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_2D)
+            tex = tex2D;
+        else if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_CUBE_MAP)
+            tex = texCube;
+        if (tex == null)
+            return true;
+        final GLEnum p = GLEnum.valueOf(param);
+        switch (GLEnum.valueOf(pname)) {
+            case GL_TEXTURE_WRAP_S:
+                tex.wrapS = p;
+                return true;
+            case GL_TEXTURE_WRAP_T:
+                tex.wrapT = p;
+                return true;
+            case GL_TEXTURE_MIN_FILTER:
+                tex.min = p;
+                return true;
+            case GL_TEXTURE_MAG_FILTER:
+                tex.mag = p;
+                return true;
+            default:
+                return true;
+        }
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java
new file mode 100644
index 0000000..5f9d513
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java
@@ -0,0 +1,542 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.sdklib.util.SparseArray;
+
+import java.nio.ByteBuffer;
+
+class GLBuffer implements Cloneable {
+    public final int name;
+    public GLEnum usage;
+    public GLEnum target;
+    /** in SampleView.targetByteOrder */
+    public ByteBuffer data;
+
+    public GLBuffer(final int name) {
+        this.name = name;
+    }
+
+    /** deep copy */
+    @Override
+    public GLBuffer clone() {
+        try {
+            GLBuffer copy = (GLBuffer) super.clone();
+            if (data != null) {
+                copy.data = ByteBuffer.allocate(data.capacity());
+                copy.data.order(SampleView.targetByteOrder);
+                data.position(0);
+                copy.data.put(data);
+            }
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            assert false;
+            return null;
+        }
+    }
+}
+
+class GLAttribPointer implements Cloneable {
+    public int size; // number of values per vertex
+    public GLEnum type; // data type
+    public int stride; // bytes
+    /**
+     * element stride in bytes, used when fetching from buffer; not for fetching
+     * from user pointer since server already packed elements
+     */
+    int elemStride; // in bytes
+    /** element size in bytes */
+    int elemSize;
+    public int ptr; // pointer in debugger server or byte offset into buffer
+    public GLBuffer buffer;
+    public boolean normalized;
+    public boolean enabled;
+
+    /** deep copy, re-maps buffer into copyBuffers */
+    public GLAttribPointer clone(SparseArray<GLBuffer> copyBuffers) {
+        try {
+            GLAttribPointer copy = (GLAttribPointer) super.clone();
+            if (buffer != null)
+                copy.buffer = copyBuffers.get(buffer.name);
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            assert false;
+            return null;
+        }
+    }
+}
+
+public class GLServerVertex implements Cloneable {
+    public SparseArray<GLBuffer> buffers = new SparseArray<GLBuffer>();
+    public GLBuffer attribBuffer, indexBuffer; // current binding
+    public GLAttribPointer attribPointers[];
+    public float defaultAttribs[][];
+
+    public GLServerVertex(final int MAX_VERTEX_ATTRIBS) {
+        buffers.append(0, null);
+        attribPointers = new GLAttribPointer[MAX_VERTEX_ATTRIBS];
+        for (int i = 0; i < attribPointers.length; i++)
+            attribPointers[i] = new GLAttribPointer();
+        defaultAttribs = new float[MAX_VERTEX_ATTRIBS][4];
+        for (int i = 0; i < defaultAttribs.length; i++) {
+            defaultAttribs[i][0] = 0;
+            defaultAttribs[i][1] = 0;
+            defaultAttribs[i][2] = 0;
+            defaultAttribs[i][3] = 1;
+        }
+    }
+
+    /** deep copy */
+    @Override
+    public GLServerVertex clone() {
+        try {
+            GLServerVertex copy = (GLServerVertex) super.clone();
+
+            copy.buffers = new SparseArray<GLBuffer>(buffers.size());
+            for (int i = 0; i < buffers.size(); i++)
+                if (buffers.valueAt(i) != null)
+                    copy.buffers.append(buffers.keyAt(i), buffers.valueAt(i).clone());
+                else
+                    copy.buffers.append(buffers.keyAt(i), null);
+
+            if (attribBuffer != null)
+                copy.attribBuffer = copy.buffers.get(attribBuffer.name);
+            if (indexBuffer != null)
+                copy.indexBuffer = copy.buffers.get(indexBuffer.name);
+
+            copy.attribPointers = new GLAttribPointer[attribPointers.length];
+            for (int i = 0; i < attribPointers.length; i++)
+                copy.attribPointers[i] = attribPointers[i].clone(copy.buffers);
+
+            copy.defaultAttribs = defaultAttribs.clone();
+
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            e.printStackTrace();
+            assert false;
+            return null;
+        }
+    }
+
+    /** returns true if processed */
+    public boolean process(final Message msg) {
+        switch (msg.getFunction()) {
+            case glBindBuffer:
+                glBindBuffer(msg);
+                return true;
+            case glBufferData:
+                glBufferData(msg);
+                return true;
+            case glBufferSubData:
+                glBufferSubData(msg);
+                return true;
+            case glDeleteBuffers:
+                glDeleteBuffers(msg);
+                return true;
+            case glDrawArrays:
+            case glDrawElements:
+                return true;
+            case glDisableVertexAttribArray:
+                glDisableVertexAttribArray(msg);
+                return true;
+            case glEnableVertexAttribArray:
+                glEnableVertexAttribArray(msg);
+                return true;
+            case glGenBuffers:
+                glGenBuffers(msg);
+                return true;
+            case glVertexAttribPointer:
+                glVertexAttribPointer(msg);
+                return true;
+            case glVertexAttrib1f:
+                glVertexAttrib1f(msg);
+                return true;
+            case glVertexAttrib1fv:
+                glVertexAttrib1fv(msg);
+                return true;
+            case glVertexAttrib2f:
+                glVertexAttrib2f(msg);
+                return true;
+            case glVertexAttrib2fv:
+                glVertexAttrib2fv(msg);
+                return true;
+            case glVertexAttrib3f:
+                glVertexAttrib3f(msg);
+                return true;
+            case glVertexAttrib3fv:
+                glVertexAttrib3fv(msg);
+                return true;
+            case glVertexAttrib4f:
+                glVertexAttrib4f(msg);
+                return true;
+            case glVertexAttrib4fv:
+                glVertexAttrib4fv(msg);
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    // void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer)
+    public void glBindBuffer(Message msg) {
+        if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_ARRAY_BUFFER) {
+            attribBuffer = buffers.get(msg.getArg1());
+            if (null != attribBuffer)
+                attribBuffer.target = GLEnum.GL_ARRAY_BUFFER;
+        } else if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_ELEMENT_ARRAY_BUFFER) {
+            indexBuffer = buffers.get(msg.getArg1());
+            if (null != indexBuffer)
+                indexBuffer.target = GLEnum.GL_ELEMENT_ARRAY_BUFFER;
+        } else
+            assert false;
+    }
+
+    // void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const
+    // GLvoid:size:in data, GLenum usage)
+    public void glBufferData(Message msg) {
+        if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_ARRAY_BUFFER) {
+            attribBuffer.usage = GLEnum.valueOf(msg.getArg3());
+            attribBuffer.data = msg.getData().asReadOnlyByteBuffer();
+            attribBuffer.data.order(SampleView.targetByteOrder);
+        } else if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_ELEMENT_ARRAY_BUFFER) {
+            indexBuffer.usage = GLEnum.valueOf(msg.getArg3());
+            indexBuffer.data = msg.getData().asReadOnlyByteBuffer();
+            indexBuffer.data.order(SampleView.targetByteOrder);
+        } else
+            assert false;
+    }
+
+    // void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset,
+    // GLsizeiptr size, const GLvoid:size:in data)
+    public void glBufferSubData(Message msg) {
+        if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_ARRAY_BUFFER) {
+            if (attribBuffer.data.isReadOnly()) {
+                ByteBuffer buffer = ByteBuffer.allocate(attribBuffer.data.capacity());
+                buffer.order(SampleView.targetByteOrder);
+                buffer.put(attribBuffer.data);
+                attribBuffer.data = buffer;
+            }
+            attribBuffer.data.position(msg.getArg1());
+            attribBuffer.data.put(msg.getData().asReadOnlyByteBuffer());
+        } else if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_ELEMENT_ARRAY_BUFFER) {
+            if (indexBuffer.data.isReadOnly()) {
+                ByteBuffer buffer = ByteBuffer.allocate(indexBuffer.data.capacity());
+                buffer.order(SampleView.targetByteOrder);
+                buffer.put(indexBuffer.data);
+                indexBuffer.data = buffer;
+            }
+            indexBuffer.data.position(msg.getArg1());
+            indexBuffer.data.put(msg.getData().asReadOnlyByteBuffer());
+        } else
+            assert false;
+    }
+
+    // void glDeleteBuffers(GLsizei n, const GLuint* buffers)
+    public void glDeleteBuffers(Message msg) {
+        final int n = msg.getArg0();
+        final ByteBuffer names = msg.getData().asReadOnlyByteBuffer();
+        names.order(SampleView.targetByteOrder);
+        for (int i = 0; i < n; i++) {
+            final int name = names.getInt();
+            final GLBuffer buffer = buffers.get(name);
+            for (int j = 0; j < attribPointers.length; j++)
+                if (attribPointers[j].buffer == buffer) {
+                    attribPointers[j].buffer = null;
+                    attribPointers[j].enabled = false;
+                }
+            if (attribBuffer == buffer)
+                attribBuffer = null;
+            if (indexBuffer == buffer)
+                indexBuffer = null;
+            buffers.remove(name);
+        }
+    }
+
+    // void glDisableVertexAttribArray(GLuint index)
+    public void glDisableVertexAttribArray(Message msg) {
+        if (msg.getArg0() >= 0 && msg.getArg0() < attribPointers.length)
+            attribPointers[msg.getArg0()].enabled = false;
+    }
+
+    float fetchConvert(final ByteBuffer src, final GLEnum type, final boolean normalized) {
+        if (GLEnum.GL_FLOAT == type)
+            return Float.intBitsToFloat(src.getInt());
+        else if (GLEnum.GL_UNSIGNED_INT == type)
+            if (normalized)
+                return (src.getInt() & 0xffffffffL) / (2e32f - 1);
+            else
+                return src.getInt() & 0xffffffffL;
+        else if (GLEnum.GL_INT == type)
+            if (normalized)
+                return (src.getInt() * 2 + 1) / (2e32f - 1);
+            else
+                return src.getInt();
+        else if (GLEnum.GL_UNSIGNED_SHORT == type)
+            if (normalized)
+                return (src.getShort() & 0xffff) / (2e16f - 1);
+            else
+                return src.getShort() & 0xffff;
+        else if (GLEnum.GL_SHORT == type)
+            if (normalized)
+                return (src.getShort() * 2 + 1) / (2e16f - 1);
+            else
+                return src.getShort();
+        else if (GLEnum.GL_UNSIGNED_BYTE == type)
+            if (normalized)
+                return (src.get() & 0xff) / (2e8f - 1);
+            else
+                return src.get() & 0xff;
+        else if (GLEnum.GL_BYTE == type)
+            if (normalized)
+                return (src.get() * 2 + 1) / (2e8f - 1);
+            else
+                return src.get();
+        else if (GLEnum.GL_FIXED == type)
+            if (normalized)
+                return (src.getInt() * 2 + 1) / (2e32f - 1);
+            else
+                return src.getInt() / (2e16f);
+        else
+            assert false;
+        return 0;
+    }
+
+    static int typeSize(final GLEnum type) {
+        switch (type) {
+            case GL_FLOAT:
+            case GL_UNSIGNED_INT:
+            case GL_INT:
+            case GL_FIXED:
+                return 4;
+            case GL_UNSIGNED_SHORT:
+            case GL_SHORT:
+                return 2;
+            case GL_UNSIGNED_BYTE:
+            case GL_BYTE:
+                return 1;
+            default:
+                assert false;
+                return 0;
+        }
+    }
+
+    void fetch(final int maxAttrib, final int index, final int dstIdx, final ByteBuffer nonVBO,
+            final float[][] fetchedAttribs) {
+        for (int i = 0; i < maxAttrib; i++) {
+            final GLAttribPointer attrib = attribPointers[i];
+            int size = 0;
+            if (attrib.enabled) {
+                size = attrib.size;
+                if (null != attrib.buffer) {
+                    final ByteBuffer src = attrib.buffer.data;
+                    src.position(attrib.ptr + index * attrib.elemStride);
+                    for (int j = 0; j < size; j++)
+                        fetchedAttribs[i][dstIdx * 4 + j] = fetchConvert(src, attrib.type,
+                                attrib.normalized);
+                } else
+                    for (int j = 0; j < size; j++)
+                        fetchedAttribs[i][dstIdx * 4 + j] = fetchConvert(nonVBO, attrib.type,
+                                attrib.normalized);
+            }
+            if (size < 1)
+                fetchedAttribs[i][dstIdx * 4 + 0] = defaultAttribs[i][0];
+            if (size < 2)
+                fetchedAttribs[i][dstIdx * 4 + 1] = defaultAttribs[i][1];
+            if (size < 3)
+                fetchedAttribs[i][dstIdx * 4 + 2] = defaultAttribs[i][2];
+            if (size < 4)
+                fetchedAttribs[i][dstIdx * 4 + 3] = defaultAttribs[i][3];
+        }
+    }
+
+    /**
+     * fetches and converts vertex data from buffers, defaults and user pointers
+     * into MessageData; mainly for display use
+     */
+    public void glDrawArrays(MessageData msgData) {
+        final Message msg = msgData.msg;
+        if (!msg.hasArg7())
+            return;
+        final int maxAttrib = msg.getArg7();
+        final int first = msg.getArg1(), count = msg.getArg2();
+        msgData.attribs = new float[maxAttrib][count * 4];
+        ByteBuffer arrays = null;
+        if (msg.hasData()) // server sends user pointer attribs
+        {
+            arrays = msg.getData().asReadOnlyByteBuffer();
+            arrays.order(SampleView.targetByteOrder);
+        }
+        for (int i = 0; i < count; i++)
+            fetch(maxAttrib, first + i, i, arrays, msgData.attribs);
+        assert null == arrays || arrays.remaining() == 0;
+    }
+
+    // void glDrawElements(GLenum mode, GLsizei count, GLenum type, const
+    // GLvoid* indices)
+    /**
+     * fetches and converts vertex data from buffers, defaults and user pointers
+     * and indices from buffer/pointer into MessageData; mainly for display use
+     */
+    public void glDrawElements(MessageData msgData) {
+        final Message msg = msgData.msg;
+        if (!msg.hasArg7())
+            return;
+        final int maxAttrib = msg.getArg7();
+        final int count = msg.getArg1();
+        final GLEnum type = GLEnum.valueOf(msg.getArg2());
+        msgData.attribs = new float[maxAttrib][count * 4];
+        msgData.indices = new short[count];
+        ByteBuffer arrays = null, index = null;
+        if (msg.hasData()) // server sends user pointer attribs
+        {
+            arrays = msg.getData().asReadOnlyByteBuffer();
+            arrays.order(SampleView.targetByteOrder);
+        }
+        if (null == indexBuffer)
+            index = arrays; // server also interleaves user pointer indices
+        else {
+            index = indexBuffer.data;
+            index.position(msg.getArg3());
+        }
+        if (GLEnum.GL_UNSIGNED_SHORT == type) {
+            for (int i = 0; i < count; i++) {
+                msgData.indices[i] = index.getShort();
+                fetch(maxAttrib, msgData.indices[i] & 0xffff, i, arrays, msgData.attribs);
+            }
+        } else if (GLEnum.GL_UNSIGNED_BYTE == type) {
+            for (int i = 0; i < count; i++) {
+                msgData.indices[i] = (short) (index.get() & 0xff);
+                fetch(maxAttrib, msgData.indices[i], i, arrays, msgData.attribs);
+            }
+        } else
+            assert false;
+        assert null == arrays || arrays.remaining() == 0;
+    }
+
+    // void glEnableVertexAttribArray(GLuint index)
+    public void glEnableVertexAttribArray(Message msg) {
+        if (msg.getArg0() >= 0 && msg.getArg0() < attribPointers.length)
+            attribPointers[msg.getArg0()].enabled = true;
+    }
+
+    // void API_ENTRY(glGenBuffers)(GLsizei n, GLuint:n:out buffers)
+    public void glGenBuffers(Message msg) {
+        final int n = msg.getArg0();
+        final ByteBuffer buffer = msg.getData().asReadOnlyByteBuffer();
+        buffer.order(SampleView.targetByteOrder);
+        for (int i = 0; i < n; i++) {
+            final int name = buffer.getInt();
+            final int index = buffers.indexOfKey(name);
+            if (index < 0)
+                buffers.append(name, new GLBuffer(name));
+        }
+    }
+
+    // void glVertexAttribPointer(GLuint index, GLint size, GLenum type,
+    // GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+    public void glVertexAttribPointer(Message msg) {
+        GLAttribPointer attrib = attribPointers[msg.getArg0()];
+        attrib.size = msg.getArg1();
+        attrib.type = GLEnum.valueOf(msg.getArg2());
+        attrib.normalized = msg.getArg3() != 0;
+        attrib.stride = msg.getArg4();
+        attrib.elemSize = attrib.size * typeSize(attrib.type);
+        if (attrib.stride == 0)
+            attrib.elemStride = attrib.elemSize;
+        else
+            attrib.elemStride = attrib.stride;
+        attrib.ptr = msg.getArg5();
+        attrib.buffer = attribBuffer;
+    }
+
+    // void glVertexAttrib1f(GLuint indx, GLfloat x)
+    public void glVertexAttrib1f(Message msg) {
+        glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(msg.getArg1()),
+                0, 0, 1);
+    }
+
+    // void glVertexAttrib1fv(GLuint indx, const GLfloat* values)
+    public void glVertexAttrib1fv(Message msg) {
+        final ByteBuffer values = msg.getData().asReadOnlyByteBuffer();
+        values.order(SampleView.targetByteOrder);
+        glVertexAttrib4f(msg.getArg0(),
+                Float.intBitsToFloat(values.getInt()),
+                0, 0, 1);
+    }
+
+    // void glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+    public void glVertexAttrib2f(Message msg) {
+        glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(msg.getArg1()),
+                Float.intBitsToFloat(msg.getArg2()), 0, 1);
+    }
+
+    // void glVertexAttrib2fv(GLuint indx, const GLfloat* values)
+    public void glVertexAttrib2fv(Message msg) {
+        final ByteBuffer values = msg.getData().asReadOnlyByteBuffer();
+        values.order(SampleView.targetByteOrder);
+        glVertexAttrib4f(msg.getArg0(),
+                Float.intBitsToFloat(values.getInt()),
+                Float.intBitsToFloat(values.getInt()), 0, 1);
+    }
+
+    // void glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+    public void glVertexAttrib3f(Message msg) {
+        glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(msg.getArg1()),
+                Float.intBitsToFloat(msg.getArg2()),
+                Float.intBitsToFloat(msg.getArg3()), 1);
+    }
+
+    // void glVertexAttrib3fv(GLuint indx, const GLfloat* values)
+    public void glVertexAttrib3fv(Message msg) {
+        final ByteBuffer values = msg.getData().asReadOnlyByteBuffer();
+        values.order(SampleView.targetByteOrder);
+        glVertexAttrib4f(msg.getArg0(),
+                Float.intBitsToFloat(values.getInt()),
+                Float.intBitsToFloat(values.getInt()),
+                Float.intBitsToFloat(values.getInt()), 1);
+    }
+
+    public void glVertexAttrib4f(Message msg) {
+        glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(msg.getArg1()),
+                Float.intBitsToFloat(msg.getArg2()),
+                Float.intBitsToFloat(msg.getArg3()),
+                Float.intBitsToFloat(msg.getArg4()));
+    }
+
+    void glVertexAttrib4f(int indx, float x, float y, float z, float w) {
+        if (indx < 0 || indx >= defaultAttribs.length)
+            return;
+        defaultAttribs[indx][0] = x;
+        defaultAttribs[indx][1] = y;
+        defaultAttribs[indx][2] = z;
+        defaultAttribs[indx][3] = w;
+    }
+
+    // void glVertexAttrib4fv(GLuint indx, const GLfloat* values)
+    public void glVertexAttrib4fv(Message msg) {
+        final ByteBuffer values = msg.getData().asReadOnlyByteBuffer();
+        values.order(SampleView.targetByteOrder);
+        glVertexAttrib4f(msg.getArg0(),
+                Float.intBitsToFloat(values.getInt()),
+                Float.intBitsToFloat(values.getInt()),
+                Float.intBitsToFloat(values.getInt()),
+                Float.intBitsToFloat(values.getInt()));
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java
new file mode 100644
index 0000000..321c538
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java
@@ -0,0 +1,128 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.android.glesv2debugger.DebuggerMessage.Message.Type;
+
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.widgets.Display;
+
+public class MessageData {
+    public final Message msg;
+    private Image image = null; // texture
+    public String shader = null; // shader source
+    public String text;
+    public String[] columns = new String[3];
+
+    float[][] attribs = null;
+    short[] indices;
+
+    public MessageData(final Device device, final Message msg, final Context context) {
+        this.msg = msg;
+        StringBuilder builder = new StringBuilder();
+        final Function function = msg.getFunction();
+        if (function != Message.Function.ACK && msg.getType() != Type.BeforeCall)
+            assert msg.hasTime();
+        builder.append(columns[0] = function.name());
+        while (builder.length() < 30)
+            builder.append(' ');
+        columns[1] = String.format("%.3f", msg.getTime());
+        if (msg.hasClock())
+            columns[1] += String.format(":%.3f", msg.getClock());
+        builder.append(columns[1]);
+
+        builder.append("  ");
+        builder.append(String.format("0x%08X", msg.getContextId()));
+        builder.append("  ");
+        columns[2] = "";
+        if (msg.getType() == Type.BeforeCall) // incomplete call, client SKIPPED
+            columns[2] = "[BeforeCall(AfterCall missing)] ";
+        else if (msg.getType() == Type.AfterGeneratedCall)
+            columns[2] = "[AfterGeneratedCall] ";
+        else
+            assert msg.getType() == Type.CompleteCall;
+        columns[2] += MessageFormatter.format(msg, false);
+        builder.append(columns[2]);
+        switch (function) {
+            case glDrawArrays:
+                if (!msg.hasArg7())
+                    break;
+                context.serverVertex.glDrawArrays(this);
+                break;
+            case glDrawElements:
+                if (!msg.hasArg7())
+                    break;
+                context.serverVertex.glDrawElements(this);
+                break;
+            case glShaderSource:
+                shader = msg.getData().toStringUtf8();
+                break;
+
+        }
+        text = builder.toString();
+    }
+
+    public Image getImage() {
+        if (image != null)
+            return image;
+        ImageData imageData = null;
+        switch (msg.getFunction()) {
+            case glTexImage2D:
+                if (!msg.hasData())
+                    return null;
+                imageData = MessageProcessor.receiveImage(msg.getArg3(), msg
+                        .getArg4(), msg.getArg6(), msg.getArg7(), msg.getData());
+                return image = new Image(Display.getCurrent(), imageData);
+            case glTexSubImage2D:
+                assert msg.hasData();
+                imageData = MessageProcessor.receiveImage(msg.getArg4(), msg
+                        .getArg5(), msg.getArg6(), msg.getArg7(), msg.getData());
+                return image = new Image(Display.getCurrent(), imageData);
+            case glCopyTexImage2D:
+                imageData = MessageProcessor.receiveImage(msg.getArg5(), msg.getArg6(),
+                        msg.getPixelFormat(), msg.getPixelType(), msg.getData());
+                imageData = imageData.scaledTo(imageData.width, -imageData.height);
+                return image = new Image(Display.getCurrent(), imageData);
+            case glCopyTexSubImage2D:
+                imageData = MessageProcessor.receiveImage(msg.getArg6(), msg.getArg7(),
+                        msg.getPixelFormat(), msg.getPixelType(), msg.getData());
+                imageData = imageData.scaledTo(imageData.width, -imageData.height);
+                return image = new Image(Display.getCurrent(), imageData);
+            case glReadPixels:
+                if (!msg.hasData())
+                    return null;
+                imageData = MessageProcessor.receiveImage(msg.getArg2(), msg.getArg3(),
+                        msg.getArg4(), msg.getArg5(), msg.getData());
+                imageData = imageData.scaledTo(imageData.width, -imageData.height);
+                return image = new Image(Display.getCurrent(), imageData);
+            case eglSwapBuffers:
+                if (!msg.hasData())
+                    return null;
+                imageData = MessageProcessor.receiveImage(msg.getImageWidth(),
+                        msg.getImageHeight(), msg.getPixelFormat(), msg.getPixelType(),
+                        msg.getData());
+                imageData = imageData.scaledTo(imageData.width, -imageData.height);
+                return image = new Image(Display.getCurrent(), imageData);
+            default:
+                return null;
+        }
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/MessageFormatter.java b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageFormatter.java
new file mode 100644
index 0000000..b9fa681
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageFormatter.java
@@ -0,0 +1,1488 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+// auto generated by generate_MessageFormatter_java.py"
+
+package com.android.glesv2debugger;
+
+import java.nio.ByteBuffer;
+
+public class MessageFormatter {
+
+    static String formatFloats(int count, final ByteBuffer data) {
+        if (data.remaining() == 0)
+            return "{}";
+        data.order(SampleView.targetByteOrder);
+        String ret = "{";
+        for (int i = 0; i < count; i++) {
+            ret += Float.intBitsToFloat(data.getInt());
+            if (i < count - 1)
+                ret += ", ";
+        }
+        return ret + "}";
+    }
+
+    static String formatInts(int count, final ByteBuffer data) {
+        if (data.remaining() == 0)
+            return "{}";
+        data.order(SampleView.targetByteOrder);
+        String ret = "{";
+        for (int i = 0; i < count; i++) {
+            ret += data.getInt();
+            if (i < count - 1)
+                ret += ", ";
+        }
+        return ret + "}";
+    }
+
+    static String formatUInts(int count, final ByteBuffer data) {
+        if (data.remaining() == 0)
+            return "{}";
+        data.order(SampleView.targetByteOrder);
+        String ret = "{";
+        for (int i = 0; i < count; i++) {
+            long bits = data.getInt() & 0xffffffff;
+            ret += bits;
+            if (i < count - 1)
+                ret += ", ";
+        }
+        return ret + "}";
+    }
+
+    static String formatMatrix(int columns, int count, final ByteBuffer data) {
+        if (data.remaining() == 0)
+            return "{}";
+        data.order(SampleView.targetByteOrder);
+        String ret = "{";
+        for (int i = 0; i < count; i++) {
+            ret += Float.intBitsToFloat(data.getInt());
+            if (i < count - 1)
+                ret += ", ";
+            if (i % columns == columns - 1)
+                ret += "\n                                             ";
+        }
+        return ret + "}";
+    }
+
+    public static String format(final DebuggerMessage.Message msg,
+                                final boolean code) {
+        String str;
+        switch (msg.getFunction()) {
+            case glActiveTexture:
+                str = String.format("%s(%s%s)",
+                    (code ? "glActiveTexture" : "void")
+                    , (code ? "/*texture*/ " : "texture=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glAttachShader:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glAttachShader" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*shader*/ " : "shader=")
+                    , (code ? "shader_" : "") + msg.getArg1());
+                break;
+            case glBindAttribLocation:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glBindAttribLocation" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*index*/ " : "index=")
+                    , msg.getArg1()
+                    , (code ? "/*name*/ " : "name=")
+                    , (code ? "\"" : "") + msg.getData().toStringUtf8() + (code ? "\"" : ""));
+                break;
+            case glBindBuffer:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glBindBuffer" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*buffer*/ " : "buffer=")
+                    , (code ? "buffer_" : "") + msg.getArg1());
+                break;
+            case glBindFramebuffer:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glBindFramebuffer" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*framebuffer*/ " : "framebuffer=")
+                    , (code ? "framebuffer_" : "") + msg.getArg1());
+                break;
+            case glBindRenderbuffer:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glBindRenderbuffer" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*renderbuffer*/ " : "renderbuffer=")
+                    , (code ? "renderbuffer_" : "") + msg.getArg1());
+                break;
+            case glBindTexture:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glBindTexture" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*texture*/ " : "texture=")
+                    , (code ? "texture_" : "") + msg.getArg1());
+                break;
+            case glBlendColor:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glBlendColor" : "void")
+                    , (code ? "/*red*/ " : "red=")
+                    , Float.intBitsToFloat(msg.getArg0())
+                    , (code ? "/*green*/ " : "green=")
+                    , Float.intBitsToFloat(msg.getArg1())
+                    , (code ? "/*blue*/ " : "blue=")
+                    , Float.intBitsToFloat(msg.getArg2())
+                    , (code ? "/*alpha*/ " : "alpha=")
+                    , Float.intBitsToFloat(msg.getArg3()));
+                break;
+            case glBlendEquation:
+                str = String.format("%s(%s%s)",
+                    (code ? "glBlendEquation" : "void")
+                    , (code ? "/*mode*/ " : "mode=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glBlendEquationSeparate:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glBlendEquationSeparate" : "void")
+                    , (code ? "/*modeRGB*/ " : "modeRGB=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*modeAlpha*/ " : "modeAlpha=")
+                    , GLEnum.valueOf(msg.getArg1()));
+                break;
+            case glBlendFunc:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glBlendFunc" : "void")
+                    , (code ? "/*sfactor*/ " : "sfactor=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*dfactor*/ " : "dfactor=")
+                    , GLEnum.valueOf(msg.getArg1()));
+                break;
+            case glBlendFuncSeparate:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glBlendFuncSeparate" : "void")
+                    , (code ? "/*srcRGB*/ " : "srcRGB=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*dstRGB*/ " : "dstRGB=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*srcAlpha*/ " : "srcAlpha=")
+                    , GLEnum.valueOf(msg.getArg2())
+                    , (code ? "/*dstAlpha*/ " : "dstAlpha=")
+                    , GLEnum.valueOf(msg.getArg3()));
+                break;
+            case glBufferData:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glBufferData" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*size*/ " : "size=")
+                    , msg.getArg1()
+                    , (code ? "/*data*/ " : "data=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2()))
+                    , (code ? "/*usage*/ " : "usage=")
+                    , GLEnum.valueOf(msg.getArg3()));
+                break;
+            case glBufferSubData:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glBufferSubData" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*offset*/ " : "offset=")
+                    , msg.getArg1()
+                    , (code ? "/*size*/ " : "size=")
+                    , msg.getArg2()
+                    , (code ? "/*data*/ " : "data=")
+                    , (code ? "arg3" : "0x" + Integer.toHexString(msg.getArg3())));
+                break;
+            case glCheckFramebufferStatus:
+                str = String.format("%s(%s%s)",
+                    (code ? "glCheckFramebufferStatus" : GLEnum.valueOf(msg.getRet()))
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glClear:
+                str = String.format("%s(%s%s)",
+                    (code ? "glClear" : "void")
+                    , (code ? "/*mask*/ " : "mask=")
+                    , msg.getArg0());
+                break;
+            case glClearColor:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glClearColor" : "void")
+                    , (code ? "/*red*/ " : "red=")
+                    , Float.intBitsToFloat(msg.getArg0())
+                    , (code ? "/*green*/ " : "green=")
+                    , Float.intBitsToFloat(msg.getArg1())
+                    , (code ? "/*blue*/ " : "blue=")
+                    , Float.intBitsToFloat(msg.getArg2())
+                    , (code ? "/*alpha*/ " : "alpha=")
+                    , Float.intBitsToFloat(msg.getArg3()));
+                break;
+            case glClearDepthf:
+                str = String.format("%s(%s%s)",
+                    (code ? "glClearDepthf" : "void")
+                    , (code ? "/*depth*/ " : "depth=")
+                    , Float.intBitsToFloat(msg.getArg0()));
+                break;
+            case glClearStencil:
+                str = String.format("%s(%s%s)",
+                    (code ? "glClearStencil" : "void")
+                    , (code ? "/*s*/ " : "s=")
+                    , msg.getArg0());
+                break;
+            case glColorMask:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glColorMask" : "void")
+                    , (code ? "/*red*/ " : "red=")
+                    , msg.getArg0()
+                    , (code ? "/*green*/ " : "green=")
+                    , msg.getArg1()
+                    , (code ? "/*blue*/ " : "blue=")
+                    , msg.getArg2()
+                    , (code ? "/*alpha*/ " : "alpha=")
+                    , msg.getArg3());
+                break;
+            case glCompileShader:
+                str = String.format("%s(%s%s)",
+                    (code ? "glCompileShader" : "void")
+                    , (code ? "/*shader*/ " : "shader=")
+                    , (code ? "shader_" : "") + msg.getArg0());
+                break;
+            case glCompressedTexImage2D:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glCompressedTexImage2D" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*level*/ " : "level=")
+                    , msg.getArg1()
+                    , (code ? "/*internalformat*/ " : "internalformat=")
+                    , GLEnum.valueOf(msg.getArg2())
+                    , (code ? "/*width*/ " : "width=")
+                    , msg.getArg3()
+                    , (code ? "/*height*/ " : "height=")
+                    , msg.getArg4()
+                    , (code ? "/*border*/ " : "border=")
+                    , msg.getArg5()
+                    , (code ? "/*imageSize*/ " : "imageSize=")
+                    , msg.getArg6()
+                    , (code ? "/*data*/ " : "data=")
+                    , (code ? "arg7" : "0x" + Integer.toHexString(msg.getArg7())));
+                break;
+            case glCompressedTexSubImage2D:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glCompressedTexSubImage2D" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*level*/ " : "level=")
+                    , msg.getArg1()
+                    , (code ? "/*xoffset*/ " : "xoffset=")
+                    , msg.getArg2()
+                    , (code ? "/*yoffset*/ " : "yoffset=")
+                    , msg.getArg3()
+                    , (code ? "/*width*/ " : "width=")
+                    , msg.getArg4()
+                    , (code ? "/*height*/ " : "height=")
+                    , msg.getArg5()
+                    , (code ? "/*format*/ " : "format=")
+                    , GLEnum.valueOf(msg.getArg6())
+                    , (code ? "/*imageSize*/ " : "imageSize=")
+                    , msg.getArg7()
+                    , (code ? "/*data*/ " : "data=")
+                    , (code ? "arg8" : "0x" + Integer.toHexString(msg.getArg8())));
+                break;
+            case glCopyTexImage2D:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glCopyTexImage2D" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*level*/ " : "level=")
+                    , msg.getArg1()
+                    , (code ? "/*internalformat*/ " : "internalformat=")
+                    , GLEnum.valueOf(msg.getArg2())
+                    , (code ? "/*x*/ " : "x=")
+                    , msg.getArg3()
+                    , (code ? "/*y*/ " : "y=")
+                    , msg.getArg4()
+                    , (code ? "/*width*/ " : "width=")
+                    , msg.getArg5()
+                    , (code ? "/*height*/ " : "height=")
+                    , msg.getArg6()
+                    , (code ? "/*border*/ " : "border=")
+                    , msg.getArg7());
+                break;
+            case glCopyTexSubImage2D:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glCopyTexSubImage2D" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*level*/ " : "level=")
+                    , msg.getArg1()
+                    , (code ? "/*xoffset*/ " : "xoffset=")
+                    , msg.getArg2()
+                    , (code ? "/*yoffset*/ " : "yoffset=")
+                    , msg.getArg3()
+                    , (code ? "/*x*/ " : "x=")
+                    , msg.getArg4()
+                    , (code ? "/*y*/ " : "y=")
+                    , msg.getArg5()
+                    , (code ? "/*width*/ " : "width=")
+                    , msg.getArg6()
+                    , (code ? "/*height*/ " : "height=")
+                    , msg.getArg7());
+                break;
+            case glCreateProgram:
+                str = String.format("%s()",
+                    (code ? "glCreateProgram" : msg.getRet())
+);
+                break;
+            case glCreateShader:
+                str = String.format("%s(%s%s)",
+                    (code ? "glCreateShader" : msg.getRet())
+                    , (code ? "/*type*/ " : "type=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glCullFace:
+                str = String.format("%s(%s%s)",
+                    (code ? "glCullFace" : "void")
+                    , (code ? "/*mode*/ " : "mode=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glDeleteBuffers:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glDeleteBuffers" : "void")
+                    , (code ? "/*n*/ " : "n=")
+                    , msg.getArg0()
+                    , (code ? "/*buffers*/ " : "buffers=")
+                    , (code ? "(GLuint [])" : "") +  formatUInts(1 * msg.getArg0(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glDeleteFramebuffers:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glDeleteFramebuffers" : "void")
+                    , (code ? "/*n*/ " : "n=")
+                    , msg.getArg0()
+                    , (code ? "/*framebuffers*/ " : "framebuffers=")
+                    , (code ? "(GLuint [])" : "") +  formatUInts(1 * msg.getArg0(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glDeleteProgram:
+                str = String.format("%s(%s%s)",
+                    (code ? "glDeleteProgram" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0());
+                break;
+            case glDeleteRenderbuffers:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glDeleteRenderbuffers" : "void")
+                    , (code ? "/*n*/ " : "n=")
+                    , msg.getArg0()
+                    , (code ? "/*renderbuffers*/ " : "renderbuffers=")
+                    , (code ? "(GLuint [])" : "") +  formatUInts(1 * msg.getArg0(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glDeleteShader:
+                str = String.format("%s(%s%s)",
+                    (code ? "glDeleteShader" : "void")
+                    , (code ? "/*shader*/ " : "shader=")
+                    , (code ? "shader_" : "") + msg.getArg0());
+                break;
+            case glDeleteTextures:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glDeleteTextures" : "void")
+                    , (code ? "/*n*/ " : "n=")
+                    , msg.getArg0()
+                    , (code ? "/*textures*/ " : "textures=")
+                    , (code ? "(GLuint [])" : "") +  formatUInts(1 * msg.getArg0(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glDepthFunc:
+                str = String.format("%s(%s%s)",
+                    (code ? "glDepthFunc" : "void")
+                    , (code ? "/*func*/ " : "func=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glDepthMask:
+                str = String.format("%s(%s%s)",
+                    (code ? "glDepthMask" : "void")
+                    , (code ? "/*flag*/ " : "flag=")
+                    , msg.getArg0());
+                break;
+            case glDepthRangef:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glDepthRangef" : "void")
+                    , (code ? "/*zNear*/ " : "zNear=")
+                    , Float.intBitsToFloat(msg.getArg0())
+                    , (code ? "/*zFar*/ " : "zFar=")
+                    , Float.intBitsToFloat(msg.getArg1()));
+                break;
+            case glDetachShader:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glDetachShader" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*shader*/ " : "shader=")
+                    , (code ? "shader_" : "") + msg.getArg1());
+                break;
+            case glDisable:
+                str = String.format("%s(%s%s)",
+                    (code ? "glDisable" : "void")
+                    , (code ? "/*cap*/ " : "cap=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glDisableVertexAttribArray:
+                str = String.format("%s(%s%s)",
+                    (code ? "glDisableVertexAttribArray" : "void")
+                    , (code ? "/*index*/ " : "index=")
+                    , msg.getArg0());
+                break;
+            case glDrawArrays:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glDrawArrays" : "void")
+                    , (code ? "/*mode*/ " : "mode=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*first*/ " : "first=")
+                    , msg.getArg1()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg2());
+                break;
+            case glDrawElements:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glDrawElements" : "void")
+                    , (code ? "/*mode*/ " : "mode=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*type*/ " : "type=")
+                    , GLEnum.valueOf(msg.getArg2())
+                    , (code ? "/*indices*/ " : "indices=")
+                    , (code ? "arg3" : "0x" + Integer.toHexString(msg.getArg3())));
+                break;
+            case glEnable:
+                str = String.format("%s(%s%s)",
+                    (code ? "glEnable" : "void")
+                    , (code ? "/*cap*/ " : "cap=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glEnableVertexAttribArray:
+                str = String.format("%s(%s%s)",
+                    (code ? "glEnableVertexAttribArray" : "void")
+                    , (code ? "/*index*/ " : "index=")
+                    , msg.getArg0());
+                break;
+            case glFinish:
+                str = String.format("%s()",
+                    (code ? "glFinish" : "void")
+);
+                break;
+            case glFlush:
+                str = String.format("%s()",
+                    (code ? "glFlush" : "void")
+);
+                break;
+            case glFramebufferRenderbuffer:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glFramebufferRenderbuffer" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*attachment*/ " : "attachment=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*renderbuffertarget*/ " : "renderbuffertarget=")
+                    , GLEnum.valueOf(msg.getArg2())
+                    , (code ? "/*renderbuffer*/ " : "renderbuffer=")
+                    , (code ? "renderbuffer_" : "") + msg.getArg3());
+                break;
+            case glFramebufferTexture2D:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glFramebufferTexture2D" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*attachment*/ " : "attachment=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*textarget*/ " : "textarget=")
+                    , GLEnum.valueOf(msg.getArg2())
+                    , (code ? "/*texture*/ " : "texture=")
+                    , (code ? "texture_" : "") + msg.getArg3()
+                    , (code ? "/*level*/ " : "level=")
+                    , msg.getArg4());
+                break;
+            case glFrontFace:
+                str = String.format("%s(%s%s)",
+                    (code ? "glFrontFace" : "void")
+                    , (code ? "/*mode*/ " : "mode=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glGenBuffers:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glGenBuffers" : "void")
+                    , (code ? "/*n*/ " : "n=")
+                    , msg.getArg0()
+                    , (code ? "/*buffers*/ " : "buffers=")
+                    , (code ? "(GLuint [])" : "") +  formatUInts(1 * msg.getArg0(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glGenerateMipmap:
+                str = String.format("%s(%s%s)",
+                    (code ? "glGenerateMipmap" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glGenFramebuffers:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glGenFramebuffers" : "void")
+                    , (code ? "/*n*/ " : "n=")
+                    , msg.getArg0()
+                    , (code ? "/*framebuffers*/ " : "framebuffers=")
+                    , (code ? "(GLuint [])" : "") +  formatUInts(1 * msg.getArg0(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glGenRenderbuffers:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glGenRenderbuffers" : "void")
+                    , (code ? "/*n*/ " : "n=")
+                    , msg.getArg0()
+                    , (code ? "/*renderbuffers*/ " : "renderbuffers=")
+                    , (code ? "(GLuint [])" : "") +  formatUInts(1 * msg.getArg0(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glGenTextures:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glGenTextures" : "void")
+                    , (code ? "/*n*/ " : "n=")
+                    , msg.getArg0()
+                    , (code ? "/*textures*/ " : "textures=")
+                    , (code ? "(GLuint [])" : "") +  formatUInts(1 * msg.getArg0(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glGetActiveAttrib:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glGetActiveAttrib" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*index*/ " : "index=")
+                    , msg.getArg1()
+                    , (code ? "/*bufsize*/ " : "bufsize=")
+                    , msg.getArg2()
+                    , (code ? "/*length*/ " : "length=")
+                    , (code ? "arg3" : "0x" + Integer.toHexString(msg.getArg3()))
+                    , (code ? "/*size*/ " : "size=")
+                    , (code ? "arg4" : "0x" + Integer.toHexString(msg.getArg4()))
+                    , (code ? "/*type*/ " : "type=")
+                    , (code ? "arg5" : "0x" + Integer.toHexString(msg.getArg5()))
+                    , (code ? "/*name*/ " : "name=")
+                    , (code ? "\"" : "") + msg.getData().toStringUtf8() + (code ? "\"" : ""));
+                break;
+            case glGetActiveUniform:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glGetActiveUniform" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*index*/ " : "index=")
+                    , msg.getArg1()
+                    , (code ? "/*bufsize*/ " : "bufsize=")
+                    , msg.getArg2()
+                    , (code ? "/*length*/ " : "length=")
+                    , (code ? "arg3" : "0x" + Integer.toHexString(msg.getArg3()))
+                    , (code ? "/*size*/ " : "size=")
+                    , (code ? "arg4" : "0x" + Integer.toHexString(msg.getArg4()))
+                    , (code ? "/*type*/ " : "type=")
+                    , (code ? "arg5" : "0x" + Integer.toHexString(msg.getArg5()))
+                    , (code ? "/*name*/ " : "name=")
+                    , (code ? "\"" : "") + msg.getData().toStringUtf8() + (code ? "\"" : ""));
+                break;
+            case glGetAttachedShaders:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glGetAttachedShaders" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*maxcount*/ " : "maxcount=")
+                    , msg.getArg1()
+                    , (code ? "/*count*/ " : "count=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2()))
+                    , (code ? "/*shaders*/ " : "shaders=")
+                    , (code ? "arg3" : "0x" + Integer.toHexString(msg.getArg3())));
+                break;
+            case glGetAttribLocation:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glGetAttribLocation" : msg.getRet())
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*name*/ " : "name=")
+                    , (code ? "\"" : "") + msg.getData().toStringUtf8() + (code ? "\"" : ""));
+                break;
+            case glGetBooleanv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glGetBooleanv" : "void")
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg1" : "0x" + Integer.toHexString(msg.getArg1())));
+                break;
+            case glGetBufferParameteriv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetBufferParameteriv" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glGetError:
+                str = String.format("%s()",
+                    (code ? "glGetError" : GLEnum.valueOf(msg.getRet()))
+);
+                break;
+            case glGetFloatv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glGetFloatv" : "void")
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg1" : "0x" + Integer.toHexString(msg.getArg1())));
+                break;
+            case glGetFramebufferAttachmentParameteriv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glGetFramebufferAttachmentParameteriv" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*attachment*/ " : "attachment=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg2())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg3" : "0x" + Integer.toHexString(msg.getArg3())));
+                break;
+            case glGetIntegerv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glGetIntegerv" : "void")
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg1" : "0x" + Integer.toHexString(msg.getArg1())));
+                break;
+            case glGetProgramiv:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetProgramiv" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "(GLint [])" : "") + formatInts(1, msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glGetProgramInfoLog:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glGetProgramInfoLog" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*bufsize*/ " : "bufsize=")
+                    , msg.getArg1()
+                    , (code ? "/*length*/ " : "length=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2()))
+                    , (code ? "/*infolog*/ " : "infolog=")
+                    , (code ? "\"" : "") + msg.getData().toStringUtf8() + (code ? "\"" : ""));
+                break;
+            case glGetRenderbufferParameteriv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetRenderbufferParameteriv" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glGetShaderiv:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetShaderiv" : "void")
+                    , (code ? "/*shader*/ " : "shader=")
+                    , (code ? "shader_" : "") + msg.getArg0()
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "(GLint [])" : "") + formatInts(1, msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glGetShaderInfoLog:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glGetShaderInfoLog" : "void")
+                    , (code ? "/*shader*/ " : "shader=")
+                    , (code ? "shader_" : "") + msg.getArg0()
+                    , (code ? "/*bufsize*/ " : "bufsize=")
+                    , msg.getArg1()
+                    , (code ? "/*length*/ " : "length=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2()))
+                    , (code ? "/*infolog*/ " : "infolog=")
+                    , (code ? "\"" : "") + msg.getData().toStringUtf8() + (code ? "\"" : ""));
+                break;
+            case glGetShaderPrecisionFormat:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glGetShaderPrecisionFormat" : "void")
+                    , (code ? "/*shadertype*/ " : "shadertype=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*precisiontype*/ " : "precisiontype=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*range*/ " : "range=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2()))
+                    , (code ? "/*precision*/ " : "precision=")
+                    , (code ? "arg3" : "0x" + Integer.toHexString(msg.getArg3())));
+                break;
+            case glGetShaderSource:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glGetShaderSource" : "void")
+                    , (code ? "/*shader*/ " : "shader=")
+                    , (code ? "shader_" : "") + msg.getArg0()
+                    , (code ? "/*bufsize*/ " : "bufsize=")
+                    , msg.getArg1()
+                    , (code ? "/*length*/ " : "length=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2()))
+                    , (code ? "/*source*/ " : "source=")
+                    , (code ? "\"" : "") + msg.getData().toStringUtf8() + (code ? "\"" : ""));
+                break;
+            case glGetString:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s)",
+                    (code ? "glGetString" : "0x" + Integer.toHexString(msg.getRet()))
+                    , (code ? "/*name*/ " : "name=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glGetTexParameterfv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetTexParameterfv" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glGetTexParameteriv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetTexParameteriv" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glGetUniformfv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetUniformfv" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg1()
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glGetUniformiv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetUniformiv" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg1()
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glGetUniformLocation:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glGetUniformLocation" : msg.getRet())
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0()
+                    , (code ? "/*name*/ " : "name=")
+                    , (code ? "\"" : "") + msg.getData().toStringUtf8() + (code ? "\"" : ""));
+                break;
+            case glGetVertexAttribfv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetVertexAttribfv" : "void")
+                    , (code ? "/*index*/ " : "index=")
+                    , msg.getArg0()
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glGetVertexAttribiv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetVertexAttribiv" : "void")
+                    , (code ? "/*index*/ " : "index=")
+                    , msg.getArg0()
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glGetVertexAttribPointerv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glGetVertexAttribPointerv" : "void")
+                    , (code ? "/*index*/ " : "index=")
+                    , msg.getArg0()
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*pointer*/ " : "pointer=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glHint:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glHint" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*mode*/ " : "mode=")
+                    , GLEnum.valueOf(msg.getArg1()));
+                break;
+            case glIsBuffer:
+                str = String.format("%s(%s%s)",
+                    (code ? "glIsBuffer" : msg.getRet())
+                    , (code ? "/*buffer*/ " : "buffer=")
+                    , (code ? "buffer_" : "") + msg.getArg0());
+                break;
+            case glIsEnabled:
+                str = String.format("%s(%s%s)",
+                    (code ? "glIsEnabled" : msg.getRet())
+                    , (code ? "/*cap*/ " : "cap=")
+                    , GLEnum.valueOf(msg.getArg0()));
+                break;
+            case glIsFramebuffer:
+                str = String.format("%s(%s%s)",
+                    (code ? "glIsFramebuffer" : msg.getRet())
+                    , (code ? "/*framebuffer*/ " : "framebuffer=")
+                    , (code ? "framebuffer_" : "") + msg.getArg0());
+                break;
+            case glIsProgram:
+                str = String.format("%s(%s%s)",
+                    (code ? "glIsProgram" : msg.getRet())
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0());
+                break;
+            case glIsRenderbuffer:
+                str = String.format("%s(%s%s)",
+                    (code ? "glIsRenderbuffer" : msg.getRet())
+                    , (code ? "/*renderbuffer*/ " : "renderbuffer=")
+                    , (code ? "renderbuffer_" : "") + msg.getArg0());
+                break;
+            case glIsShader:
+                str = String.format("%s(%s%s)",
+                    (code ? "glIsShader" : msg.getRet())
+                    , (code ? "/*shader*/ " : "shader=")
+                    , (code ? "shader_" : "") + msg.getArg0());
+                break;
+            case glIsTexture:
+                str = String.format("%s(%s%s)",
+                    (code ? "glIsTexture" : msg.getRet())
+                    , (code ? "/*texture*/ " : "texture=")
+                    , (code ? "texture_" : "") + msg.getArg0());
+                break;
+            case glLineWidth:
+                str = String.format("%s(%s%s)",
+                    (code ? "glLineWidth" : "void")
+                    , (code ? "/*width*/ " : "width=")
+                    , Float.intBitsToFloat(msg.getArg0()));
+                break;
+            case glLinkProgram:
+                str = String.format("%s(%s%s)",
+                    (code ? "glLinkProgram" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0());
+                break;
+            case glPixelStorei:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glPixelStorei" : "void")
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*param*/ " : "param=")
+                    , msg.getArg1());
+                break;
+            case glPolygonOffset:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glPolygonOffset" : "void")
+                    , (code ? "/*factor*/ " : "factor=")
+                    , Float.intBitsToFloat(msg.getArg0())
+                    , (code ? "/*units*/ " : "units=")
+                    , Float.intBitsToFloat(msg.getArg1()));
+                break;
+            case glReadPixels:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glReadPixels" : "void")
+                    , (code ? "/*x*/ " : "x=")
+                    , msg.getArg0()
+                    , (code ? "/*y*/ " : "y=")
+                    , msg.getArg1()
+                    , (code ? "/*width*/ " : "width=")
+                    , msg.getArg2()
+                    , (code ? "/*height*/ " : "height=")
+                    , msg.getArg3()
+                    , (code ? "/*format*/ " : "format=")
+                    , GLEnum.valueOf(msg.getArg4())
+                    , (code ? "/*type*/ " : "type=")
+                    , GLEnum.valueOf(msg.getArg5())
+                    , (code ? "/*pixels*/ " : "pixels=")
+                    , (code ? "arg6" : "0x" + Integer.toHexString(msg.getArg6())));
+                break;
+            case glReleaseShaderCompiler:
+                str = String.format("%s()",
+                    (code ? "glReleaseShaderCompiler" : "void")
+);
+                break;
+            case glRenderbufferStorage:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glRenderbufferStorage" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*internalformat*/ " : "internalformat=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*width*/ " : "width=")
+                    , msg.getArg2()
+                    , (code ? "/*height*/ " : "height=")
+                    , msg.getArg3());
+                break;
+            case glSampleCoverage:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glSampleCoverage" : "void")
+                    , (code ? "/*value*/ " : "value=")
+                    , Float.intBitsToFloat(msg.getArg0())
+                    , (code ? "/*invert*/ " : "invert=")
+                    , msg.getArg1());
+                break;
+            case glScissor:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glScissor" : "void")
+                    , (code ? "/*x*/ " : "x=")
+                    , msg.getArg0()
+                    , (code ? "/*y*/ " : "y=")
+                    , msg.getArg1()
+                    , (code ? "/*width*/ " : "width=")
+                    , msg.getArg2()
+                    , (code ? "/*height*/ " : "height=")
+                    , msg.getArg3());
+                break;
+            case glShaderBinary:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glShaderBinary" : "void")
+                    , (code ? "/*n*/ " : "n=")
+                    , msg.getArg0()
+                    , (code ? "/*shaders*/ " : "shaders=")
+                    , (code ? "arg1" : "0x" + Integer.toHexString(msg.getArg1()))
+                    , (code ? "/*binaryformat*/ " : "binaryformat=")
+                    , GLEnum.valueOf(msg.getArg2())
+                    , (code ? "/*binary*/ " : "binary=")
+                    , (code ? "arg3" : "0x" + Integer.toHexString(msg.getArg3()))
+                    , (code ? "/*length*/ " : "length=")
+                    , msg.getArg4());
+                break;
+            case glShaderSource:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glShaderSource" : "void")
+                    , (code ? "/*shader*/ " : "shader=")
+                    , (code ? "shader_" : "") + msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*string*/ " : "string=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2()))
+                    , (code ? "/*length*/ " : "length=")
+                    , (code ? "arg3" : "0x" + Integer.toHexString(msg.getArg3())));
+                break;
+            case glStencilFunc:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glStencilFunc" : "void")
+                    , (code ? "/*func*/ " : "func=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*ref*/ " : "ref=")
+                    , msg.getArg1()
+                    , (code ? "/*mask*/ " : "mask=")
+                    , msg.getArg2());
+                break;
+            case glStencilFuncSeparate:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glStencilFuncSeparate" : "void")
+                    , (code ? "/*face*/ " : "face=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*func*/ " : "func=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*ref*/ " : "ref=")
+                    , msg.getArg2()
+                    , (code ? "/*mask*/ " : "mask=")
+                    , msg.getArg3());
+                break;
+            case glStencilMask:
+                str = String.format("%s(%s%s)",
+                    (code ? "glStencilMask" : "void")
+                    , (code ? "/*mask*/ " : "mask=")
+                    , msg.getArg0());
+                break;
+            case glStencilMaskSeparate:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glStencilMaskSeparate" : "void")
+                    , (code ? "/*face*/ " : "face=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*mask*/ " : "mask=")
+                    , msg.getArg1());
+                break;
+            case glStencilOp:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glStencilOp" : "void")
+                    , (code ? "/*fail*/ " : "fail=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*zfail*/ " : "zfail=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*zpass*/ " : "zpass=")
+                    , GLEnum.valueOf(msg.getArg2()));
+                break;
+            case glStencilOpSeparate:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glStencilOpSeparate" : "void")
+                    , (code ? "/*face*/ " : "face=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*fail*/ " : "fail=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*zfail*/ " : "zfail=")
+                    , GLEnum.valueOf(msg.getArg2())
+                    , (code ? "/*zpass*/ " : "zpass=")
+                    , GLEnum.valueOf(msg.getArg3()));
+                break;
+            case glTexImage2D:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glTexImage2D" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*level*/ " : "level=")
+                    , msg.getArg1()
+                    , (code ? "/*internalformat*/ " : "internalformat=")
+                    , msg.getArg2()
+                    , (code ? "/*width*/ " : "width=")
+                    , msg.getArg3()
+                    , (code ? "/*height*/ " : "height=")
+                    , msg.getArg4()
+                    , (code ? "/*border*/ " : "border=")
+                    , msg.getArg5()
+                    , (code ? "/*format*/ " : "format=")
+                    , GLEnum.valueOf(msg.getArg6())
+                    , (code ? "/*type*/ " : "type=")
+                    , GLEnum.valueOf(msg.getArg7())
+                    , (code ? "/*pixels*/ " : "pixels=")
+                    , (code ? "arg8" : "0x" + Integer.toHexString(msg.getArg8())));
+                break;
+            case glTexParameterf:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glTexParameterf" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*param*/ " : "param=")
+                    , Float.intBitsToFloat(msg.getArg2()));
+                break;
+            case glTexParameterfv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glTexParameterfv" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glTexParameteri:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glTexParameteri" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*param*/ " : "param=")
+                    , msg.getArg2());
+                break;
+            case glTexParameteriv:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glTexParameteriv" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*pname*/ " : "pname=")
+                    , GLEnum.valueOf(msg.getArg1())
+                    , (code ? "/*params*/ " : "params=")
+                    , (code ? "arg2" : "0x" + Integer.toHexString(msg.getArg2())));
+                break;
+            case glTexSubImage2D:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glTexSubImage2D" : "void")
+                    , (code ? "/*target*/ " : "target=")
+                    , GLEnum.valueOf(msg.getArg0())
+                    , (code ? "/*level*/ " : "level=")
+                    , msg.getArg1()
+                    , (code ? "/*xoffset*/ " : "xoffset=")
+                    , msg.getArg2()
+                    , (code ? "/*yoffset*/ " : "yoffset=")
+                    , msg.getArg3()
+                    , (code ? "/*width*/ " : "width=")
+                    , msg.getArg4()
+                    , (code ? "/*height*/ " : "height=")
+                    , msg.getArg5()
+                    , (code ? "/*format*/ " : "format=")
+                    , GLEnum.valueOf(msg.getArg6())
+                    , (code ? "/*type*/ " : "type=")
+                    , GLEnum.valueOf(msg.getArg7())
+                    , (code ? "/*pixels*/ " : "pixels=")
+                    , (code ? "arg8" : "0x" + Integer.toHexString(msg.getArg8())));
+                break;
+            case glUniform1f:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glUniform1f" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , Float.intBitsToFloat(msg.getArg1()));
+                break;
+            case glUniform1fv:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glUniform1fv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*v*/ " : "v=")
+                    , (code ? "(GLfloat [])" : "") +  formatFloats(1 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUniform1i:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glUniform1i" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , msg.getArg1());
+                break;
+            case glUniform1iv:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glUniform1iv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*v*/ " : "v=")
+                    , (code ? "(GLint [])" : "") +  formatInts(1 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUniform2f:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glUniform2f" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , Float.intBitsToFloat(msg.getArg1())
+                    , (code ? "/*y*/ " : "y=")
+                    , Float.intBitsToFloat(msg.getArg2()));
+                break;
+            case glUniform2fv:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glUniform2fv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*v*/ " : "v=")
+                    , (code ? "(GLfloat [])" : "") +  formatFloats(2 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUniform2i:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glUniform2i" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , msg.getArg1()
+                    , (code ? "/*y*/ " : "y=")
+                    , msg.getArg2());
+                break;
+            case glUniform2iv:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glUniform2iv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*v*/ " : "v=")
+                    , (code ? "(GLint [])" : "") +  formatInts(2 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUniform3f:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glUniform3f" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , Float.intBitsToFloat(msg.getArg1())
+                    , (code ? "/*y*/ " : "y=")
+                    , Float.intBitsToFloat(msg.getArg2())
+                    , (code ? "/*z*/ " : "z=")
+                    , Float.intBitsToFloat(msg.getArg3()));
+                break;
+            case glUniform3fv:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glUniform3fv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*v*/ " : "v=")
+                    , (code ? "(GLfloat [])" : "") +  formatFloats(3 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUniform3i:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glUniform3i" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , msg.getArg1()
+                    , (code ? "/*y*/ " : "y=")
+                    , msg.getArg2()
+                    , (code ? "/*z*/ " : "z=")
+                    , msg.getArg3());
+                break;
+            case glUniform3iv:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glUniform3iv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*v*/ " : "v=")
+                    , (code ? "(GLint [])" : "") +  formatInts(3 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUniform4f:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glUniform4f" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , Float.intBitsToFloat(msg.getArg1())
+                    , (code ? "/*y*/ " : "y=")
+                    , Float.intBitsToFloat(msg.getArg2())
+                    , (code ? "/*z*/ " : "z=")
+                    , Float.intBitsToFloat(msg.getArg3())
+                    , (code ? "/*w*/ " : "w=")
+                    , Float.intBitsToFloat(msg.getArg4()));
+                break;
+            case glUniform4fv:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glUniform4fv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*v*/ " : "v=")
+                    , (code ? "(GLfloat [])" : "") +  formatFloats(4 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUniform4i:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glUniform4i" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , msg.getArg1()
+                    , (code ? "/*y*/ " : "y=")
+                    , msg.getArg2()
+                    , (code ? "/*z*/ " : "z=")
+                    , msg.getArg3()
+                    , (code ? "/*w*/ " : "w=")
+                    , msg.getArg4());
+                break;
+            case glUniform4iv:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glUniform4iv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*v*/ " : "v=")
+                    , (code ? "(GLint [])" : "") +  formatInts(4 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUniformMatrix2fv:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glUniformMatrix2fv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*transpose*/ " : "transpose=")
+                    , msg.getArg2()
+                    , (code ? "/*value*/ " : "value=")
+                    , (code ? "(GLfloat [])" : "") + formatMatrix(2, 4 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUniformMatrix3fv:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glUniformMatrix3fv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*transpose*/ " : "transpose=")
+                    , msg.getArg2()
+                    , (code ? "/*value*/ " : "value=")
+                    , (code ? "(GLfloat [])" : "") + formatMatrix(3, 9 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUniformMatrix4fv:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glUniformMatrix4fv" : "void")
+                    , (code ? "/*location*/ " : "location=")
+                    , msg.getArg0()
+                    , (code ? "/*count*/ " : "count=")
+                    , msg.getArg1()
+                    , (code ? "/*transpose*/ " : "transpose=")
+                    , msg.getArg2()
+                    , (code ? "/*value*/ " : "value=")
+                    , (code ? "(GLfloat [])" : "") + formatMatrix(4, 16 * msg.getArg1(), msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glUseProgram:
+                str = String.format("%s(%s%s)",
+                    (code ? "glUseProgram" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0());
+                break;
+            case glValidateProgram:
+                str = String.format("%s(%s%s)",
+                    (code ? "glValidateProgram" : "void")
+                    , (code ? "/*program*/ " : "program=")
+                    , (code ? "program_" : "") + msg.getArg0());
+                break;
+            case glVertexAttrib1f:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glVertexAttrib1f" : "void")
+                    , (code ? "/*indx*/ " : "indx=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , Float.intBitsToFloat(msg.getArg1()));
+                break;
+            case glVertexAttrib1fv:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glVertexAttrib1fv" : "void")
+                    , (code ? "/*indx*/ " : "indx=")
+                    , msg.getArg0()
+                    , (code ? "/*values*/ " : "values=")
+                    , (code ? "(GLfloat [])" : "") + formatFloats(1, msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glVertexAttrib2f:
+                str = String.format("%s(%s%s, %s%s, %s%s)",
+                    (code ? "glVertexAttrib2f" : "void")
+                    , (code ? "/*indx*/ " : "indx=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , Float.intBitsToFloat(msg.getArg1())
+                    , (code ? "/*y*/ " : "y=")
+                    , Float.intBitsToFloat(msg.getArg2()));
+                break;
+            case glVertexAttrib2fv:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glVertexAttrib2fv" : "void")
+                    , (code ? "/*indx*/ " : "indx=")
+                    , msg.getArg0()
+                    , (code ? "/*values*/ " : "values=")
+                    , (code ? "(GLfloat [])" : "") + formatFloats(2, msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glVertexAttrib3f:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glVertexAttrib3f" : "void")
+                    , (code ? "/*indx*/ " : "indx=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , Float.intBitsToFloat(msg.getArg1())
+                    , (code ? "/*y*/ " : "y=")
+                    , Float.intBitsToFloat(msg.getArg2())
+                    , (code ? "/*z*/ " : "z=")
+                    , Float.intBitsToFloat(msg.getArg3()));
+                break;
+            case glVertexAttrib3fv:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glVertexAttrib3fv" : "void")
+                    , (code ? "/*indx*/ " : "indx=")
+                    , msg.getArg0()
+                    , (code ? "/*values*/ " : "values=")
+                    , (code ? "(GLfloat [])" : "") + formatFloats(3, msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glVertexAttrib4f:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glVertexAttrib4f" : "void")
+                    , (code ? "/*indx*/ " : "indx=")
+                    , msg.getArg0()
+                    , (code ? "/*x*/ " : "x=")
+                    , Float.intBitsToFloat(msg.getArg1())
+                    , (code ? "/*y*/ " : "y=")
+                    , Float.intBitsToFloat(msg.getArg2())
+                    , (code ? "/*z*/ " : "z=")
+                    , Float.intBitsToFloat(msg.getArg3())
+                    , (code ? "/*w*/ " : "w=")
+                    , Float.intBitsToFloat(msg.getArg4()));
+                break;
+            case glVertexAttrib4fv:
+                str = String.format("%s(%s%s, %s%s)",
+                    (code ? "glVertexAttrib4fv" : "void")
+                    , (code ? "/*indx*/ " : "indx=")
+                    , msg.getArg0()
+                    , (code ? "/*values*/ " : "values=")
+                    , (code ? "(GLfloat [])" : "") + formatFloats(4, msg.getData().asReadOnlyByteBuffer()));
+                break;
+            case glVertexAttribPointer:
+                // FIXME: this function uses pointers, debugger may send data in msg.data
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glVertexAttribPointer" : "void")
+                    , (code ? "/*indx*/ " : "indx=")
+                    , msg.getArg0()
+                    , (code ? "/*size*/ " : "size=")
+                    , msg.getArg1()
+                    , (code ? "/*type*/ " : "type=")
+                    , GLEnum.valueOf(msg.getArg2())
+                    , (code ? "/*normalized*/ " : "normalized=")
+                    , msg.getArg3()
+                    , (code ? "/*stride*/ " : "stride=")
+                    , msg.getArg4()
+                    , (code ? "/*ptr*/ " : "ptr=")
+                    , (code ? "arg5" : "0x" + Integer.toHexString(msg.getArg5())));
+                break;
+            case glViewport:
+                str = String.format("%s(%s%s, %s%s, %s%s, %s%s)",
+                    (code ? "glViewport" : "void")
+                    , (code ? "/*x*/ " : "x=")
+                    , msg.getArg0()
+                    , (code ? "/*y*/ " : "y=")
+                    , msg.getArg1()
+                    , (code ? "/*width*/ " : "width=")
+                    , msg.getArg2()
+                    , (code ? "/*height*/ " : "height=")
+                    , msg.getArg3());
+                break;
+            default:
+                str = msg.toString();
+        }
+        return str;
+    }
+}
\ No newline at end of file
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/MessageParser.java b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageParser.java
new file mode 100644
index 0000000..8536728
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageParser.java
@@ -0,0 +1,747 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+// auto generated by generate_MessageParser_java.py,
+//  which also prints skeleton code for MessageParserEx.java
+
+package com.android.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.google.protobuf.ByteString;
+
+import java.nio.ByteBuffer;
+
+public abstract class MessageParser {
+
+    String args;
+
+    String[] getList()
+    {
+        String arg = args;
+        args = args.substring(args.lastIndexOf('}') + 1);
+        final int comma = args.indexOf(',');
+        if (comma >= 0)
+            args = args.substring(comma + 1).trim();
+        else
+            args = null;
+
+        final int comment = arg.indexOf('=');
+        if (comment >= 0)
+            arg = arg.substring(comment + 1);
+        arg = arg.trim();
+        assert arg.charAt(0) == '{';
+        arg = arg.substring(1, arg.lastIndexOf('}')).trim();
+        return arg.split("\\s*,\\s*");
+    }
+
+    ByteString parseFloats(int count) {
+        ByteBuffer buffer = ByteBuffer.allocate(count * 4);
+        buffer.order(SampleView.targetByteOrder);
+        String [] arg = getList();
+        for (int i = 0; i < count; i++)
+            buffer.putFloat(Float.parseFloat(arg[i].trim()));
+        buffer.rewind();
+        return ByteString.copyFrom(buffer);
+    }
+
+    ByteString parseInts(int count) {
+        ByteBuffer buffer = ByteBuffer.allocate(count * 4);
+        buffer.order(SampleView.targetByteOrder);
+        String [] arg = getList();
+        for (int i = 0; i < count; i++)
+            buffer.putInt(Integer.parseInt(arg[i].trim()));
+        buffer.rewind();
+        return ByteString.copyFrom(buffer);
+    }
+
+    ByteString parseUInts(int count) {
+        ByteBuffer buffer = ByteBuffer.allocate(count * 4);
+        buffer.order(SampleView.targetByteOrder);
+        String [] arg = getList();
+        for (int i = 0; i < count; i++)
+            buffer.putInt((int)(Long.parseLong(arg[i].trim()) & 0xffffffff));
+        buffer.rewind();
+        return ByteString.copyFrom(buffer);
+    }
+
+    ByteString parseMatrix(int columns, int count) {
+        return parseFloats(columns * columns * count);
+    }
+
+    ByteString parseString() {
+        // TODO: escape sequence and proper string literal
+        String arg = args.substring(args.indexOf('"') + 1, args.lastIndexOf('"'));
+        args = args.substring(args.lastIndexOf('"'));
+        int comma = args.indexOf(',');
+        if (comma >= 0)
+            args = args.substring(comma + 1).trim();
+        else
+            args = null;
+        return ByteString.copyFromUtf8(arg);
+    }
+
+    String getArgument()
+    {
+        final int comma = args.indexOf(',');
+        String arg = null;
+        if (comma >= 0)
+        {
+            arg = args.substring(0, comma);
+            args = args.substring(comma + 1);
+        }
+        else
+        {
+            arg = args;
+            args = null;
+        }
+        final int comment = arg.indexOf('=');
+        if (comment >= 0)
+            arg = arg.substring(comment + 1);
+        return arg.trim();
+    }
+
+    int parseArgument()
+    {
+        String arg = getArgument();
+        if (arg.startsWith("GL_"))
+            return GLEnum.valueOf(arg).value;
+        else if (arg.toLowerCase().startsWith("0x"))
+            return Integer.parseInt(arg.substring(2), 16);
+        else
+            return Integer.parseInt(arg);
+    }
+
+    int parseFloat()
+    {
+        String arg = getArgument();
+        return Float.floatToRawIntBits(Float.parseFloat(arg));
+    }
+
+    public void parse(final Message.Builder builder, String string) {
+        int lparen = string.indexOf("("), rparen = string.lastIndexOf(")");
+        String s = string.substring(0, lparen).trim();
+        args = string.substring(lparen + 1, rparen);
+        String[] t = s.split(" ");
+        Function function = Function.valueOf(t[t.length - 1]);
+        builder.setFunction(function);
+        switch (function) {
+            case glActiveTexture:
+                builder.setArg0(parseArgument()); // GLenum texture
+                break;
+            case glAttachShader:
+                builder.setArg0(parseArgument()); // GLuint program
+                builder.setArg1(parseArgument()); // GLuint shader
+                break;
+            case glBindAttribLocation:
+                builder.setArg0(parseArgument()); // GLuint program
+                builder.setArg1(parseArgument()); // GLuint index
+                builder.setData(parseString()); // GLchar name
+                break;
+            case glBindBuffer:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLuint buffer
+                break;
+            case glBindFramebuffer:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLuint framebuffer
+                break;
+            case glBindRenderbuffer:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLuint renderbuffer
+                break;
+            case glBindTexture:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLuint texture
+                break;
+            case glBlendColor:
+                builder.setArg0(parseFloat()); // GLclampf red
+                builder.setArg1(parseFloat()); // GLclampf green
+                builder.setArg2(parseFloat()); // GLclampf blue
+                builder.setArg3(parseFloat()); // GLclampf alpha
+                break;
+            case glBlendEquation:
+                builder.setArg0(parseArgument()); // GLenum mode
+                break;
+            case glBlendEquationSeparate:
+                builder.setArg0(parseArgument()); // GLenum modeRGB
+                builder.setArg1(parseArgument()); // GLenum modeAlpha
+                break;
+            case glBlendFunc:
+                builder.setArg0(parseArgument()); // GLenum sfactor
+                builder.setArg1(parseArgument()); // GLenum dfactor
+                break;
+            case glBlendFuncSeparate:
+                builder.setArg0(parseArgument()); // GLenum srcRGB
+                builder.setArg1(parseArgument()); // GLenum dstRGB
+                builder.setArg2(parseArgument()); // GLenum srcAlpha
+                builder.setArg3(parseArgument()); // GLenum dstAlpha
+                break;
+            case glBufferData:
+                parse_glBufferData(builder);
+                break;
+            case glBufferSubData:
+                parse_glBufferSubData(builder);
+                break;
+            case glCheckFramebufferStatus:
+                builder.setArg0(parseArgument()); // GLenum target
+                break;
+            case glClear:
+                builder.setArg0(parseArgument()); // GLbitfield mask
+                break;
+            case glClearColor:
+                builder.setArg0(parseFloat()); // GLclampf red
+                builder.setArg1(parseFloat()); // GLclampf green
+                builder.setArg2(parseFloat()); // GLclampf blue
+                builder.setArg3(parseFloat()); // GLclampf alpha
+                break;
+            case glClearDepthf:
+                builder.setArg0(parseFloat()); // GLclampf depth
+                break;
+            case glClearStencil:
+                builder.setArg0(parseArgument()); // GLint s
+                break;
+            case glColorMask:
+                builder.setArg0(parseArgument()); // GLboolean red
+                builder.setArg1(parseArgument()); // GLboolean green
+                builder.setArg2(parseArgument()); // GLboolean blue
+                builder.setArg3(parseArgument()); // GLboolean alpha
+                break;
+            case glCompileShader:
+                builder.setArg0(parseArgument()); // GLuint shader
+                break;
+            case glCompressedTexImage2D:
+                parse_glCompressedTexImage2D(builder);
+                break;
+            case glCompressedTexSubImage2D:
+                parse_glCompressedTexSubImage2D(builder);
+                break;
+            case glCopyTexImage2D:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLint level
+                builder.setArg2(parseArgument()); // GLenum internalformat
+                builder.setArg3(parseArgument()); // GLint x
+                builder.setArg4(parseArgument()); // GLint y
+                builder.setArg5(parseArgument()); // GLsizei width
+                builder.setArg6(parseArgument()); // GLsizei height
+                builder.setArg7(parseArgument()); // GLint border
+                break;
+            case glCopyTexSubImage2D:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLint level
+                builder.setArg2(parseArgument()); // GLint xoffset
+                builder.setArg3(parseArgument()); // GLint yoffset
+                builder.setArg4(parseArgument()); // GLint x
+                builder.setArg5(parseArgument()); // GLint y
+                builder.setArg6(parseArgument()); // GLsizei width
+                builder.setArg7(parseArgument()); // GLsizei height
+                break;
+            case glCreateProgram:
+                break;
+            case glCreateShader:
+                builder.setArg0(parseArgument()); // GLenum type
+                break;
+            case glCullFace:
+                builder.setArg0(parseArgument()); // GLenum mode
+                break;
+            case glDeleteBuffers:
+                builder.setArg0(parseArgument()); // GLsizei n
+                builder.setData(parseUInts(1 * builder.getArg0())); // GLuint buffers
+                break;
+            case glDeleteFramebuffers:
+                builder.setArg0(parseArgument()); // GLsizei n
+                builder.setData(parseUInts(1 * builder.getArg0())); // GLuint framebuffers
+                break;
+            case glDeleteProgram:
+                builder.setArg0(parseArgument()); // GLuint program
+                break;
+            case glDeleteRenderbuffers:
+                builder.setArg0(parseArgument()); // GLsizei n
+                builder.setData(parseUInts(1 * builder.getArg0())); // GLuint renderbuffers
+                break;
+            case glDeleteShader:
+                builder.setArg0(parseArgument()); // GLuint shader
+                break;
+            case glDeleteTextures:
+                builder.setArg0(parseArgument()); // GLsizei n
+                builder.setData(parseUInts(1 * builder.getArg0())); // GLuint textures
+                break;
+            case glDepthFunc:
+                builder.setArg0(parseArgument()); // GLenum func
+                break;
+            case glDepthMask:
+                builder.setArg0(parseArgument()); // GLboolean flag
+                break;
+            case glDepthRangef:
+                builder.setArg0(parseFloat()); // GLclampf zNear
+                builder.setArg1(parseFloat()); // GLclampf zFar
+                break;
+            case glDetachShader:
+                builder.setArg0(parseArgument()); // GLuint program
+                builder.setArg1(parseArgument()); // GLuint shader
+                break;
+            case glDisable:
+                builder.setArg0(parseArgument()); // GLenum cap
+                break;
+            case glDisableVertexAttribArray:
+                builder.setArg0(parseArgument()); // GLuint index
+                break;
+            case glDrawArrays:
+                builder.setArg0(parseArgument()); // GLenum mode
+                builder.setArg1(parseArgument()); // GLint first
+                builder.setArg2(parseArgument()); // GLsizei count
+                break;
+            case glDrawElements:
+                parse_glDrawElements(builder);
+                break;
+            case glEnable:
+                builder.setArg0(parseArgument()); // GLenum cap
+                break;
+            case glEnableVertexAttribArray:
+                builder.setArg0(parseArgument()); // GLuint index
+                break;
+            case glFinish:
+                break;
+            case glFlush:
+                break;
+            case glFramebufferRenderbuffer:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLenum attachment
+                builder.setArg2(parseArgument()); // GLenum renderbuffertarget
+                builder.setArg3(parseArgument()); // GLuint renderbuffer
+                break;
+            case glFramebufferTexture2D:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLenum attachment
+                builder.setArg2(parseArgument()); // GLenum textarget
+                builder.setArg3(parseArgument()); // GLuint texture
+                builder.setArg4(parseArgument()); // GLint level
+                break;
+            case glFrontFace:
+                builder.setArg0(parseArgument()); // GLenum mode
+                break;
+            case glGenBuffers:
+                builder.setArg0(parseArgument()); // GLsizei n
+                builder.setData(parseUInts(1 * builder.getArg0())); // GLuint buffers
+                break;
+            case glGenerateMipmap:
+                builder.setArg0(parseArgument()); // GLenum target
+                break;
+            case glGenFramebuffers:
+                builder.setArg0(parseArgument()); // GLsizei n
+                builder.setData(parseUInts(1 * builder.getArg0())); // GLuint framebuffers
+                break;
+            case glGenRenderbuffers:
+                builder.setArg0(parseArgument()); // GLsizei n
+                builder.setData(parseUInts(1 * builder.getArg0())); // GLuint renderbuffers
+                break;
+            case glGenTextures:
+                builder.setArg0(parseArgument()); // GLsizei n
+                builder.setData(parseUInts(1 * builder.getArg0())); // GLuint textures
+                break;
+            case glGetActiveAttrib:
+                parse_glGetActiveAttrib(builder);
+                break;
+            case glGetActiveUniform:
+                parse_glGetActiveUniform(builder);
+                break;
+            case glGetAttachedShaders:
+                parse_glGetAttachedShaders(builder);
+                break;
+            case glGetAttribLocation:
+                builder.setArg0(parseArgument()); // GLuint program
+                builder.setData(parseString()); // GLchar name
+                break;
+            case glGetBooleanv:
+                parse_glGetBooleanv(builder);
+                break;
+            case glGetBufferParameteriv:
+                parse_glGetBufferParameteriv(builder);
+                break;
+            case glGetError:
+                break;
+            case glGetFloatv:
+                parse_glGetFloatv(builder);
+                break;
+            case glGetFramebufferAttachmentParameteriv:
+                parse_glGetFramebufferAttachmentParameteriv(builder);
+                break;
+            case glGetIntegerv:
+                parse_glGetIntegerv(builder);
+                break;
+            case glGetProgramiv:
+                builder.setArg0(parseArgument()); // GLuint program
+                builder.setArg1(parseArgument()); // GLenum pname
+                builder.setData(parseInts(1)); // GLint params
+                break;
+            case glGetProgramInfoLog:
+                parse_glGetProgramInfoLog(builder);
+                break;
+            case glGetRenderbufferParameteriv:
+                parse_glGetRenderbufferParameteriv(builder);
+                break;
+            case glGetShaderiv:
+                builder.setArg0(parseArgument()); // GLuint shader
+                builder.setArg1(parseArgument()); // GLenum pname
+                builder.setData(parseInts(1)); // GLint params
+                break;
+            case glGetShaderInfoLog:
+                parse_glGetShaderInfoLog(builder);
+                break;
+            case glGetShaderPrecisionFormat:
+                parse_glGetShaderPrecisionFormat(builder);
+                break;
+            case glGetShaderSource:
+                parse_glGetShaderSource(builder);
+                break;
+            case glGetString:
+                builder.setArg0(parseArgument()); // GLenum name
+                break;
+            case glGetTexParameterfv:
+                parse_glGetTexParameterfv(builder);
+                break;
+            case glGetTexParameteriv:
+                parse_glGetTexParameteriv(builder);
+                break;
+            case glGetUniformfv:
+                parse_glGetUniformfv(builder);
+                break;
+            case glGetUniformiv:
+                parse_glGetUniformiv(builder);
+                break;
+            case glGetUniformLocation:
+                builder.setArg0(parseArgument()); // GLuint program
+                builder.setData(parseString()); // GLchar name
+                break;
+            case glGetVertexAttribfv:
+                parse_glGetVertexAttribfv(builder);
+                break;
+            case glGetVertexAttribiv:
+                parse_glGetVertexAttribiv(builder);
+                break;
+            case glGetVertexAttribPointerv:
+                parse_glGetVertexAttribPointerv(builder);
+                break;
+            case glHint:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLenum mode
+                break;
+            case glIsBuffer:
+                builder.setArg0(parseArgument()); // GLuint buffer
+                break;
+            case glIsEnabled:
+                builder.setArg0(parseArgument()); // GLenum cap
+                break;
+            case glIsFramebuffer:
+                builder.setArg0(parseArgument()); // GLuint framebuffer
+                break;
+            case glIsProgram:
+                builder.setArg0(parseArgument()); // GLuint program
+                break;
+            case glIsRenderbuffer:
+                builder.setArg0(parseArgument()); // GLuint renderbuffer
+                break;
+            case glIsShader:
+                builder.setArg0(parseArgument()); // GLuint shader
+                break;
+            case glIsTexture:
+                builder.setArg0(parseArgument()); // GLuint texture
+                break;
+            case glLineWidth:
+                builder.setArg0(parseFloat()); // GLfloat width
+                break;
+            case glLinkProgram:
+                builder.setArg0(parseArgument()); // GLuint program
+                break;
+            case glPixelStorei:
+                builder.setArg0(parseArgument()); // GLenum pname
+                builder.setArg1(parseArgument()); // GLint param
+                break;
+            case glPolygonOffset:
+                builder.setArg0(parseFloat()); // GLfloat factor
+                builder.setArg1(parseFloat()); // GLfloat units
+                break;
+            case glReadPixels:
+                parse_glReadPixels(builder);
+                break;
+            case glReleaseShaderCompiler:
+                break;
+            case glRenderbufferStorage:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLenum internalformat
+                builder.setArg2(parseArgument()); // GLsizei width
+                builder.setArg3(parseArgument()); // GLsizei height
+                break;
+            case glSampleCoverage:
+                builder.setArg0(parseFloat()); // GLclampf value
+                builder.setArg1(parseArgument()); // GLboolean invert
+                break;
+            case glScissor:
+                builder.setArg0(parseArgument()); // GLint x
+                builder.setArg1(parseArgument()); // GLint y
+                builder.setArg2(parseArgument()); // GLsizei width
+                builder.setArg3(parseArgument()); // GLsizei height
+                break;
+            case glShaderBinary:
+                parse_glShaderBinary(builder);
+                break;
+            case glShaderSource:
+                parse_glShaderSource(builder);
+                break;
+            case glStencilFunc:
+                builder.setArg0(parseArgument()); // GLenum func
+                builder.setArg1(parseArgument()); // GLint ref
+                builder.setArg2(parseArgument()); // GLuint mask
+                break;
+            case glStencilFuncSeparate:
+                builder.setArg0(parseArgument()); // GLenum face
+                builder.setArg1(parseArgument()); // GLenum func
+                builder.setArg2(parseArgument()); // GLint ref
+                builder.setArg3(parseArgument()); // GLuint mask
+                break;
+            case glStencilMask:
+                builder.setArg0(parseArgument()); // GLuint mask
+                break;
+            case glStencilMaskSeparate:
+                builder.setArg0(parseArgument()); // GLenum face
+                builder.setArg1(parseArgument()); // GLuint mask
+                break;
+            case glStencilOp:
+                builder.setArg0(parseArgument()); // GLenum fail
+                builder.setArg1(parseArgument()); // GLenum zfail
+                builder.setArg2(parseArgument()); // GLenum zpass
+                break;
+            case glStencilOpSeparate:
+                builder.setArg0(parseArgument()); // GLenum face
+                builder.setArg1(parseArgument()); // GLenum fail
+                builder.setArg2(parseArgument()); // GLenum zfail
+                builder.setArg3(parseArgument()); // GLenum zpass
+                break;
+            case glTexImage2D:
+                parse_glTexImage2D(builder);
+                break;
+            case glTexParameterf:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLenum pname
+                builder.setArg2(parseFloat()); // GLfloat param
+                break;
+            case glTexParameterfv:
+                parse_glTexParameterfv(builder);
+                break;
+            case glTexParameteri:
+                builder.setArg0(parseArgument()); // GLenum target
+                builder.setArg1(parseArgument()); // GLenum pname
+                builder.setArg2(parseArgument()); // GLint param
+                break;
+            case glTexParameteriv:
+                parse_glTexParameteriv(builder);
+                break;
+            case glTexSubImage2D:
+                parse_glTexSubImage2D(builder);
+                break;
+            case glUniform1f:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseFloat()); // GLfloat x
+                break;
+            case glUniform1fv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setData(parseFloats(1 * builder.getArg1())); // GLfloat v
+                break;
+            case glUniform1i:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLint x
+                break;
+            case glUniform1iv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setData(parseInts(1 * builder.getArg1())); // GLint v
+                break;
+            case glUniform2f:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseFloat()); // GLfloat x
+                builder.setArg2(parseFloat()); // GLfloat y
+                break;
+            case glUniform2fv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setData(parseFloats(2 * builder.getArg1())); // GLfloat v
+                break;
+            case glUniform2i:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLint x
+                builder.setArg2(parseArgument()); // GLint y
+                break;
+            case glUniform2iv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setData(parseInts(2 * builder.getArg1())); // GLint v
+                break;
+            case glUniform3f:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseFloat()); // GLfloat x
+                builder.setArg2(parseFloat()); // GLfloat y
+                builder.setArg3(parseFloat()); // GLfloat z
+                break;
+            case glUniform3fv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setData(parseFloats(3 * builder.getArg1())); // GLfloat v
+                break;
+            case glUniform3i:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLint x
+                builder.setArg2(parseArgument()); // GLint y
+                builder.setArg3(parseArgument()); // GLint z
+                break;
+            case glUniform3iv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setData(parseInts(3 * builder.getArg1())); // GLint v
+                break;
+            case glUniform4f:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseFloat()); // GLfloat x
+                builder.setArg2(parseFloat()); // GLfloat y
+                builder.setArg3(parseFloat()); // GLfloat z
+                builder.setArg4(parseFloat()); // GLfloat w
+                break;
+            case glUniform4fv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setData(parseFloats(4 * builder.getArg1())); // GLfloat v
+                break;
+            case glUniform4i:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLint x
+                builder.setArg2(parseArgument()); // GLint y
+                builder.setArg3(parseArgument()); // GLint z
+                builder.setArg4(parseArgument()); // GLint w
+                break;
+            case glUniform4iv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setData(parseInts(4 * builder.getArg1())); // GLint v
+                break;
+            case glUniformMatrix2fv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setArg2(parseArgument()); // GLboolean transpose
+                builder.setData(parseMatrix(2, builder.getArg1())); // GLfloat value
+                break;
+            case glUniformMatrix3fv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setArg2(parseArgument()); // GLboolean transpose
+                builder.setData(parseMatrix(3, builder.getArg1())); // GLfloat value
+                break;
+            case glUniformMatrix4fv:
+                builder.setArg0(parseArgument()); // GLint location
+                builder.setArg1(parseArgument()); // GLsizei count
+                builder.setArg2(parseArgument()); // GLboolean transpose
+                builder.setData(parseMatrix(4, builder.getArg1())); // GLfloat value
+                break;
+            case glUseProgram:
+                builder.setArg0(parseArgument()); // GLuint program
+                break;
+            case glValidateProgram:
+                builder.setArg0(parseArgument()); // GLuint program
+                break;
+            case glVertexAttrib1f:
+                builder.setArg0(parseArgument()); // GLuint indx
+                builder.setArg1(parseFloat()); // GLfloat x
+                break;
+            case glVertexAttrib1fv:
+                builder.setArg0(parseArgument()); // GLuint indx
+                builder.setData(parseFloats(1)); // GLfloat values
+                break;
+            case glVertexAttrib2f:
+                builder.setArg0(parseArgument()); // GLuint indx
+                builder.setArg1(parseFloat()); // GLfloat x
+                builder.setArg2(parseFloat()); // GLfloat y
+                break;
+            case glVertexAttrib2fv:
+                builder.setArg0(parseArgument()); // GLuint indx
+                builder.setData(parseFloats(2)); // GLfloat values
+                break;
+            case glVertexAttrib3f:
+                builder.setArg0(parseArgument()); // GLuint indx
+                builder.setArg1(parseFloat()); // GLfloat x
+                builder.setArg2(parseFloat()); // GLfloat y
+                builder.setArg3(parseFloat()); // GLfloat z
+                break;
+            case glVertexAttrib3fv:
+                builder.setArg0(parseArgument()); // GLuint indx
+                builder.setData(parseFloats(3)); // GLfloat values
+                break;
+            case glVertexAttrib4f:
+                builder.setArg0(parseArgument()); // GLuint indx
+                builder.setArg1(parseFloat()); // GLfloat x
+                builder.setArg2(parseFloat()); // GLfloat y
+                builder.setArg3(parseFloat()); // GLfloat z
+                builder.setArg4(parseFloat()); // GLfloat w
+                break;
+            case glVertexAttrib4fv:
+                builder.setArg0(parseArgument()); // GLuint indx
+                builder.setData(parseFloats(4)); // GLfloat values
+                break;
+            case glVertexAttribPointer:
+                parse_glVertexAttribPointer(builder);
+                break;
+            case glViewport:
+                builder.setArg0(parseArgument()); // GLint x
+                builder.setArg1(parseArgument()); // GLint y
+                builder.setArg2(parseArgument()); // GLsizei width
+                builder.setArg3(parseArgument()); // GLsizei height
+                break;
+            default:
+                assert false;
+        }
+    }
+    abstract void parse_glBufferData(Message.Builder builder);
+    abstract void parse_glBufferSubData(Message.Builder builder);
+    abstract void parse_glCompressedTexImage2D(Message.Builder builder);
+    abstract void parse_glCompressedTexSubImage2D(Message.Builder builder);
+    abstract void parse_glDrawElements(Message.Builder builder);
+    abstract void parse_glGetActiveAttrib(Message.Builder builder);
+    abstract void parse_glGetActiveUniform(Message.Builder builder);
+    abstract void parse_glGetAttachedShaders(Message.Builder builder);
+    abstract void parse_glGetBooleanv(Message.Builder builder);
+    abstract void parse_glGetBufferParameteriv(Message.Builder builder);
+    abstract void parse_glGetFloatv(Message.Builder builder);
+    abstract void parse_glGetFramebufferAttachmentParameteriv(Message.Builder builder);
+    abstract void parse_glGetIntegerv(Message.Builder builder);
+    abstract void parse_glGetProgramInfoLog(Message.Builder builder);
+    abstract void parse_glGetRenderbufferParameteriv(Message.Builder builder);
+    abstract void parse_glGetShaderInfoLog(Message.Builder builder);
+    abstract void parse_glGetShaderPrecisionFormat(Message.Builder builder);
+    abstract void parse_glGetShaderSource(Message.Builder builder);
+    abstract void parse_glGetTexParameterfv(Message.Builder builder);
+    abstract void parse_glGetTexParameteriv(Message.Builder builder);
+    abstract void parse_glGetUniformfv(Message.Builder builder);
+    abstract void parse_glGetUniformiv(Message.Builder builder);
+    abstract void parse_glGetVertexAttribfv(Message.Builder builder);
+    abstract void parse_glGetVertexAttribiv(Message.Builder builder);
+    abstract void parse_glGetVertexAttribPointerv(Message.Builder builder);
+    abstract void parse_glReadPixels(Message.Builder builder);
+    abstract void parse_glShaderBinary(Message.Builder builder);
+    abstract void parse_glShaderSource(Message.Builder builder);
+    abstract void parse_glTexImage2D(Message.Builder builder);
+    abstract void parse_glTexParameterfv(Message.Builder builder);
+    abstract void parse_glTexParameteriv(Message.Builder builder);
+    abstract void parse_glTexSubImage2D(Message.Builder builder);
+    abstract void parse_glVertexAttribPointer(Message.Builder builder);
+}
\ No newline at end of file
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/MessageParserEx.java b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageParserEx.java
new file mode 100644
index 0000000..5099146
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageParserEx.java
@@ -0,0 +1,306 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+// skeleton from stdout of generate_MessageParser_java.py
+
+package com.android.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+
+public class MessageParserEx extends MessageParser {
+
+    @Override
+    void parse_glBufferData(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLsizeiptr size
+        // TODO // GLvoid data
+        builder.setArg3(parseArgument()); // GLenum usage
+    }
+
+    @Override
+    void parse_glBufferSubData(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLintptr offset
+        builder.setArg2(parseArgument()); // GLsizeiptr size
+        // TODO // GLvoid data
+    }
+
+    @Override
+    void parse_glCompressedTexImage2D(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLint level
+        builder.setArg2(parseArgument()); // GLenum internalformat
+        builder.setArg3(parseArgument()); // GLsizei width
+        builder.setArg4(parseArgument()); // GLsizei height
+        builder.setArg5(parseArgument()); // GLint border
+        builder.setArg6(parseArgument()); // GLsizei imageSize
+        // TODO: GLvoid* data
+    }
+
+    @Override
+    void parse_glCompressedTexSubImage2D(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLint level
+        builder.setArg2(parseArgument()); // GLint xoffset
+        builder.setArg3(parseArgument()); // GLint yoffset
+        builder.setArg4(parseArgument()); // GLsizei width
+        builder.setArg5(parseArgument()); // GLsizei height
+        builder.setArg6(parseArgument()); // GLenum format
+        builder.setArg7(parseArgument()); // GLsizei imageSize
+        // TODO: GLvoid* data
+    }
+
+    @Override
+    void parse_glDrawElements(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum mode
+        builder.setArg1(parseArgument()); // GLsizei count
+        builder.setArg2(parseArgument()); // GLenum type
+        // TODO: GLvoid* indices
+    }
+
+    @Override
+    void parse_glGetActiveAttrib(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint program
+        builder.setArg1(parseArgument()); // GLuint index
+        builder.setArg2(parseArgument()); // GLsizei bufsize
+        // TODO: GLsizei* length
+        // TODO: GLint* size
+        // TODO: GLenum* type
+        builder.setData(parseString()); // GLchar name
+    }
+
+    @Override
+    void parse_glGetActiveUniform(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint program
+        builder.setArg1(parseArgument()); // GLuint index
+        builder.setArg2(parseArgument()); // GLsizei bufsize
+        // TODO: GLsizei* length
+        // TODO: GLint* size
+        // TODO: GLenum* type
+        builder.setData(parseString()); // GLchar name
+    }
+
+    @Override
+    void parse_glGetAttachedShaders(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint program
+        builder.setArg1(parseArgument()); // GLsizei maxcount
+        // TODO: GLsizei* count
+        // TODO: GLuint* shaders
+    }
+
+    @Override
+    void parse_glGetBooleanv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum pname
+        // TODO: GLboolean* params
+    }
+
+    @Override
+    void parse_glGetBufferParameteriv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLenum pname
+        // TODO: GLint* params
+    }
+
+    @Override
+    void parse_glGetFloatv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum pname
+        // TODO: GLfloat* params
+    }
+
+    @Override
+    void parse_glGetFramebufferAttachmentParameteriv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLenum attachment
+        builder.setArg2(parseArgument()); // GLenum pname
+        // TODO: GLint* params
+    }
+
+    @Override
+    void parse_glGetIntegerv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum pname
+        // TODO: GLint* params
+    }
+
+    @Override
+    void parse_glGetProgramInfoLog(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint program
+        builder.setArg1(parseArgument()); // GLsizei bufsize
+        // TODO: GLsizei* length
+        builder.setData(parseString()); // GLchar infolog
+    }
+
+    @Override
+    void parse_glGetRenderbufferParameteriv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLenum pname
+        // TODO: GLint* params
+    }
+
+    @Override
+    void parse_glGetShaderInfoLog(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint shader
+        builder.setArg1(parseArgument()); // GLsizei bufsize
+        // TODO: GLsizei* length
+        builder.setData(parseString()); // GLchar infolog
+    }
+
+    @Override
+    void parse_glGetShaderPrecisionFormat(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum shadertype
+        builder.setArg1(parseArgument()); // GLenum precisiontype
+        // TODO: GLint* range
+        // TODO: GLint* precision
+    }
+
+    @Override
+    void parse_glGetShaderSource(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint shader
+        builder.setArg1(parseArgument()); // GLsizei bufsize
+        // TODO: GLsizei* length
+        builder.setData(parseString()); // GLchar source
+    }
+
+    @Override
+    void parse_glGetTexParameterfv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLenum pname
+        // TODO: GLfloat* params
+    }
+
+    @Override
+    void parse_glGetTexParameteriv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLenum pname
+        // TODO: GLint* params
+    }
+
+    @Override
+    void parse_glGetUniformfv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint program
+        builder.setArg1(parseArgument()); // GLint location
+        // TODO: GLfloat* params
+    }
+
+    @Override
+    void parse_glGetUniformiv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint program
+        builder.setArg1(parseArgument()); // GLint location
+        // TODO: GLint* params
+    }
+
+    @Override
+    void parse_glGetVertexAttribfv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint index
+        builder.setArg1(parseArgument()); // GLenum pname
+        // TODO: GLfloat* params
+    }
+
+    @Override
+    void parse_glGetVertexAttribiv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint index
+        builder.setArg1(parseArgument()); // GLenum pname
+        // TODO: GLint* params
+    }
+
+    @Override
+    void parse_glGetVertexAttribPointerv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint index
+        builder.setArg1(parseArgument()); // GLenum pname
+        // TODO: GLvoid** pointer
+    }
+
+    @Override
+    void parse_glReadPixels(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLint x
+        builder.setArg1(parseArgument()); // GLint y
+        builder.setArg2(parseArgument()); // GLsizei width
+        builder.setArg3(parseArgument()); // GLsizei height
+        builder.setArg4(parseArgument()); // GLenum format
+        builder.setArg5(parseArgument()); // GLenum type
+        // TODO: GLvoid* pixels
+    }
+
+    @Override
+    void parse_glShaderBinary(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLsizei n
+        // TODO: GLuint* shaders
+        builder.setArg2(parseArgument()); // GLenum binaryformat
+        // TODO: GLvoid* binary
+        builder.setArg4(parseArgument()); // GLsizei length
+    }
+
+    @Override
+    void parse_glShaderSource(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint shader
+        builder.setArg1(parseArgument()); // GLsizei count
+        assert 1 == builder.getArg1();
+        builder.setData(parseString()); // GLchar** string
+        builder.setArg3(parseArgument());// not used, always 1 null terminated
+                                         // string; GLint* length
+    }
+
+    @Override
+    void parse_glTexImage2D(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLint level
+        builder.setArg2(parseArgument()); // GLint internalformat
+        builder.setArg3(parseArgument()); // GLsizei width
+        builder.setArg4(parseArgument()); // GLsizei height
+        builder.setArg5(parseArgument()); // GLint border
+        builder.setArg6(parseArgument()); // GLenum format
+        builder.setArg7(parseArgument()); // GLenum type
+        // TODO: GLvoid* pixels
+    }
+
+    @Override
+    void parse_glTexParameterfv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLenum pname
+        // TODO: GLfloat* params
+    }
+
+    @Override
+    void parse_glTexParameteriv(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLenum pname
+        // TODO: GLint* params
+    }
+
+    @Override
+    void parse_glTexSubImage2D(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLenum target
+        builder.setArg1(parseArgument()); // GLint level
+        builder.setArg2(parseArgument()); // GLint xoffset
+        builder.setArg3(parseArgument()); // GLint yoffset
+        builder.setArg4(parseArgument()); // GLsizei width
+        builder.setArg5(parseArgument()); // GLsizei height
+        builder.setArg6(parseArgument()); // GLenum format
+        builder.setArg7(parseArgument()); // GLenum type
+        // TODO: GLvoid* pixels
+    }
+
+    @Override
+    void parse_glVertexAttribPointer(Message.Builder builder) {
+        builder.setArg0(parseArgument()); // GLuint indx
+        builder.setArg1(parseArgument()); // GLint size
+        builder.setArg2(parseArgument()); // GLenum type
+        builder.setArg3(parseArgument()); // GLboolean normalized
+        builder.setArg4(parseArgument()); // GLsizei stride
+        // TODO: GLvoid* ptr
+    }
+
+    public final static MessageParserEx instance = new MessageParserEx();
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/MessageProcessor.java b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageProcessor.java
new file mode 100644
index 0000000..bdd53d1
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageProcessor.java
@@ -0,0 +1,173 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.google.protobuf.ByteString;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+public class MessageProcessor {
+    static void showError(final String message) {
+        // need to call SWT from UI thread
+        MessageDialog.openError(null, "MessageProcessor", message);
+    }
+
+    /**
+     * data layout: uint32 total decompressed length, (chunks: uint32 chunk
+     * decompressed size, uint32 chunk compressed size, chunk data)+. 0 chunk
+     * compressed size means chunk is not compressed
+     */
+    public static byte[] lzfDecompressChunks(final ByteString data) {
+        ByteBuffer in = data.asReadOnlyByteBuffer();
+        in.order(SampleView.targetByteOrder);
+        ByteBuffer out = ByteBuffer.allocate(in.getInt());
+        byte[] inChunk = new byte[0];
+        byte[] outChunk = new byte[0];
+        while (in.remaining() > 0) {
+            int decompressed = in.getInt();
+            int compressed = in.getInt();
+            if (decompressed > outChunk.length)
+                outChunk = new byte[decompressed];
+            if (compressed == 0) {
+                in.get(outChunk, 0, decompressed);
+                out.put(outChunk, 0, decompressed);
+            } else {
+                if (compressed > inChunk.length)
+                    inChunk = new byte[compressed];
+                in.get(inChunk, 0, compressed);
+                int size = org.liblzf.CLZF
+                        .lzf_decompress(inChunk, compressed, outChunk, outChunk.length);
+                assert size == decompressed;
+                out.put(outChunk, 0, size);
+            }
+        }
+        assert !out.hasRemaining();
+        return out.array();
+    }
+
+    /** same data layout as LZFDecompressChunks */
+    public static byte[] lzfCompressChunks(final byte[] in, final int inSize) {
+        byte[] chunk = new byte[256 * 1024]; // chunk size is arbitrary
+        final ByteBuffer out = ByteBuffer.allocate(4 + (inSize + chunk.length - 1)
+                / chunk.length * (chunk.length + 4 * 2));
+        out.order(SampleView.targetByteOrder);
+        out.putInt(inSize);
+        for (int i = 0; i < inSize; i += chunk.length) {
+            int chunkIn = chunk.length;
+            if (i + chunkIn > inSize)
+                chunkIn = inSize - i;
+            final byte[] inChunk = java.util.Arrays.copyOfRange(in, i, i + chunkIn);
+            final int chunkOut = org.liblzf.CLZF
+                    .lzf_compress(inChunk, chunkIn, chunk, chunk.length);
+            out.putInt(chunkIn);
+            out.putInt(chunkOut);
+            if (chunkOut == 0) // compressed bigger than chunk (uncompressed)
+                out.put(inChunk);
+            else
+                out.put(chunk, 0, chunkOut);
+        }
+        return Arrays.copyOf(out.array(), out.position());
+    }
+
+    /**
+     * returns new ref, which is also the decoded image; ref could be bigger
+     * than pixels, in which case the first pixels.length bytes form the image
+     */
+    public static byte[] decodeReferencedImage(byte[] ref, byte[] pixels) {
+        if (ref.length < pixels.length)
+            ref = new byte[pixels.length];
+        for (int i = 0; i < pixels.length; i++)
+            ref[i] ^= pixels[i];
+        for (int i = pixels.length; i < ref.length; i++)
+            ref[i] = 0; // clear unused ref to maintain consistency
+        return ref;
+    }
+
+    public static ImageData receiveImage(int width, int height, int format,
+            int type, final ByteString data) {
+        assert width > 0 && height > 0;
+        int bpp = 0;
+        int redMask = 0, blueMask = 0, greenMask = 0;
+        switch (GLEnum.valueOf(type)) {
+            case GL_UNSIGNED_SHORT_5_6_5:
+            case GL_UNSIGNED_SHORT_4_4_4_4:
+            case GL_UNSIGNED_SHORT_5_5_5_1:
+                format = type;
+                break;
+            case GL_UNSIGNED_BYTE:
+                break;
+            default:
+                showError("unsupported texture type " + type);
+                return null;
+        }
+
+        switch (GLEnum.valueOf(format)) {
+            case GL_ALPHA:
+            case GL_LUMINANCE:
+                redMask = blueMask = greenMask = 0xff;
+                bpp = 8;
+                break;
+            case GL_LUMINANCE_ALPHA:
+                blueMask = 0xff;
+                redMask = 0xff00;
+                bpp = 16;
+                break;
+            case GL_RGB:
+                blueMask = 0xff;
+                greenMask = 0xff00;
+                redMask = 0xff0000;
+                bpp = 24;
+                break;
+            case GL_RGBA:
+                blueMask = 0xff00;
+                greenMask = 0xff0000;
+                redMask = 0xff000000;
+                bpp = 32;
+                break;
+            case GL_UNSIGNED_SHORT_5_6_5:
+                blueMask = ((1 << 5) - 1) << 0;
+                greenMask = ((1 << 6) - 1) << 5;
+                redMask = ((1 << 5) - 1) << 11;
+                bpp = 16;
+                break;
+            case GL_UNSIGNED_SHORT_4_4_4_4:
+                blueMask = ((1 << 4) - 1) << 4;
+                greenMask = ((1 << 4) - 1) << 8;
+                redMask = ((1 << 4) - 1) << 12;
+                bpp = 16;
+                break;
+            case GL_UNSIGNED_SHORT_5_5_5_1:
+                blueMask = ((1 << 5) - 1) << 1;
+                greenMask = ((1 << 5) - 1) << 6;
+                redMask = ((1 << 5) - 1) << 11;
+                bpp = 16;
+                break;
+            default:
+                showError("unsupported texture format: " + format);
+                return null;
+        }
+        byte[] pixels = lzfDecompressChunks(data);
+        assert pixels.length == width * height * (bpp / 8);
+        PaletteData palette = new PaletteData(redMask, greenMask, blueMask);
+        return new ImageData(width, height, bpp, palette, 1, pixels);
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/MessageQueue.java b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageQueue.java
new file mode 100644
index 0000000..c633d06
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageQueue.java
@@ -0,0 +1,322 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.android.glesv2debugger.DebuggerMessage.Message.Type;
+import com.android.sdklib.util.SparseArray;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+
+abstract interface ProcessMessage {
+    abstract boolean processMessage(final MessageQueue queue, final Message msg)
+            throws IOException;
+}
+
+public class MessageQueue implements Runnable {
+
+    private boolean running = false;
+    private ByteOrder byteOrder;
+    private FileInputStream file; // if null, create and use socket
+    Thread thread = null;
+    private final ProcessMessage[] processes;
+    private ArrayList<Message> complete = new ArrayList<Message>(); // synchronized
+    private ArrayList<Message> commands = new ArrayList<Message>(); // synchronized
+    private SampleView sampleView;
+
+    public MessageQueue(SampleView sampleView, final ProcessMessage[] processes) {
+        this.sampleView = sampleView;
+        this.processes = processes;
+    }
+
+    public void start(final ByteOrder byteOrder, final FileInputStream file) {
+        if (running)
+            return;
+        running = true;
+        this.byteOrder = byteOrder;
+        this.file = file;
+        thread = new Thread(this);
+        thread.start();
+    }
+
+    public void stop() {
+        if (!running)
+            return;
+        running = false;
+    }
+
+    public boolean isRunning() {
+        return running;
+    }
+
+    private void sendCommands(final int contextId) throws IOException {
+        synchronized (commands) {
+            for (int i = 0; i < commands.size(); i++) {
+                Message command = commands.get(i);
+                if (command.getContextId() == contextId || command.getContextId() == 0) {
+                    sendMessage(commands.remove(i));
+                    i--;
+                }
+            }
+        }
+    }
+
+    public void addCommand(Message command) {
+        synchronized (commands) {
+            commands.add(command);
+        }
+    }
+
+    // these should only be accessed from the network thread;
+    // access call chain starts with run()
+    private DataInputStream dis = null;
+    private DataOutputStream dos = null;
+    private SparseArray<ArrayList<Message>> incoming = new SparseArray<ArrayList<Message>>();
+
+    @Override
+    public void run() {
+        Socket socket = null;
+        if (file == null)
+            try {
+                socket = new Socket();
+                socket.connect(new java.net.InetSocketAddress("127.0.0.1", Integer
+                        .parseInt(sampleView.actionPort.getText())));
+                dis = new DataInputStream(socket.getInputStream());
+                dos = new DataOutputStream(socket.getOutputStream());
+            } catch (Exception e) {
+                running = false;
+                Error(e);
+            }
+        else
+            dis = new DataInputStream(file);
+
+        while (running) {
+            try {
+                if (file != null && file.available() == 0) {
+                    running = false;
+                    break;
+                }
+            } catch (IOException e1) {
+                e1.printStackTrace();
+                assert false;
+            }
+
+            Message msg = null;
+            if (incoming.size() > 0) { // find queued incoming
+                for (int i = 0; i < incoming.size(); i++) {
+                    final ArrayList<Message> messages = incoming.valueAt(i);
+                    if (messages.size() > 0) {
+                        msg = messages.remove(0);
+                        break;
+                    }
+                }
+            }
+            try {
+                if (null == msg) // get incoming from network
+                    msg = receiveMessage(dis);
+                processMessage(dos, msg);
+            } catch (IOException e) {
+                Error(e);
+                running = false;
+                break;
+            }
+        }
+
+        try {
+            if (socket != null)
+                socket.close();
+            else
+                file.close();
+        } catch (IOException e) {
+            Error(e);
+            running = false;
+        }
+
+    }
+
+    private void putMessage(final Message msg) {
+        ArrayList<Message> existing = incoming.get(msg.getContextId());
+        if (existing == null)
+            incoming.put(msg.getContextId(), existing = new ArrayList<Message>());
+        existing.add(msg);
+    }
+
+    Message receiveMessage(final int contextId) throws IOException {
+        Message msg = receiveMessage(dis);
+        while (msg.getContextId() != contextId) {
+            putMessage(msg);
+            msg = receiveMessage(dis);
+        }
+        return msg;
+    }
+
+    void sendMessage(final Message msg) throws IOException {
+        sendMessage(dos, msg);
+    }
+
+    // should only be used by DefaultProcessMessage
+    private SparseArray<Message> partials = new SparseArray<Message>();
+
+    Message getPartialMessage(final int contextId) {
+        return partials.get(contextId);
+    }
+
+    // used to add BeforeCall to complete if it was skipped
+    void completePartialMessage(final int contextId) {
+        final Message msg = partials.get(contextId);
+        partials.remove(contextId);
+        assert msg != null;
+        assert msg.getType() == Type.BeforeCall;
+        if (msg != null)
+            synchronized (complete) {
+                complete.add(msg);
+            }
+    }
+
+    // can be used by other message processor as default processor
+    void defaultProcessMessage(final Message msg, boolean expectResponse,
+            boolean sendResponse) throws IOException {
+        final int contextId = msg.getContextId();
+        if (msg.getType() == Type.BeforeCall) {
+            if (sendResponse) {
+                final Message.Builder builder = Message.newBuilder();
+                builder.setContextId(contextId);
+                builder.setType(Type.Response);
+                builder.setExpectResponse(expectResponse);
+                builder.setFunction(Function.CONTINUE);
+                sendMessage(dos, builder.build());
+            }
+            assert partials.indexOfKey(contextId) < 0;
+            partials.put(contextId, msg);
+        } else if (msg.getType() == Type.AfterCall) {
+            if (sendResponse) {
+                final Message.Builder builder = Message.newBuilder();
+                builder.setContextId(contextId);
+                builder.setType(Type.Response);
+                builder.setExpectResponse(expectResponse);
+                builder.setFunction(Function.SKIP);
+                sendMessage(dos, builder.build());
+            }
+            assert partials.indexOfKey(contextId) >= 0;
+            final Message before = partials.get(contextId);
+            partials.remove(contextId);
+            assert before.getFunction() == msg.getFunction();
+            final Message completed = before.toBuilder().mergeFrom(msg)
+                    .setType(Type.CompleteCall).build();
+            synchronized (complete) {
+                complete.add(completed);
+            }
+        } else if (msg.getType() == Type.CompleteCall) {
+            // this type should only be encountered on client after processing
+            assert file != null;
+            assert !msg.getExpectResponse();
+            assert !sendResponse;
+            assert partials.indexOfKey(contextId) < 0;
+            synchronized (complete) {
+                complete.add(msg);
+            }
+        } else if (msg.getType() == Type.Response && msg.getFunction() == Function.SETPROP) {
+            synchronized (complete) {
+                complete.add(msg);
+            }
+        } else
+            assert false;
+    }
+
+    public Message removeCompleteMessage(int contextId) {
+        synchronized (complete) {
+            if (complete.size() == 0)
+                return null;
+            if (0 == contextId) // get a message for any context
+                return complete.remove(0);
+            for (int i = 0; i < complete.size(); i++) {
+                Message msg = complete.get(i);
+                if (msg.getContextId() == contextId) {
+                    complete.remove(i);
+                    return msg;
+                }
+            }
+        }
+        return null;
+    }
+
+    private Message receiveMessage(final DataInputStream dis)
+            throws IOException {
+        int len = 0;
+        try {
+            len = dis.readInt();
+            if (byteOrder == ByteOrder.LITTLE_ENDIAN)
+                len = Integer.reverseBytes(len); // readInt reads BIT_ENDIAN
+        } catch (EOFException e) {
+            Error(new Exception("EOF"));
+        }
+        byte[] buffer = new byte[len];
+        int readLen = 0;
+        while (readLen < len) {
+            int read = -1;
+            try {
+                read = dis.read(buffer, readLen, len - readLen);
+            } catch (EOFException e) {
+                Error(new Exception("EOF"));
+            }
+            if (read < 0) {
+                Error(new Exception("read length = " + read));
+                return null;
+            } else
+                readLen += read;
+        }
+        Message msg = Message.parseFrom(buffer);
+        sendCommands(msg.getContextId());
+        return msg;
+    }
+
+    private void sendMessage(final DataOutputStream dos, final Message message)
+            throws IOException {
+        if (dos == null)
+            return;
+        assert message.getFunction() != Function.NEG;
+        final byte[] data = message.toByteArray();
+        if (byteOrder == ByteOrder.BIG_ENDIAN)
+            dos.writeInt(data.length);
+        else
+            dos.writeInt(Integer.reverseBytes(data.length));
+        dos.write(data);
+    }
+
+    private void processMessage(final DataOutputStream dos, final Message msg) throws IOException {
+        if (msg.getExpectResponse()) {
+            assert dos != null; // readonly source cannot expectResponse
+            for (ProcessMessage process : processes)
+                if (process.processMessage(this, msg))
+                    return;
+            defaultProcessMessage(msg, msg.getExpectResponse(), msg.getExpectResponse());
+        } else
+            defaultProcessMessage(msg, msg.getExpectResponse(), msg.getExpectResponse());
+    }
+
+    void Error(Exception e) {
+        sampleView.showError(e);
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java b/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java
new file mode 100644
index 0000000..4a8cdc9
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java
@@ -0,0 +1,835 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.android.glesv2debugger.DebuggerMessage.Message.Prop;
+import com.android.glesv2debugger.DebuggerMessage.Message.Type;
+import com.android.sdklib.util.SparseArray;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.ListViewer;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Slider;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.nio.ByteOrder;
+
+/**
+ * This sample class demonstrates how to plug-in a new workbench view. The view
+ * shows data obtained from the model. The sample creates a dummy model on the
+ * fly, but a real implementation would connect to the model available either in
+ * this or another plug-in (e.g. the workspace). The view is connected to the
+ * model using a content provider.
+ * <p>
+ * The view uses a label provider to define how model objects should be
+ * presented in the view. Each view can present the same model objects using
+ * different labels and icons, if needed. Alternatively, a single label provider
+ * can be shared between views in order to ensure that objects of the same type
+ * are presented in the same way everywhere.
+ * <p>
+ */
+
+public class SampleView extends ViewPart implements Runnable, SelectionListener {
+    public static final ByteOrder targetByteOrder = ByteOrder.LITTLE_ENDIAN;
+
+    boolean running = false;
+    Thread thread;
+    MessageQueue messageQueue;
+    SparseArray<DebugContext> debugContexts = new SparseArray<DebugContext>();
+
+    /** The ID of the view as specified by the extension. */
+    public static final String ID = "glesv2debuggerclient.views.SampleView";
+
+    TabFolder tabFolder;
+    TabItem tabItemText, tabItemImage, tabItemBreakpointOption;
+    TabItem tabItemShaderEditor, tabContextViewer;
+    ListViewer viewer; // ListViewer / TableViewer
+    Slider frameNum; // scale max cannot overlap min, so max is array size
+    TreeViewer contextViewer;
+    BreakpointOption breakpointOption;
+    ShaderEditor shaderEditor;
+    Canvas canvas;
+    Text text;
+    Action actionConnect; // connect / disconnect
+
+    Action actionAutoScroll;
+    Action actionFilter;
+    Action actionPort;
+
+    Action actContext; // for toggling contexts
+    DebugContext current = null;
+
+    Point origin = new Point(0, 0); // for smooth scrolling canvas
+    String[] filters = null;
+
+    class ViewContentProvider extends LabelProvider implements IStructuredContentProvider,
+            ITableLabelProvider {
+        Frame frame = null;
+
+        @Override
+        public void inputChanged(Viewer v, Object oldInput, Object newInput) {
+            frame = (Frame) newInput;
+        }
+
+        @Override
+        public void dispose() {
+        }
+
+        @Override
+        public Object[] getElements(Object parent) {
+            return frame.get().toArray();
+        }
+
+        @Override
+        public String getText(Object obj) {
+            MessageData msgData = (MessageData) obj;
+            return msgData.text;
+        }
+
+        @Override
+        public Image getImage(Object obj) {
+            MessageData msgData = (MessageData) obj;
+            return msgData.getImage();
+        }
+
+        @Override
+        public String getColumnText(Object obj, int index) {
+            MessageData msgData = (MessageData) obj;
+            if (index >= msgData.columns.length)
+                return null;
+            return msgData.columns[index];
+        }
+
+        @Override
+        public Image getColumnImage(Object obj, int index) {
+            if (index > -1)
+                return null;
+            MessageData msgData = (MessageData) obj;
+            return msgData.getImage();
+        }
+    }
+
+    class NameSorter extends ViewerSorter {
+        @Override
+        public int compare(Viewer viewer, Object e1, Object e2) {
+            MessageData m1 = (MessageData) e1;
+            MessageData m2 = (MessageData) e2;
+            return (int) ((m1.msg.getTime() - m2.msg.getTime()) * 100);
+        }
+    }
+
+    class Filter extends ViewerFilter {
+        @Override
+        public boolean select(Viewer viewer, Object parentElement,
+                Object element) {
+            MessageData msgData = (MessageData) element;
+            if (null == filters)
+                return true;
+            for (int i = 0; i < filters.length; i++)
+                if (msgData.text.contains(filters[i]))
+                    return true;
+            return false;
+        }
+    }
+
+    public SampleView() {
+
+    }
+
+    public void createLeftPane(Composite parent) {
+        Composite composite = new Composite(parent, 0);
+
+        GridLayout gridLayout = new GridLayout();
+        gridLayout.numColumns = 1;
+        composite.setLayout(gridLayout);
+
+        frameNum = new Slider(composite, SWT.BORDER | SWT.HORIZONTAL);
+        frameNum.setMinimum(0);
+        frameNum.setMaximum(1);
+        frameNum.setSelection(0);
+        frameNum.addSelectionListener(this);
+
+        GridData gridData = new GridData();
+        gridData.horizontalAlignment = SWT.FILL;
+        gridData.grabExcessHorizontalSpace = true;
+        gridData.verticalAlignment = SWT.FILL;
+        frameNum.setLayoutData(gridData);
+
+        // Table table = new Table(composite, SWT.H_SCROLL | SWT.V_SCROLL |
+        // SWT.MULTI
+        // | SWT.FULL_SELECTION);
+        // TableLayout layout = new TableLayout();
+        // table.setLayout(layout);
+        // table.setLinesVisible(true);
+        // table.setHeaderVisible(true);
+        // String[] headings = {
+        // "Name", "Elapsed (ms)", "Detail"
+        // };
+        // int[] weights = {
+        // 50, 16, 60
+        // };
+        // int[] widths = {
+        // 180, 90, 200
+        // };
+        // for (int i = 0; i < headings.length; i++) {
+        // layout.addColumnData(new ColumnWeightData(weights[i], widths[i],
+        // true));
+        // TableColumn nameCol = new TableColumn(table, SWT.NONE, i);
+        // nameCol.setText(headings[i]);
+        // }
+
+        // viewer = new TableViewer(table);
+        viewer = new ListViewer(composite, SWT.DEFAULT);
+        viewer.getList().setFont(new Font(viewer.getList().getDisplay(),
+                "Courier", 10, SWT.BOLD));
+        ViewContentProvider contentProvider = new ViewContentProvider();
+        viewer.setContentProvider(contentProvider);
+        viewer.setLabelProvider(contentProvider);
+        // viewer.setSorter(new NameSorter());
+        viewer.setFilters(new ViewerFilter[] {
+                new Filter()
+        });
+
+        gridData = new GridData();
+        gridData.horizontalAlignment = SWT.FILL;
+        gridData.grabExcessHorizontalSpace = true;
+        gridData.verticalAlignment = SWT.FILL;
+        gridData.grabExcessVerticalSpace = true;
+        viewer.getControl().setLayoutData(gridData);
+    }
+
+    /**
+     * This is a callback that will allow us to create the viewer and initialize
+     * it.
+     */
+    @Override
+    public void createPartControl(Composite parent) {
+        createLeftPane(parent);
+
+        // Create the help context id for the viewer's control
+        PlatformUI.getWorkbench().getHelpSystem()
+                .setHelp(viewer.getControl(), "GLESv2DebuggerClient.viewer");
+
+        tabFolder = new TabFolder(parent, SWT.BORDER);
+
+        text = new Text(tabFolder, SWT.NO_BACKGROUND | SWT.READ_ONLY
+                | SWT.V_SCROLL | SWT.H_SCROLL);
+
+        tabItemText = new TabItem(tabFolder, SWT.NONE);
+        tabItemText.setText("Text");
+        tabItemText.setControl(text);
+
+        canvas = new Canvas(tabFolder, SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE
+                | SWT.V_SCROLL | SWT.H_SCROLL);
+        tabItemImage = new TabItem(tabFolder, SWT.NONE);
+        tabItemImage.setText("Image");
+        tabItemImage.setControl(canvas);
+
+        breakpointOption = new BreakpointOption(this, tabFolder);
+        tabItemBreakpointOption = new TabItem(tabFolder, SWT.NONE);
+        tabItemBreakpointOption.setText("Breakpoint Option");
+        tabItemBreakpointOption.setControl(breakpointOption);
+
+        shaderEditor = new ShaderEditor(this, tabFolder);
+        tabItemShaderEditor = new TabItem(tabFolder, SWT.NONE);
+        tabItemShaderEditor.setText("Shader Editor");
+        tabItemShaderEditor.setControl(shaderEditor);
+
+        contextViewer = new TreeViewer(tabFolder);
+        ContextViewProvider contextViewProvider = new ContextViewProvider(this);
+        contextViewer.addSelectionChangedListener(contextViewProvider);
+        contextViewer.setContentProvider(contextViewProvider);
+        contextViewer.setLabelProvider(contextViewProvider);
+        tabContextViewer = new TabItem(tabFolder, SWT.NONE);
+        tabContextViewer.setText("Context Viewer");
+        tabContextViewer.setControl(contextViewer.getTree());
+
+        final ScrollBar hBar = canvas.getHorizontalBar();
+        hBar.addListener(SWT.Selection, new Listener() {
+            @Override
+            public void handleEvent(Event e) {
+                if (null == canvas.getBackgroundImage())
+                    return;
+                Image image = canvas.getBackgroundImage();
+                int hSelection = hBar.getSelection();
+                int destX = -hSelection - origin.x;
+                Rectangle rect = image.getBounds();
+                canvas.scroll(destX, 0, 0, 0, rect.width, rect.height, false);
+                origin.x = -hSelection;
+            }
+        });
+        final ScrollBar vBar = canvas.getVerticalBar();
+        vBar.addListener(SWT.Selection, new Listener() {
+            @Override
+            public void handleEvent(Event e) {
+                if (null == canvas.getBackgroundImage())
+                    return;
+                Image image = canvas.getBackgroundImage();
+                int vSelection = vBar.getSelection();
+                int destY = -vSelection - origin.y;
+                Rectangle rect = image.getBounds();
+                canvas.scroll(0, destY, 0, 0, rect.width, rect.height, false);
+                origin.y = -vSelection;
+            }
+        });
+        canvas.addListener(SWT.Resize, new Listener() {
+            @Override
+            public void handleEvent(Event e) {
+                if (null == canvas.getBackgroundImage())
+                    return;
+                Image image = canvas.getBackgroundImage();
+                Rectangle rect = image.getBounds();
+                Rectangle client = canvas.getClientArea();
+                hBar.setMaximum(rect.width);
+                vBar.setMaximum(rect.height);
+                hBar.setThumb(Math.min(rect.width, client.width));
+                vBar.setThumb(Math.min(rect.height, client.height));
+                int hPage = rect.width - client.width;
+                int vPage = rect.height - client.height;
+                int hSelection = hBar.getSelection();
+                int vSelection = vBar.getSelection();
+                if (hSelection >= hPage) {
+                    if (hPage <= 0)
+                        hSelection = 0;
+                    origin.x = -hSelection;
+                }
+                if (vSelection >= vPage) {
+                    if (vPage <= 0)
+                        vSelection = 0;
+                    origin.y = -vSelection;
+                }
+                canvas.redraw();
+            }
+        });
+        canvas.addListener(SWT.Paint, new Listener() {
+            @Override
+            public void handleEvent(Event e) {
+                if (null == canvas.getBackgroundImage())
+                    return;
+                Image image = canvas.getBackgroundImage();
+                GC gc = e.gc;
+                gc.drawImage(image, origin.x, origin.y);
+                Rectangle rect = image.getBounds();
+                Rectangle client = canvas.getClientArea();
+                int marginWidth = client.width - rect.width;
+                if (marginWidth > 0) {
+                    gc.fillRectangle(rect.width, 0, marginWidth, client.height);
+                }
+                int marginHeight = client.height - rect.height;
+                if (marginHeight > 0) {
+                    gc.fillRectangle(0, rect.height, client.width, marginHeight);
+                }
+            }
+        });
+
+        hookContextMenu();
+        hookSelectionChanged();
+        contributeToActionBars();
+
+        messageQueue = new MessageQueue(this, new ProcessMessage[] {
+                breakpointOption, shaderEditor
+        });
+    }
+
+    private void hookContextMenu() {
+        MenuManager menuMgr = new MenuManager("#PopupMenu");
+        menuMgr.setRemoveAllWhenShown(true);
+        menuMgr.addMenuListener(new IMenuListener() {
+            @Override
+            public void menuAboutToShow(IMenuManager manager) {
+                SampleView.this.fillContextMenu(manager);
+            }
+        });
+        Menu menu = menuMgr.createContextMenu(viewer.getControl());
+        viewer.getControl().setMenu(menu);
+        getSite().registerContextMenu(menuMgr, viewer);
+    }
+
+    private void contributeToActionBars() {
+        IActionBars bars = getViewSite().getActionBars();
+        fillLocalPullDown(bars.getMenuManager());
+        fillLocalToolBar(bars.getToolBarManager());
+    }
+
+    private void fillLocalPullDown(IMenuManager manager) {
+        // manager.add(actionConnect);
+        // manager.add(new Separator());
+        // manager.add(actionDisconnect);
+    }
+
+    private void fillContextMenu(IMenuManager manager) {
+        // manager.add(actionConnect);
+        // manager.add(actionDisconnect);
+        // Other plug-ins can contribute there actions here
+        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+    }
+
+    private void fillLocalToolBar(final IToolBarManager manager) {
+        actionConnect = new Action("Connect", Action.AS_PUSH_BUTTON) {
+            @Override
+            public void run() {
+                if (!running)
+                    changeContext(null); // viewer will switch to newest context
+                connectDisconnect();
+            }
+        };
+        manager.add(actionConnect);
+
+        manager.add(new Action("Open File", Action.AS_PUSH_BUTTON)
+        {
+            @Override
+            public void run()
+            {
+                if (!running)
+                {
+                    changeContext(null); // viewer will switch to newest context
+                    openFile();
+                }
+            }
+        });
+
+        final Shell shell = this.getViewSite().getShell();
+        actionAutoScroll = new Action("Auto Scroll", Action.AS_CHECK_BOX) {
+            @Override
+            public void run() {
+            }
+        };
+        actionAutoScroll.setChecked(true);
+        manager.add(actionAutoScroll);
+
+        actionFilter = new Action("*", Action.AS_DROP_DOWN_MENU) {
+            @Override
+            public void run() {
+                org.eclipse.jface.dialogs.InputDialog dialog = new org.eclipse.jface.dialogs.InputDialog(
+                        shell, "Contains Filter",
+                        "case sensitive substring or *",
+                        actionFilter.getText(), null);
+                if (Window.OK == dialog.open()) {
+                    actionFilter.setText(dialog.getValue());
+                    manager.update(true);
+                    filters = dialog.getValue().split("\\|");
+                    if (filters.length == 1 && filters[0].equals("*"))
+                        filters = null;
+                    viewer.refresh();
+                }
+
+            }
+        };
+        manager.add(actionFilter);
+
+        manager.add(new Action("CaptureDraw", Action.AS_DROP_DOWN_MENU)
+        {
+            @Override
+            public void run()
+            {
+                int contextId = 0;
+                if (current != null)
+                    contextId = current.contextId;
+                InputDialog inputDialog = new InputDialog(shell,
+                        "Capture glDrawArrays/Elements",
+                        "Enter number of glDrawArrays/Elements to glReadPixels for "
+                                + "context 0x" + Integer.toHexString(contextId) +
+                                "\n(0x0 is any context)", "9001", null);
+                if (inputDialog.open() != Window.OK)
+                    return;
+                Message.Builder builder = Message.newBuilder();
+                builder.setContextId(contextId);
+                builder.setType(Type.Response);
+                builder.setExpectResponse(false);
+                builder.setFunction(Function.SETPROP);
+                builder.setProp(Prop.CaptureDraw);
+                builder.setArg0(Integer.parseInt(inputDialog.getValue()));
+                messageQueue.addCommand(builder.build());
+            }
+        });
+
+        manager.add(new Action("CaptureSwap", Action.AS_DROP_DOWN_MENU)
+        {
+            @Override
+            public void run()
+            {
+                int contextId = 0;
+                if (current != null)
+                    contextId = current.contextId;
+                InputDialog inputDialog = new InputDialog(shell,
+                        "Capture eglSwapBuffers",
+                        "Enter number of eglSwapBuffers to glReadPixels for "
+                                + "context 0x" + Integer.toHexString(contextId) +
+                                "\n(0x0 is any context)", "9001", null);
+                if (inputDialog.open() != Window.OK)
+                    return;
+                Message.Builder builder = Message.newBuilder();
+                builder.setContextId(contextId);
+                builder.setType(Type.Response);
+                builder.setExpectResponse(false);
+                builder.setFunction(Function.SETPROP);
+                builder.setProp(Prop.CaptureSwap);
+                builder.setArg0(Integer.parseInt(inputDialog.getValue()));
+                messageQueue.addCommand(builder.build());
+            }
+        });
+
+        manager.add(new Action("SYSTEM_TIME_THREAD", Action.AS_DROP_DOWN_MENU)
+        {
+            @Override
+            public void run()
+            {
+                final String[] timeModes = {
+                        "SYSTEM_TIME_REALTIME", "SYSTEM_TIME_MONOTONIC", "SYSTEM_TIME_PROCESS",
+                        "SYSTEM_TIME_THREAD"
+                };
+                int i = java.util.Arrays.asList(timeModes).indexOf(this.getText());
+                i = (i + 1) % timeModes.length;
+                Message.Builder builder = Message.newBuilder();
+                builder.setContextId(0); // FIXME: proper context id
+                builder.setType(Type.Response);
+                builder.setExpectResponse(false);
+                builder.setFunction(Message.Function.SETPROP);
+                builder.setProp(Prop.TimeMode);
+                builder.setArg0(i);
+                messageQueue.addCommand(builder.build());
+                this.setText(timeModes[i]);
+                manager.update(true);
+            }
+        });
+
+        actContext = new Action("Context: 0x", Action.AS_DROP_DOWN_MENU) {
+            @Override
+            public void run() {
+                if (debugContexts.size() < 2)
+                    return;
+                final String idStr = this.getText().substring(
+                                          "Context: 0x".length());
+                if (idStr.length() == 0)
+                    return;
+                final int contextId = Integer.parseInt(idStr, 16);
+                int index = debugContexts.indexOfKey(contextId);
+                index = (index + 1) % debugContexts.size();
+                changeContext(debugContexts.valueAt(index));
+            }
+        };
+        manager.add(actContext);
+
+        actionPort = new Action("5039", Action.AS_DROP_DOWN_MENU)
+        {
+            @Override
+            public void run() {
+                InputDialog dialog = new InputDialog(shell, "Port", "Debugger port",
+                        actionPort.getText(), null);
+                if (Window.OK == dialog.open()) {
+                    actionPort.setText(dialog.getValue());
+                    manager.update(true);
+                }
+            }
+        };
+        manager.add(actionPort);
+
+        manager.add(new Action("CodeGen Frame", Action.AS_PUSH_BUTTON)
+        {
+            @Override
+            public void run()
+            {
+                if (current != null)
+                {
+                    new CodeGen().codeGenFrame((Frame) viewer.getInput());
+                    // need to reload current frame
+                    viewer.setInput(current.getFrame(frameNum.getSelection()));
+                }
+            }
+        });
+
+        manager.add(new Action("CodeGen Frames", Action.AS_PUSH_BUTTON)
+        {
+            @Override
+            public void run()
+            {
+                if (current != null)
+                {
+                    new CodeGen().codeGenFrames(current, frameNum.getSelection() + 1,
+                            getSite().getShell());
+                    // need to reload current frame
+                    viewer.setInput(current.getFrame(frameNum.getSelection()));
+                }
+            }
+        });
+    }
+
+    private void openFile() {
+        FileDialog dialog = new FileDialog(getSite().getShell(), SWT.OPEN);
+        dialog.setText("Open");
+        dialog.setFilterExtensions(new String[] {
+                "*.gles2dbg"
+        });
+        String filePath = dialog.open();
+        if (filePath == null)
+            return;
+        FileInputStream file = null;
+        try {
+            file = new FileInputStream(filePath);
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+            return;
+        }
+        running = true;
+        messageQueue.start(targetByteOrder, file);
+        thread = new Thread(this);
+        thread.start();
+        actionConnect.setText("Disconnect");
+        getViewSite().getActionBars().getToolBarManager().update(true);
+    }
+
+    private void connectDisconnect() {
+        if (!running) {
+            running = true;
+            messageQueue.start(targetByteOrder, null);
+            thread = new Thread(this);
+            thread.start();
+            actionConnect.setText("Disconnect");
+        } else {
+            running = false;
+            messageQueue.stop();
+            actionConnect.setText("Connect");
+        }
+        this.getSite().getShell().getDisplay().syncExec(new Runnable() {
+            @Override
+            public void run() {
+                getViewSite().getActionBars().getToolBarManager().update(true);
+            }
+        });
+    }
+
+    void messageDataSelected(final MessageData msgData) {
+        if (null == msgData)
+            return;
+        if (frameNum.getSelection() == frameNum.getMaximum())
+            return; // scale max cannot overlap min, so max is array size
+        final Frame frame = current.getFrame(frameNum.getSelection());
+        final Context context = frame.computeContext(msgData);
+        contextViewer.setInput(context);
+        if (msgData.getImage() != null) {
+            canvas.setBackgroundImage(msgData.getImage());
+            tabFolder.setSelection(tabItemImage);
+            canvas.redraw();
+        } else if (null != msgData.shader) {
+            text.setText(msgData.shader);
+            tabFolder.setSelection(tabItemText);
+        } else if (null != msgData.attribs) {
+            StringBuilder builder = new StringBuilder();
+            final int maxAttrib = msgData.msg.getArg7();
+            for (int i = 0; i < msgData.attribs[0].length / 4; i++) {
+                if (msgData.indices != null) {
+                    builder.append(msgData.indices[i] & 0xffff);
+                    builder.append(": ");
+                }
+                for (int j = 0; j < maxAttrib; j++) {
+                    for (int k = 0; k < 4; k++)
+                        builder.append(String.format("%.3g ", msgData.attribs[j][i * 4 + k]));
+                    if (j < maxAttrib - 1)
+                        builder.append("|| ");
+                }
+                builder.append('\n');
+            }
+            text.setText(builder.toString());
+            tabFolder.setSelection(tabItemText);
+        }
+    }
+
+    private void hookSelectionChanged() {
+        viewer.addSelectionChangedListener(new ISelectionChangedListener() {
+            @Override
+            public void selectionChanged(SelectionChangedEvent event) {
+                StructuredSelection selection = (StructuredSelection) event
+                        .getSelection();
+                if (null == selection)
+                    return;
+                MessageData msgData = (MessageData) selection.getFirstElement();
+                messageDataSelected(msgData);
+            }
+        });
+    }
+
+    public void showError(final Exception e) {
+        viewer.getControl().getDisplay().syncExec(new Runnable() {
+            @Override
+            public void run() {
+                MessageDialog.openError(viewer.getControl().getShell(),
+                        "GL ES 2.0 Debugger Client", e.getMessage());
+            }
+        });
+    }
+
+    /**
+     * Passing the focus request to the viewer's control.
+     */
+    @Override
+    public void setFocus() {
+        viewer.getControl().setFocus();
+    }
+
+    @Override
+    public void run() {
+        int newMessages = 0;
+
+        boolean shaderEditorUpdate = false;
+        while (running) {
+            final Message oriMsg = messageQueue.removeCompleteMessage(0);
+            if (oriMsg == null && !messageQueue.isRunning())
+                break;
+            if (newMessages > 60 || (newMessages > 0 && null == oriMsg)) {
+                newMessages = 0;
+                if (current != null && current.uiUpdate)
+                    getSite().getShell().getDisplay().syncExec(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (frameNum.getSelection() == current.frameCount() - 1 ||
+                                    frameNum.getSelection() == current.frameCount() - 2)
+                            {
+                                viewer.refresh(false);
+                                if (actionAutoScroll.isChecked())
+                                    viewer.getList().setSelection(
+                                            viewer.getList().getItemCount() - 1);
+                            }
+                            frameNum.setMaximum(current.frameCount());
+                        }
+                    });
+                current.uiUpdate = false;
+
+                if (shaderEditorUpdate)
+                    this.getSite().getShell().getDisplay().syncExec(new Runnable() {
+                        @Override
+                        public void run() {
+                            shaderEditor.updateUI();
+                        }
+                    });
+                shaderEditorUpdate = false;
+            }
+            if (null == oriMsg) {
+                try {
+                    Thread.sleep(1);
+                    continue;
+                } catch (InterruptedException e) {
+                    showError(e);
+                }
+            }
+            DebugContext debugContext = debugContexts.get(oriMsg.getContextId());
+            if (debugContext == null) {
+                debugContext = new DebugContext(oriMsg.getContextId());
+                debugContexts.put(oriMsg.getContextId(), debugContext);
+            }
+            debugContext.processMessage(oriMsg);
+            shaderEditorUpdate |= debugContext.currentContext.serverShader.uiUpdate;
+            debugContext.currentContext.serverShader.uiUpdate = false;
+            if (current == null && debugContext.frameCount() > 0)
+                changeContext(debugContext);
+            newMessages++;
+        }
+        if (running)
+            connectDisconnect(); // error occurred, disconnect
+    }
+
+    /** can be called from non-UI thread */
+    void changeContext(final DebugContext newContext) {
+        getSite().getShell().getDisplay().syncExec(new Runnable() {
+            @Override
+            public void run() {
+                current = newContext;
+                if (current != null)
+                {
+                    frameNum.setMaximum(current.frameCount());
+                    if (frameNum.getSelection() >= current.frameCount())
+                        if (current.frameCount() > 0)
+                            frameNum.setSelection(current.frameCount() - 1);
+                        else
+                            frameNum.setSelection(0);
+                    viewer.setInput(current.getFrame(frameNum.getSelection()));
+                    actContext.setText("Context: 0x" + Integer.toHexString(current.contextId));
+                }
+                else
+                {
+                    frameNum.setMaximum(1); // cannot overlap min
+                    frameNum.setSelection(0);
+                    viewer.setInput(null);
+                    actContext.setText("Context: 0x");
+                }
+                shaderEditor.updateUI();
+                getViewSite().getActionBars().getToolBarManager().update(true);
+            }
+        });
+    }
+
+    @Override
+    public void widgetSelected(SelectionEvent e) {
+        if (e.widget != frameNum)
+            assert false;
+        if (current == null)
+            return;
+        if (frameNum.getSelection() == current.frameCount())
+            return; // scale maximum cannot overlap minimum
+        Frame frame = current.getFrame(frameNum.getSelection());
+        viewer.setInput(frame);
+    }
+
+    @Override
+    public void widgetDefaultSelected(SelectionEvent e) {
+        widgetSelected(e);
+    }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java b/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java
new file mode 100644
index 0000000..c125143
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java
@@ -0,0 +1,407 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.android.glesv2debugger.DebuggerMessage.Message.Type;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ExtendedModifyEvent;
+import org.eclipse.swt.custom.ExtendedModifyListener;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+public class ShaderEditor extends Composite implements SelectionListener, ExtendedModifyListener,
+        ProcessMessage {
+    SampleView sampleView;
+
+    ToolBar toolbar;
+    ToolItem uploadShader, restoreShader, currentPrograms;
+    List list;
+    StyledText styledText;
+
+    GLShader current;
+
+    ArrayList<GLShader> shadersToUpload = new ArrayList<GLShader>();
+
+    ShaderEditor(SampleView sampleView, Composite parent) {
+        super(parent, 0);
+        this.sampleView = sampleView;
+
+        GridLayout gridLayout = new GridLayout();
+        gridLayout.numColumns = 1;
+        this.setLayout(gridLayout);
+
+        toolbar = new ToolBar(this, SWT.BORDER);
+
+        uploadShader = new ToolItem(toolbar, SWT.PUSH);
+        uploadShader.setText("Upload Shader");
+        uploadShader.addSelectionListener(this);
+
+        restoreShader = new ToolItem(toolbar, SWT.PUSH);
+        restoreShader.setText("Original Shader");
+        restoreShader.addSelectionListener(this);
+
+        currentPrograms = new ToolItem(toolbar, SWT.PUSH);
+        currentPrograms.setText("Current Programs: ");
+
+        list = new List(this, SWT.V_SCROLL);
+        list.setFont(new Font(parent.getDisplay(), "Courier", 10, 0));
+        list.addSelectionListener(this);
+        GridData gridData = new GridData();
+        gridData.horizontalAlignment = SWT.FILL;
+        gridData.grabExcessHorizontalSpace = true;
+        gridData.verticalAlignment = SWT.FILL;
+        gridData.grabExcessVerticalSpace = true;
+        list.setLayoutData(gridData);
+
+        styledText = new StyledText(this, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI);
+        gridData = new GridData();
+        gridData.horizontalAlignment = SWT.FILL;
+        gridData.grabExcessHorizontalSpace = true;
+        gridData.verticalAlignment = SWT.FILL;
+        gridData.grabExcessVerticalSpace = true;
+        gridData.verticalSpan = 2;
+        styledText.setLayoutData(gridData);
+        styledText.addExtendedModifyListener(this);
+    }
+
+    public void updateUI() {
+        list.removeAll();
+        String progs = "Current Programs: ";
+        for (int j = 0; j < sampleView.debugContexts.size(); j++) {
+            final Context context = sampleView.debugContexts.valueAt(j).currentContext;
+
+            if (context.serverShader.current != null) {
+                progs += context.serverShader.current.name + "(0x";
+                progs += Integer.toHexString(context.contextId) + ") ";
+            }
+            for (int i = 0; i < context.serverShader.shaders.size(); i++) {
+                GLShader shader = context.serverShader.shaders.valueAt(i);
+                StringBuilder builder = new StringBuilder();
+                builder.append(String.format("%08X", context.contextId));
+                builder.append(' ');
+                builder.append(shader.type);
+                while (builder.length() < 30)
+                    builder.append(" ");
+                builder.append(shader.name);
+                while (builder.length() < 40)
+                    builder.append(" ");
+                builder.append(" : ");
+                for (Context ctx : context.shares) {
+                    builder.append(String.format("%08X", ctx.contextId));
+                    builder.append(' ');
+                }
+                builder.append(": ");
+                for (int program : shader.programs) {
+                    builder.append(program);
+                    builder.append(" ");
+                }
+                list.add(builder.toString());
+            }
+
+        }
+
+        currentPrograms.setText(progs);
+        toolbar.redraw();
+        toolbar.pack(true);
+        toolbar.update();
+    }
+
+    void uploadShader() {
+        current.source = styledText.getText();
+
+        // optional syntax check by glsl_compiler, built from external/mesa3d
+        if (new File("./glsl_compiler").exists())
+            try {
+                File file = File.createTempFile("shader",
+                        current.type == GLEnum.GL_VERTEX_SHADER ? ".vert" : ".frag");
+                FileWriter fileWriter = new FileWriter(file, false);
+                fileWriter.write(current.source);
+                fileWriter.close();
+
+                ProcessBuilder processBuilder = new ProcessBuilder(
+                        "./glsl_compiler", "--glsl-es", file.getAbsolutePath());
+                final Process process = processBuilder.start();
+                InputStream is = process.getInputStream();
+                InputStreamReader isr = new InputStreamReader(is);
+                BufferedReader br = new BufferedReader(isr);
+                String line;
+                String infolog = "";
+
+                styledText.setLineBackground(0, styledText.getLineCount(), null);
+
+                while ((line = br.readLine()) != null) {
+                    infolog += line;
+                    if (!line.startsWith("0:"))
+                        continue;
+                    String[] details = line.split(":|\\(|\\)");
+                    final int ln = Integer.parseInt(details[1]);
+                    if (ln > 0) // usually line 0 means errors other than syntax
+                        styledText.setLineBackground(ln - 1, 1,
+                                new Color(Display.getCurrent(), 255, 230, 230));
+                }
+                file.delete();
+                if (infolog.length() > 0) {
+                    if (!MessageDialog.openConfirm(getShell(),
+                            "Shader Syntax Error, Continue?", infolog))
+                        return;
+                }
+            } catch (IOException e) {
+                sampleView.showError(e);
+            }
+
+        // add the initial command, which when read by server will set
+        // expectResponse for the message loop and go into message exchange
+        synchronized (shadersToUpload) {
+            for (GLShader shader : shadersToUpload) {
+                if (shader.context.context.contextId != current.context.context.contextId)
+                    continue;
+                MessageDialog.openWarning(this.getShell(), "Context 0x" +
+                        Integer.toHexString(current.context.context.contextId),
+                        "Previous shader upload not complete, try again");
+                return;
+            }
+            shadersToUpload.add(current);
+            final int contextId = current.context.context.contextId;
+            Message.Builder builder = getBuilder(contextId);
+            MessageParserEx.instance.parse(builder,
+                    String.format("glShaderSource(%d,1,\"%s\",0)", current.name, current.source));
+            sampleView.messageQueue.addCommand(builder.build());
+        }
+    }
+
+    Message.Builder getBuilder(int contextId) {
+        Message.Builder builder = Message.newBuilder();
+        builder.setContextId(contextId);
+        builder.setType(Type.Response);
+        builder.setExpectResponse(true);
+        return builder;
+    }
+
+    Message exchangeMessage(final int contextId, final MessageQueue queue,
+            String format, Object... args) throws IOException {
+        Message.Builder builder = getBuilder(contextId);
+        MessageParserEx.instance.parse(builder, String.format(format, args));
+        final Function function = builder.getFunction();
+        queue.sendMessage(builder.build());
+        final Message msg = queue.receiveMessage(contextId);
+        assert msg.getContextId() == contextId;
+        assert msg.getType() == Type.AfterGeneratedCall;
+        assert msg.getFunction() == function;
+        return msg;
+    }
+
+    // this is called from network thread
+    public boolean processMessage(final MessageQueue queue, final Message msg)
+            throws IOException {
+        GLShader shader = null;
+        final int contextId = msg.getContextId();
+        synchronized (shadersToUpload) {
+            if (shadersToUpload.size() == 0)
+                return false;
+            boolean matchingContext = false;
+            for (int i = 0; i < shadersToUpload.size(); i++) {
+                shader = shadersToUpload.get(i);
+                for (Context ctx : shader.context.context.shares)
+                    if (ctx.contextId == contextId) {
+                        matchingContext = true;
+                        break;
+                    }
+                if (matchingContext) {
+                    shadersToUpload.remove(i);
+                    break;
+                }
+            }
+            if (!matchingContext)
+                return false;
+        }
+
+        // glShaderSource was already sent to trigger set expectResponse
+        assert msg.getType() == Type.AfterGeneratedCall;
+        assert msg.getFunction() == Function.glShaderSource;
+
+        exchangeMessage(contextId, queue, "glCompileShader(%d)", shader.name);
+
+        // the 0, "" and {0} are dummies for the parser
+        Message rcv = exchangeMessage(contextId, queue,
+                "glGetShaderiv(%d, GL_COMPILE_STATUS, {0})", shader.name);
+        assert rcv.hasData();
+        if (rcv.getData().asReadOnlyByteBuffer().getInt() == 0) {
+            // compile failed
+            rcv = exchangeMessage(contextId, queue,
+                    "glGetShaderInfoLog(%d, 0, 0, \"\")", shader.name);
+            final String title = String.format("Shader %d in 0x%s failed to compile",
+                    shader.name, Integer.toHexString(shader.context.context.contextId));
+            final String message = rcv.getData().toStringUtf8();
+            sampleView.getSite().getShell().getDisplay().syncExec(new Runnable() {
+                @Override
+                public void run()
+                {
+                    MessageDialog.openWarning(getShell(), title, message);
+                }
+            });
+        } else
+            for (int programName : shader.programs) {
+                GLProgram program = shader.context.getProgram(programName);
+                exchangeMessage(contextId, queue, "glLinkProgram(%d)", program.name);
+                rcv = exchangeMessage(contextId, queue,
+                        "glGetProgramiv(%d, GL_LINK_STATUS, {0})", program.name);
+                assert rcv.hasData();
+                if (rcv.getData().asReadOnlyByteBuffer().getInt() != 0)
+                    continue;
+                // link failed
+                rcv = exchangeMessage(contextId, queue,
+                            "glGetProgramInfoLog(%d, 0, 0, \"\")", program.name);
+                final String title = String.format("Program %d in 0x%s failed to link",
+                        program.name, Integer.toHexString(program.context.context.contextId));
+                final String message = rcv.getData().toStringUtf8();
+                sampleView.getSite().getShell().getDisplay().syncExec(new Runnable() {
+                    @Override
+                    public void run()
+                    {
+                        MessageDialog.openWarning(getShell(), title, message);
+                    }
+                });
+                // break;
+            }
+
+        // TODO: add to upload results if failed
+
+        Message.Builder builder = getBuilder(contextId);
+        builder.setExpectResponse(false);
+        if (queue.getPartialMessage(contextId) != null)
+            // the glShaderSource interrupted a BeforeCall, so continue
+            builder.setFunction(Function.CONTINUE);
+        else
+            builder.setFunction(Function.SKIP);
+        queue.sendMessage(builder.build());
+
+        return true;
+    }
+
+    @Override
+    public void widgetSelected(SelectionEvent e) {
+        if (e.getSource() == uploadShader && null != current) {
+            uploadShader();
+            return;
+        } else if (e.getSource() == restoreShader && null != current) {
+            current.source = styledText.getText();
+            styledText.setText(current.originalSource);
+            return;
+        }
+
+        if (list.getSelectionCount() < 1)
+            return;
+        if (null != current && !current.source.equals(styledText.getText())) {
+            String[] btns = {
+                    "&Upload", "&Save", "&Discard"
+            };
+            MessageDialog dialog = new MessageDialog(this.getShell(), "Shader Edited",
+                    null, "Shader source has been edited", MessageDialog.QUESTION, btns, 0);
+            int rc = dialog.open();
+            if (rc == SWT.DEFAULT || rc == 0)
+                uploadShader();
+            else if (rc == 1)
+                current.source = styledText.getText();
+            // else if (rc == 2) do nothing; selection is changing
+        }
+        String[] details = list.getSelection()[0].split("\\s+");
+        final int contextId = Integer.parseInt(details[0], 16);
+        int name = Integer.parseInt(details[2]);
+        current = sampleView.debugContexts.get(contextId).currentContext.serverShader.shaders
+                .get(name);
+        styledText.setText(current.source);
+    }
+
+    @Override
+    public void widgetDefaultSelected(SelectionEvent e) {
+        widgetSelected(e);
+    }
+
+    @Override
+    public void modifyText(ExtendedModifyEvent event) {
+        final String[] keywords = {
+                "gl_Position", "gl_FragColor"
+        };
+        // FIXME: proper scanner for syntax highlighting
+        String text = styledText.getText();
+        int start = event.start;
+        int end = event.start + event.length;
+        start -= 20; // deleting chars from keyword causes rescan
+        end += 20;
+        if (start < 0)
+            start = 0;
+        if (end > text.length())
+            end = text.length();
+        if (null != styledText.getStyleRangeAtOffset(event.start)) {
+            StyleRange clearStyleRange = new StyleRange();
+            clearStyleRange.start = start;
+            clearStyleRange.length = end - start;
+            clearStyleRange.foreground = event.display.getSystemColor(SWT.COLOR_BLACK);
+            styledText.setStyleRange(clearStyleRange);
+        }
+
+        while (start < end) {
+            for (final String keyword : keywords) {
+                if (!text.substring(start).startsWith(keyword))
+                    continue;
+                if (start > 0) {
+                    final char before = text.charAt(start - 1);
+                    if (Character.isLetterOrDigit(before))
+                        continue;
+                    else if (before == '_')
+                        continue;
+                }
+                if (start + keyword.length() < text.length()) {
+                    final char after = text.charAt(start + keyword.length());
+                    if (Character.isLetterOrDigit(after))
+                        continue;
+                    else if (after == '_')
+                        continue;
+                }
+                StyleRange style1 = new StyleRange();
+                style1.start = start;
+                style1.length = keyword.length();
+                style1.foreground = event.display.getSystemColor(SWT.COLOR_BLUE);
+                styledText.setStyleRange(style1);
+            }
+            start++;
+        }
+    }
+}
diff --git a/tools/glesv2debugger/test/com/android/glesv2debugger/MessageParserExTest.java b/tools/glesv2debugger/test/com/android/glesv2debugger/MessageParserExTest.java
new file mode 100644
index 0000000..d2a9a7e
--- /dev/null
+++ b/tools/glesv2debugger/test/com/android/glesv2debugger/MessageParserExTest.java
@@ -0,0 +1,115 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.android.glesv2debugger.DebuggerMessage.Message.Type;
+import com.google.protobuf.ByteString;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+public class MessageParserExTest {
+    /**
+     * @throws java.lang.Exception
+     */
+    @Before
+    public void setUp() throws Exception {
+    }
+
+    @Test
+    public void testParseFloats() {
+        final MessageParserEx parser = new MessageParserEx();
+        final String args = "{0, 1    ,2,3  }";
+        parser.args = args;
+        final ByteBuffer data = parser.parseFloats(4).asReadOnlyByteBuffer();
+        data.order(SampleView.targetByteOrder);
+        for (int i = 0; i < 4; i++)
+            assertEquals(i, data.getFloat(), 0);
+    }
+
+    @Test
+    public void testParseArgument() {
+        final MessageParserEx parser = new MessageParserEx();
+        final String args = "sdfa   =  GL_VERTEX_SHADER , -5421 ,0x443=0x54f";
+        parser.args = args;
+        assertEquals(GLEnum.GL_VERTEX_SHADER.value, parser.parseArgument());
+        assertEquals(-5421, parser.parseArgument());
+        assertEquals(0x54f, parser.parseArgument());
+    }
+
+    /**
+     * Test method for
+     * {@link com.android.glesv2debugger.MessageParserEx#parse_glShaderSource(com.android.glesv2debugger.DebuggerMessage.Message.Builder)}
+     * .
+     */
+    @Test
+    public void testParse_glShaderSource() {
+        final Message.Builder builder = Message.newBuilder();
+        final MessageParserEx messageParserEx = new MessageParserEx();
+        final String source = "dks \n jafhskjaho { urehg ; } hskjg";
+        messageParserEx.parse(builder, "void glShaderSource ( shader=4, count= 1, "
+                                + "string =\"" + source + "\"  , 0x0)");
+        assertEquals(Function.glShaderSource, builder.getFunction());
+        assertEquals(4, builder.getArg0());
+        assertEquals(1, builder.getArg1());
+        assertEquals(source, builder.getData().toStringUtf8());
+        assertEquals(0, builder.getArg3());
+    }
+
+    @Test
+    public void testParse_glBlendEquation() {
+        assertNotNull(MessageParserEx.instance);
+        final Message.Builder builder = Message.newBuilder();
+        MessageParserEx.instance.parse(builder, "void glBlendEquation ( mode= GL_ADD ) ; ");
+        assertEquals(Function.glBlendEquation, builder.getFunction());
+        assertEquals(GLEnum.GL_ADD.value, builder.getArg0());
+    }
+
+    /** loopback testing of typical generated MessageFormatter and MessageParser */
+    @Test
+    public void testParseFormatterMessage() {
+        final ByteBuffer srcData = ByteBuffer.allocate(4 * 2 * 4);
+        srcData.order(SampleView.targetByteOrder);
+        for (int i = 0; i < 4 * 2; i++)
+            srcData.putFloat(i);
+        srcData.rewind();
+        Message.Builder builder = Message.newBuilder();
+        builder.setContextId(3752).setExpectResponse(false).setType(Type.CompleteCall);
+        builder.setFunction(Function.glUniformMatrix2fv);
+        builder.setArg0(54).setArg1(2).setArg2(0).setData(ByteString.copyFrom(srcData));
+        Message msg = builder.build();
+        builder = msg.toBuilder();
+        String formatted = MessageFormatter.format(msg, false);
+        formatted = formatted.substring(0, formatted.indexOf('(')) + ' ' + builder.getFunction() +
+                formatted.substring(formatted.indexOf('('));
+        Message.Builder parsed = Message.newBuilder();
+        MessageParserEx.instance.parse(parsed, formatted);
+        assertEquals(builder.getFunction(), parsed.getFunction());
+        assertEquals(builder.getArg0(), parsed.getArg0());
+        assertEquals(builder.getArg1(), parsed.getArg1());
+        assertEquals(builder.getArg2(), parsed.getArg2());
+        assertEquals(builder.getData().toStringUtf8(), parsed.getData().toStringUtf8());
+    }
+
+}
diff --git a/tools/glesv2debugger/test/com/android/glesv2debugger/MessageQueueTest.java b/tools/glesv2debugger/test/com/android/glesv2debugger/MessageQueueTest.java
new file mode 100644
index 0000000..5f8e93d
--- /dev/null
+++ b/tools/glesv2debugger/test/com/android/glesv2debugger/MessageQueueTest.java
@@ -0,0 +1,183 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT 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.glesv2debugger;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.glesv2debugger.DebuggerMessage.Message.Function;
+import com.android.glesv2debugger.DebuggerMessage.Message.Type;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+public class MessageQueueTest {
+    private MessageQueue queue;
+
+    /**
+     * @throws java.lang.Exception
+     */
+    @Before
+    public void setUp() throws Exception {
+        queue = new MessageQueue(null, new ProcessMessage[0]);
+    }
+
+    /**
+     * Test method for
+     * {@link com.android.glesv2debugger.MessageQueue#defaultProcessMessage(com.android.glesv2debugger.DebuggerMessage.Message, boolean, boolean)}
+     * .
+     * 
+     * @throws IOException
+     */
+    @Test
+    public void testDefaultProcessMessage() throws IOException {
+        final int contextId = 8784;
+        assertNull(queue.getPartialMessage(contextId));
+        Message.Builder builder = Message.newBuilder();
+        builder.setContextId(contextId);
+        builder.setExpectResponse(false);
+        builder.setFunction(Function.glFinish);
+        builder.setType(Type.BeforeCall);
+        Message msg = builder.build();
+        queue.defaultProcessMessage(msg, false, false);
+        assertNotNull(queue.getPartialMessage(contextId));
+
+        builder = msg.toBuilder();
+        builder.setType(Type.AfterCall);
+        builder.setTime(5);
+        msg = builder.build();
+        queue.defaultProcessMessage(msg, false, false);
+        assertNull(queue.getPartialMessage(contextId));
+        Message complete = queue.removeCompleteMessage(contextId);
+        assertNotNull(complete);
+        assertEquals(contextId, complete.getContextId());
+        assertEquals(msg.getFunction(), complete.getFunction());
+        assertEquals(msg.getTime(), complete.getTime(), 0);
+        assertEquals(Type.CompleteCall, complete.getType());
+
+        // an already complete message should just be added to complete queue
+        queue.defaultProcessMessage(complete, false, false);
+        assertNull(queue.getPartialMessage(contextId));
+        complete = queue.removeCompleteMessage(contextId);
+        assertNotNull(complete);
+        assertEquals(contextId, complete.getContextId());
+        assertEquals(msg.getFunction(), complete.getFunction());
+        assertEquals(msg.getTime(), complete.getTime(), 0);
+        assertEquals(Type.CompleteCall, complete.getType());
+    }
+
+    @Test
+    public void testCompletePartialMessage() throws IOException {
+        final int contextId = 8784;
+        assertNull(queue.getPartialMessage(contextId));
+        Message.Builder builder = Message.newBuilder();
+        builder.setContextId(contextId);
+        builder.setExpectResponse(false);
+        builder.setFunction(Function.glFinish);
+        builder.setType(Type.BeforeCall);
+        Message msg = builder.build();
+        queue.defaultProcessMessage(msg, false, false);
+        assertNotNull(queue.getPartialMessage(contextId));
+        queue.completePartialMessage(contextId);
+
+        final Message complete = queue.removeCompleteMessage(contextId);
+        assertNotNull(complete);
+        assertEquals(contextId, complete.getContextId());
+        assertEquals(msg.getFunction(), complete.getFunction());
+        assertEquals(msg.getTime(), complete.getTime(), 0);
+        assertEquals(Type.BeforeCall, complete.getType());
+    }
+
+    /** Write two messages from two contexts to file and test handling them */
+    @Test
+    public void testRunWithFile() throws FileNotFoundException, IOException, InterruptedException {
+        final File filePath = File.createTempFile("test", ".gles2dbg");
+        DataOutputStream file = new DataOutputStream(new FileOutputStream(filePath));
+        Message.Builder builder = Message.newBuilder();
+        final int contextId0 = 521643, contextId1 = 87634;
+        assertNull(queue.removeCompleteMessage(contextId0));
+        assertNull(queue.removeCompleteMessage(contextId1));
+
+        builder.setContextId(contextId0).setExpectResponse(false).setType(Type.BeforeCall);
+        builder.setFunction(Function.glClear).setArg0(contextId0);
+        Message msg0 = builder.build();
+        byte[] data = msg0.toByteArray();
+        file.writeInt(data.length);
+        file.write(data);
+
+        builder = Message.newBuilder();
+        builder.setContextId(contextId1).setExpectResponse(false).setType(Type.BeforeCall);
+        builder.setFunction(Function.glDisable).setArg0(contextId1);
+        Message msg1 = builder.build();
+        data = msg1.toByteArray();
+        file.writeInt(data.length);
+        file.write(data);
+
+        builder = Message.newBuilder();
+        msg0 = builder.setContextId(msg0.getContextId()).setExpectResponse(false)
+                .setType(Type.AfterCall).setFunction(msg0.getFunction()).setTime(2).build();
+        data = msg0.toByteArray();
+        file.writeInt(data.length);
+        file.write(data);
+
+        builder = Message.newBuilder();
+        msg1 = builder.setContextId(msg1.getContextId()).setExpectResponse(false)
+                .setType(Type.AfterCall).setFunction(msg1.getFunction()).setTime(465).build();
+        data = msg1.toByteArray();
+        file.writeInt(data.length);
+        file.write(data);
+
+        file.close();
+
+        FileInputStream fis = new FileInputStream(filePath);
+        // Java VM uses big endian, so the file was written in big endian
+        queue.start(ByteOrder.BIG_ENDIAN, fis);
+        queue.thread.join();
+
+        Message complete0 = queue.removeCompleteMessage(msg0.getContextId());
+        assertNotNull(complete0);
+        assertNull(queue.removeCompleteMessage(contextId0));
+        assertEquals(contextId0, complete0.getContextId());
+        assertEquals(false, complete0.getExpectResponse());
+        assertEquals(Type.CompleteCall, complete0.getType());
+        assertEquals(msg0.getFunction(), complete0.getFunction());
+        assertEquals(contextId0, complete0.getArg0());
+        assertEquals(msg0.getTime(), complete0.getTime(), 0);
+
+        Message complete1 = queue.removeCompleteMessage(msg1.getContextId());
+        assertNotNull(complete1);
+        assertNull(queue.removeCompleteMessage(contextId1));
+        assertEquals(contextId1, complete1.getContextId());
+        assertEquals(false, complete1.getExpectResponse());
+        assertEquals(Type.CompleteCall, complete1.getType());
+        assertEquals(msg1.getFunction(), complete1.getFunction());
+        assertEquals(contextId1, complete1.getArg0());
+        assertEquals(msg1.getTime(), complete1.getTime(), 0);
+
+        filePath.delete();
+    }
+}
diff --git a/tools/jdwpspy/Android.mk b/tools/jdwpspy/Android.mk
index eca3e22..2201aab 100644
--- a/tools/jdwpspy/Android.mk
+++ b/tools/jdwpspy/Android.mk
@@ -4,9 +4,9 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	Main.c \
-	Net.c \
-	find_JdwpConstants.c
+	Main.cpp \
+	Net.cpp \
+	find_JdwpConstants.cpp
 
 LOCAL_C_INCLUDES += \
 	dalvik/vm
diff --git a/tools/jdwpspy/Common.h b/tools/jdwpspy/Common.h
index c42d183..ddaba9c 100644
--- a/tools/jdwpspy/Common.h
+++ b/tools/jdwpspy/Common.h
@@ -14,11 +14,6 @@
 typedef unsigned int u4;
 typedef unsigned long long u8;
 
-#ifndef __bool_true_false_are_defined
-typedef enum { false=0, true=!false } bool;
-#define __bool_true_false_are_defined 1
-#endif
-
 #define NELEM(x) (sizeof(x) / sizeof((x)[0]))
 
 #ifndef _JDWP_MISC_INLINE
diff --git a/tools/jdwpspy/Main.c b/tools/jdwpspy/Main.cpp
similarity index 87%
rename from tools/jdwpspy/Main.c
rename to tools/jdwpspy/Main.cpp
index 62a0007..0f68d52 100644
--- a/tools/jdwpspy/Main.c
+++ b/tools/jdwpspy/Main.cpp
@@ -33,7 +33,7 @@
 void printHexDumpEx(FILE* fp, const void* vaddr, size_t length,
     HexDumpMode mode, const char* prefix)
 {
-    const unsigned char* addr = vaddr;
+    const unsigned char* addr = reinterpret_cast<const unsigned char*>(vaddr);
     char out[77];       /* exact fit */
     unsigned int offset;    /* offset to show while printing */
     char* hex;
@@ -53,19 +53,17 @@
     gap = (int) offset & 0x0f;
     while (length) {
         unsigned int lineOffset = offset & ~0x0f;
-        int i, count;
-        
-        hex = out;
-        asc = out + 59;
+        char* hex = out;
+        char* asc = out + 59;
 
-        for (i = 0; i < 8; i++) {
+        for (int i = 0; i < 8; i++) {
             *hex++ = gHexDigit[lineOffset >> 28];
             lineOffset <<= 4;
         }
         hex++;
         hex++;
 
-        count = ((int)length > 16-gap) ? 16-gap : (int) length; /* cap length */
+        int count = ((int)length > 16-gap) ? 16-gap : (int) length; /* cap length */
         assert(count != 0);
         assert(count+gap <= 16);
 
@@ -75,6 +73,7 @@
             asc += gap;
         }
 
+        int i;
         for (i = gap ; i < count+gap; i++) {
             *hex++ = gHexDigit[*addr >> 4];
             *hex++ = gHexDigit[*addr & 0x0f];
@@ -118,9 +117,6 @@
  */
 int main(int argc, char* argv[])
 {
-    int connectPort, listenPort;
-    int cc;
-
     if (argc < 2 || argc > 3) {
         usage("jdwpspy");
         return 2;
@@ -129,15 +125,15 @@
     setvbuf(stdout, NULL, _IONBF, 0);
 
     /* may want this to be host:port */
-    connectPort = atoi(argv[1]);
+    int connectPort = atoi(argv[1]);
 
+    int listenPort;
     if (argc > 2)
         listenPort = atoi(argv[2]);
     else
         listenPort = connectPort + 1;
 
-    cc = run("localhost", connectPort, listenPort);
+    int cc = run("localhost", connectPort, listenPort);
 
     return (cc != 0);
 }
-
diff --git a/tools/jdwpspy/Net.c b/tools/jdwpspy/Net.cpp
similarity index 97%
rename from tools/jdwpspy/Net.c
rename to tools/jdwpspy/Net.cpp
index 555fe49..b923006 100644
--- a/tools/jdwpspy/Net.c
+++ b/tools/jdwpspy/Net.cpp
@@ -7,9 +7,9 @@
 #include "jdwp/JdwpConstants.h"
 
 #include <stdlib.h>
-#include <unistd.h>     
+#include <unistd.h>
 #include <stdio.h>
-#include <string.h>     
+#include <string.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -205,9 +205,7 @@
  */
 static const char* getCommandName(int cmdSet, int cmd)
 {
-    int i;
-
-    for (i = 0; i < (int) NELEM(gHandlerMap); i++) {
+    for (int i = 0; i < (int) NELEM(gHandlerMap); i++) {
         if (gHandlerMap[i].cmdSet == cmdSet &&
             gHandlerMap[i].cmd == cmd)
         {
@@ -229,10 +227,7 @@
 NetState* jdwpNetStartup(unsigned short listenPort, const char* connectHost,
     unsigned short connectPort)
 {
-    NetState* netState;
-    int one = 1;
-
-    netState = (NetState*) malloc(sizeof(*netState));
+    NetState* netState = (NetState*) malloc(sizeof(*netState));
     memset(netState, 0, sizeof(*netState));
     netState->listenSock = -1;
     netState->dbg.sock = netState->vm.sock = -1;
@@ -251,12 +246,15 @@
     }
 
     /* allow immediate re-use if we die */
-    if (setsockopt(netState->listenSock, SOL_SOCKET, SO_REUSEADDR, &one,
-            sizeof(one)) < 0)
     {
-        fprintf(stderr, "setsockopt(SO_REUSEADDR) failed: %s\n",
-            strerror(errno));
-        goto fail;
+        int one = 1;
+        if (setsockopt(netState->listenSock, SOL_SOCKET, SO_REUSEADDR, &one,
+                sizeof(one)) < 0)
+        {
+            fprintf(stderr, "setsockopt(SO_REUSEADDR) failed: %s\n",
+                strerror(errno));
+            goto fail;
+        }
     }
 
     struct sockaddr_in addr;
@@ -474,7 +472,7 @@
     char prefix[3];
     u4 length, id;
     u1 flags, cmdSet=0, cmd=0;
-    u2 error=0;
+    JdwpError error = ERR_NONE;
     bool reply;
     int dataLen;
 
@@ -483,7 +481,7 @@
     flags = get1(buf+8);
     if ((flags & kJDWPFlagReply) != 0) {
         reply = true;
-        error = get2BE(buf+9);
+        error = static_cast<JdwpError>(get2BE(buf+9));
     } else {
         reply = false;
         cmdSet = get1(buf+9);
@@ -748,4 +746,3 @@
 
     return 0;
 }
-
diff --git a/tools/jdwpspy/find_JdwpConstants.c b/tools/jdwpspy/find_JdwpConstants.c
deleted file mode 100644
index 8ff8186..0000000
--- a/tools/jdwpspy/find_JdwpConstants.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "jdwp/JdwpConstants.c"
diff --git a/tools/jdwpspy/find_JdwpConstants.cpp b/tools/jdwpspy/find_JdwpConstants.cpp
new file mode 100644
index 0000000..57b7dbb
--- /dev/null
+++ b/tools/jdwpspy/find_JdwpConstants.cpp
@@ -0,0 +1 @@
+#include "jdwp/JdwpConstants.cpp"