auto import from //depot/cupcake/@135843
diff --git a/apps/CustomLocale/Android.mk b/apps/CustomLocale/Android.mk
new file mode 100644
index 0000000..275207f
--- /dev/null
+++ b/apps/CustomLocale/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := CustomLocale
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/apps/CustomLocale/AndroidManifest.xml b/apps/CustomLocale/AndroidManifest.xml
new file mode 100644
index 0000000..9dfa896
--- /dev/null
+++ b/apps/CustomLocale/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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"
+    android:versionCode="1"
+    android:versionName="1.0" package="com.android.customlocale">
+    <application
+        android:icon="@drawable/icon"
+        android:label="@string/app_name">
+        <activity
+            android:label="@string/app_name" android:name="CustomLocaleActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name="NewLocaleDialog"
+            android:theme="@android:style/Theme.Dialog" />
+    </application>
+    <uses-sdk android:minSdkVersion="3" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+</manifest>
diff --git a/apps/CustomLocale/res/drawable/icon.png b/apps/CustomLocale/res/drawable/icon.png
new file mode 100644
index 0000000..cb40a19
--- /dev/null
+++ b/apps/CustomLocale/res/drawable/icon.png
Binary files differ
diff --git a/apps/CustomLocale/res/layout/list_item.xml b/apps/CustomLocale/res/layout/list_item.xml
new file mode 100644
index 0000000..8c59f92
--- /dev/null
+++ b/apps/CustomLocale/res/layout/list_item.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="wrap_content"
+    android:padding="5dip">
+    <TextView
+        android:id="@+id/locale_code"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:textAppearanceLarge"
+        android:layout_weight="1"
+        android:text="@string/locale_default" />
+    <TextView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/locale_name"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:textAppearance"
+        android:layout_weight="1" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CustomLocale/res/layout/main.xml b/apps/CustomLocale/res/layout/main.xml
new file mode 100644
index 0000000..b1eaa51
--- /dev/null
+++ b/apps/CustomLocale/res/layout/main.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="0"
+        android:text="@string/header_current_locale"
+        android:textAppearance="@style/TextAppearance.header"
+        android:gravity="center_horizontal"
+        android:background="@color/header_background" />
+    <TextView
+        android:id="@+id/current_locale"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="0"
+        android:padding="5dip" />
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="0"
+        android:text="@string/header_locale_list"
+        android:textAppearance="@style/TextAppearance.header"
+        android:gravity="center_horizontal"
+        android:background="@color/header_background" />
+    <ListView
+        android:id="@id/android:list"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:layout_weight="1"
+        android:padding="8dip" />
+    <TextView
+        android:id="@id/android:empty"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:text="@string/no_data_label" />
+    <Button
+        android:id="@+id/new_locale"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="0"
+        android:paddingLeft="8dip"
+        android:paddingRight="8dip"
+        android:text="@string/add_new_locale_button" />
+</LinearLayout>
diff --git a/apps/CustomLocale/res/layout/new_locale.xml b/apps/CustomLocale/res/layout/new_locale.xml
new file mode 100644
index 0000000..d0d9d6c
--- /dev/null
+++ b/apps/CustomLocale/res/layout/new_locale.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip">
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/new_locale_label" />
+    <EditText
+        android:id="@+id/value"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/locale_default" android:inputType="text"/>
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+        <Button
+            android:id="@+id/add"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/add_button" android:layout_gravity="center_vertical"/>
+        <Button
+            android:id="@+id/add_and_select"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/add_select_button" android:layout_gravity="center_vertical"/>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CustomLocale/res/values-fr/strings.xml b/apps/CustomLocale/res/values-fr/strings.xml
new file mode 100644
index 0000000..8852a9a
--- /dev/null
+++ b/apps/CustomLocale/res/values-fr/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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">Locales Personalisées</string>
+    <string name="add_new_locale_button">Ajouter une nouvelle locale</string>
+    <string name="new_locale_label">Code de la nouvelle locale:</string>
+    <string name="add_button">Ajouter</string>
+    <string name="no_data_label">Aucune locale</string>
+    <string name="header_current_locale">Locale courrante</string>
+    <string name="header_locale_list">Liste des locales</string>
+    <string name="add_select_button">Ajouter et sélectionner</string>
+</resources>
diff --git a/apps/CustomLocale/res/values/colors.xml b/apps/CustomLocale/res/values/colors.xml
new file mode 100644
index 0000000..b9b5ad2
--- /dev/null
+++ b/apps/CustomLocale/res/values/colors.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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>
+    <color name="header_background">#888</color>
+</resources>
diff --git a/apps/CustomLocale/res/values/strings.xml b/apps/CustomLocale/res/values/strings.xml
new file mode 100644
index 0000000..313fb87
--- /dev/null
+++ b/apps/CustomLocale/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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">Custom Locale</string>
+    <string name="locale_default">ex_EX</string>
+    <string name="add_new_locale_button">Add New Locale</string>
+    <string name="new_locale_label">New locale code:</string>
+    <string name="add_button">Add</string>
+    <string name="no_data_label">No data</string>
+    <string name="header_current_locale">Current Locale</string>
+    <string name="header_locale_list">Locale List</string>
+    <string name="add_select_button">Add and Select</string>
+</resources>
diff --git a/apps/CustomLocale/res/values/styles.xml b/apps/CustomLocale/res/values/styles.xml
new file mode 100644
index 0000000..8ccc11c
--- /dev/null
+++ b/apps/CustomLocale/res/values/styles.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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>
+    <style name="TextAppearance"
+           parent="android:TextAppearance" />
+
+    <style name="TextAppearance.header">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textStyle">bold</item>
+    </style>
+
+</resources>
diff --git a/apps/CustomLocale/src/com/android/customlocale/CustomLocaleActivity.java b/apps/CustomLocale/src/com/android/customlocale/CustomLocaleActivity.java
new file mode 100644
index 0000000..768f910
--- /dev/null
+++ b/apps/CustomLocale/src/com/android/customlocale/CustomLocaleActivity.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.customlocale;
+
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.ListActivity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.Button;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Displays the list of system locales as well as maintain a custom list of user
+ * locales. The user can select a locale and apply it or it can create or remove
+ * a custom locale.
+ */
+public class CustomLocaleActivity extends ListActivity {
+
+    private static final String CUSTOM_LOCALES_SEP = " ";
+    private static final String CUSTOM_LOCALES = "custom_locales";
+    private static final String KEY_CUSTOM = "custom";
+    private static final String KEY_NAME = "name";
+    private static final String KEY_CODE = "code";
+
+    private static final String TAG = "LocaleSetup";
+    private static final boolean DEBUG = true;
+
+    /** Request code returned when the NewLocaleDialog activity finishes. */
+    private static final int UPDATE_LIST = 42;
+    /** Menu item id for applying a locale */
+    private static final int MENU_APPLY = 43;
+    /** Menu item id for removing a custom locale */
+    private static final int MENU_REMOVE = 44;
+
+    /** List view displaying system and custom locales. */
+    private ListView mListView;
+    /** Textview used to display current locale */
+    private TextView mCurrentLocaleTextView;
+    /** Private shared preferences of this activity. */
+    private SharedPreferences mPrefs;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        mPrefs = getPreferences(MODE_PRIVATE);
+
+        Button newLocaleButton = (Button) findViewById(R.id.new_locale);
+
+        newLocaleButton.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                Intent i = new Intent(CustomLocaleActivity.this, NewLocaleDialog.class);
+                startActivityForResult(i, UPDATE_LIST);
+            }
+        });
+
+        mListView = (ListView) findViewById(android.R.id.list);
+        mListView.setFocusable(true);
+        mListView.setFocusableInTouchMode(true);
+        mListView.requestFocus();
+        registerForContextMenu(mListView);
+        setupLocaleList();
+
+        mCurrentLocaleTextView = (TextView) findViewById(R.id.current_locale);
+        displayCurrentLocale();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+
+        if (requestCode == UPDATE_LIST && resultCode == RESULT_OK && data != null) {
+            String locale = data.getExtras().getString(NewLocaleDialog.INTENT_EXTRA_LOCALE);
+            if (locale != null && locale.length() > 0) {
+                // Get current custom locale list
+                String customLocales = mPrefs.getString(CUSTOM_LOCALES, null);
+
+                // Update
+                if (customLocales == null) {
+                    customLocales = locale;
+                } else {
+                    customLocales += CUSTOM_LOCALES_SEP + locale;
+                }
+
+                // Save prefs
+                if (DEBUG) {
+                    Log.d(TAG, "add/customLocales: " + customLocales);
+                }
+                mPrefs.edit().putString(CUSTOM_LOCALES, customLocales).commit();
+
+                Toast.makeText(this, "Added custom locale: " + locale, Toast.LENGTH_SHORT).show();
+
+                // Update list view
+                setupLocaleList();
+
+                // Find the item to select it in the list view
+                ListAdapter a = mListView.getAdapter();
+                for (int i = 0; i < a.getCount(); i++) {
+                    Object o = a.getItem(i);
+                    if (o instanceof Map<?, ?>) {
+                        String code = ((Map<String, String>) o).get(KEY_CODE);
+                        if (code != null && code.equals(locale)) {
+                            mListView.setSelection(i);
+                            break;
+                        }
+                    }
+                }
+
+                if (data.getExtras().getBoolean(NewLocaleDialog.INTENT_EXTRA_SELECT)) {
+                    selectLocale(locale);
+                }
+            }
+        }
+    }
+
+    private void setupLocaleList() {
+        if (DEBUG) {
+            Log.d(TAG, "Update locate list");
+        }
+
+        ArrayList<Map<String, String>> data = new ArrayList<Map<String, String>>();
+
+        // Insert all system locales
+        String[] locales = getAssets().getLocales();
+        for (String locale : locales) {
+            Locale loc = new Locale(locale);
+
+            Map<String, String> map = new HashMap<String, String>(1);
+            map.put(KEY_CODE, locale);
+            map.put(KEY_NAME, loc.getDisplayName());
+            data.add(map);
+        }
+        locales = null;
+
+        // Insert all custom locales
+        String customLocales = mPrefs.getString(CUSTOM_LOCALES, "");
+        if (DEBUG) {
+            Log.d(TAG, "customLocales: " + customLocales);
+        }
+        for (String locale : customLocales.split(CUSTOM_LOCALES_SEP)) {
+            if (locale != null && locale.length() > 0) {
+                Locale loc = new Locale(locale);
+
+                Map<String, String> map = new HashMap<String, String>(1);
+                map.put(KEY_CODE, locale);
+                map.put(KEY_NAME, loc.getDisplayName() + " [Custom]");
+                // the presence of the "custom" key marks it as custom.
+                map.put(KEY_CUSTOM, "");
+                data.add(map);
+            }
+        }
+
+        // Sort all locales by code
+        Collections.sort(data, new Comparator<Map<String, String>>() {
+            public int compare(Map<String, String> lhs, Map<String, String> rhs) {
+                return lhs.get(KEY_CODE).compareTo(rhs.get(KEY_CODE));
+            }
+        });
+
+        // Update the list view adapter
+        mListView.setAdapter(new SimpleAdapter(this, data, R.layout.list_item, new String[] {
+                KEY_CODE, KEY_NAME}, new int[] {R.id.locale_code, R.id.locale_name}));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+        super.onCreateContextMenu(menu, v, menuInfo);
+
+        if (menuInfo instanceof AdapterContextMenuInfo) {
+            int position = ((AdapterContextMenuInfo) menuInfo).position;
+            Object o = mListView.getItemAtPosition(position);
+            if (o instanceof Map<?, ?>) {
+                String locale = ((Map<String, String>) o).get(KEY_CODE);
+                String custom = ((Map<String, String>) o).get(KEY_CUSTOM);
+
+                if (custom == null) {
+                    menu.setHeaderTitle("System Locale");
+                    menu.add(0, MENU_APPLY, 0, "Apply");
+                } else {
+                    menu.setHeaderTitle("Custom Locale");
+                    menu.add(0, MENU_APPLY, 0, "Apply");
+                    menu.add(0, MENU_REMOVE, 0, "Remove");
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean onContextItemSelected(MenuItem item) {
+
+        String pendingLocale = null;
+        boolean is_custom = false;
+
+        ContextMenuInfo menuInfo = item.getMenuInfo();
+        if (menuInfo instanceof AdapterContextMenuInfo) {
+            int position = ((AdapterContextMenuInfo) menuInfo).position;
+            Object o = mListView.getItemAtPosition(position);
+            if (o instanceof Map<?, ?>) {
+                pendingLocale = ((Map<String, String>) o).get(KEY_CODE);
+                is_custom = ((Map<String, String>) o).get(KEY_CUSTOM) != null;
+            }
+        }
+
+        if (pendingLocale == null) {
+            // should never happen
+            return super.onContextItemSelected(item);
+        }
+
+        if (item.getItemId() == MENU_REMOVE) {
+            // Get current custom locale list
+            String customLocales = mPrefs.getString(CUSTOM_LOCALES, "");
+
+            if (DEBUG) {
+                Log.d(TAG, "Remove " + pendingLocale + " from custom locales: " + customLocales);
+            }
+
+            // Update
+            StringBuilder sb = new StringBuilder();
+            for (String locale : customLocales.split(CUSTOM_LOCALES_SEP)) {
+                if (locale != null && locale.length() > 0 && !locale.equals(pendingLocale)) {
+                    if (sb.length() > 0) {
+                        sb.append(CUSTOM_LOCALES_SEP);
+                    }
+                    sb.append(locale);
+                }
+            }
+            String newLocales = sb.toString();
+            if (!newLocales.equals(customLocales)) {
+                // Save prefs
+                mPrefs.edit().putString(CUSTOM_LOCALES, customLocales).commit();
+
+                Toast.makeText(this, "Removed custom locale: " + pendingLocale, Toast.LENGTH_SHORT)
+                        .show();
+            }
+
+        } else if (item.getItemId() == MENU_APPLY) {
+            selectLocale(pendingLocale);
+        }
+
+        return super.onContextItemSelected(item);
+    }
+
+    private void selectLocale(String locale) {
+        if (DEBUG) {
+            Log.d(TAG, "Select locale " + locale);
+        }
+
+        try {
+            IActivityManager am = ActivityManagerNative.getDefault();
+            Configuration config = am.getConfiguration();
+
+            Locale loc = new Locale(locale);
+            config.locale = loc;
+
+            // indicate this isn't some passing default - the user wants this
+            // remembered
+            config.userSetLocale = true;
+
+            am.updateConfiguration(config);
+
+            Toast.makeText(this, "Select locale: " + locale, Toast.LENGTH_SHORT).show();
+        } catch (RemoteException e) {
+            if (DEBUG) {
+                Log.e(TAG, "Select locale failed", e);
+            }
+        }
+    }
+
+    private void displayCurrentLocale() {
+        try {
+            IActivityManager am = ActivityManagerNative.getDefault();
+            Configuration config = am.getConfiguration();
+
+            if (config.locale != null) {
+                String text = String.format("%s - %s",
+                        config.locale.toString(),
+                        config.locale.getDisplayName());
+                mCurrentLocaleTextView.setText(text);
+            }
+        } catch (RemoteException e) {
+            if (DEBUG) {
+                Log.e(TAG, "get current locale failed", e);
+            }
+        }
+    }
+}
diff --git a/apps/CustomLocale/src/com/android/customlocale/NewLocaleDialog.java b/apps/CustomLocale/src/com/android/customlocale/NewLocaleDialog.java
new file mode 100644
index 0000000..3626f73
--- /dev/null
+++ b/apps/CustomLocale/src/com/android/customlocale/NewLocaleDialog.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.customlocale;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+
+/**
+ * Dialog to ask the user for a new locale. <p/> Returns the locale code (e.g.
+ * "en_US") via an intent with a "locale" extra string and a "select" extra
+ * boolean.
+ */
+public class NewLocaleDialog extends Activity
+    implements View.OnClickListener, View.OnKeyListener {
+
+    public static final String INTENT_EXTRA_LOCALE = "locale";
+    public static final String INTENT_EXTRA_SELECT = "select";
+
+    private static final String TAG = "NewLocale";
+    private static final boolean DEBUG = true;
+    private Button mButtonAdd;
+    private Button mButtonAddSelect;
+    private EditText mEditText;
+    private boolean mWasEmpty;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.new_locale);
+
+        mEditText = (EditText) findViewById(R.id.value);
+        mWasEmpty = true;
+
+        mButtonAdd = (Button) findViewById(R.id.add);
+        mButtonAdd.setOnClickListener(this);
+        mButtonAdd.setEnabled(false);
+
+        mButtonAddSelect = (Button) findViewById(R.id.add_and_select);
+        mButtonAddSelect.setOnClickListener(this);
+        mButtonAddSelect.setEnabled(false);
+        
+        mEditText.setOnKeyListener(this);
+    }
+
+    public void onClick(View v) {
+        String locale = mEditText.getText().toString();
+        boolean select = v == mButtonAddSelect;
+        
+        if (DEBUG) {
+            Log.d(TAG, "New Locale: " + locale + (select ? " + select" : ""));
+        }
+
+        Intent data = new Intent(NewLocaleDialog.this, NewLocaleDialog.class);
+        data.putExtra(INTENT_EXTRA_LOCALE, locale);
+        data.putExtra(INTENT_EXTRA_SELECT, select);
+        setResult(RESULT_OK, data);
+
+        finish();
+    }
+
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        boolean isEmpty = TextUtils.isEmpty(mEditText.getText());
+        if (isEmpty != mWasEmpty) {
+            mWasEmpty = isEmpty;
+            
+            mButtonAdd.setEnabled(!isEmpty);
+            mButtonAddSelect.setEnabled(!isEmpty);
+        }
+        return false;
+    }
+}
diff --git a/apps/Development/Android.mk b/apps/Development/Android.mk
new file mode 100644
index 0000000..9578e79
--- /dev/null
+++ b/apps/Development/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := eng development tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files) \
+                src/com/android/development/IRemoteService.aidl \
+
+LOCAL_PACKAGE_NAME := Development
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/apps/Development/AndroidManifest.xml b/apps/Development/AndroidManifest.xml
new file mode 100644
index 0000000..879e7d6
--- /dev/null
+++ b/apps/Development/AndroidManifest.xml
@@ -0,0 +1,136 @@
+<?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.development"
+        android:versionCode="1" android:versionName="1.0">
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.DUMP" />
+    <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
+    <uses-permission android:name="android.permission.RESTART_PACKAGES" />
+    <uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
+    <uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
+    <uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
+    <uses-permission android:name="android.permission.SET_DEBUG_APP" />
+    <uses-permission android:name="android.permission.HARDWARE_TEST" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
+    <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" />
+    <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.YouTubeUser" />
+    <uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
+
+    <application android:label="Dev Tools"
+            android:icon="@drawable/ic_launcher_devtools">
+
+        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="com.google.android.maps" />
+
+        <activity android:name="Development" android:label="Dev Tools"
+            android:icon="@drawable/ic_launcher_devtools">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="PackageBrowser" android:label="Package Browser">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+        <activity android:name="ExceptionBrowser" android:label="Exception Browser">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+        <activity android:name="StacktraceViewer" android:label="Stacktrace Viewer"/>
+        <activity android:name="PackageSummary" android:label="Package Summary">
+        </activity>
+        <activity android:name="ShowActivity" android:label="Activity">
+        </activity>
+        <activity android:name="AppPicker"
+                android:theme="@android:style/Theme.Dialog">
+        </activity>
+        <activity android:name="PointerLocation" android:label="Pointer Location"
+                android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
+                android:configChanges="keyboard|keyboardHidden|navigation|orientation">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="DataList">
+        </activity>
+        <activity android:name="Details">
+        </activity>
+        <activity android:name="DevelopmentSettings" android:label="Development Settings" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="InstrumentationList" android:label="Instrumentation">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="MediaScannerActivity" android:label="Media Scanner">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+
+    <activity android:name="GLSTester" android:label="Google Login Service">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+
+    <activity android:name="RunningProcesses" android:label="Running processes">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+    <activity android:name="ProcessInfo" android:label="Process Information">
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+    </activity>
+    <!--
+    <activity android:name="AppHwConfigList" android:label="Applications Hw Configuration">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+    </activity>
+    -->
+    <activity android:name="AppHwPref" android:label="Applications Hardware Preferences">
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+    </activity>
+    </application>
+</manifest>
diff --git a/apps/Development/res/drawable/box.xml b/apps/Development/res/drawable/box.xml
new file mode 100644
index 0000000..6849bd3
--- /dev/null
+++ b/apps/Development/res/drawable/box.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/drawable/box.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#00000000"/>
+    <stroke android:width="1dp" color="#ff000000"/>
+    <padding android:left="1dp" android:top="1dp"
+        android:right="1dp" android:bottom="1dp" />
+</shape>
diff --git a/apps/Development/res/drawable/ic_launcher_devtools.png b/apps/Development/res/drawable/ic_launcher_devtools.png
new file mode 100644
index 0000000..cb40a19
--- /dev/null
+++ b/apps/Development/res/drawable/ic_launcher_devtools.png
Binary files differ
diff --git a/apps/Development/res/drawable/stat_sample.png b/apps/Development/res/drawable/stat_sample.png
new file mode 100644
index 0000000..a2e5ce3
--- /dev/null
+++ b/apps/Development/res/drawable/stat_sample.png
Binary files differ
diff --git a/apps/Development/res/layout/application_hw_pref.xml b/apps/Development/res/layout/application_hw_pref.xml
new file mode 100755
index 0000000..859c7ab
--- /dev/null
+++ b/apps/Development/res/layout/application_hw_pref.xml
@@ -0,0 +1,82 @@
+<?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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:padding="4dip" >
+    
+        <TextView android:id="@+id/attr_package_label"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/package_label"
+            android:textStyle="bold" />
+        <TextView android:id="@+id/attr_package"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"/>
+
+        <TextView android:id="@+id/attr_touchscreen_label"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/touchscreen_label"
+            android:textStyle="bold" />
+        <TextView android:id="@+id/attr_touchscreen"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"/>
+
+        <TextView android:id="@+id/attr_input_method_label"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/input_method_label"
+            android:textStyle="bold" />
+        <TextView android:id="@+id/attr_input_method"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"/>
+
+        <TextView android:id="@+id/attr_hard_keyboard_label"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/hard_keyboard_label"
+            android:textStyle="bold" />
+        <TextView android:id="@+id/attr_hard_keyboard"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"/>
+
+        <TextView android:id="@+id/attr_navigation_label"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/navigation_label"
+            android:textStyle="bold" />
+        <TextView android:id="@+id/attr_navigation"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"/>
+
+        <TextView android:id="@+id/attr_five_way_nav_label"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/five_way_nav_label"
+            android:textStyle="bold" />
+        <TextView android:id="@+id/attr_five_way_nav"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+</ScrollView>
+
diff --git a/apps/Development/res/layout/development_settings.xml b/apps/Development/res/layout/development_settings.xml
new file mode 100644
index 0000000..0486748
--- /dev/null
+++ b/apps/Development/res/layout/development_settings.xml
@@ -0,0 +1,156 @@
+<?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="fill_parent"
+    android:layout_height="fill_parent">
+
+    <RelativeLayout 
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+        <TextView android:id="@+id/debug_app_label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_debug_app_label_text" />
+
+        <Button android:id="@+id/debug_app"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/debug_app_label"
+            android:layout_alignParentLeft="true"
+            android:layout_toRightOf="@id/debug_app_label" />
+
+        <!-- android:visibility="gone" -->
+                
+        <CheckBox android:id="@+id/wait_for_debugger"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/debug_app"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_wait_for_debugger_text" />
+
+        <View android:id="@+id/separator"
+            android:layout_width="8dip"
+            android:layout_height="8dip"
+            android:layout_below="@id/wait_for_debugger"
+            android:layout_alignParentLeft="true" />
+
+        <CheckBox android:id="@+id/show_load"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/separator"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_show_load_text" />
+
+        <CheckBox android:id="@+id/show_updates"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/show_load"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_show_updates_text" />
+
+        <Spinner android:id="@+id/max_procs"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/show_updates"
+            android:layout_alignParentLeft="true" />
+
+        <View android:id="@+id/separator2"
+            android:layout_width="8dip"
+            android:layout_height="8dip"
+            android:layout_below="@id/max_procs"
+            android:layout_alignParentLeft="true" />
+
+        <CheckBox android:id="@+id/always_finish"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/separator2"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_always_finish_text" />
+
+        <CheckBox android:id="@+id/show_cpu"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/always_finish"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_show_cpu_text" />
+
+        <CheckBox android:id="@+id/enable_gl"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/show_cpu"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_enable_gl_text" />
+
+        <CheckBox android:id="@+id/show_background"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/enable_gl"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_show_background_text" />
+
+        <CheckBox android:id="@+id/show_sleep"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/show_background"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_show_sleep_text" />
+            
+        <Spinner android:id="@+id/window_animation_scale"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/show_sleep"
+            android:layout_alignParentLeft="true">
+        </Spinner>
+
+        <Spinner android:id="@+id/transition_animation_scale"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/window_animation_scale"
+            android:layout_alignParentLeft="true">
+        </Spinner>
+
+        <Spinner android:id="@+id/font_hinting"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/transition_animation_scale"
+            android:layout_alignParentLeft="true">
+        </Spinner>
+
+        <CheckBox android:id="@+id/show_xmpp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/font_hinting"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_show_xmpp_text" />
+
+        <CheckBox android:id="@+id/show_maps_compass"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/show_xmpp"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_show_maps_compass_text" />
+            
+    </RelativeLayout>
+
+</ScrollView>
+
diff --git a/apps/Development/res/layout/enter_url.xml b/apps/Development/res/layout/enter_url.xml
new file mode 100644
index 0000000..062c67e
--- /dev/null
+++ b/apps/Development/res/layout/enter_url.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"
+    android:layout_width="fill_parent" android:layout_height="fill_parent">          	
+    <com.android.development.UrlEditText android:id="@+id/url_edit_text"
+        android:textSize="13sp"
+        android:autoText="false"
+        android:capitalize="none"
+        android:layout_width="fill_parent" android:layout_height="wrap_content"/>
+    <com.android.development.DisplayEditText android:id="@+id/display_edit_text"
+        android:textSize="13sp"
+        android:autoText="false"
+        android:capitalize="none"
+        android:layout_width="fill_parent" android:layout_height="wrap_content"/>
+    <ListView android:id="@android:id/list"
+        android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+</LinearLayout>
+
+
diff --git a/apps/Development/res/layout/gls_tester.xml b/apps/Development/res/layout/gls_tester.xml
new file mode 100644
index 0000000..fbd4549
--- /dev/null
+++ b/apps/Development/res/layout/gls_tester.xml
@@ -0,0 +1,111 @@
+<?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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <LinearLayout
+       android:orientation="horizontal"
+       android:layout_width="fill_parent"
+       android:layout_height="wrap_content">
+
+      <Button
+         android:id="@+id/prefer_hosted"
+         android:layout_width="wrap_content"
+         android:layout_height="wrap_content"
+         android:text="@string/gls_tester_prefer_hosted"/>
+
+      <Button
+         android:id="@+id/require_google"
+         android:layout_width="wrap_content"
+         android:layout_height="wrap_content"
+         android:text="@string/gls_tester_require_google"/>
+
+      <Button
+         android:id="@+id/get_accounts"
+         android:layout_width="wrap_content"
+         android:layout_height="wrap_content"
+         android:text="@string/gls_tester_get_accounts"/>
+
+      <Button
+         android:id="@+id/clear"
+         android:layout_width="wrap_content"
+         android:layout_height="wrap_content"
+         android:text="@string/gls_tester_clear"/>
+
+      <Button android:id="@+id/go"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:text="@string/gls_tester_go"/>
+
+    </LinearLayout>
+
+    <EditText android:id="@+id/username_edit"
+              android:singleLine="true"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content"
+              android:minWidth="250dip"
+              android:scrollHorizontally="true"
+              android:capitalize="none"
+              android:autoText="false"/>
+
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="fill_parent"
+                  android:layout_height="wrap_content">
+
+      <CheckBox android:id="@+id/do_notification"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/gls_tester_do_notification"/>
+
+      <CheckBox android:id="@+id/run_intent"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/gls_tester_run_intent"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+       android:orientation="horizontal"
+       android:layout_width="fill_parent"
+       android:layout_height="wrap_content">
+
+      <Spinner android:id="@+id/service_spinner"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:entries="@array/glstester_services"/>
+
+      <Button
+         android:id="@+id/wipe_passwords"
+         android:layout_width="wrap_content"
+         android:layout_height="wrap_content"
+         android:text="@string/gls_tester_wipe_passwords"/>
+    </LinearLayout>
+
+    <com.android.development.LogTextBox
+        android:id="@+id/text"
+        android:background="@drawable/box"
+        android:layout_width="fill_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:scrollbars="vertical"
+        android:textSize="10dip"
+       />
+
+</LinearLayout>
diff --git a/apps/Development/res/layout/log_viewer.xml b/apps/Development/res/layout/log_viewer.xml
new file mode 100644
index 0000000..98fe14e
--- /dev/null
+++ b/apps/Development/res/layout/log_viewer.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<com.android.development.LogTextBox xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    />
diff --git a/apps/Development/res/layout/media_scanner_activity.xml b/apps/Development/res/layout/media_scanner_activity.xml
new file mode 100644
index 0000000..53f2b15
--- /dev/null
+++ b/apps/Development/res/layout/media_scanner_activity.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 	 	
+	android:layout_width="fill_parent" 
+	android:layout_height="fill_parent"
+	android:orientation="horizontal">
+
+    <TextView android:id="@+id/title" android:textSize="16sp" android:textStyle="bold"
+        android:layout_width="fill_parent" android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/apps/Development/res/layout/monkey_screen.xml b/apps/Development/res/layout/monkey_screen.xml
new file mode 100644
index 0000000..c508338
--- /dev/null
+++ b/apps/Development/res/layout/monkey_screen.xml
@@ -0,0 +1,70 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="10dip" >
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingRight="5dip"
+            android:text="@string/monkey_screen_initial_activity_label" />
+
+        <Button android:id="@+id/initialActivity"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/monkey_screen_initialActivity_text" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="5dip" >
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingRight="5dip"
+            android:text="@string/monkey_screen_number_of_events_label" />
+
+        <EditText android:id="@+id/numberOfEvents"
+            android:layout_marginLeft="2dip"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:background="@android:drawable/editbox_background"
+            android:numeric="integer"
+            android:scrollHorizontally="true"
+            android:maxLines="1" />
+    </LinearLayout>
+
+    <Button android:id="@+id/start"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingTop="10dip"
+        android:text="@string/monkey_screen_start_text" />
+
+</LinearLayout>
+
+
diff --git a/apps/Development/res/layout/package_item.xml b/apps/Development/res/layout/package_item.xml
new file mode 100644
index 0000000..7860f9b
--- /dev/null
+++ b/apps/Development/res/layout/package_item.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+	android:layout_width="fill_parent"
+	android:layout_height="wrap_content" />
+    <!--android:background="@android:drawable/list_highlight"-->
diff --git a/apps/Development/res/layout/package_summary.xml b/apps/Development/res/layout/package_summary.xml
new file mode 100644
index 0000000..99717e6
--- /dev/null
+++ b/apps/Development/res/layout/package_summary.xml
@@ -0,0 +1,151 @@
+<?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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:padding="4dip" >
+    
+        <TextView android:id="@+id/packageView"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" />
+
+        <LinearLayout
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingTop="4dip"
+            android:paddingBottom="6dip"
+            android:paddingRight="4dip" >
+
+            <ImageView android:id="@+id/icon"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"
+                android:paddingRight="8dip" />
+
+            <LinearLayout
+                android:layout_width="wrap_content" android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <TextView android:id="@+id/classView"
+                    android:layout_width="fill_parent" android:layout_height="wrap_content" />
+
+                <TextView android:id="@+id/label"
+                    android:layout_width="fill_parent" android:layout_height="wrap_content" />
+
+                <TextView android:id="@+id/disabled"
+                    android:layout_width="fill_parent" android:layout_height="wrap_content"
+                    android:text="@string/disabled" />
+
+                <TextView android:id="@+id/system"
+                    android:layout_width="fill_parent" android:layout_height="wrap_content"
+                    android:text="@string/system" />
+
+                <TextView android:id="@+id/debuggable"
+                    android:layout_width="fill_parent" android:layout_height="wrap_content"
+                    android:text="@string/debuggable" />
+
+                <TextView android:id="@+id/nocode"
+                    android:layout_width="fill_parent" android:layout_height="wrap_content"
+                    android:text="@string/nocode" />
+
+                <TextView android:id="@+id/persistent"
+                    android:layout_width="fill_parent" android:layout_height="wrap_content"
+                    android:text="@string/persistent" />
+
+            </LinearLayout>
+
+            <Button android:id="@+id/restart"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/restart" />
+            
+        </LinearLayout>
+
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/package_summary_process_label" />
+
+        <TextView android:id="@+id/process"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/package_summary_uid_label" />
+
+        <TextView android:id="@+id/uid"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/package_summary_task_label" />
+
+        <TextView android:id="@+id/task"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/package_summary_version_label" />
+
+        <TextView android:id="@+id/version"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/package_summary_source_label" />
+
+        <TextView android:id="@+id/source"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/package_summary_data_label" />
+
+        <TextView android:id="@+id/data"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+
+        <LinearLayout android:id="@+id/activities" style="@style/SummaryCategoryLayout">
+            <TextView style="@style/SummaryCategoryHeader"
+                android:text="@string/package_summary_activities_label" />
+        </LinearLayout>
+    
+        <LinearLayout android:id="@+id/receivers" style="@style/SummaryCategoryLayout">
+            <TextView style="@style/SummaryCategoryHeader"
+                android:text="@string/package_summary_receivers_label" />
+        </LinearLayout>
+    
+        <LinearLayout android:id="@+id/services" style="@style/SummaryCategoryLayout">
+            <TextView style="@style/SummaryCategoryHeader"
+                android:text="@string/package_summary_services_label" />
+        </LinearLayout>
+    
+        <LinearLayout android:id="@+id/providers" style="@style/SummaryCategoryLayout">
+            <TextView style="@style/SummaryCategoryHeader"
+                android:text="@string/package_summary_providers_label" />
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/instrumentation" style="@style/SummaryCategoryLayout">
+            <TextView style="@style/SummaryCategoryHeader"
+                android:text="@string/package_summary_instrumentation_label" />
+        </LinearLayout>
+    
+    </LinearLayout>
+</ScrollView>
+
diff --git a/apps/Development/res/layout/process_info.xml b/apps/Development/res/layout/process_info.xml
new file mode 100755
index 0000000..b25f223
--- /dev/null
+++ b/apps/Development/res/layout/process_info.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:padding="4dip" >
+    
+        <TextView android:id="@+id/process_name_header"
+            android:layout_width="fill_parent" 
+            android:layout_height="wrap_content"
+            android:text="@string/process_name_header"
+            android:textStyle="bold" />
+        <TextView android:id="@+id/process_name"
+            android:layout_width="fill_parent" 
+            android:layout_height="wrap_content" />
+        <TextView android:id="@+id/package_list_header"
+            android:layout_width="fill_parent" 
+            android:layout_height="wrap_content"
+            android:text="@string/package_list_header"
+            android:textStyle="bold" />
+
+        <LinearLayout android:id="@+id/package_list"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingTop="4dip"
+            android:paddingBottom="6dip"
+            android:paddingRight="4dip" />
+
+    </LinearLayout>
+</ScrollView>
+
diff --git a/apps/Development/res/layout/radio_issue.xml b/apps/Development/res/layout/radio_issue.xml
new file mode 100644
index 0000000..b13b6bb
--- /dev/null
+++ b/apps/Development/res/layout/radio_issue.xml
@@ -0,0 +1,49 @@
+<!--
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent" android:layout_height="fill_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="fill_parent" android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button android:id="@+id/submit" 
+            android:textSize="14sp" 
+            android:layout_marginTop="8dip"
+            android:layout_width="wrap_content" android:layout_height="wrap_content" 
+            android:text="@string/radio_issue_submit_text"
+            />	         
+        <TextView android:id="@+id/instructions"
+            android:textSize="14sp" 
+            android:layout_marginTop="10dip"
+            android:layout_marginLeft="4dip"
+            android:layout_width="wrap_content" android:layout_height="wrap_content" 
+            android:text="@string/radio_issue_instructions_text"
+            />
+
+    </LinearLayout>
+
+    <EditText android:id="@+id/report_text"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:textSize="14sp"
+        />
+
+</LinearLayout>
diff --git a/apps/Development/res/layout/show_activity.xml b/apps/Development/res/layout/show_activity.xml
new file mode 100644
index 0000000..6a7617c
--- /dev/null
+++ b/apps/Development/res/layout/show_activity.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/Settings/res/layout/keyguard.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <LinearLayout
+        android:layout_width="fill_parent" android:layout_height="fill_parent"
+        android:orientation="vertical"
+        android:paddingTop="8dip" android:paddingLeft="2dip" android:paddingRight="2dip" >
+    
+        <TextView android:id="@+id/packageView"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" />
+    
+        <LinearLayout
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingTop="4dip"
+            android:paddingBottom="6dip" >
+    
+            <ImageView android:id="@+id/icon"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"
+                android:paddingRight="8dip" />
+                 
+            <LinearLayout
+                android:layout_width="fill_parent" android:layout_height="wrap_content"
+                android:orientation="vertical">
+    
+                <TextView android:id="@+id/classView"
+                    android:layout_width="fill_parent" android:layout_height="wrap_content" />
+    
+                <TextView android:id="@+id/label"
+                    android:layout_width="fill_parent" android:layout_height="wrap_content" />
+    
+                <TextView android:id="@+id/launch"
+                    android:layout_width="fill_parent" android:layout_height="wrap_content" />
+
+            </LinearLayout>
+    
+        </LinearLayout>
+    
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/show_activity_process_label" />
+    
+        <TextView android:id="@+id/process"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+    
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/show_activity_task_affinity_label" />
+    
+        <TextView android:id="@+id/taskAffinity"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+    
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/show_activity_required_permission_label" />
+    
+        <TextView android:id="@+id/permission"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+    
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/show_activity_multiprocess_label" />
+    
+        <TextView android:id="@+id/multiprocess"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+    
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/show_activity_clear_on_background_label" />
+    
+        <TextView android:id="@+id/clearOnBackground"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+    
+        <TextView style="@style/SummaryCategoryLayout"
+            android:layout_width="fill_parent" android:layout_height="wrap_content"
+            android:textStyle="bold" android:text="@string/show_activity_state_not_needed_label" />
+    
+        <TextView android:id="@+id/stateNotNeeded"
+            android:layout_width="fill_parent" android:layout_height="wrap_content" />
+    
+    </LinearLayout>
+
+</ScrollView>
+
diff --git a/apps/Development/res/layout/url_list.xml b/apps/Development/res/layout/url_list.xml
new file mode 100644
index 0000000..f004eff
--- /dev/null
+++ b/apps/Development/res/layout/url_list.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" 
+	android:layout_width="fill_parent"
+	android:layout_height="wrap_content"
+	android:textColor="#FF000000"
+	android:textSize="13sp"
+	android:maxLines="1" />
diff --git a/apps/Development/res/values/arrays.xml b/apps/Development/res/values/arrays.xml
new file mode 100644
index 0000000..cb38127
--- /dev/null
+++ b/apps/Development/res/values/arrays.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<resources>
+  <string-array name="glstester_services">
+    <item>mail</item>
+    <item>SID</item>
+    <item>LSID</item>
+    <item>youtube</item>
+    <item>YouTubeUser</item>
+    <item>sierra</item>
+    <item>lh2</item>
+    <item>cl</item>
+    <item>cp</item>
+  </string-array>
+</resources>
+
+			
diff --git a/apps/Development/res/values/strings.xml b/apps/Development/res/values/strings.xml
new file mode 100644
index 0000000..8d343ae
--- /dev/null
+++ b/apps/Development/res/values/strings.xml
@@ -0,0 +1,126 @@
+<?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="menu_upload_exceptions">Upload Exceptions</string>
+    <string name="menu_clear_exceptions">Clear Exceptions</string>
+
+        <string name="device_info_default">unknown</string>
+        <string name="device_info_uptime">Uptime</string>
+        <string name="device_info_awaketime">Awake Time</string>
+        <string name="device_info_asleeptime">Asleep Time</string>
+
+    <string name="build_id_label">Build ID</string>
+    <string name="build_date_label">Build Date</string>
+    <string name="build_type_label">Build Type</string>
+    <string name="build_product_label">Build Product</string>
+    <string name="build_user_label">Build Label</string>
+    <string name="build_host_label">Build Host</string>
+    <string name="gsm_version_baseband_label">Baseband Version</string>
+    <string name="gsm_version_ril_impl_label">RIL Impl Version</string>
+
+    <string name="turn_on_radio">Turn on radio</string>
+    <string name="turn_off_radio">Turn off radio</string>
+
+    <string name="refresh_networks">Refresh Network List</string>
+
+    <string name="radioInfo_menu_viewADN">View SIM Address Book</string>
+    <string name="radioInfo_menu_viewFDN">View Fixed Dialing Numbers</string>
+    <string name="radioInfo_menu_viewSDN">View Service Dialing Numbers</string>
+
+    <!-- Package summary in Package Browser -->
+    <string name="disabled"><i>disabled</i></string>
+    <string name="system"><i>system</i></string>
+    <string name="debuggable"><i>debuggable</i></string>
+    <string name="nocode"><i>no code</i></string>
+    <string name="persistent"><i>persistent</i></string>
+    <string name="restart">Restart</string>
+    <string name="package_summary_uid_label">User ID</string>
+    <string name="package_summary_task_label">Task Affinity</string>
+    <string name="package_summary_version_label">Version</string>
+    <string name="package_summary_source_label">Source</string>
+    <string name="package_summary_receivers_label">Receivers</string>
+    <string name="package_summary_data_label">Data</string>
+    <string name="package_summary_instrumentation_label">Instrumentation</string>
+    <string name="package_summary_process_label">Process</string>
+    <string name="package_summary_services_label">Services</string>
+    <string name="package_summary_providers_label">Providers</string>
+    <string name="package_summary_activities_label">Activities</string>
+
+    <!-- Activity details in Package Browser -->
+    <string name="none">"(none)"</string>
+    <string name="yes">Yes</string>
+    <string name="no">No</string>
+    <string name="launch_multiple">Multiple (normal)</string>
+    <string name="launch_singleTop">Single Top</string>
+    <string name="launch_singleTask">Single Task</string>
+    <string name="launch_singleInstance">Single Instance</string>
+    <string name="launch_unknown">"(Unknown)"</string>
+
+    <string name="development_settings_show_cpu_text">Show CPU usage</string>
+    <string name="development_settings_always_finish_text">Immediately destroy activities</string>
+    <string name="development_settings_show_load_text">Show running processes</string>
+    <string name="development_settings_show_updates_text">Show screen updates</string>
+    <string name="development_settings_enable_gl_text">Enable OpenGL ES (reboot needed)</string>
+    <string name="development_settings_allow_mock_location_text">Allow mock locations for testing</string>
+    <string name="development_settings_wait_for_debugger_text">Wait for debugger</string>
+    <string name="development_settings_show_background_text">Show background</string>
+    <string name="development_settings_show_xmpp_text">Show GTalk service connection status</string>
+    <string name="development_settings_debug_app_label_text">Debug App:</string>
+    <string name="development_settings_show_sleep_text">Show sleep state on LED</string>
+    <string name="development_settings_show_maps_compass_text">Show compass in Maps</string>
+    <string name="development_settings_keep_screen_on_text">Keep screen on while plugged in</string>
+
+    <string name="monkey_screen_initialActivity_text"></string>
+    <string name="monkey_screen_number_of_events_label">Number of Events: </string>
+    <string name="monkey_screen_start_text">Start</string>
+    <string name="monkey_screen_initial_activity_label">Initial Activity: </string>
+
+    <string name="radio_issue_submit_text">Submit report</string>
+    <string name="radio_issue_instructions_text">Enter a description of the issue.</string>
+
+    <string name="show_activity_clear_on_background_label">Clear on Background</string>
+    <string name="show_activity_task_affinity_label">Task Affinity</string>
+    <string name="show_activity_process_label">Process</string>
+    <string name="show_activity_state_not_needed_label">State Not Needed</string>
+    <string name="show_activity_required_permission_label">Required Permission</string>
+    <string name="show_activity_multiprocess_label">Multiprocess</string>
+
+    <string name="red_button_behavior_label">End Button Behavior</string>
+
+    <string name="gls_tester_label">GLS Tester</string>
+    <string name="gls_tester_prefer_hosted">Hosted</string>
+    <string name="gls_tester_require_google">Google</string>
+    <string name="gls_tester_get_accounts">List</string>
+    <string name="gls_tester_clear">Clear</string>
+    <string name="gls_tester_go">Go</string>
+    <string name="gls_tester_do_notification">Notify on failure</string>
+    <string name="gls_tester_run_intent">Run intent</string>
+    <string name="gls_tester_wipe_passwords">Wipe passwords</string>
+    <string name="process_name_header">Process Name:</string>
+    <string name="package_list_header">Packages in process:</string>
+    <string name="package_label">Package Name:</string>
+
+    <!-- Application configuration requirements related attributes -->
+    <string name="touchscreen_label">touchscreen:</string>
+    <string name="input_method_label">inputMethod:</string>
+    <string name="hard_keyboard_label">hardKeyboard:</string>
+    <string name="navigation_label">navigation:</string>
+    <string name="five_way_nav_label">five way nav:</string>
+</resources>
diff --git a/apps/Development/res/values/styles.xml b/apps/Development/res/values/styles.xml
new file mode 100644
index 0000000..591eed8
--- /dev/null
+++ b/apps/Development/res/values/styles.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="SummaryCategoryLayout">
+        <item name="android:layout_width">fill_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:orientation">vertical</item>
+    </style>
+    <style name="SummaryCategoryHeader">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:paddingTop">7dip</item>
+        <item name="android:paddingBottom">1dip</item>
+        <item name="android:maxLines">1</item>
+        <item name="android:textAppearance">@style/TextAppearance.SummaryCategoryHeader</item>
+    </style>
+    <style name="info_layout">
+        <item name="android:orientation">vertical</item>
+        <item name="android:paddingLeft">10dip</item>
+        <item name="android:paddingTop">10dip</item>
+        <item name="android:paddingRight">10dip</item>
+        <item name="android:paddingBottom">10dip</item>
+        <item name="android:layout_width">fill_parent</item>
+        <item name="android:layout_height">fill_parent</item>
+    </style>
+    <style name="entry_layout">
+        <item name="android:orientation">horizontal</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+    <style name="info_label">
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:textAppearance">@style/TextAppearance.info_label</item>
+        <item name="android:paddingRight">4dip</item>
+    </style>
+
+    <style name="info_value">
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:textAppearance">@style/TextAppearance.info_value</item>
+    </style>
+
+    <style name="TextAppearance" parent="android:TextAppearance">
+    </style>
+
+    <style name="TextAppearance.info_label">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textStyle">bold</item>
+    </style>
+
+    <style name="TextAppearance.SummaryCategoryHeader">
+        <item name="android:textStyle">bold</item>
+    </style>
+
+    <style name="TextAppearance.info_value">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textStyle">normal</item>
+    </style>
+
+</resources>
+
diff --git a/apps/Development/src/com/android/development/AppHwConfigList.java b/apps/Development/src/com/android/development/AppHwConfigList.java
new file mode 100755
index 0000000..52aff0d
--- /dev/null
+++ b/apps/Development/src/com/android/development/AppHwConfigList.java
@@ -0,0 +1,156 @@
+/*
+**
+** 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.development;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class AppHwConfigList extends ListActivity {
+    private static final String TAG = "AppHwConfigList";
+    PackageManager mPm;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mPm = getPackageManager();
+        mAdapter = new AppListAdapter(this);
+        if (mAdapter.getCount() <= 0) {
+            finish();
+        } else {
+            setListAdapter(mAdapter);
+        }
+    }
+    
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        PackageInfo app = mAdapter.appForPosition(position);
+        // TODO display all preference settings
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.setClass(this, AppHwPref.class);
+        intent.putExtra("packageName", app.packageName);
+        startActivity(intent);
+    }
+
+    private final class AppListAdapter extends BaseAdapter {
+        public AppListAdapter(Context context) {
+            mContext = context;
+            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+            List<ApplicationInfo> appList = mPm.getInstalledApplications(0);
+            for (ApplicationInfo app : appList) {
+                PackageInfo pkgInfo = null;
+                try {
+                    pkgInfo = mPm.getPackageInfo(app.packageName, 0);
+                } catch (NameNotFoundException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+                if ((pkgInfo != null)) {
+                        if(mList == null) {
+                             mList = new ArrayList<PackageInfo>();
+                         }
+                         mList.add(pkgInfo);
+                }
+            }
+            if (mList != null) {
+                Collections.sort(mList, sDisplayNameComparator);
+            }
+        }
+    
+        public PackageInfo appForPosition(int position) {
+            if (mList == null) {
+                return null;
+            }
+            return mList.get(position);
+        }
+
+        public int getCount() {
+            return mList != null ? mList.size() : 0;
+        }
+
+        public Object getItem(int position) {
+            return position;
+        }
+    
+        public long getItemId(int position) {
+            return position;
+        }
+    
+        public View getView(int position, View convertView, ViewGroup parent) {
+            View view;
+            if (convertView == null) {
+                view = mInflater.inflate(
+                        android.R.layout.simple_list_item_1, parent, false);
+            } else {
+                view = convertView;
+            }
+            bindView(view, mList.get(position));
+            return view;
+        }
+    
+        private final void bindView(View view, PackageInfo info) {
+            TextView text = (TextView)view.findViewById(android.R.id.text1);
+            text.setText(info != null ? info.applicationInfo.loadLabel(mPm) : "(none)");
+        }
+    
+        protected final Context mContext;
+        protected final LayoutInflater mInflater;
+        protected List<PackageInfo> mList;
+        
+    }
+
+    private final Comparator sDisplayNameComparator = new Comparator() {
+        public final int compare(Object a, Object b) {
+            CharSequence  sa = ((PackageInfo) a).applicationInfo.loadLabel(mPm);
+            CharSequence  sb = ((PackageInfo) b).applicationInfo.loadLabel(mPm);
+            return collator.compare(sa, sb);
+        }
+        private final Collator   collator = Collator.getInstance();
+    };
+
+    private AppListAdapter mAdapter;
+}
+
diff --git a/apps/Development/src/com/android/development/AppHwPref.java b/apps/Development/src/com/android/development/AppHwPref.java
new file mode 100644
index 0000000..bf0f84f
--- /dev/null
+++ b/apps/Development/src/com/android/development/AppHwPref.java
@@ -0,0 +1,228 @@
+/*
+**
+** 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.development;
+
+import com.android.development.R;
+import android.app.Activity;
+import android.app.ListActivity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.BaseAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+
+/* This activity displays the hardware configuration details
+ * of an application as defined in its manifests
+ */
+public class AppHwPref extends Activity {
+    private static final String TAG = "AppHwPref";
+    PackageManager mPm;
+    private static final int BASE = 0;
+    private static final int TOUCHSCREEN = BASE + 1;
+    private static final int KEYBOARD_TYPE = BASE + 2;
+    private static final int NAVIGATION = BASE + 3;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Intent intent = getIntent();
+        String pkgName = intent.getStringExtra("packageName");
+        if(pkgName == null) {
+           handleError("Null package name", true);
+           return;
+        }
+        mPm = getPackageManager();
+        PackageInfo pInfo;
+        try {
+            pInfo = mPm.getPackageInfo(pkgName, PackageManager.GET_CONFIGURATIONS);
+        } catch (NameNotFoundException e) {
+            pInfo = null;
+        }
+        if(pInfo == null) {
+            handleError("Failed retrieving packageInfo for pkg:"+pkgName, true);
+            return;
+        }
+        ConfigurationInfo appHwPref[] = pInfo.configPreferences;
+        
+        setContentView(R.layout.application_hw_pref);
+        if(appHwPref != null) {
+        	displayTextView(R.id.attr_package, pInfo.applicationInfo.loadLabel(mPm));
+        	displayTextView(R.id.attr_touchscreen, appHwPref, TOUCHSCREEN);
+        	displayTextView(R.id.attr_input_method, appHwPref, KEYBOARD_TYPE);
+        	displayTextView(R.id.attr_navigation, appHwPref, NAVIGATION);
+        	displayFlag(R.id.attr_hard_keyboard, ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD, appHwPref);
+        	displayFlag(R.id.attr_five_way_nav, ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV, appHwPref);
+        }
+    }
+    
+    void displayFlag(int viewId, int flagMask, ConfigurationInfo[] appHwPref) {
+    	if(appHwPref == null) {
+    		return;
+    	}
+    	boolean flag = false;
+    	for (int i = 0; i < appHwPref.length; i++) {
+    		ConfigurationInfo pref = appHwPref[i];
+        	if((pref.reqInputFeatures & flagMask) != 0) {
+        		flag = true;
+        		break;
+        	}
+        }
+        if(flag) {
+            displayTextView(viewId, "true");
+        } else {
+        	displayTextView(viewId, "false");
+        }
+    }
+    
+    void handleError(String errMsg, boolean finish) {
+        // TODO display dialog
+        Log.i(TAG, errMsg);
+        if(finish) {
+            finish();
+        }
+    }
+    
+    void displayTextView(int textViewId, CharSequence displayStr) {
+        TextView tView = (TextView) findViewById(textViewId);
+        if(displayStr != null) {
+            tView.setText(displayStr);
+        }
+    }
+    
+    void displayTextView(int viewId, ConfigurationInfo[] config, int type) {
+        if((config == null) || (config.length < 1)) {
+            return;
+        }
+        
+        HashSet<String> list = new HashSet<String>();
+        for(int i = 0; i < config.length; i++) {
+            String str = null;
+            switch(type) {
+            case TOUCHSCREEN:
+                str = getTouchScreenStr(config[i]);
+                break;
+            case KEYBOARD_TYPE:
+                str =  getKeyboardTypeStr(config[i]);
+                break;
+            case NAVIGATION:
+                str = getNavigationStr(config[i]);
+                break;
+            }
+            if(str != null) {
+                list.add(str);
+            }
+        }
+        String listStr = "";
+        boolean set = false;
+        for(String str : list) {
+            set = true;
+            listStr += str+",";
+        }
+        if(set) {
+            TextView tView = (TextView)findViewById(viewId);
+            CharSequence txt = listStr.subSequence(0, listStr.length()-1);
+            tView.setText(txt);
+        }
+    }
+    
+    String getTouchScreenStr(ConfigurationInfo appHwPref) {
+        if(appHwPref == null) {
+            handleError("Invalid HardwareConfigurationObject", true);
+            return null;
+        }
+        switch(appHwPref.reqTouchScreen) {
+        case Configuration.TOUCHSCREEN_FINGER:
+            return "finger";
+        case Configuration.TOUCHSCREEN_NOTOUCH:
+            return "notouch";
+        case Configuration.TOUCHSCREEN_STYLUS:
+            return "stylus";
+        case Configuration.TOUCHSCREEN_UNDEFINED:
+            return null;
+        default:
+                return null;
+        }
+    }
+    
+    String getKeyboardTypeStr(ConfigurationInfo appHwPref) {
+        if(appHwPref == null) {
+            handleError("Invalid HardwareConfigurationObject", true);
+            return null;
+        }
+        switch(appHwPref.reqKeyboardType) {
+        case Configuration.KEYBOARD_12KEY:
+            return "12key";
+        case Configuration.KEYBOARD_NOKEYS:
+            return "nokeys";
+        case Configuration.KEYBOARD_QWERTY:
+            return "querty";
+        case Configuration.KEYBOARD_UNDEFINED:
+            return null;
+        default:
+                return null;
+        }
+    }
+    
+    String getNavigationStr(ConfigurationInfo appHwPref) {
+        if(appHwPref == null) {
+            handleError("Invalid HardwareConfigurationObject", true);
+            return null;
+        }
+        switch(appHwPref.reqNavigation) {
+        case Configuration.NAVIGATION_DPAD:
+            return "dpad";
+        case Configuration.NAVIGATION_TRACKBALL:
+            return "trackball";
+        case Configuration.NAVIGATION_WHEEL:
+            return "wheel";
+        case Configuration.NAVIGATION_UNDEFINED:
+            return null;
+        default:
+                return null;
+        }
+    }
+    
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+    }
+}
+
diff --git a/apps/Development/src/com/android/development/AppPicker.java b/apps/Development/src/com/android/development/AppPicker.java
new file mode 100644
index 0000000..693defb
--- /dev/null
+++ b/apps/Development/src/com/android/development/AppPicker.java
@@ -0,0 +1,167 @@
+/* //device/java/android/android/app/ResolveListActivity.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.development;
+
+import android.app.ActivityManagerNative;
+import android.app.ListActivity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.text.Collator;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class AppPicker extends ListActivity
+{
+    @Override
+    protected void onCreate(Bundle icicle)
+    {
+        super.onCreate(icicle);
+
+        mAdapter = new AppListAdapter(this);
+        if (mAdapter.getCount() <= 0) {
+            finish();
+        } else {
+            setListAdapter(mAdapter);
+        }
+    }
+    
+    @Override
+    protected void onResume()
+    {
+        super.onResume();
+    }
+
+    @Override
+    protected void onStop()
+    {
+        super.onStop();
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+        ApplicationInfo app = mAdapter.appForPosition(position);
+        Intent intent = new Intent();
+        if (app != null) intent.setAction(app.packageName);
+        setResult(RESULT_OK, intent);
+        
+        /* This is a temporary fix for 824637 while it is blocked by 805226.  When 805226 is resolved, please remove this. */
+        try {
+            boolean waitForDebugger = Settings.System.getInt(
+                    getContentResolver(), Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
+            ActivityManagerNative.getDefault().setDebugApp(
+                    app != null ? app.packageName : null, waitForDebugger, true);
+        } catch (RemoteException ex) {
+        }
+        
+        finish();
+    }
+
+    private final class AppListAdapter extends BaseAdapter
+    {
+        public AppListAdapter(Context context)
+        {
+            mContext = context;
+            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+            mList = context.getPackageManager().getInstalledApplications(0);
+            if (mList != null) {
+                Collections.sort(mList, sDisplayNameComparator);
+                mList.add(0, null);
+            }
+        }
+    
+        public ApplicationInfo appForPosition(int position)
+        {
+            if (mList == null) {
+                return null;
+            }
+
+            return mList.get(position);
+        }
+
+        public int getCount()
+        {
+            return mList != null ? mList.size() : 0;
+        }
+
+        public Object getItem(int position)
+        {
+            return position;
+        }
+    
+        public long getItemId(int position)
+        {
+            return position;
+        }
+    
+        public View getView(int position, View convertView, ViewGroup parent)
+        {
+            View view;
+            if (convertView == null) {
+                view = mInflater.inflate(
+                        android.R.layout.simple_list_item_1, parent, false);
+            } else {
+                view = convertView;
+            }
+            bindView(view, mList.get(position));
+            return view;
+        }
+    
+        private final void bindView(View view, ApplicationInfo info)
+        {
+            TextView text = (TextView)view.findViewById(android.R.id.text1);
+    
+            text.setText(info != null ? info.packageName : "(none)");
+        }
+    
+        protected final Context mContext;
+        protected final LayoutInflater mInflater;
+    
+        protected List<ApplicationInfo> mList;
+        
+    }
+
+    private final static Comparator sDisplayNameComparator = new Comparator() {
+        public final int
+        compare(Object a, Object b)
+        {
+            CharSequence  sa = ((ApplicationInfo) a).packageName;
+            CharSequence  sb = ((ApplicationInfo) b).packageName;
+
+            return collator.compare(sa, sb);
+        }
+
+        private final Collator   collator = Collator.getInstance();
+    };
+
+    private AppListAdapter mAdapter;
+}
+
diff --git a/apps/Development/src/com/android/development/ArrayAdapter.java b/apps/Development/src/com/android/development/ArrayAdapter.java
new file mode 100644
index 0000000..378e98f
--- /dev/null
+++ b/apps/Development/src/com/android/development/ArrayAdapter.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package com.android.development;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.BaseAdapter;
+
+import java.util.List;
+
+public abstract class ArrayAdapter<E> extends BaseAdapter
+{
+    public ArrayAdapter(Context context, int layoutRes) {
+        mContext = context;
+        mInflater = (LayoutInflater)context.getSystemService(
+            Context.LAYOUT_INFLATER_SERVICE);
+        mLayoutRes = layoutRes;
+    }
+
+    public void setSource(List<E> list) {
+        mList = list;
+    }
+
+    public abstract void bindView(View view, E item);
+
+    public E itemForPosition(int position) {
+        if (mList == null) {
+            return null;
+        }
+
+        return mList.get(position);
+    }
+
+    public int getCount() {
+        return mList != null ? mList.size() : 0;
+    }
+
+    public Object getItem(int position) {
+        return position;
+    }
+
+    public long getItemId(int position) {
+        return position;
+    }
+
+    public View getView(int position, View convertView, ViewGroup parent) {
+        View view;
+        if (convertView == null) {
+            view = mInflater.inflate(mLayoutRes, parent, false);
+        } else {
+            view = convertView;
+        }
+        bindView(view, mList.get(position));
+        return view;
+    }
+
+    private final Context mContext;
+    private final LayoutInflater mInflater;
+    private final int mLayoutRes;
+    private List<E> mList;
+}
+
diff --git a/apps/Development/src/com/android/development/ColumnData.java b/apps/Development/src/com/android/development/ColumnData.java
new file mode 100644
index 0000000..28781c2
--- /dev/null
+++ b/apps/Development/src/com/android/development/ColumnData.java
@@ -0,0 +1,31 @@
+/* //device/apps/Notes/NotesList.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.development;
+
+import java.util.ArrayList;
+
+class ColumnData
+{
+    ColumnData(String k, String v)
+    {
+        key = k;
+        value = v;
+    }
+    public String key;
+    public String value;
+}
+
diff --git a/apps/Development/src/com/android/development/DataList.java b/apps/Development/src/com/android/development/DataList.java
new file mode 100644
index 0000000..5dee2fe
--- /dev/null
+++ b/apps/Development/src/com/android/development/DataList.java
@@ -0,0 +1,134 @@
+/* //device/apps/Notes/NotesList.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.development;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+
+import java.util.ArrayList;
+
+public class DataList extends ListActivity
+{
+    public void onCreate(Bundle icicle)
+    {
+        super.onCreate(icicle);
+
+        Intent intent = getIntent();
+
+        mCursor = getContentResolver().query(intent.getData(), null, null, null, null);
+        mDisplay = intent.getStringExtra("display");
+        if (mDisplay == null) {
+            mDisplay = "_id";
+        }
+        
+        if (mCursor != null) {
+            setListAdapter(new SimpleCursorAdapter(
+                    this,
+                    R.layout.url_list,
+                    mCursor,
+                    new String[] {mDisplay},
+                    new int[] {android.R.id.text1}));
+        }
+    }
+
+    public void onStop()
+    {
+        super.onStop();
+
+        if (mCursor != null) {
+            mCursor.deactivate();
+        }
+    }
+
+    public void onResume()
+    {
+        super.onResume();
+
+        if (mCursor != null) {
+            mCursor.requery();
+        }
+        
+        setTitle("Showing " + mDisplay);
+    }
+
+    public boolean onCreateOptionsMenu(Menu menu)
+    {
+        super.onCreateOptionsMenu(menu);
+        menu.add(0, 0, 0, "Requery").setOnMenuItemClickListener(mRequery);
+        return true;
+    }
+
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+        mCursor.moveToPosition(position);
+
+        ArrayList<ColumnData> data = new ArrayList<ColumnData>();
+
+        String[] columnNames = mCursor.getColumnNames();
+        for (int i=0; i<columnNames.length; i++) {
+            String str = mCursor.getString(i);
+            ColumnData cd = new ColumnData(columnNames[i], str);
+            data.add(cd);
+        }
+
+
+        Uri uri = null;
+        int idCol = mCursor.getColumnIndex("_id");
+        if (idCol >= 0) {
+            uri = Uri.withAppendedPath(getIntent().getData(), mCursor.getString(idCol));
+        }
+        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+        intent.setClass(this, Details.class);
+
+        intent.putExtra("data", data);
+        int displayColumn = mCursor.getColumnIndex(mDisplay);
+        if (displayColumn >= 0) {
+            intent.putExtra("title",
+                                ((ColumnData)data.get(displayColumn)).value);
+        }
+
+        startActivity(intent);
+    }
+
+    MenuItem.OnMenuItemClickListener mRequery = new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            // Should just do requery on cursor, but 
+            // doesn't work right now.  So do this instead.
+            mCursor.requery();
+            if (mCursor != null) {
+                setListAdapter(new SimpleCursorAdapter(
+                        DataList.this,
+                        R.layout.url_list,
+                        mCursor,
+                        new String[] {mDisplay},
+                        new int[] {android.R.id.text1}));
+            }
+            return true;
+        }
+    };
+
+    private String mDisplay;
+    private Cursor mCursor;
+}
diff --git a/apps/Development/src/com/android/development/Details.java b/apps/Development/src/com/android/development/Details.java
new file mode 100644
index 0000000..16722a3
--- /dev/null
+++ b/apps/Development/src/com/android/development/Details.java
@@ -0,0 +1,157 @@
+/* //device/apps/Notes/NotesList.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.development;
+
+import java.util.ArrayList;
+
+import android.content.Intent;
+import android.app.Activity;
+import android.database.Cursor;
+import android.graphics.Typeface;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class Details extends Activity
+{
+    public void onCreate(Bundle icicle)
+    {
+        super.onCreate(icicle);
+
+        Intent intent = getIntent();
+
+        String title = intent.getStringExtra("title");
+        if (title == null) {
+            title = "Details";
+        }
+        setTitle(title);
+
+        mScrollView = new ScrollView(this);
+        setContentView(mScrollView);
+        mScrollView.setFocusable(true);
+
+        mData = (ArrayList<ColumnData>)getIntent().getExtra("data");
+        addDataViews();
+    }
+
+    public void onResume()
+    {
+        super.onResume();
+    }
+
+    public boolean onCreateOptionsMenu(Menu menu)
+    {
+        super.onCreateOptionsMenu(menu);
+        menu.add(0, 0, 0, "Requery").setOnMenuItemClickListener(mRequery);
+        menu.add(0, 0, 0, "Print to stdout").setOnMenuItemClickListener(mPrintToStdout);
+        return true;
+    }
+
+    void addDataViews()
+    {
+        int oldScroll = 0;
+
+        if (mLinearLayout != null) {
+            mScrollView.removeView(mLinearLayout);
+        }
+        mLinearLayout = new LinearLayout(this);
+        mScrollView.addView(mLinearLayout, new ViewGroup.LayoutParams(
+                                        ViewGroup.LayoutParams.FILL_PARENT,
+                                        ViewGroup.LayoutParams.FILL_PARENT));
+        mLinearLayout.setOrientation(LinearLayout.VERTICAL);
+
+        // Here in onStart, we're given data.  We use that because some
+        // data that we show is transient and can't be retrieved from a url.
+        // We'll try to use that in requery
+        int count = mData.size();
+        for (int i=0; i<count; i++) {
+            ColumnData cd = mData.get(i);
+            TextView label = makeView(cd.key, true, 12);
+            TextView contents = makeView(cd.value, false, 12);
+            contents.setPadding(3, 0, 0, i==count-1?0:3);
+            mLinearLayout.addView(label, lazy());
+            mLinearLayout.addView(contents, lazy());
+        }
+    }
+
+    TextView makeView(String str, boolean bold, int fontSize)
+    {
+        if (str == null) {
+            str = "(null)";
+        }
+        TextView v = new TextView(this);
+        v.setText(str);
+        v.setTextSize(fontSize);
+        if (bold) {
+            v.setTypeface(Typeface.DEFAULT_BOLD);
+        }
+        return v;
+    }
+    
+    LinearLayout.LayoutParams lazy()
+    {
+        return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
+                                 ViewGroup.LayoutParams.WRAP_CONTENT, 0);
+    }
+
+    MenuItem.OnMenuItemClickListener mRequery = new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            Intent intent = getIntent();
+            Cursor c = getContentResolver().query(intent.getData(), null, null, null, null);
+            if (c != null && c.moveToNext()) {
+                mData.clear();
+                String[] columnNames = c.getColumnNames();
+                for (int i=0; i<columnNames.length; i++) {
+                    String str = c.getString(i);
+                    ColumnData cd = new ColumnData(columnNames[i], str);
+                    mData.add(cd);
+                }
+                addDataViews();
+            } else {
+                TextView error = new TextView(Details.this);
+                error.setText("Showing old data.\nURL couldn't be requeried:\n"
+                        + intent.getData());
+                error.setTextColor(0xffff0000);
+                error.setTextSize(11);
+                mLinearLayout.addView(error, 0, lazy());
+            }
+            return true;
+        }
+    };
+
+    MenuItem.OnMenuItemClickListener mPrintToStdout = new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            System.out.println("=== begin data ===");
+            int count = mData.size();
+            for (int i=0; i<count; i++) {
+                ColumnData cd = mData.get(i);
+                System.out.println("  " + cd.key + ": " + cd.value);
+            }
+            System.out.println("=== end data ===");
+            return true;
+        }
+    };
+
+    LinearLayout mLinearLayout;
+    ScrollView mScrollView;
+    ArrayList<ColumnData> mData;
+}
diff --git a/apps/Development/src/com/android/development/Development.java b/apps/Development/src/com/android/development/Development.java
new file mode 100644
index 0000000..a3979f2
--- /dev/null
+++ b/apps/Development/src/com/android/development/Development.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package com.android.development;
+
+import android.app.LauncherActivity;
+import android.content.Intent;
+
+public class Development extends LauncherActivity
+{
+    @Override
+    protected Intent getTargetIntent() {
+        Intent targetIntent = new Intent(Intent.ACTION_MAIN, null);
+        targetIntent.addCategory(Intent.CATEGORY_TEST);
+        targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return targetIntent;
+    }
+}
diff --git a/apps/Development/src/com/android/development/DevelopmentSettings.java b/apps/Development/src/com/android/development/DevelopmentSettings.java
new file mode 100644
index 0000000..cdc1e0a
--- /dev/null
+++ b/apps/Development/src/com/android/development/DevelopmentSettings.java
@@ -0,0 +1,510 @@
+/* //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.development;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.ServiceManager;
+import android.os.ServiceManagerNative;
+import android.provider.Settings;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.Spinner;
+import android.widget.AdapterView.OnItemSelectedListener;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.Map;
+
+public class DevelopmentSettings extends Activity {
+    private static final String TAG = "DevelopmentSettings";
+    private static final int DEBUG_APP_REQUEST = 1;
+
+    private Button mDebugAppButton;
+    private CheckBox mWaitForDebuggerCB;
+    private CheckBox mAlwaysFinishCB;
+    private CheckBox mShowLoadCB;
+    private CheckBox mShowCpuCB;
+    private CheckBox mEnableGLCB;
+    private CheckBox mShowUpdatesCB;
+    private CheckBox mShowBackgroundCB;
+    private CheckBox mShowSleepCB;
+    private CheckBox mShowMapsCompassCB;
+    private CheckBox mShowXmppCB;
+    private Spinner mMaxProcsSpinner;
+    private Spinner mWindowAnimationScaleSpinner;
+    private Spinner mTransitionAnimationScaleSpinner;
+    private Spinner mFontHintingSpinner;
+
+    private String mDebugApp;
+    private boolean mWaitForDebugger;
+    private boolean mAlwaysFinish;
+    private int mProcessLimit;
+    private boolean mShowSleep;
+    private boolean mShowMapsCompass;
+    private boolean mShowXmpp;
+    private AnimationScaleSelectedListener mWindowAnimationScale
+            = new AnimationScaleSelectedListener(0);
+    private AnimationScaleSelectedListener mTransitionAnimationScale
+            = new AnimationScaleSelectedListener(1);
+    private SharedPreferences mSharedPrefs;
+    private IWindowManager mWindowManager;
+
+    private static final boolean FONT_HINTING_ENABLED = true;
+    private static final String  FONT_HINTING_FILE = "/data/misc/font-hack";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.development_settings);
+
+        mDebugAppButton = (Button)findViewById(R.id.debug_app);
+        mDebugAppButton.setOnClickListener(mDebugAppClicked);
+        mWaitForDebuggerCB = (CheckBox)findViewById(R.id.wait_for_debugger);
+        mWaitForDebuggerCB.setOnClickListener(mWaitForDebuggerClicked);
+        mAlwaysFinishCB = (CheckBox)findViewById(R.id.always_finish);
+        mAlwaysFinishCB.setOnClickListener(mAlwaysFinishClicked);
+        mShowLoadCB = (CheckBox)findViewById(R.id.show_load);
+        mShowLoadCB.setOnClickListener(mShowLoadClicked);
+        mShowCpuCB = (CheckBox)findViewById(R.id.show_cpu);
+        mShowCpuCB.setOnCheckedChangeListener(new SurfaceFlingerClicker(1000));
+        mEnableGLCB = (CheckBox)findViewById(R.id.enable_gl);
+        mEnableGLCB.getLayoutParams().height = 0; // doesn't do anything
+        mEnableGLCB.setOnCheckedChangeListener(new SurfaceFlingerClicker(1004));
+        mShowUpdatesCB = (CheckBox)findViewById(R.id.show_updates);
+        mShowUpdatesCB.setOnCheckedChangeListener(new SurfaceFlingerClicker(1002));
+        mShowBackgroundCB = (CheckBox)findViewById(R.id.show_background);
+        mShowBackgroundCB.setOnCheckedChangeListener(new SurfaceFlingerClicker(1003));
+        mShowSleepCB = (CheckBox)findViewById(R.id.show_sleep);
+        mShowSleepCB.setOnClickListener(mShowSleepClicked);
+        mShowMapsCompassCB = (CheckBox)findViewById(R.id.show_maps_compass);
+        mShowMapsCompassCB.setOnClickListener(mShowMapsCompassClicked);
+        mShowXmppCB = (CheckBox)findViewById(R.id.show_xmpp);
+        mShowXmppCB.setOnClickListener(mShowXmppClicked);
+        mMaxProcsSpinner = (Spinner)findViewById(R.id.max_procs);
+        mMaxProcsSpinner.setOnItemSelectedListener(mMaxProcsChanged);
+        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
+                this,
+                android.R.layout.simple_spinner_item,
+                new String[] {
+                        "No App Process Limit",
+                        "Max 1 App Process",
+                        "Max 2 App Processes",
+                        "Max 3 App Processes",
+                        "Max 4 App Processes" });
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mMaxProcsSpinner.setAdapter(adapter);
+        mWindowAnimationScaleSpinner = setupAnimationSpinner(
+                R.id.window_animation_scale, mWindowAnimationScale, "Window");
+        mTransitionAnimationScaleSpinner = setupAnimationSpinner(
+                R.id.transition_animation_scale, mTransitionAnimationScale, "Transition");
+
+        if (FONT_HINTING_ENABLED) {
+            mFontHintingSpinner = (Spinner)findViewById(R.id.font_hinting);
+            mFontHintingSpinner.setOnItemSelectedListener(mFontHintingChanged);
+            adapter = new ArrayAdapter<String>(
+                    this,
+                    android.R.layout.simple_spinner_item,
+                    new String[] {
+                            "Light Hinting",
+                            "Medium Hinting" });
+            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+            mFontHintingSpinner.setAdapter(adapter);
+        }
+        mSharedPrefs = getSharedPreferences("global", 0);
+        mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+    }
+
+    Spinner setupAnimationSpinner(int resid,
+            AnimationScaleSelectedListener listener, String name) {
+        Spinner spinner = (Spinner)findViewById(resid);
+        spinner.setOnItemSelectedListener(listener);
+        ArrayAdapter adapter = new ArrayAdapter<String>(
+                this,
+                android.R.layout.simple_spinner_item,
+                new String[] {
+                        name + " Animation Scale 1x",
+                        name + " Animation Scale 2x",
+                        name + " Animation Scale 5x",
+                        name + " Animation Scale 10x",
+                        name + " Animation Off" });
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        spinner.setAdapter(adapter);
+        listener.spinner = spinner;
+        return spinner;
+    }
+    
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateDebugOptions();
+        updateFinishOptions();
+        updateProcessLimitOptions();
+        updateSharedOptions();
+        updateFlingerOptions();
+        updateSleepOptions();
+        updateMapsCompassOptions();
+        updateXmppOptions();        
+
+        try {
+            FileInputStream  in = new FileInputStream( FONT_HINTING_FILE );
+            int    mode = in.read() - 48;
+            if (mode >= 0 && mode < 3)
+                mFontHintingSpinner.setSelection(mode);
+            in.close();
+        } catch (Exception e) {
+        }
+
+        mWindowAnimationScale.load();
+        mTransitionAnimationScale.load();
+    }
+
+    private void writeDebugOptions() {
+        try {
+            ActivityManagerNative.getDefault().setDebugApp(
+                mDebugApp, mWaitForDebugger, true);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    private void updateDebugOptions() {
+        mDebugApp = Settings.System.getString(
+            getContentResolver(), Settings.System.DEBUG_APP);
+        mWaitForDebugger = Settings.System.getInt(
+            getContentResolver(), Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
+
+        mDebugAppButton.setText(
+            mDebugApp == null || mDebugApp.length() == 0 ? "(none)" : mDebugApp);
+        mWaitForDebuggerCB.setChecked(mWaitForDebugger);
+    }
+
+    private void writeFinishOptions() {
+        try {
+            ActivityManagerNative.getDefault().setAlwaysFinish(mAlwaysFinish);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    private void updateFinishOptions() {
+        mAlwaysFinish = Settings.System.getInt(
+            getContentResolver(), Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
+        mAlwaysFinishCB.setChecked(mAlwaysFinish);
+    }
+
+    private void writeProcessLimitOptions() {
+        try {
+            ActivityManagerNative.getDefault().setProcessLimit(mProcessLimit);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    private void updateProcessLimitOptions() {
+        try {
+            mProcessLimit = ActivityManagerNative.getDefault().getProcessLimit();
+            mMaxProcsSpinner.setSelection(mProcessLimit);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    private void updateSharedOptions() {
+        mShowLoadCB.setChecked(Settings.System.getInt(getContentResolver(),
+                Settings.System.SHOW_PROCESSES, 0) != 0);
+    }
+
+    private void updateFlingerOptions() {
+        // magic communication with surface flinger.
+        try {
+            IBinder flinger = ServiceManager.getService("SurfaceFlinger");
+            if (flinger != null) {
+                Parcel data = Parcel.obtain();
+                Parcel reply = Parcel.obtain();
+                data.writeInterfaceToken("android.ui.ISurfaceComposer");
+                flinger.transact(1010, data, reply, 0);
+                int v;
+                v = reply.readInt();
+                mShowCpuCB.setChecked(v != 0);
+                v = reply.readInt();
+                mEnableGLCB.setChecked(v != 0);
+                v = reply.readInt();
+                mShowUpdatesCB.setChecked(v != 0);
+                v = reply.readInt();
+                mShowBackgroundCB.setChecked(v != 0);
+                reply.recycle();
+                data.recycle();
+            }
+        } catch (RemoteException ex) {
+        }
+    }
+
+    private void writeSleepOptions() {
+        try {
+            FileOutputStream os = new FileOutputStream(
+                "/sys/devices/platform/gpio_sleep_debug/enable", true);
+            if(mShowSleep)
+                os.write(new byte[] { (byte)'1' });
+            else
+                os.write(new byte[] { (byte)'0' });
+            os.close();
+        } catch (Exception e) {
+            Log.w(TAG, "Failed setting gpio_sleep_debug");
+        }
+    }
+
+    private void updateSleepOptions() {
+        try {
+            FileInputStream is = new FileInputStream(
+                "/sys/devices/platform/gpio_sleep_debug/enable");
+            int character = is.read();
+            mShowSleep = character == '1';
+            is.close();
+        } catch (Exception e) {
+            Log.w(TAG, "Failed reading gpio_sleep_debug");
+            mShowSleep = false;
+        }
+        mShowSleepCB.setChecked(mShowSleep);
+    }
+
+    private void writeMapsCompassOptions() {
+        try {
+            Context c = createPackageContext("com.google.android.apps.maps", 0);
+            c.getSharedPreferences("extra-features", MODE_WORLD_WRITEABLE)
+                .edit()
+                .putBoolean("compass", mShowMapsCompass)
+                .commit();
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Failed setting maps compass");
+            e.printStackTrace();
+        }
+    }
+
+    private void updateMapsCompassOptions() {
+        try {
+            Context c = createPackageContext("com.google.android.apps.maps", 0);
+            mShowMapsCompass = c.getSharedPreferences("extra-features", MODE_WORLD_READABLE)
+                .getBoolean("compass", false);
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Failed reading maps compass");
+            e.printStackTrace();
+        }
+        mShowMapsCompassCB.setChecked(mShowMapsCompass);
+    }
+
+    private void writeXmppOptions() {
+        Settings.System.setShowGTalkServiceStatus(getContentResolver(), mShowXmpp);
+    }
+
+    private void updateXmppOptions() {
+        mShowXmpp = Settings.System.getShowGTalkServiceStatus(getContentResolver());
+        mShowXmppCB.setChecked(mShowXmpp);
+    }
+
+    private View.OnClickListener mDebugAppClicked = new View.OnClickListener() {
+        public void onClick(View v) {
+            Intent intent = new Intent(Intent.ACTION_MAIN);
+            intent.setClass(DevelopmentSettings.this, AppPicker.class);
+            startActivityForResult(intent, DEBUG_APP_REQUEST);
+        }
+    };
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+        if (requestCode == DEBUG_APP_REQUEST && resultCode == RESULT_OK) {
+            mDebugApp = intent.getAction();
+            writeDebugOptions();
+            updateDebugOptions();
+        }
+    }
+
+    private View.OnClickListener mWaitForDebuggerClicked =
+            new View.OnClickListener() {
+        public void onClick(View v) {
+            mWaitForDebugger = ((CheckBox)v).isChecked();
+            writeDebugOptions();
+            updateDebugOptions();
+        }
+    };
+
+    private View.OnClickListener mAlwaysFinishClicked =
+            new View.OnClickListener() {
+        public void onClick(View v) {
+            mAlwaysFinish = ((CheckBox)v).isChecked();
+            writeFinishOptions();
+            updateFinishOptions();
+        }
+    };
+
+    private View.OnClickListener mShowLoadClicked = new View.OnClickListener() {
+        public void onClick(View v) {
+            boolean value = ((CheckBox)v).isChecked();
+            Settings.System.putInt(getContentResolver(),
+                    Settings.System.SHOW_PROCESSES, value ? 1 : 0);
+            Intent service = (new Intent())
+                    .setClassName("android", "com.android.server.LoadAverageService");
+            if (value) {
+                startService(service);
+            } else {
+                stopService(service);
+            }
+        }
+    };
+
+    private class SurfaceFlingerClicker implements CheckBox.OnCheckedChangeListener {
+        SurfaceFlingerClicker(int code) {
+            mCode = code;
+        }
+
+        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+            try {
+                IBinder flinger = ServiceManager.getService("SurfaceFlinger");
+                if (flinger != null) {
+                    Parcel data = Parcel.obtain();
+                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
+                    data.writeInt(isChecked ? 1 : 0);
+                    flinger.transact(mCode, data, null, 0);
+                    data.recycle();
+
+                    updateFlingerOptions();
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+
+        final int mCode;
+    }
+
+    private View.OnClickListener mShowSleepClicked =
+            new View.OnClickListener() {
+        public void onClick(View v) {
+            mShowSleep = ((CheckBox)v).isChecked();
+            writeSleepOptions();
+            updateSleepOptions();
+        }
+    };
+
+    private View.OnClickListener mShowMapsCompassClicked =
+        new View.OnClickListener() {
+        public void onClick(View v) {
+            mShowMapsCompass = ((CheckBox)v).isChecked();
+            writeMapsCompassOptions();
+            updateMapsCompassOptions();
+        }
+    };
+
+    
+    private View.OnClickListener mShowXmppClicked = new View.OnClickListener() {
+        public void onClick(View v) {
+            mShowXmpp = ((CheckBox)v).isChecked();
+            // can streamline these calls, but keeping consistent with the
+            // other development settings code.
+            writeXmppOptions();
+            updateXmppOptions();
+        }
+    };
+
+    private Spinner.OnItemSelectedListener mMaxProcsChanged
+                                    = new Spinner.OnItemSelectedListener() {
+        public void onItemSelected(android.widget.AdapterView av, View v,
+                                    int position, long id) {
+            mProcessLimit = position;
+            writeProcessLimitOptions();
+        }
+
+        public void onNothingSelected(android.widget.AdapterView av) {
+        }
+    };
+
+    private Spinner.OnItemSelectedListener mFontHintingChanged
+                                    = new Spinner.OnItemSelectedListener() {
+        public void onItemSelected(android.widget.AdapterView  av, View v,
+                                    int position, long id) {
+            try {
+                FileOutputStream  out = new FileOutputStream( FONT_HINTING_FILE );
+                out.write(position+48);
+                out.close();
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to write font hinting settings to /data/misc/font-hack");
+            }
+        }
+
+        public void onNothingSelected(android.widget.AdapterView av) {
+        }
+    };
+
+    class AnimationScaleSelectedListener implements OnItemSelectedListener {
+        final int which;
+        float scale;
+        Spinner spinner;
+        
+        AnimationScaleSelectedListener(int _which) {
+            which = _which;
+        }
+        
+        void load() {
+            try {
+                scale = mWindowManager.getAnimationScale(which);
+
+                if (scale > 0.1f && scale < 2.0f) {
+                    spinner.setSelection(0);
+                } else if (scale >= 2.0f && scale < 3.0f) {
+                    spinner.setSelection(1);
+                } else if (scale >= 4.9f && scale < 6.0f) {
+                    spinner.setSelection(2);
+                }  else if (scale >= 9.9f && scale < 11.0f) {
+                    spinner.setSelection(3);
+                } else {
+                    spinner.setSelection(4);
+                }
+            } catch (RemoteException e) {
+            }
+        }
+        
+        public void onItemSelected(android.widget.AdapterView av, View v,
+                int position, long id) {
+            switch (position) {
+                case 0: scale = 1.0f; break;
+                case 1: scale = 2.0f; break;
+                case 2: scale = 5.0f; break;
+                case 3: scale = 10.0f; break;
+                case 4: scale = 0.0f; break;
+                default: break;
+            }
+
+            try {
+                mWindowManager.setAnimationScale(which, scale);
+            } catch (RemoteException e) {
+            }
+        }
+
+        public void onNothingSelected(android.widget.AdapterView av) {
+        }
+    }
+}
diff --git a/apps/Development/src/com/android/development/EnterURL.java b/apps/Development/src/com/android/development/EnterURL.java
new file mode 100644
index 0000000..76b8a34
--- /dev/null
+++ b/apps/Development/src/com/android/development/EnterURL.java
@@ -0,0 +1,310 @@
+/* //device/apps/Notes/NotesList.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.development;
+
+import android.app.ListActivity;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.format.DateUtils;
+import android.util.AttributeSet;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+import android.graphics.Rect;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+
+public class EnterURL extends ListActivity
+{
+    private static final int DATABASE_VERSION = 1;
+    public static class UrlEditText extends EditText
+    {
+        public UrlEditText(Context context, AttributeSet attrs)
+        {
+            super(context, attrs);
+        }
+        
+        @Override
+        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect)
+        {
+            super.onFocusChanged(focused, direction, previouslyFocusedRect);
+            if (focused) {
+                Editable text = getText();
+                String str = text.toString();
+                int highlightStart = 0;
+                if (str.startsWith("content://")) {
+                    highlightStart = "content://".length();
+                }
+                Selection.setSelection(text, highlightStart, text.length());
+            }
+        }
+    }
+
+    public static class DisplayEditText extends EditText
+    {
+        public DisplayEditText(Context context, AttributeSet attrs)
+        {
+            super(context, attrs);
+        }
+        
+        @Override
+        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect)
+        {
+            super.onFocusChanged(focused, direction, previouslyFocusedRect);
+            if (focused) {
+                Editable text = getText();
+                Selection.setSelection(text, 0, text.length());
+            }
+        }
+    }
+
+    @Override
+    public View onCreateView(String name, Context context, AttributeSet attrs)
+    {
+        if (name.equals("com.android.development.UrlEditText")) {
+            return new UrlEditText(this, attrs);
+        }
+        if (name.equals("com.android.development.DisplayEditText")) {
+            return new DisplayEditText(this, attrs);
+        }
+        return null;
+    }
+
+    View.OnClickListener mViewItemAction = new View.OnClickListener () {
+        public void onClick(View v)
+        {
+            String url = mUrlField.getText().toString();
+            String display = mDisplayField.getText().toString();
+            viewItem(url, display);
+        }
+    };
+
+    public void onCreate(Bundle icicle)
+    {
+        super.onCreate(icicle);
+        setContentView(R.layout.enter_url);
+
+        // display
+        mDisplayField = (DisplayEditText)findViewById(R.id.display_edit_text);
+        mDisplayField.setOnClickListener(mViewItemAction);
+        // url
+        mUrlField = (UrlEditText)findViewById(R.id.url_edit_text);
+        mUrlField.setOnClickListener(mViewItemAction);
+    }
+
+    public void onStop()
+    {
+        super.onStop();
+
+        if (mCursor != null) {
+            mCursor.deactivate();
+        }
+    }
+
+    public void onResume()
+    {
+        super.onResume();
+
+        // show the history
+        loadPrefs();
+        fillListView();
+        if (mHistory.size() > 0) {
+            ListView lv = this.getListView();
+            lv.setSelection(0);
+            lv.requestFocus();
+        }
+    }
+
+    public boolean onCreateOptionsMenu(Menu menu)
+    {
+        super.onCreateOptionsMenu(menu);
+        menu.add(0, 0, 0, "Clear Bookmarks").setOnMenuItemClickListener(mClearBookmarks);
+        return true;
+    }
+
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+        HistoryEntry he = mHistory.get(position);
+        viewItem(he.url, he.display);
+    }
+
+    private final void viewItem(String url, String display)
+    {
+        // -------------- save this in the history ----------------
+        // look in the history
+        int count = mHistory.size();
+        int i;
+        for (i=0; i<count; i++) {
+            HistoryEntry he = mHistory.get(i);
+            if (he.url.equals(url) && he.display.equals(display)) {
+                he.updateAccessTime();
+                mHistory.remove(i);
+                mHistory.add(0, he);
+                break;
+            }
+        }
+        if (i >= count) {
+            // didn't find it, add it first
+            HistoryEntry he = new HistoryEntry();
+            he.url = url;
+            he.display = display;
+            he.updateAccessTime();
+            mHistory.add(0, he);
+        }
+
+        savePrefs();
+
+        // -------------- view it ---------------------------------
+        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+        intent.setClass(this, DataList.class);
+        intent.putExtra("display", display);
+        startActivity(intent);
+    }
+
+    MenuItem.OnMenuItemClickListener mClearBookmarks = new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            mHistory.clear();
+            savePrefs();
+            fillListView();
+            return true;
+        }
+    };
+
+    private void fillListView()
+    {
+        loadPrefs();
+        ArrayList<HashMap<String, String>> d = new ArrayList<HashMap<String, String>>();
+        int count = mHistory.size();
+        for (int i=0; i<count; i++) {
+            HashMap<String, String> m = new HashMap<String, String>();
+            HistoryEntry he = mHistory.get(i);
+            m.put("title", he.url + " (" + he.display + ")");
+            d.add(m);
+        }
+        setListAdapter(new SimpleAdapter(this, d, R.layout.url_list,
+                                         new String[] {"title"},
+                                         new int[] {android.R.id.text1}));
+    }
+
+    SQLiteDatabase openDB()
+    {
+        SQLiteDatabase db = null;
+        db = openOrCreateDatabase("inspector.db", 0, null);
+        int version = db.getVersion();
+        if (version != DATABASE_VERSION) {
+            db.execSQL("CREATE TABLE History ("
+                        + " url TEXT,"
+                        + " display TEXT,"
+                        + " lastAccessTime TEXT"
+                        + ");");
+            db.execSQL("CREATE TABLE FieldState ("
+                        + " url TEXT,"
+                        + " display TEXT"
+                        + ");");
+            db.setVersion(DATABASE_VERSION);
+        }
+        return db;
+    }
+
+    private void loadPrefs()
+    {
+        SQLiteDatabase db = openDB();
+        Cursor c = db.query("History",
+                            new String[] { "url", "display", "lastAccessTime" },
+                            null, null, null, null, "lastAccessTime DESC");
+        int urlCol = c.getColumnIndex("url");
+        int accessCol = c.getColumnIndex("lastAccessTime");
+        int displayCol = c.getColumnIndex("display");
+        mHistory.clear();
+        while (c.moveToNext()) {
+            HistoryEntry he = new HistoryEntry();
+            he.url = c.getString(urlCol);
+            he.display = c.getString(displayCol);
+            he.lastAccessTime = c.getString(accessCol);
+            mHistory.add(he);
+        }
+
+        c = db.query("FieldState", null, null, null, null, null, null);
+        if (c.moveToNext()) {
+            urlCol = c.getColumnIndex("url");
+            displayCol = c.getColumnIndex("display");
+            mUrlField.setText(c.getString(urlCol));
+            mDisplayField.setText(c.getString(displayCol));
+        } else {
+            mDisplayField.setText("_id");
+            mUrlField.setText("content://");
+        }
+
+        db.close();
+    }
+
+    private void savePrefs()
+    {
+        ContentValues m;
+        HistoryEntry he;
+
+        SQLiteDatabase db = openDB();
+        db.execSQL("DELETE FROM History;");
+        int count = mHistory.size();
+        for (int i=0; i<count; i++) {
+            m = new ContentValues();
+            he = mHistory.get(i);
+            m.put("url", he.url);
+            m.put("display", he.display);
+            m.put("lastAccessTime", he.lastAccessTime);
+            db.insert("History", null, m);
+        }
+
+        db.execSQL("DELETE FROM FieldState");
+        m = new ContentValues();
+        m.put("url", mUrlField.getText().toString());
+        m.put("display", mDisplayField.getText().toString());
+        db.insert("FieldState", null, m);
+
+        db.close();
+    }
+
+    private class HistoryEntry
+    {
+        public String url;
+        public String display;
+        public String lastAccessTime;
+        public void updateAccessTime()
+        {
+            this.lastAccessTime = DateUtils.writeDateTime(
+                                                    new GregorianCalendar());
+        }
+    }
+
+    private ArrayList<HistoryEntry> mHistory = new ArrayList<HistoryEntry>();
+    private UrlEditText mUrlField;
+    private DisplayEditText mDisplayField;
+    private Cursor mCursor;
+}
diff --git a/apps/Development/src/com/android/development/ExceptionBrowser.java b/apps/Development/src/com/android/development/ExceptionBrowser.java
new file mode 100644
index 0000000..63270aa
--- /dev/null
+++ b/apps/Development/src/com/android/development/ExceptionBrowser.java
@@ -0,0 +1,171 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+package com.android.development;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.database.ContentObserver;
+import android.database.DataSetObserver;
+import android.graphics.Typeface;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Checkin;
+import android.server.data.CrashData;
+import android.server.data.ThrowableData;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.KeyEvent;
+import android.widget.*;
+
+import org.apache.commons.codec.binary.Base64;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ *
+ */
+public class ExceptionBrowser extends ListActivity {
+    /** Logging identifier. */
+    private static final String TAG = "ExceptionBrowser";
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        Cursor cursor = getContentResolver().query(
+                Checkin.Crashes.CONTENT_URI,
+                new String[] { Checkin.Crashes._ID, Checkin.Crashes.DATA },
+                null, null, null);
+
+        if (cursor != null) {
+            startManagingCursor(cursor);
+
+            setListAdapter(new CursorAdapter(this, cursor, true) {
+                public View newView(Context context, Cursor c, ViewGroup v) {
+                    return new CrashListItem(context);
+                }
+
+                public void bindView(View view, Context c, Cursor cursor) {
+                    CrashListItem item = (CrashListItem) view;
+                    try {
+                        String data = cursor.getString(1);
+                        CrashData crash = new CrashData(
+                            new DataInputStream(
+                                new ByteArrayInputStream(
+                                    Base64.decodeBase64(data.getBytes()))));
+
+                        ThrowableData exc = crash.getThrowableData();
+                        item.setText(exc.getType() + ": " + exc.getMessage());
+                        item.setCrashData(crash);
+                    } catch (IOException e) {
+                        item.setText("Invalid crash: " + e);
+                        Log.e(TAG, "Invalid crash", e);
+                    }
+                }
+            });
+        } else {
+            // No database, no exceptions, empty list.
+            setListAdapter(new BaseAdapter() {
+                public int getCount() {
+                    return 0;
+                }
+
+                public Object getItem(int position) {
+                    throw new AssertionError();
+                }
+
+                public long getItemId(int position) {
+                    throw new AssertionError();
+                }
+
+                public View getView(int position, View convertView,
+                        ViewGroup parent) {
+                    throw new AssertionError();
+                }
+            });
+        }
+    }
+
+    private static final int UPLOAD_ID = Menu.FIRST;
+    private static final int CLEAR_ID = Menu.FIRST + 1;
+
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+
+        menu.add(0, UPLOAD_ID, 0, R.string.menu_upload_exceptions);
+        menu.add(0, CLEAR_ID, 0, R.string.menu_clear_exceptions);
+
+        return true;
+    }
+
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle all of the possible menu actions.
+        switch (item.getItemId()) {
+            case UPLOAD_ID:
+                sendBroadcast(new Intent(Checkin.TriggerIntent.ACTION));
+                break;
+            case CLEAR_ID:
+                getContentResolver().delete(
+                        Checkin.Crashes.CONTENT_URI, null, null);
+                break;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    static class CrashListItem extends TextView {
+        CrashData crashData = null;
+
+        public CrashListItem(Context context) {
+            super(context);
+            setTextSize(10);
+            setTypeface(Typeface.MONOSPACE);
+        }
+
+        public CrashData getCrashData() {
+            return crashData;
+        }
+
+        public void setCrashData(CrashData crashData) {
+            this.crashData = crashData;
+        }
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View view, int pos, long id) {
+        // TODO: Use a generic VIEW action on the crash's content URI.
+        CrashData crash = ((CrashListItem) view).getCrashData();
+        if (crash != null) {
+            Intent intent = new Intent();
+            intent.setClass(this, StacktraceViewer.class);
+            intent.putExtra(
+                    CrashData.class.getName(),
+                    crash.getThrowableData().toString());
+            startActivity(intent);
+        }
+    }
+}
diff --git a/apps/Development/src/com/android/development/GLSTester.java b/apps/Development/src/com/android/development/GLSTester.java
new file mode 100644
index 0000000..4995b4d
--- /dev/null
+++ b/apps/Development/src/com/android/development/GLSTester.java
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+package com.android.development;
+
+import com.google.android.googleapps.GoogleLoginCredentialsResult;
+import com.google.android.googlelogin.GoogleLoginServiceConstants;
+import com.google.android.googleapps.IGoogleLoginService;
+import com.google.android.googleapps.LoginData;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.Spinner;
+
+/**
+ * Using a LogTextBox to display a scrollable text area
+ * to which text is appended.
+ *
+ */
+public class GLSTester extends Activity {
+
+    private static final String TAG = "GLSTester";
+
+    private LogTextBox mText;
+
+    private IGoogleLoginService mGls = null;
+    private ServiceConnection mConnection = null;
+
+    CheckBox mDoNotify = null;
+    CheckBox mRunIntent = null;
+    Spinner mService = null;
+    EditText mUsernameEdit = null;
+
+    private class Listener implements View.OnClickListener {
+        public Listener() {
+        }
+
+        public void onClick(View v) {
+            if (mGls == null) {
+                mText.append("mGls is null\n");
+                return;
+            }
+            try {
+                String service = (String) mService.getSelectedItem();
+                mText.append("service: " + service + "\n");
+
+                String account = mUsernameEdit.getText().toString();
+                if (account.length() == 0) {
+                    account = null;
+                }
+                mText.append("account: " + account + "\n");
+                GoogleLoginCredentialsResult result =
+                    mGls.blockingGetCredentials(account, service, mDoNotify.isChecked());
+                mText.append("result account: " + result.getAccount() + "\n");
+                mText.append("result string: " + result.getCredentialsString() + "\n");
+                Intent intent = result.getCredentialsIntent();
+                mText.append("result intent: " + intent + "\n");
+
+                if (intent != null && mRunIntent.isChecked()) {
+                    startActivityForResult(intent, 0);
+                }
+            } catch (RemoteException e) {
+                mText.append("caught exception " + e + "\n");
+            }
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        mText.append("resultCode: " + resultCode + "\n");
+        if (data != null) {
+            mText.append("account: " +
+                         data.getStringExtra(GoogleLoginServiceConstants.AUTH_ACCOUNT_KEY) + "\n");
+            mText.append("authtoken: " +
+                         data.getStringExtra(GoogleLoginServiceConstants.AUTHTOKEN_KEY) + "\n");
+        } else {
+            mText.append("intent is null");
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Open a connection to the Google Login Service.  Return the account.
+        mConnection = new ServiceConnection() {
+                public void onServiceConnected(ComponentName className, IBinder service) {
+                    mGls = IGoogleLoginService.Stub.asInterface(service);
+                }
+                public void onServiceDisconnected(ComponentName className) {
+                    mGls = null;
+                }
+            };
+
+        bindService(GoogleLoginServiceConstants.SERVICE_INTENT,
+                    mConnection, Context.BIND_AUTO_CREATE);
+
+        setContentView(R.layout.gls_tester);
+
+        mText = (LogTextBox) findViewById(R.id.text);
+        mText.append("Hello, world!\n");
+        Log.v(TAG, "hello, world!");
+
+        mDoNotify = (CheckBox) findViewById(R.id.do_notification);
+        mRunIntent = (CheckBox) findViewById(R.id.run_intent);
+        mRunIntent.setChecked(true);
+
+        mService = (Spinner) findViewById(R.id.service_spinner);
+
+        mUsernameEdit = (EditText) findViewById(R.id.username_edit);
+
+        Button b;
+        b = (Button) findViewById(R.id.require_google);
+        b.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                try {
+                    String account = mGls.getAccount(GoogleLoginServiceConstants.REQUIRE_GOOGLE);
+                    mText.append("REQUIRE_GOOGLE gave: " + account + "\n");
+                    mUsernameEdit.setText(account == null ? "" : account);
+                } catch (RemoteException e) {
+                    mText.append("exception: " + e + "\n");
+                }
+            } });
+
+        b = (Button) findViewById(R.id.prefer_hosted);
+        b.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                try {
+                    String account = mGls.getAccount(GoogleLoginServiceConstants.PREFER_HOSTED);
+                    mText.append("PREFER_HOSTED gave: " + account + "\n");
+                    mUsernameEdit.setText(account == null ? "" : account);
+                } catch (RemoteException e) {
+                    mText.append("exception: " + e + "\n");
+                }
+            } });
+
+
+        b = (Button) findViewById(R.id.get_accounts);
+        b.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                try {
+                    String[] accounts = mGls.getAccounts();
+                    mText.append("account list: (" + accounts.length + " entries)\n");
+                    for (String username: accounts) {
+                        mText.append("  " + username + "\n");
+                    }
+                } catch (RemoteException e) {
+                    mText.append("exception: " + e + "\n");
+                }
+            } });
+
+        b = (Button) findViewById(R.id.clear);
+        b.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                mText.setText("");
+            } });
+
+        b = (Button) findViewById(R.id.go);
+        b.setOnClickListener(new Listener());
+
+        b = (Button) findViewById(R.id.wipe_passwords);
+        b.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                mText.setText("wiping passwords:\n");
+                try {
+                    String[] accounts = mGls.getAccounts();
+                    LoginData ld = new LoginData();
+                    for (String username: accounts) {
+                        ld.mUsername = username;
+                        mGls.updatePassword(ld);
+                        mText.append("  " + username + "\n");
+                    }
+                    mText.append("done.\n");
+                } catch (RemoteException e) {
+                    mText.append("caught exception " + e + "\n");
+                }
+            } });
+
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unbindService(mConnection);
+    }
+}
diff --git a/apps/Development/src/com/android/development/IRemoteService.aidl b/apps/Development/src/com/android/development/IRemoteService.aidl
new file mode 100644
index 0000000..0a60d34
--- /dev/null
+++ b/apps/Development/src/com/android/development/IRemoteService.aidl
@@ -0,0 +1,24 @@
+/* //device/samples/SampleCode/src/com/android/development/IRemoteService.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+package com.android.development;
+
+interface IRemoteService
+{
+    int getPid();
+}
+
diff --git a/apps/Development/src/com/android/development/InstrumentationList.java b/apps/Development/src/com/android/development/InstrumentationList.java
new file mode 100644
index 0000000..88f09f8
--- /dev/null
+++ b/apps/Development/src/com/android/development/InstrumentationList.java
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+package com.android.development;
+
+import android.app.ActivityManagerNative;
+import android.app.IInstrumentationWatcher;
+import android.app.ListActivity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.Collections;
+import java.util.List;
+
+class InstrumentationAdapter extends BaseAdapter
+{
+    private PackageManager mPM;
+
+    public InstrumentationAdapter(Context context, String targetPackage)
+    {
+        mContext = context;
+        mTargetPackage = targetPackage;
+        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mPM = context.getPackageManager();
+
+        mList = context.getPackageManager().queryInstrumentation(mTargetPackage, 0);
+        if (mList != null) {
+            Collections.sort(mList, new InstrumentationInfo.DisplayNameComparator(mPM));
+        }
+    }
+
+    public ComponentName instrumentationForPosition(int position)
+    {
+        if (mList == null) {
+            return null;
+        }
+        InstrumentationInfo ii = mList.get(position);
+        return new ComponentName(ii.packageName, ii.name);
+    }
+
+    public int getCount()
+    {
+        return mList != null ? mList.size() : 0;
+    }
+
+    public Object getItem(int position)
+    {
+        return position;
+    }
+
+    public long getItemId(int position)
+    {
+        return position;
+    }
+
+    public View getView(int position, View convertView, ViewGroup parent)
+    {
+        View view;
+        if (convertView == null) {
+            view = mInflater.inflate(
+                    android.R.layout.simple_list_item_1, parent, false);
+        } else {
+            view = convertView;
+        }
+        bindView(view, mList.get(position));
+        return view;
+    }
+
+    private final void bindView(View view, InstrumentationInfo info)
+    {
+        TextView text = (TextView)view.findViewById(android.R.id.text1);
+        CharSequence label = info.loadLabel(mPM);
+        text.setText(label != null ? label : info.name);
+    }
+
+    protected final Context mContext;
+    protected final String mTargetPackage;
+    protected final LayoutInflater mInflater;
+
+    protected List<InstrumentationInfo> mList;
+}
+
+public class InstrumentationList extends ListActivity
+{
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mProfilingMode = icicle != null && icicle.containsKey("profiling");
+        setListAdapter(new InstrumentationAdapter(this, null));
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu)
+    {
+        super.onCreateOptionsMenu(menu);
+        mProfilingItem = menu.add(0, 0, 0, "Profiling Mode")
+        .setOnMenuItemClickListener(mProfilingCallback);
+        mProfilingItem.setCheckable(true);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu)
+    {
+        super.onPrepareOptionsMenu(menu);
+        mProfilingItem.setChecked(mProfilingMode);
+        return true;
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState)
+    {
+        if (mProfilingMode) {
+            outState.putBoolean("profiling", true);
+        }
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+        ComponentName className = ((InstrumentationAdapter)getListAdapter()).
+            instrumentationForPosition(position);
+        if (className != null) {
+            String profilingFile = null;
+            if (mProfilingMode) {
+                profilingFile = "/tmp/trace/" + className + ".dmtrace";
+            }
+            try {
+                ActivityManagerNative.getDefault().
+                    startInstrumentation(className, profilingFile, 0, null, mWatcher);
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    private MenuItem.OnMenuItemClickListener mProfilingCallback =
+            new MenuItem.OnMenuItemClickListener()
+    {
+        public boolean onMenuItemClick(MenuItem item) {
+            mProfilingMode = !mProfilingMode;
+            return true;
+        }
+    };
+
+    private IInstrumentationWatcher mWatcher = new IInstrumentationWatcher.Stub() {
+        
+        public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
+            if (results != null) {
+                for (String key : results.keySet()) {
+                    Log.i("instrumentation", 
+                            "INSTRUMENTATION_STATUS_RESULT: " + key + "=" + results.get(key));
+                }
+            }
+            Log.i("instrumentation", "INSTRUMENTATION_STATUS_CODE: " + resultCode);
+        }
+    	public void instrumentationFinished(ComponentName name,
+    	            int resultCode, Bundle results) {
+            if (results != null) {
+                for (String key : results.keySet()) {
+                    Log.i("instrumentation", 
+                            "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key));
+                }
+            }
+            Log.i("instrumentation", "INSTRUMENTATION_CODE: " + resultCode);
+    	}
+    };
+
+    private MenuItem mProfilingItem;
+    private boolean mProfilingMode;
+}
diff --git a/apps/Development/src/com/android/development/LogTextBox.java b/apps/Development/src/com/android/development/LogTextBox.java
new file mode 100644
index 0000000..2f99ab2
--- /dev/null
+++ b/apps/Development/src/com/android/development/LogTextBox.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.development;
+
+import android.widget.TextView;
+import android.content.Context;
+import android.text.method.ScrollingMovementMethod;
+import android.text.method.MovementMethod;
+import android.text.method.KeyListener;
+import android.text.method.TransformationMethod;
+import android.text.Editable;
+import android.util.AttributeSet;
+
+
+/**
+ * This is a TextView that is Editable and by default scrollable,
+ * like EditText without a cursor.
+ *
+ * <p>
+ * <b>XML attributes</b>
+ * <p>
+ * See
+ * {@link android.R.styleable#TextView TextView Attributes},
+ * {@link android.R.styleable#View View Attributes}
+ */
+public class LogTextBox extends TextView {
+    public LogTextBox(Context context) {
+        this(context, null);
+    }
+
+    public LogTextBox(Context context, AttributeSet attrs) {
+        this(context, attrs, android.R.attr.textViewStyle);
+    }
+
+    public LogTextBox(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected boolean getDefaultEditable() {
+        return true;
+    }
+
+    @Override
+    protected MovementMethod getDefaultMovementMethod() {
+        return ScrollingMovementMethod.getInstance();
+    }
+
+    @Override
+    public Editable getText() {
+        return (Editable) super.getText();
+    }
+
+    @Override
+    public void setText(CharSequence text, BufferType type) {
+        super.setText(text, BufferType.EDITABLE);
+    }
+}
diff --git a/apps/Development/src/com/android/development/LogViewer.java b/apps/Development/src/com/android/development/LogViewer.java
new file mode 100644
index 0000000..aadc0d4
--- /dev/null
+++ b/apps/Development/src/com/android/development/LogViewer.java
@@ -0,0 +1,169 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+package com.android.development;
+
+import static com.android.internal.util.CharSequences.forAsciiBytes;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.FileOutputStream;
+import java.net.Socket;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Bundle;
+import android.util.Log;
+import android.graphics.Typeface;
+import android.view.Gravity;
+
+/**
+ * Views the device log.
+ */
+public class LogViewer extends Activity {
+
+    static final String TAG = LogViewer.class.getSimpleName();
+
+    FileOutputStream logger;
+
+    volatile boolean active = true;
+    Handler handler;
+    LogTextBox text;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.log_viewer);
+        this.handler = new Handler();
+
+        text = (LogTextBox) findViewById(R.id.text);
+
+        text.setTextSize(10);
+        text.setHorizontallyScrolling(true);
+        text.setTypeface(Typeface.MONOSPACE);
+        text.setGravity(Gravity.BOTTOM | Gravity.LEFT);
+
+        this.active = true;
+        try {
+            logger = new FileOutputStream("/tmp/logviewer.txt");
+            new Thread(new LogReader()).start();
+        } catch (IOException e) {
+            appendThrowable(e);
+        }
+    }
+
+    private void appendThrowable(Throwable t) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("Error reading log: ");
+        builder.append(Log.getStackTraceString(t));
+        text.getText().append(builder);
+    }
+
+    private class LogReader implements Runnable {
+
+        final Socket socket;
+        final DataInputStream in;
+        StringBuilder builder = new StringBuilder();
+        long lastTime = System.currentTimeMillis();
+
+        private static final int HEADER_SIZE = 24;
+
+        public LogReader() throws IOException {
+            this.socket = new Socket("127.0.0.1", 5040);
+            this.in = new DataInputStream(this.socket.getInputStream());
+            // Write two newlines to indicate "no reader args"
+            this.socket.getOutputStream().write('\n');
+            this.socket.getOutputStream().write('\n');
+        }
+
+        public void run() {
+            while (active) {
+                try {
+                    while (in.available() > 0) {
+                        logger.write("Reading message.\n".getBytes());
+
+                        int length = in.readInt();
+                        byte[] bytes = new byte[length];
+                        in.readFully(bytes);
+
+                        int tagEnd = next0(bytes, HEADER_SIZE);
+                        int fileEnd = next0(bytes, tagEnd + 1);
+                        int messageEnd = next0(bytes, fileEnd + 1);
+
+                        CharSequence tag
+                                = forAsciiBytes(bytes, HEADER_SIZE, tagEnd);
+                        CharSequence message
+                                = forAsciiBytes(bytes, fileEnd + 1, messageEnd);
+
+                        builder.append(tag)
+                                .append(": ")
+                                .append(message)
+                                .append("\n");
+                    }
+
+                    logger.write("Updating UI.\n".getBytes());
+                    handler.post(new AppendCharacters(builder));
+                    builder = new StringBuilder();
+
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {}
+                } catch (final IOException e) {
+                    handler.post(new AppendThrowable(e));
+                }
+            }
+        }
+    }
+
+    static int next0(byte[] bytes, int start) {
+        for (int current = start; current < bytes.length; current++) {
+            if (bytes[current] == 0)
+                return current;
+        }
+        return bytes.length;
+    }
+
+    private class AppendThrowable implements Runnable {
+
+        private final Throwable t;
+
+        public AppendThrowable(Throwable t) {
+            this.t = t;
+        }
+
+        public void run() {
+            appendThrowable(t);
+        }
+    }
+
+    private class AppendCharacters implements Runnable {
+
+        private final CharSequence message;
+
+        public AppendCharacters(CharSequence message) {
+            this.message = message;
+        }
+
+        public void run() {
+            text.getText().append(message);
+//            try {
+//                logger.write(builder.toString().getBytes());
+//            } catch (IOException e) {
+//                appendThrowable(e);
+//            }
+        }
+    }
+}
diff --git a/apps/Development/src/com/android/development/MediaScannerActivity.java b/apps/Development/src/com/android/development/MediaScannerActivity.java
new file mode 100644
index 0000000..f78910a
--- /dev/null
+++ b/apps/Development/src/com/android/development/MediaScannerActivity.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.development;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.BroadcastReceiver;
+import android.net.Uri;
+import android.os.Environment;
+import android.widget.TextView;
+
+public class MediaScannerActivity extends Activity
+{
+    public MediaScannerActivity() {
+    }
+ 
+    /** Called when the activity is first created or resumed. */
+    @Override
+    public void onResume() {
+        super.onResume();
+        
+        setContentView(R.layout.media_scanner_activity);
+        
+        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
+        intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
+        intentFilter.addDataScheme("file");
+        registerReceiver(mReceiver, intentFilter);
+        
+        sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"
+                + Environment.getExternalStorageDirectory())));
+            
+        mTitle = (TextView) findViewById(R.id.title);
+        mTitle.setText("Sent ACTION_MEDIA_MOUNTED to trigger the Media Scanner.");
+    }
+
+    /** Called when the activity going into the background or being destroyed. */
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(mReceiver);
+    }
+    
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
+                mTitle.setText("Media Scanner started scanning " + intent.getData().getPath());     
+            }
+            else if (intent.getAction().equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
+                mTitle.setText("Media Scanner finished scanning " + intent.getData().getPath());     
+            }
+        }
+    };
+
+    private TextView mTitle;
+}
diff --git a/apps/Development/src/com/android/development/PackageBrowser.java b/apps/Development/src/com/android/development/PackageBrowser.java
new file mode 100644
index 0000000..e4c233f
--- /dev/null
+++ b/apps/Development/src/com/android/development/PackageBrowser.java
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ */
+
+package com.android.development;
+
+import android.app.AlertDialog;
+import android.app.ListActivity;
+import android.content.Context;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.BroadcastReceiver;
+import android.content.pm.PackageInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.Handler;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.text.Collator;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class PackageBrowser extends ListActivity
+{
+    private PackageListAdapter mAdapter;
+    private List<PackageInfo> mPackageInfoList = null;
+    private Handler mHandler;
+
+    public class PackageListAdapter extends ArrayAdapter<PackageInfo>
+    {
+
+        public PackageListAdapter(Context context)
+        {
+            super(context, android.R.layout.simple_list_item_1);
+            mPackageInfoList = context.getPackageManager().getInstalledPackages(0);
+            if (mPackageInfoList != null) {
+                Collections.sort(mPackageInfoList, sDisplayNameComparator);
+            }
+            setSource(mPackageInfoList);
+        }
+    
+        @Override
+        public void bindView(View view, PackageInfo info)
+        {
+            TextView text = (TextView)view.findViewById(android.R.id.text1);
+            text.setText(info.packageName);
+        }
+    }
+
+    /**
+     * Receives notifications when applications are added/removed.
+     */
+    private class ApplicationsIntentReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // todo: this is a bit brute force.  We should probably get the action and package name
+            //       from the intent and just add to or delete from the mPackageInfoList
+            setupAdapter();
+        }
+    }
+
+    private final static Comparator sDisplayNameComparator = new Comparator() {
+        public final int
+        compare(Object a, Object b)
+        {
+            CharSequence  sa = ((PackageInfo) a).packageName;
+            CharSequence  sb = ((PackageInfo) b).packageName;
+            return collator.compare(sa, sb);
+        }
+
+        private final Collator   collator = Collator.getInstance();
+    };
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setupAdapter();
+        mHandler= new Handler();
+        registerIntentReceivers();
+    }
+
+    private void setupAdapter() {
+        mAdapter = new PackageListAdapter(this);
+        setListAdapter(mAdapter);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        menu.add(0, 0, 0, "Delete package").setOnMenuItemClickListener(
+                new MenuItem.OnMenuItemClickListener() {
+            public boolean onMenuItemClick(MenuItem item) {
+                deletePackage();
+                return true;
+            }
+        });
+        return true;
+    }
+
+    private void deletePackage() {
+        final int curSelection = getSelectedItemPosition();
+        if (curSelection >= 0) {
+            // todo: verification dialog for package deletion
+            final PackageInfo packageInfo = mAdapter.itemForPosition(curSelection);
+            if (packageInfo != null) {
+                getPackageManager().deletePackage(packageInfo.packageName,
+                                                  new IPackageDeleteObserver.Stub() {
+                    public void packageDeleted(boolean succeeded) throws RemoteException {
+                        if (succeeded) {
+                            mPackageInfoList.remove(curSelection);
+                            mHandler.post(new Runnable() {
+                                    public void run() {
+                                        mAdapter.notifyDataSetChanged();
+                                    }
+                                });
+
+                            // todo: verification dialog for data directory
+                            final String dataPath = packageInfo.applicationInfo.dataDir;
+                            // todo: delete the data directory
+                        } else {
+                            mHandler.post(new Runnable() {
+                                    public void run() {
+                                        new AlertDialog.Builder(PackageBrowser.this)
+                                            .setTitle("Oops")
+                                            .setMessage("Could not delete package." +
+                                                "  Maybe it is in /system/app rather than /data/app?")
+                                            .show();
+                                    }
+                                });
+
+                        }
+                    }
+                },
+                                                  0);
+            }
+        }
+    }
+
+    private void registerIntentReceivers() {
+        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addDataScheme("package");
+        registerReceiver(new ApplicationsIntentReceiver(), filter);
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+        PackageInfo info =
+            mAdapter.itemForPosition(position);
+        if (info != null) {
+            Intent intent = new Intent(
+                null, Uri.fromParts("package", info.packageName, null));
+            intent.setClass(this, PackageSummary.class);
+            startActivity(intent);
+        }
+    }
+}
diff --git a/apps/Development/src/com/android/development/PackageSummary.java b/apps/Development/src/com/android/development/PackageSummary.java
new file mode 100644
index 0000000..a6bbbb2
--- /dev/null
+++ b/apps/Development/src/com/android/development/PackageSummary.java
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+package com.android.development;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+
+public class PackageSummary extends Activity {
+
+    String mPackageName;
+    private TextView mPackage;
+    private ImageView mIconImage;
+    private TextView mClass;
+    private TextView mLabel;
+    private View mDisabled;
+    private View mSystem;
+    private View mDebuggable;
+    private View mNoCode;
+    private View mPersistent;
+    private Button mRestart;
+    private TextView mTask;
+    private TextView mVersion;
+    private TextView mProcess;
+    private TextView mUid;
+    private TextView mSource;
+    private TextView mData;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.package_summary);
+
+        final PackageManager pm = getPackageManager();
+
+        mPackage = (TextView)findViewById(R.id.packageView);
+        mIconImage = (ImageView)findViewById(R.id.icon);
+        mClass = (TextView)findViewById(R.id.classView);
+        mLabel = (TextView)findViewById(R.id.label);
+        mDisabled = findViewById(R.id.disabled);
+        mSystem = findViewById(R.id.system);
+        mDebuggable = findViewById(R.id.debuggable);
+        mNoCode = findViewById(R.id.nocode);
+        mPersistent = findViewById(R.id.persistent);
+        mRestart = (Button)findViewById(R.id.restart);
+        mTask = (TextView)findViewById(R.id.task);
+        mVersion = (TextView)findViewById(R.id.version);
+        mUid = (TextView)findViewById(R.id.uid);
+        mProcess = (TextView)findViewById(R.id.process);
+        mSource = (TextView)findViewById(R.id.source);
+        mData = (TextView)findViewById(R.id.data);
+
+        mPackageName = getIntent().getData().getSchemeSpecificPart();
+        PackageInfo info = null;
+        try {
+            info = pm.getPackageInfo(mPackageName,
+                PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
+                | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS
+                | PackageManager.GET_INSTRUMENTATION);
+        } catch (PackageManager.NameNotFoundException e) {
+        }
+
+        if (info != null) {
+            mPackage.setText(info.packageName);
+            CharSequence label = null;
+            String appClass = null;
+            if (info.applicationInfo != null) {
+                mIconImage.setImageDrawable(
+                    pm.getApplicationIcon(info.applicationInfo));
+                label = info.applicationInfo.nonLocalizedLabel;
+                appClass = info.applicationInfo.className;
+                if (info.applicationInfo.enabled) {
+                    mDisabled.setVisibility(View.GONE);
+                }
+                if ((info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    mSystem.setVisibility(View.GONE);
+                }
+                if ((info.applicationInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+                    mDebuggable.setVisibility(View.GONE);
+                }
+                if ((info.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
+                    mNoCode.setVisibility(View.GONE);
+                }
+                if ((info.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
+                    mPersistent.setVisibility(View.GONE);
+                }
+                mUid.setText(Integer.toString(info.applicationInfo.uid));
+                mProcess.setText(info.applicationInfo.processName);
+                if (info.versionName != null) {
+                    mVersion.setText(info.versionName + " (#" + info.versionCode + ")");
+                } else {
+                    mVersion.setText("(#" + info.versionCode + ")");
+                }
+                mSource.setText(info.applicationInfo.sourceDir);
+                mData.setText(info.applicationInfo.dataDir);
+                if (info.applicationInfo.taskAffinity != null) {
+                    mTask.setText("\"" + info.applicationInfo.taskAffinity + "\"");
+                } else {
+                    mTask.setText("(No Task Affinity)");
+                }
+            }
+            if (appClass != null) {
+                if (appClass.startsWith(info.packageName + "."))
+                    mClass.setText(appClass.substring(info.packageName.length()));
+                else
+                    mClass.setText(appClass);
+            } else {
+                mClass.setText("(No Application Class)");
+            }
+            if (label != null) {
+                mLabel.setText("\"" + label + "\"");
+            } else {
+                mLabel.setText("(No Label)");
+            }
+
+            mRestart.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View v) {
+                    try {
+                        ActivityManagerNative.getDefault().restartPackage(mPackageName);
+                    } catch (RemoteException e) {
+                    }
+                }
+            });
+            
+            final LayoutInflater inflate =
+                (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.WRAP_CONTENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT);
+            LinearLayout activities = (LinearLayout)findViewById(R.id.activities);
+            LinearLayout receivers = (LinearLayout)findViewById(R.id.receivers);
+            LinearLayout services = (LinearLayout)findViewById(R.id.services);
+            LinearLayout providers = (LinearLayout)findViewById(R.id.providers);
+            LinearLayout instrumentation = (LinearLayout)findViewById(R.id.instrumentation);
+
+            if (info.activities != null) {
+                final int N = info.activities.length;
+                for (int i=0; i<N; i++) {
+                    ActivityInfo ai = info.activities[i];
+                    // If an activity is disabled then the ActivityInfo will be null 
+                    if (ai != null) {
+                        Button view = (Button)inflate.inflate(
+                                R.layout.package_item, null, false);
+                        view.setOnClickListener(new ActivityOnClick(
+                                new ComponentName(ai.applicationInfo.packageName,
+                                                  ai.name)));
+                        setItemText(view, info, ai.name);
+                        activities.addView(view, lp);
+                    }
+                }
+            } else {
+                activities.setVisibility(View.GONE);
+            }
+
+            if (info.receivers != null) {
+                final int N = info.receivers.length;
+                for (int i=0; i<N; i++) {
+                    ActivityInfo ai = info.receivers[i];
+                    Button view = (Button)inflate.inflate(
+                        R.layout.package_item, null, false);
+                    setItemText(view, info, ai.name);
+                    receivers.addView(view, lp);
+                }
+            } else {
+                receivers.setVisibility(View.GONE);
+            }
+
+            if (info.services != null) {
+                final int N = info.services.length;
+                for (int i=0; i<N; i++) {
+                    ServiceInfo si = info.services[i];
+                    Button view = (Button)inflate.inflate(
+                        R.layout.package_item, null, false);
+                    setItemText(view, info, si.name);
+                    services.addView(view, lp);
+                }
+            } else {
+                services.setVisibility(View.GONE);
+            }
+
+            if (info.providers != null) {
+                final int N = info.providers.length;
+                for (int i=0; i<N; i++) {
+                    ProviderInfo pi = info.providers[i];
+                    Button view = (Button)inflate.inflate(
+                        R.layout.package_item, null, false);
+                    setItemText(view, info, pi.name);
+                    providers.addView(view, lp);
+                }
+            } else {
+                providers.setVisibility(View.GONE);
+            }
+
+            if (info.instrumentation != null) {
+                final int N = info.instrumentation.length;
+                for (int i=0; i<N; i++) {
+                    InstrumentationInfo ii = info.instrumentation[i];
+                    Button view = (Button)inflate.inflate(
+                        R.layout.package_item, null, false);
+                    setItemText(view, info, ii.name);
+                    instrumentation.addView(view, lp);
+                }
+            } else {
+                instrumentation.setVisibility(View.GONE);
+            }
+
+        }
+        
+        // Put focus here, so a button doesn't get focus and cause the
+        // scroll view to move to it.
+        mPackage.requestFocus();
+    }
+
+    private final static void setItemText(Button item, PackageInfo pi,
+                                          String className)
+    {
+        item.setText(className.substring(pi.packageName.length()+1));
+    }
+
+    private final class ActivityOnClick implements View.OnClickListener
+    {
+        private final ComponentName mClassName;
+        ActivityOnClick(ComponentName className) {
+            mClassName = className;
+        }
+
+        public void onClick(View v) {
+            Intent intent = new Intent(
+                null, Uri.fromParts("component",
+                    mClassName.flattenToString(), null));
+            intent.setClass(PackageSummary.this, ShowActivity.class);
+            startActivity(intent);
+        }
+    }
+}
diff --git a/apps/Development/src/com/android/development/PointerLocation.java b/apps/Development/src/com/android/development/PointerLocation.java
new file mode 100644
index 0000000..668e9ba
--- /dev/null
+++ b/apps/Development/src/com/android/development/PointerLocation.java
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+package com.android.development;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Paint.FontMetricsInt;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.VelocityTracker;
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * Demonstrates wrapping a layout in a ScrollView.
+ *
+ */
+public class PointerLocation extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(new MyView(this));
+        
+        // Make the screen full bright for this activity.
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+        lp.screenBrightness = 1.0f;
+        getWindow().setAttributes(lp);
+    }
+    
+    public class MyView extends View {
+        private final Paint mTextPaint;
+        private final Paint mTextBackgroundPaint;
+        private final Paint mTextLevelPaint;
+        private final Paint mPaint;
+        private final Paint mTargetPaint;
+        private final FontMetricsInt mTextMetrics = new FontMetricsInt();
+        private final ArrayList<Float> mXs = new ArrayList<Float>();
+        private final ArrayList<Float> mYs = new ArrayList<Float>();
+        private int mHeaderBottom;
+        private boolean mCurDown;
+        private int mCurX;
+        private int mCurY;
+        private float mCurPressure;
+        private float mCurSize;
+        private int mCurWidth;
+        private VelocityTracker mVelocity;
+        
+        public MyView(Context c) {
+            super(c);
+            mTextPaint = new Paint();
+            mTextPaint.setAntiAlias(true);
+            mTextPaint.setTextSize(10);
+            mTextPaint.setARGB(255, 0, 0, 0);
+            mTextBackgroundPaint = new Paint();
+            mTextBackgroundPaint.setAntiAlias(false);
+            mTextBackgroundPaint.setARGB(128, 255, 255, 255);
+            mTextLevelPaint = new Paint();
+            mTextLevelPaint.setAntiAlias(false);
+            mTextLevelPaint.setARGB(192, 255, 0, 0);
+            mPaint = new Paint();
+            mPaint.setAntiAlias(true);
+            mPaint.setARGB(255, 255, 255, 255);
+            mPaint.setStyle(Paint.Style.STROKE);
+            mPaint.setStrokeWidth(2);
+            mTargetPaint = new Paint();
+            mTargetPaint.setAntiAlias(false);
+            mTargetPaint.setARGB(192, 0, 0, 255);
+            mPaint.setStyle(Paint.Style.STROKE);
+            mPaint.setStrokeWidth(1);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            mTextPaint.getFontMetricsInt(mTextMetrics);
+            mHeaderBottom = -mTextMetrics.ascent+mTextMetrics.descent+2;
+            Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent
+                    + " descent=" + mTextMetrics.descent
+                    + " leading=" + mTextMetrics.leading
+                    + " top=" + mTextMetrics.top
+                    + " bottom=" + mTextMetrics.bottom);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            int w = getWidth()/5;
+            int base = -mTextMetrics.ascent+1;
+            int bottom = mHeaderBottom;
+            canvas.drawRect(0, 0, w-1, bottom, mTextBackgroundPaint);
+            canvas.drawText("X: " + mCurX, 1, base, mTextPaint);
+            canvas.drawRect(w, 0, (w * 2) - 1, bottom, mTextBackgroundPaint);
+            canvas.drawText("Y: " + mCurY, 1 + w, base, mTextPaint);
+            canvas.drawRect(w * 2, 0, (w * 3) - 1, bottom, mTextBackgroundPaint);
+            canvas.drawRect(w * 2, 0, (w * 2) + (mCurPressure * w) - 1, bottom, mTextLevelPaint);
+            canvas.drawText("Pres: " + mCurPressure, 1 + w * 2, base, mTextPaint);
+            canvas.drawRect(w * 3, 0, (w * 4) - 1, bottom, mTextBackgroundPaint);
+            canvas.drawRect(w * 3, 0, (w * 3) + (mCurSize * w) - 1, bottom, mTextLevelPaint);
+            canvas.drawText("Size: " + mCurSize, 1 + w * 3, base, mTextPaint);
+            canvas.drawRect(w * 4, 0, getWidth(), bottom, mTextBackgroundPaint);
+            int velocity = mVelocity == null ? 0 : (int) (mVelocity.getYVelocity() * 1000);
+            canvas.drawText("yVel: " + velocity, 1 + w * 4, base, mTextPaint);
+            
+            final int N = mXs.size();
+            float lastX=0, lastY=0;
+            mPaint.setARGB(255, 0, 255, 255);
+            for (int i=0; i<N; i++) {
+                float x = mXs.get(i);
+                float y = mYs.get(i);
+                if (i > 0) {
+                    canvas.drawLine(lastX, lastY, x, y, mTargetPaint);
+                    canvas.drawPoint(lastX, lastY, mPaint);
+                }
+                lastX = x;
+                lastY = y;
+            }
+            if (mVelocity != null) {
+                mPaint.setARGB(255, 255, 0, 0);
+                float xVel = mVelocity.getXVelocity() * (1000/60);
+                float yVel = mVelocity.getYVelocity() * (1000/60);
+                canvas.drawLine(lastX, lastY, lastX+xVel, lastY+yVel, mPaint);
+            } else {
+                canvas.drawPoint(lastX, lastY, mPaint);
+            }
+            
+            if (mCurDown) {
+                canvas.drawLine(0, (int)mCurY, getWidth(), (int)mCurY, mTargetPaint);
+                canvas.drawLine((int)mCurX, 0, (int)mCurX, getHeight(), mTargetPaint);
+                int pressureLevel = (int)(mCurPressure*255);
+                mPaint.setARGB(255, pressureLevel, 128, 255-pressureLevel);
+                canvas.drawPoint(mCurX, mCurY, mPaint);
+                canvas.drawCircle(mCurX, mCurY, mCurWidth, mPaint);
+            }
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            int action = event.getAction();
+            //mRect.set(0, 0, getWidth(), mHeaderBottom+1);
+            //invalidate(mRect);
+            //if (mCurDown) {
+            //    mRect.set(mCurX-mCurWidth-3, mCurY-mCurWidth-3,
+            //            mCurX+mCurWidth+3, mCurY+mCurWidth+3);
+            //} else {
+            //    mRect.setEmpty();
+            //}
+            if (action == MotionEvent.ACTION_DOWN) {
+                mXs.clear();
+                mYs.clear();
+                mVelocity = VelocityTracker.obtain();
+            }
+            mVelocity.addMovement(event);
+            mVelocity.computeCurrentVelocity(1);
+            final int N = event.getHistorySize();
+            for (int i=0; i<N; i++) {
+                mXs.add(event.getHistoricalX(i));
+                mYs.add(event.getHistoricalY(i));
+            }
+            mXs.add(event.getX());
+            mYs.add(event.getY());
+            mCurDown = action == MotionEvent.ACTION_DOWN
+                    || action == MotionEvent.ACTION_MOVE;
+            mCurX = (int)event.getX();
+            mCurY = (int)event.getY();
+            mCurPressure = event.getPressure();
+            mCurSize = event.getSize();
+            mCurWidth = (int)(mCurSize*(getWidth()/3));
+            //if (mCurDown) {
+            //    mRect.union(mCurX-mCurWidth-3, mCurY-mCurWidth-3,
+            //            mCurX+mCurWidth+3, mCurY+mCurWidth+3);
+            //}
+            //invalidate(mRect);
+            invalidate();
+            return true;
+        }
+        
+    }
+}
diff --git a/apps/Development/src/com/android/development/ProcessInfo.java b/apps/Development/src/com/android/development/ProcessInfo.java
new file mode 100755
index 0000000..5ece1a4
--- /dev/null
+++ b/apps/Development/src/com/android/development/ProcessInfo.java
@@ -0,0 +1,62 @@
+/*
+**
+** 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.development;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class ProcessInfo extends Activity {
+    PackageManager mPm;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Intent intent = getIntent();
+        String processName = intent.getStringExtra("processName");
+        String pkgList[] = intent.getStringArrayExtra("packageList");
+        mPm = getPackageManager();
+        setContentView(R.layout.process_info);
+       TextView processNameView = (TextView) findViewById(R.id.process_name);
+       LinearLayout pkgListView = (LinearLayout) findViewById(R.id.package_list);
+       if(processName != null) {
+           processNameView.setText(processName);
+       }
+       if(pkgList != null) {
+           for(String pkg : pkgList) {
+               TextView pkgView = new TextView(this);
+               pkgView.setText(pkg);
+               pkgListView.addView(pkgView);
+           }
+       }
+    }
+    
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+    }
+}
+
diff --git a/apps/Development/src/com/android/development/RadioIssueReport.java b/apps/Development/src/com/android/development/RadioIssueReport.java
new file mode 100644
index 0000000..b1a95f4
--- /dev/null
+++ b/apps/Development/src/com/android/development/RadioIssueReport.java
@@ -0,0 +1,191 @@
+/*
+** 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.development;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.SystemProperties;
+import android.provider.Checkin;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+import android.telephony.ServiceState;
+import android.text.format.DateFormat;
+import static com.android.internal.util.CharSequences.forAsciiBytes;
+import android.util.Log;
+import android.view.View.OnClickListener;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+
+import com.google.android.collect.Maps;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Map;
+
+/**
+ * Report radio issues to the StatisticsService.
+ */
+public class RadioIssueReport extends Activity
+{
+    private static final String TAG = "RadioIssue";
+    private static final int HEADER_SIZE = 24;
+    private static final String RADIO_BUFFER_OPTIONS = "-b radio\n-d\n";
+
+    /** List of system properties to snapshot. */
+    private static String[] SYSTEM_PROPERTIES = {
+        "net.gsm.radio-reset",
+        "net.gsm.attempt-gprs",
+        "net.gsm.succeed-gprs",
+        "net.gsm.disconnect",
+        "net.ppp.sent",
+        "net.ppp.received",
+        "gsm.version.baseband",
+        "gsm.version.ril-impl",
+    };
+
+    private Button          mSubmitButton;
+    private EditText        mReportText;
+    private ServiceState mServiceState;
+    private Phone.State     mPhoneState;
+    private int             mSignalStrength;
+    private Phone.DataState mDataState;
+    private String          mRadioLog;
+
+    /** Snapshot of interesting variables relevant to the radio. */
+    private Map<String, String> mRadioState;
+
+    @Override
+    public void
+    onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.radio_issue);
+
+        initSubmitButton();
+        initReportText();
+
+        mRadioState = snapState();
+    }
+
+    /**
+     * @return a snapshot of phone state variables to report.
+     */
+    private static Map<String, String> snapState() {
+        Map<String, String> state = Maps.newHashMap();
+
+        // Capture a bunch of system properties
+        for (String property: SYSTEM_PROPERTIES) {
+            String value = SystemProperties.get(property);
+            state.put(property, SystemProperties.get(property));
+        }
+
+        Phone phone = PhoneFactory.getDefaultPhone();
+        state.put("phone-data", phone.getDataConnectionState().toString());
+        state.put("phone-service", phone.getServiceState().toString());
+        state.put("phone-signal", String.valueOf(phone.getSignalStrengthASU()));
+        state.put("phone-state", phone.getState().toString());
+
+        try {
+            state.put("radio-log", getRadioLog());
+        } catch (IOException e) {
+            Log.e(TAG, "Error reading radio log", e);
+        }
+
+        return state;
+    }
+
+    private void initSubmitButton() {
+        mSubmitButton = (Button) findViewById(R.id.submit);
+        mSubmitButton.setOnClickListener(mSubmitButtonHandler);
+    }
+
+    private void initReportText() {
+        mReportText = (EditText) findViewById(R.id.report_text);
+        mReportText.requestFocus();
+    }
+
+    OnClickListener mSubmitButtonHandler = new OnClickListener() {
+        public void onClick(View v) {
+            // Include the user-supplied report text.
+            mRadioState.put("user-report", mReportText.getText().toString());
+
+            // Dump the state variables directly into the report.
+            Checkin.logEvent(getContentResolver(),
+                    Checkin.Events.Tag.RADIO_BUG_REPORT,
+                    mRadioState.toString());
+
+            finish();
+        }
+    };
+
+    // Largely stolen from LogViewer.java
+    private static String getRadioLog() throws IOException {
+        Socket sock = new Socket("127.0.0.1", 5040);
+        DataInputStream in = new DataInputStream(sock.getInputStream());
+        StringBuilder log = new StringBuilder();
+
+        // Set options
+        sock.getOutputStream().write(RADIO_BUFFER_OPTIONS.getBytes());
+        sock.getOutputStream().write('\n');
+        sock.getOutputStream().write('\n');
+
+        // Read in the log
+        try {
+            Calendar cal = new GregorianCalendar();
+
+            while (true) {
+                int length = in.readInt();
+                long when = (long)in.readInt();
+                byte[] bytes = new byte[length-4];
+                in.readFully(bytes);
+
+                int tagEnd = next0(bytes, HEADER_SIZE-4);
+                int fileEnd = next0(bytes, tagEnd + 1);
+                int messageEnd = next0(bytes, fileEnd + 1);
+
+                CharSequence tag
+                        = forAsciiBytes(bytes, HEADER_SIZE-4, tagEnd);
+                CharSequence message
+                        = forAsciiBytes(bytes, fileEnd + 1, messageEnd);
+
+                cal.setTimeInMillis(when*1000);
+                log.append(DateFormat.format("MM-dd kk:mm:ss ", cal));
+                log.append(tag)
+                   .append(": ")
+                   .append(message)
+                   .append("\n");
+            }
+        } catch (EOFException e) {
+            Log.d(TAG, "reached end of stream");
+        }
+
+        return log.toString();
+    }
+
+    private static int next0(byte[] bytes, int start) {
+        for (int current = start; current < bytes.length; current++) {
+            if (bytes[current] == 0)
+                return current;
+        }
+        return bytes.length;
+    }
+}
diff --git a/apps/Development/src/com/android/development/RunningProcesses.java b/apps/Development/src/com/android/development/RunningProcesses.java
new file mode 100755
index 0000000..7b56be9
--- /dev/null
+++ b/apps/Development/src/com/android/development/RunningProcesses.java
@@ -0,0 +1,154 @@
+/*
+**
+** 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.development;
+
+import android.app.ActivityManager;
+import android.app.ListActivity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class RunningProcesses extends ListActivity {
+    PackageManager mPm;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mPm = getPackageManager();
+        mAdapter = new AppListAdapter(this);
+        if (mAdapter.getCount() <= 0) {
+            finish();
+        } else {
+            setListAdapter(mAdapter);
+        }
+    }
+    
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        ListItem app = mAdapter.appForPosition(position);
+        // Create intent to start new activity
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.setClass(this, ProcessInfo.class);
+        intent.putExtra("processName", app.procInfo.processName);
+        intent.putExtra("packageList", app.procInfo.pkgList);
+        // start new activity to display extended information
+        startActivity(intent);
+    }
+
+    private final class AppListAdapter extends BaseAdapter {
+        public AppListAdapter(Context context) {
+            mContext = context;
+            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+            ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
+            List<ActivityManager.RunningAppProcessInfo> appList = am.getRunningAppProcesses();
+            for (ActivityManager.RunningAppProcessInfo app : appList) {
+                if(mList == null) {
+                    mList = new ArrayList<ListItem>();
+                }
+                mList.add(new ListItem(app));    
+            }
+            if (mList != null) {
+                Collections.sort(mList, sDisplayNameComparator);
+            }
+        }
+    
+        public ListItem appForPosition(int position) {
+            if (mList == null) {
+                return null;
+            }
+            return mList.get(position);
+        }
+
+        public int getCount() {
+            return mList != null ? mList.size() : 0;
+        }
+
+        public Object getItem(int position) {
+            return position;
+        }
+    
+        public long getItemId(int position) {
+            return position;
+        }
+    
+        public View getView(int position, View convertView, ViewGroup parent) {
+            View view;
+            if (convertView == null) {
+                view = mInflater.inflate(
+                        android.R.layout.simple_list_item_1, parent, false);
+            } else {
+                view = convertView;
+            }
+            bindView(view, mList.get(position));
+            return view;
+        }
+    
+        private final void bindView(View view, ListItem info) {
+            TextView text = (TextView)view.findViewById(android.R.id.text1);
+            text.setText(info != null ? info.procInfo.processName : "(none)");
+        }
+    
+        protected final Context mContext;
+        protected final LayoutInflater mInflater;
+        protected List<ListItem> mList;
+        
+    }
+
+    private final Comparator sDisplayNameComparator = new Comparator() {
+        public final int compare(Object a, Object b) {
+            CharSequence  sa = ((ListItem) a).procInfo.processName;
+            CharSequence  sb = ((ListItem) b).procInfo.processName;
+            return collator.compare(sa, sb);
+        }
+        private final Collator   collator = Collator.getInstance();
+    };
+    
+    private class ListItem {
+        ActivityManager.RunningAppProcessInfo procInfo;
+        public ListItem(ActivityManager.RunningAppProcessInfo pInfo) {
+            procInfo = pInfo;
+        }
+    }
+
+    private AppListAdapter mAdapter;
+}
+
diff --git a/apps/Development/src/com/android/development/ShowActivity.java b/apps/Development/src/com/android/development/ShowActivity.java
new file mode 100644
index 0000000..1fc2816
--- /dev/null
+++ b/apps/Development/src/com/android/development/ShowActivity.java
@@ -0,0 +1,122 @@
+/* //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.development;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+
+public class ShowActivity extends Activity {
+
+    private ActivityInfo mActivityInfo;
+
+    private TextView mPackage;
+    private ImageView mIconImage;
+    private TextView mClass;
+    private TextView mLabel;
+    private TextView mLaunch;
+    private TextView mProcess;
+    private TextView mTaskAffinity;
+    private TextView mPermission;
+    private TextView mMultiprocess;
+    private TextView mClearOnBackground;
+    private TextView mStateNotNeeded;
+
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.show_activity);
+
+        mPackage = (TextView)findViewById(R.id.packageView);
+        mIconImage = (ImageView)findViewById(R.id.icon);
+        mClass = (TextView)findViewById(R.id.classView);
+        mLabel = (TextView)findViewById(R.id.label);
+        mLaunch = (TextView)findViewById(R.id.launch);
+        mProcess = (TextView)findViewById(R.id.process);
+        mTaskAffinity = (TextView)findViewById(R.id.taskAffinity);
+        mPermission = (TextView)findViewById(R.id.permission);
+        mMultiprocess = (TextView)findViewById(R.id.multiprocess);
+        mClearOnBackground = (TextView)findViewById(R.id.clearOnBackground);
+        mStateNotNeeded = (TextView)findViewById(R.id.stateNotNeeded);
+
+        final PackageManager pm = getPackageManager();
+        try {
+            mActivityInfo = pm.getActivityInfo(ComponentName.unflattenFromString(
+                getIntent().getData().getSchemeSpecificPart()), 0);
+        } catch (PackageManager.NameNotFoundException e) {
+        }
+        if (mActivityInfo != null) {
+            mPackage.setText(mActivityInfo.applicationInfo.packageName);
+            mIconImage.setImageDrawable(mActivityInfo.loadIcon(pm));
+            if (mActivityInfo.name.startsWith(
+                    mActivityInfo.applicationInfo.packageName + ".")) {
+                mClass.setText(mActivityInfo.name.substring(
+                        mActivityInfo.applicationInfo.packageName.length()));
+            } else {
+                mClass.setText(mActivityInfo.name);
+            }
+            CharSequence label = mActivityInfo.loadLabel(pm);
+            mLabel.setText("\"" + (label != null ? label : "") + "\"");
+            switch (mActivityInfo.launchMode) {
+            case ActivityInfo.LAUNCH_MULTIPLE:
+                mLaunch.setText(getText(R.string.launch_multiple));
+                break;
+            case ActivityInfo.LAUNCH_SINGLE_TOP:
+                mLaunch.setText(getText(R.string.launch_singleTop));
+                break;
+            case ActivityInfo.LAUNCH_SINGLE_TASK:
+                mLaunch.setText(getText(R.string.launch_singleTask));
+                break;
+            case ActivityInfo.LAUNCH_SINGLE_INSTANCE:
+                mLaunch.setText(getText(R.string.launch_singleInstance));
+                break;
+            default:
+                mLaunch.setText(getText(R.string.launch_unknown));
+            }
+            mProcess.setText(mActivityInfo.processName);
+            mTaskAffinity.setText(mActivityInfo.taskAffinity != null
+                    ? mActivityInfo.taskAffinity : getText(R.string.none));
+            mPermission.setText(mActivityInfo.permission != null
+                    ? mActivityInfo.permission : getText(R.string.none));
+            mMultiprocess.setText(
+                    (mActivityInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
+                    ? getText(R.string.yes) : getText(R.string.no));
+            mClearOnBackground.setText(
+                    (mActivityInfo.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0
+                    ? getText(R.string.yes) : getText(R.string.no));
+            mStateNotNeeded.setText(
+                    (mActivityInfo.flags&ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0
+                    ? getText(R.string.yes) : getText(R.string.no));
+        }
+    }
+
+    public void onResume() {
+        super.onResume();
+    }
+}
diff --git a/apps/Development/src/com/android/development/StacktraceViewer.java b/apps/Development/src/com/android/development/StacktraceViewer.java
new file mode 100644
index 0000000..96b0521
--- /dev/null
+++ b/apps/Development/src/com/android/development/StacktraceViewer.java
@@ -0,0 +1,50 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+package com.android.development;
+
+
+import android.app.Activity;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.text.method.ScrollingMovementMethod;
+import android.os.Bundle;
+import android.server.data.CrashData;
+import android.server.data.ThrowableData;
+import android.server.data.StackTraceElementData;
+import android.graphics.Typeface;
+
+/**
+ * Views a single stack trace.
+ */
+public class StacktraceViewer extends Activity {
+
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.log_viewer);
+
+        TextView text = (TextView) findViewById(R.id.text);
+        text.setTextSize(10);
+        text.setHorizontallyScrolling(true);
+        text.setTypeface(Typeface.MONOSPACE);
+        text.setMovementMethod(ScrollingMovementMethod.getInstance());
+        
+        String stacktrace = getIntent().getExtras().getString(
+                CrashData.class.getName());
+
+        text.setText(stacktrace);
+    }
+}
diff --git a/apps/Development/src/com/android/development/UnderdevelopedSettings.java b/apps/Development/src/com/android/development/UnderdevelopedSettings.java
new file mode 100644
index 0000000..9cf1b90
--- /dev/null
+++ b/apps/Development/src/com/android/development/UnderdevelopedSettings.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package com.android.development;
+
+import android.app.LauncherActivity;
+import android.content.Intent;
+
+public class UnderdevelopedSettings extends LauncherActivity {
+
+    @Override
+    protected Intent getTargetIntent() {
+        Intent targetIntent = new Intent(Intent.ACTION_MAIN, null);
+        targetIntent.addCategory(Intent.CATEGORY_DEVELOPMENT_PREFERENCE);
+        return targetIntent;
+    }
+
+}
diff --git a/apps/Fallback/Android.mk b/apps/Fallback/Android.mk
new file mode 100644
index 0000000..64b7d17
--- /dev/null
+++ b/apps/Fallback/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user development
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := Fallback
+
+include $(BUILD_PACKAGE)
diff --git a/apps/Fallback/AndroidManifest.xml b/apps/Fallback/AndroidManifest.xml
new file mode 100644
index 0000000..802406d
--- /dev/null
+++ b/apps/Fallback/AndroidManifest.xml
@@ -0,0 +1,62 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.fallback">
+    <application android:label="@string/appTitle">
+
+        <activity android:name="Fallback" android:label="@string/title"
+				android:theme="@android:style/Theme.Dialog">
+<!-- for debugging on non-SDK builds
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+-->
+			<!-- SMS intents -->
+            <intent-filter android:priority="-1000">
+                <action android:name="android.intent.action.VIEW" />
+				<category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.item/sms-chat" />
+            </intent-filter>
+            <intent-filter android:priority="-1000">
+                <action android:name="android.intent.action.VIEW" />
+                <action android:name="android.intent.action.SENDTO" />
+				<category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="sms" />
+            </intent-filter>
+            <intent-filter android:priority="-1000">
+	            <action android:name="android.intent.action.VIEW" />
+				<category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+	            <data android:mimeType="vnd.android.cursor.item/sms" />
+            </intent-filter>
+
+			<!-- Mail intents -->
+            <intent-filter android:priority="-1000">
+                <action android:name="android.intent.action.VIEW" />
+                <action android:name="android.intent.action.SENDTO" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="mailto" />
+            </intent-filter>
+
+			<!-- Wallpaper intents -->
+            <intent-filter android:priority="-1000">
+                <action android:name="android.intent.action.WALLPAPER_SETTINGS" />
+				<category android:name="android.intent.category.DEFAULT" />
+			</intent-filter>
+			
+			<!-- Camera intents -->
+			<intent-filter android:priority="-1000">
+			    <action android:name="android.intent.action.GET_CONTENT" />
+                <category android:name="android.intent.category.DEFAULT" />
+			    <data android:mimeType="image/*" />
+			</intent-filter>
+			
+			<!-- Settings Intent -->
+			<intent-filter android:priority="-1000">
+				<action android:name="android.settings.SETTINGS" />
+				<category android:name="android.intent.category.DEFAULT" />
+			</intent-filter>
+        </activity>
+                                
+    </application>
+
+</manifest>
diff --git a/apps/Fallback/MODULE_LICENSE_APACHE2 b/apps/Fallback/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/Fallback/MODULE_LICENSE_APACHE2
diff --git a/apps/Fallback/NOTICE b/apps/Fallback/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/apps/Fallback/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/apps/Fallback/res/layout/fallback.xml b/apps/Fallback/res/layout/fallback.xml
new file mode 100644
index 0000000..5ddfd82
--- /dev/null
+++ b/apps/Fallback/res/layout/fallback.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <TextView android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="6dip"
+        android:layout_marginLeft="6dip"
+        android:text="@string/error" />
+</RelativeLayout>
diff --git a/apps/Fallback/res/values-cs/strings.xml b/apps/Fallback/res/values-cs/strings.xml
new file mode 100644
index 0000000..b9d34f9
--- /dev/null
+++ b/apps/Fallback/res/values-cs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Záloha"</string>
+    <string name="title">"Akce není podporována"</string>
+    <string name="error">"Tato akce není momentálně podporována."</string>
+</resources>
diff --git a/apps/Fallback/res/values-de/strings.xml b/apps/Fallback/res/values-de/strings.xml
new file mode 100644
index 0000000..8d59ddf
--- /dev/null
+++ b/apps/Fallback/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Fallback"</string>
+    <string name="title">"Nicht unterstützte Aktion"</string>
+    <string name="error">"Diese Aktion wird zurzeit nicht unterstützt."</string>
+</resources>
diff --git a/apps/Fallback/res/values-es/strings.xml b/apps/Fallback/res/values-es/strings.xml
new file mode 100644
index 0000000..0ce5751
--- /dev/null
+++ b/apps/Fallback/res/values-es/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Fallback"</string>
+    <string name="title">"Acción no admitida"</string>
+    <string name="error">"Esa acción no se admite actualmente."</string>
+</resources>
diff --git a/apps/Fallback/res/values-fr/strings.xml b/apps/Fallback/res/values-fr/strings.xml
new file mode 100644
index 0000000..024ae42
--- /dev/null
+++ b/apps/Fallback/res/values-fr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Application de secours"</string>
+    <string name="title">"Action non prise en charge"</string>
+    <string name="error">"Cette action n\'est actuellement pas prise en charge."</string>
+</resources>
diff --git a/apps/Fallback/res/values-it/strings.xml b/apps/Fallback/res/values-it/strings.xml
new file mode 100644
index 0000000..d216e59
--- /dev/null
+++ b/apps/Fallback/res/values-it/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Fallback"</string>
+    <string name="title">"Azione non supportata"</string>
+    <string name="error">"L\'azione non è al momento supportata."</string>
+</resources>
diff --git a/apps/Fallback/res/values-ja/strings.xml b/apps/Fallback/res/values-ja/strings.xml
new file mode 100644
index 0000000..79aeb42
--- /dev/null
+++ b/apps/Fallback/res/values-ja/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Fallback"</string>
+    <string name="title">"サポートされていない操作"</string>
+    <string name="error">"現在サポートされていない操作です。"</string>
+</resources>
diff --git a/apps/Fallback/res/values-ko/strings.xml b/apps/Fallback/res/values-ko/strings.xml
new file mode 100644
index 0000000..1e98e20
--- /dev/null
+++ b/apps/Fallback/res/values-ko/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Fallback"</string>
+    <string name="title">"지원되지 않는 작업"</string>
+    <string name="error">"이 작업은 현재 지원되지 않습니다."</string>
+</resources>
diff --git a/apps/Fallback/res/values-nb/strings.xml b/apps/Fallback/res/values-nb/strings.xml
new file mode 100644
index 0000000..6fed660
--- /dev/null
+++ b/apps/Fallback/res/values-nb/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Fallback"</string>
+    <string name="title">"Ustøttet handling"</string>
+    <string name="error">"Denne handlingen er ikke støttet nå."</string>
+</resources>
diff --git a/apps/Fallback/res/values-nl/strings.xml b/apps/Fallback/res/values-nl/strings.xml
new file mode 100644
index 0000000..f347964
--- /dev/null
+++ b/apps/Fallback/res/values-nl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Reserve"</string>
+    <string name="title">"Niet-ondersteunde actie"</string>
+    <string name="error">"Die actie wordt momenteel niet ondersteund."</string>
+</resources>
diff --git a/apps/Fallback/res/values-pl/strings.xml b/apps/Fallback/res/values-pl/strings.xml
new file mode 100644
index 0000000..73a176a
--- /dev/null
+++ b/apps/Fallback/res/values-pl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Wycofanie"</string>
+    <string name="title">"Nieobsługiwana czynność"</string>
+    <string name="error">"Ta czynność nie jest aktualnie obsługiwana."</string>
+</resources>
diff --git a/apps/Fallback/res/values-ru/strings.xml b/apps/Fallback/res/values-ru/strings.xml
new file mode 100644
index 0000000..dc292a8
--- /dev/null
+++ b/apps/Fallback/res/values-ru/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Fallback"</string>
+    <string name="title">"Действие не поддерживается"</string>
+    <string name="error">"В настоящее время это действие не поддерживается."</string>
+</resources>
diff --git a/apps/Fallback/res/values-zh-rCN/strings.xml b/apps/Fallback/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..13ef687
--- /dev/null
+++ b/apps/Fallback/res/values-zh-rCN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"Fallback"</string>
+    <string name="title">"不支持的操作"</string>
+    <string name="error">"当前不支持该操作。"</string>
+</resources>
diff --git a/apps/Fallback/res/values-zh-rTW/strings.xml b/apps/Fallback/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..52afdbe
--- /dev/null
+++ b/apps/Fallback/res/values-zh-rTW/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle">"備用"</string>
+    <string name="title">"不支援的操作"</string>
+    <string name="error">"目前不支援此操作。"</string>
+</resources>
diff --git a/apps/Fallback/res/values/strings.xml b/apps/Fallback/res/values/strings.xml
new file mode 100644
index 0000000..bc0b71d
--- /dev/null
+++ b/apps/Fallback/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?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>
+    <!-- Name of the fallback application. It's used only on the SDK when applications from
+         real phones aren't available. -->
+    <string name="appTitle">Fallback</string>
+    <!-- Dialog title informing the user that the requested action is not supported -->
+    <string name="title">Unsupported action</string>
+    <!-- Dialog content informing the user that the requested action is not supported -->
+    <string name="error">That action is not currently supported.</string>
+</resources>
diff --git a/apps/Fallback/src/com/android/fallback/Fallback.java b/apps/Fallback/src/com/android/fallback/Fallback.java
new file mode 100644
index 0000000..1a7600e
--- /dev/null
+++ b/apps/Fallback/src/com/android/fallback/Fallback.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package com.android.fallback;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * A fall back activity that registers itself for common intents which
+ * may possibly not otherwise be handled.
+ */
+public class Fallback extends Activity {
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.fallback);
+    }
+}
diff --git a/apps/FontLab/Android.mk b/apps/FontLab/Android.mk
new file mode 100644
index 0000000..3cad52a
--- /dev/null
+++ b/apps/FontLab/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := FontLab
+
+include $(BUILD_PACKAGE)
diff --git a/apps/FontLab/AndroidManifest.xml b/apps/FontLab/AndroidManifest.xml
new file mode 100644
index 0000000..ea961d5
--- /dev/null
+++ b/apps/FontLab/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.fontlab">
+    <application android:label="Font lab">
+		<activity android:name="FontLab">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+		</activity>
+		<activity android:name="BackgroundPicker"/>
+		<activity android:name="FontPicker"/>
+    </application>
+</manifest>
diff --git a/apps/FontLab/MODULE_LICENSE_APACHE2 b/apps/FontLab/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/FontLab/MODULE_LICENSE_APACHE2
diff --git a/apps/FontLab/NOTICE b/apps/FontLab/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/apps/FontLab/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/apps/FontLab/res/layout/font_lab.xml b/apps/FontLab/res/layout/font_lab.xml
new file mode 100644
index 0000000..1a79add
--- /dev/null
+++ b/apps/FontLab/res/layout/font_lab.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content"
+    android:layout_width="fill_parent" android:layout_height="fill_parent"
+    android:orientation="vertical"
+    android:paddingLeft="4dip" android:paddingRight="4dip"
+    android:paddingTop="4dip" android:paddingBottom="4dip">
+        
+    <TextView android:id="@+id/column1" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1"
+        android:layout_marginBottom="8dip" />
+    <TextView android:id="@+id/column2" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" />
+        
+</LinearLayout>
+
+
diff --git a/apps/FontLab/src/com/android/fontlab/BackgroundPicker.java b/apps/FontLab/src/com/android/fontlab/BackgroundPicker.java
new file mode 100644
index 0000000..e23ac82
--- /dev/null
+++ b/apps/FontLab/src/com/android/fontlab/BackgroundPicker.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package com.android.fontlab;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+
+
+public abstract class BackgroundPicker extends ListActivity 
+{
+    
+    public void onCreate(Bundle icicle) 
+    {
+        super.onCreate(icicle);
+
+        setListAdapter(new SimpleAdapter(this,
+                getData(),
+                android.R.layout.simple_list_item_1,
+                new String[] {"title"},
+                new int[] {android.R.id.text1}));
+    }
+    
+    protected List getData()
+    {
+        List myData = new ArrayList<Bundle>();
+        addItem(myData, "Solid White", 0, 0xFFFFFFFF, 0xFF000000);
+        addItem(myData, "Solid Light Gray", 0, 0xFFBFBFBF, 0xFF000000);
+        addItem(myData, "Solid Dark Gray", 0, 0xFF404040, 0xFFFFFFFF);
+        addItem(myData, "Solid Black", 0, 0xFF000000, 0xFFFFFFFF);
+        addItem(myData, "Solid Blue", 0, 0xFF1a387a, 0xFFFFFFFF);
+        addItem(myData, "Textured White", 0, 0, 0xFF000000);
+        // addItem(myData, "Textured Blue", android.R.drawable.screen_background_blue, 0, 0xFFFFFFFF);
+
+        return myData;
+    }
+    
+    protected void addItem(List<Bundle> data, String name, int textureRes, int bgColor, int textColor)
+    {
+        Bundle temp = new Bundle();
+        temp.putString("title", name);
+        if (textureRes != 0) {
+            temp.putInt("texture", textureRes);
+        }
+        temp.putInt("bgcolor", bgColor);
+        temp.putInt("text", textColor);
+        data.add(temp);
+    }
+
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+        Bundle map = (Bundle) l.getItemAtPosition(position);
+        setResult(RESULT_OK, (new Intent()).putExtras(map));
+        finish();
+    }
+  
+}
diff --git a/apps/FontLab/src/com/android/fontlab/FontLab.java b/apps/FontLab/src/com/android/fontlab/FontLab.java
new file mode 100644
index 0000000..27f2d4c
--- /dev/null
+++ b/apps/FontLab/src/com/android/fontlab/FontLab.java
@@ -0,0 +1,361 @@
+/*
+ * 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.
+ */
+
+package com.android.fontlab;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.graphics.drawable.PaintDrawable;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.TextView;
+
+class FontLab extends Activity
+{
+    private static final int MIN_SIZE = 1;
+    private static final int MAX_SIZE = 60;
+    
+    private static final float SCALE_X_RANGE = 20;
+    private static final int MAX_SCALE_X = 20;
+    private static final int MIN_SCALE_X = -19;   // -20 would make zero-scale
+
+    private static final String[] sText = {
+        "Applications Contacts Maps Google Browser Text messages Address book"
+        + " Development Earth Quake Settings Voicemail Zoolander. Four score"
+        + " and seven years ago our fathers brought forth on this continent, a"
+        + " new nation, conceived in Liberty, and dedicated to the proposition"
+        + " that all men are created equal. Now we are engaged in a great civil"
+        + " war, testing whether that nation, or any nation so conceived and so"
+        + " dedicated, can long endure. We are met on a great battle-field of"
+        + " that war. We have come to dedicate a portion of that field, as a"
+        + " final resting place for those who here gave their lives that that"
+        + " nation might live. It is altogether fitting and proper that we"
+        + " should do this. But, in a larger sense, we can not dedicate - we"
+        + " can not consecrate - we can not hallow - this ground. The brave"
+        + " men, living and dead, who struggled here, have consecrated it, far"
+        + " above our poor power to add or detract. The world will little note,"
+        + " nor long remember what we say here, but it can never forget what"
+        + " they did here. It is for us the living, rather, to be dedicated"
+        + " here to the unfinished work which they who fought here have thus"
+        + " far so nobly advanced. It is rather for us to be here dedicated to"
+        + " the great task remaining before us - that from these honored dead"
+        + " we take increased devotion to that cause for which they gave the"
+        + " last full measure of devotion - that we here highly resolve that"
+        + " these dead shall not have died in vain - that this nation, under"
+        + " God, shall have a new birth of freedom - and that government of the"
+        + " people, by the people, for the people, shall not perish from the"
+        + " earth."
+        ,
+        "A Spanish doctor on Tuesday stood by his opinion that Fidel Castro is recovering from stomach surgery despite a newspaper report stating the Cuban leader is in a serious condition after a number of failed operations."
+        + " When Senator Wayne Allard, Republican of Colorado, announced Monday that he would not seek re-election, the uphill battle for his party to reclaim the Senate in 2008 became an even steeper climb."
+        + " Naomi Campbell was today sentenced to five days' community service and ordered to attend an anger management course after she admitted throwing a mobile phone at her maid."
+        ,
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 !@#$%^&*()-_=+[]\\{}|;':\",./<>?"
+        ,
+        "HaH HbH HcH HdH HeH HfH HgH HhH HiH HjH HkH HlH HmH HnH HoH HpH HqH HrH HsH HtH HuH HvH HwH HxH HyH HzH"
+        + "HAH HBH HCH HDH HEH HFH HGH HHH HIH HJH HKH HLH HMH HNH HOH HPH HQH HRH HSH HTH HUH HVH HWH HXH HYH HZH"
+    };
+    
+    private void updateText() {
+        mTextIndex %= sText.length;
+        String s = sText[mTextIndex];
+        mColumn1.setText(s);
+        mColumn2.setText(s);
+    }
+    
+    public FontLab() {}
+
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.font_lab);
+        
+        mColumn1 = (TextView)findViewById(R.id.column1);
+        mColumn2 = (TextView)findViewById(R.id.column2);
+        mContentView = findViewById(R.id.content);
+
+        
+        mColumn1.setTextSize(mFontSize);
+        mColumn2.setTextSize(mFontSize);
+        
+        mColumn1.setTextColor(Color.BLACK);
+        mColumn1.setBackgroundDrawable(new PaintDrawable(Color.WHITE));
+        mColumn2.setTextColor(Color.WHITE);
+        mColumn2.setBackgroundDrawable(new PaintDrawable(Color.BLACK));
+        
+        refreshFont();
+        updateTitle();
+        updateText();
+        
+        setDefaultKeyMode(Activity.DEFAULT_KEYS_SHORTCUT);
+    }
+    
+    private void updateTitle() {
+        Typeface tf = mColumn1.getTypeface();
+        String title = " ps=" + mFontSize + " scaleX="
+                    + (1 + mTextScaleXDelta/SCALE_X_RANGE)
+                    + " gamma=" + (mGamma/20.f)
+                    + " " + sTypefaceName[mFontIndex]
+                    + " " + sStyleName[tf.getStyle()]
+                    ;
+        setTitle(title);
+    }
+    
+    /** Called when it is time to initialize the activity state. */
+    protected void onRestoreInstanceState(Bundle state) {
+        super.onRestoreInstanceState(state);
+    }
+
+    protected void onResume() {
+        super.onResume();
+    }
+    
+    private static final String sStyleName[] = {
+        "Regular", "Bold", "Italic", "Bold Italic"
+    };
+    private static final String sTypefaceName[] = {
+        "Droid Sans",
+        "Droid Serif",
+        "Droid Mono"
+    };
+    private static final Typeface sTypeface[] = {
+        Typeface.SANS_SERIF,
+        Typeface.SERIF,
+        Typeface.MONOSPACE
+    };
+    private static final int FONT_INDEX_SANS = 0;   // index into sTypeface
+    private static final int FONT_INDEX_SERIF = 1;  // index into sTypeface
+    private static final int FONT_INDEX_MONO = 2;   // index into sTypeface
+    
+    private static boolean canSupportStyle(Typeface tf, int styleBits) {
+        tf = Typeface.create(tf, styleBits);
+        return (tf.getStyle() & styleBits) == styleBits;
+    }
+
+    private void refreshFont() {
+        Typeface tf = Typeface.create(sTypeface[mFontIndex], mFontStyle);
+        mColumn1.setTypeface(tf);
+        mColumn2.setTypeface(tf);
+        updateTitle();
+    }
+    
+    private MenuItem.OnMenuItemClickListener mFontClickListener = new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            mFontIndex = item.getItemId();
+            refreshFont();
+            return true;
+        }
+    };
+    
+    private void addFontMenu(Menu menu, int index) {
+        MenuItem item = menu.add(0, index, 0, sTypefaceName[index]);
+        item.setCheckable(true);
+        item.setOnMenuItemClickListener(mFontClickListener);
+        item.setChecked(index == mFontIndex);
+    }
+    
+    private MenuItem.OnMenuItemClickListener mStyleClickListener = new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            mFontStyle = mFontStyle ^ item.getItemId();
+            refreshFont();
+            return true;
+        }
+    };
+    
+    private void addStyleMenu(Menu menu, int style, char shortCut) {
+        MenuItem item = menu.add(0, style, 0, (style == Typeface.BOLD) ? "Bold" : "Italic");
+        item.setCheckable(true);
+        item.setOnMenuItemClickListener(mStyleClickListener);
+        item.setChecked((mFontStyle & style) != 0);
+
+        item.setVisible(canSupportStyle(sTypeface[mFontIndex], style));
+        if (shortCut != 0) {
+            item.setAlphabeticShortcut(shortCut);
+        }
+    }
+    
+    private MenuItem.OnMenuItemClickListener mFlagClickListener = new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            int mask = item.getItemId();
+            mColumn1.setPaintFlags(mColumn1.getPaintFlags() ^ mask);
+            mColumn2.setPaintFlags(mColumn2.getPaintFlags() ^ mask);
+            return true;
+        }
+    };
+    
+    private
+    void addFlagMenu(Menu menu, int paintFlag, String label, char shortCut) {
+        MenuItem item = menu.add(0, paintFlag, 0, label);
+        item.setCheckable(true);
+        item.setOnMenuItemClickListener(mFlagClickListener);
+        item.setChecked((mColumn1.getPaintFlags() & paintFlag) != 0);
+        if (shortCut != 0) {
+            item.setAlphabeticShortcut(shortCut);
+        }
+    }
+    
+    private static void addListenerMenu(MenuItem item,
+                                        MenuItem.OnMenuItemClickListener listener,
+                                        char keyChar) {
+        item.setOnMenuItemClickListener(listener);
+        if (keyChar != '\0') {
+            item.setAlphabeticShortcut(keyChar);
+        }
+    }
+    
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        return true;
+    }
+    
+    @Override public boolean onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
+        menu.clear();
+
+        addFontMenu(menu, FONT_INDEX_SANS);
+        addFontMenu(menu, FONT_INDEX_SERIF);
+        addFontMenu(menu, FONT_INDEX_MONO);
+        addStyleMenu(menu, Typeface.BOLD, 'b');
+        addStyleMenu(menu, Typeface.ITALIC, 'i');
+        addFlagMenu(menu, Paint.DEV_KERN_TEXT_FLAG, "DevKern", 'k');
+        menu.add(0, 0, 0, "Text").setOnMenuItemClickListener(mTextCallback).setAlphabeticShortcut('t');
+        
+        return true;
+    }
+
+    protected void onActivityResult(int requestCode, int resultCode,
+                                    String data, Map extras) {
+        if (resultCode == RESULT_OK) {
+            switch (requestCode) {
+            case BACKGROUND_PICKED:
+                {
+                    int color = ((Integer)extras.get("text")).intValue();
+                    mColumn1.setTextColor(color);
+                    mColumn2.setTextColor(color);
+                    
+                    int colorTranslucent = (color & 0x00FFFFFF) + 0x77000000;
+                    
+                    setTitleColor(color);
+                    
+                    Integer texture = (Integer)extras.get("texture");
+                    if (texture != null) {
+                        mContentView.setBackgroundResource(texture.intValue());
+                    } else {
+                        color = ((Integer)extras.get("bgcolor")).intValue();
+                        mContentView.setBackgroundColor(color);
+                    }
+                }
+                break;   
+            }
+        }
+    }
+
+    @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
+        int size = mFontSize;
+        int scaleX = mTextScaleXDelta;
+        
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                size -= 1;
+                break;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                size += 1;
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                scaleX += 1;
+                break;
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                scaleX -= 1;
+                break;
+                /*
+            case KeyEvent.KEYCODE_U:
+                changeGamma(1);
+                return true;
+            case KeyEvent.KEYCODE_D:
+                changeGamma(-1);
+                return true;
+                 */
+            default:
+                return super.onKeyDown(keyCode, event);
+        }
+        
+        size = Math.min(MAX_SIZE, Math.max(MIN_SIZE, size));
+        if (size != mFontSize) {
+            mFontSize = size;
+            mColumn1.setTextSize(mFontSize);
+            mColumn2.setTextSize(mFontSize);
+            updateTitle();
+            return true;
+        }
+        
+        scaleX = Math.min(MAX_SCALE_X, Math.max(MIN_SCALE_X, scaleX));
+        if (scaleX != mTextScaleXDelta) {
+            mTextScaleXDelta = scaleX;
+            mColumn1.setTextScaleX(1 + scaleX / SCALE_X_RANGE);
+            mColumn2.setTextScaleX(1 + scaleX / SCALE_X_RANGE);
+            updateTitle();
+            return true;
+        }
+
+        return super.onKeyDown(keyCode, event);
+    }
+    
+    private int mGamma = 28;    // current default is 1.4 (* 20)
+    private void changeGamma(int delta) {
+        int gamma = Math.min(100, Math.max(1, mGamma + delta));
+        if (gamma != mGamma) {
+            mGamma = gamma;
+            updateTitle();
+//            Paint.setTextGamma(mGamma / 20.f);
+            mContentView.invalidate();
+            android.util.Log.d("skia", "setTextGamma " + mGamma);
+        }
+    }
+    
+    private void setFont(TextView t, TextView f, Map extras) {
+        int style = ((Integer)extras.get("style")).intValue();
+        String font = (String)extras.get("font");
+        t.setTypeface(Typeface.create(font, style));
+        
+        f.setText((String)extras.get("title"));
+    }
+
+    MenuItem.OnMenuItemClickListener mTextCallback = new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            mTextIndex += 1;
+            updateText();
+            return true;
+        }
+    };
+
+    private static final int BACKGROUND_PICKED = 1;
+    
+    private TextView mColumn1;
+    private TextView mColumn2;
+    private View mContentView;
+    private int mFontIndex = FONT_INDEX_SANS;
+    private int mFontStyle = Typeface.NORMAL;
+    private int mFontSize = 18;
+    private int mTextIndex;
+    private int mTextScaleXDelta;
+}
+
diff --git a/apps/FontLab/src/com/android/fontlab/FontPicker.java b/apps/FontLab/src/com/android/fontlab/FontPicker.java
new file mode 100644
index 0000000..7f4fdb6
--- /dev/null
+++ b/apps/FontLab/src/com/android/fontlab/FontPicker.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.fontlab;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+
+
+public abstract class FontPicker extends ListActivity 
+{
+    
+    public void onCreate(Bundle icicle) 
+    {
+        super.onCreate(icicle);
+
+        setListAdapter(new SimpleAdapter(this,
+                getData(),
+                android.R.layout.simple_list_item_1,
+                new String[] {"title"},
+                new int[] {android.R.id.text1}));
+    }
+    
+    protected List getData()
+    {
+        List myData = new ArrayList<Bundle>(7);
+        addItem(myData, "Sans",                 "sans-serif",   Typeface.NORMAL);
+        addItem(myData, "Sans Bold",            "sans-serif",   Typeface.BOLD);
+        addItem(myData, "Serif",                "serif",        Typeface.NORMAL);
+        addItem(myData, "Serif Bold",           "serif",        Typeface.BOLD);
+        addItem(myData, "Serif Italic",         "serif",        Typeface.ITALIC);
+        addItem(myData, "Serif Bold Italic",    "serif",        Typeface.BOLD_ITALIC);
+        addItem(myData, "Mono",                 "monospace",    Typeface.NORMAL);
+        return myData;
+    }
+    
+    protected void addItem(List<Bundle> data, String name, String fontName, int style)
+    {
+        Bundle temp = new Bundle();
+        temp.putString("title", name);
+        temp.putString("font", fontName);
+        temp.putInt("style", style);
+        data.add(temp);
+    }
+
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+        Bundle map = (Bundle) l.getItemAtPosition(position);
+        setResult(RESULT_OK, (new Intent()).putExtras(map));
+        finish();
+    }
+  
+}
diff --git a/apps/OBJViewer/Android.mk b/apps/OBJViewer/Android.mk
new file mode 100644
index 0000000..3d5786c
--- /dev/null
+++ b/apps/OBJViewer/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := OBJViewer
+
+LOCAL_MODULE_TAGS := tests
+
+# currently disabled because of API changes. won't be fixed for 1.0
+#include $(BUILD_PACKAGE)
diff --git a/apps/OBJViewer/AndroidManifest.xml b/apps/OBJViewer/AndroidManifest.xml
new file mode 100644
index 0000000..b1c39b8
--- /dev/null
+++ b/apps/OBJViewer/AndroidManifest.xml
@@ -0,0 +1,10 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.objviewer">
+    <application>
+        <activity android:name="OBJViewer" android:label="3D .obj File Viewer">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/apps/OBJViewer/MODULE_LICENSE_APACHE2 b/apps/OBJViewer/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/OBJViewer/MODULE_LICENSE_APACHE2
diff --git a/apps/OBJViewer/NOTICE b/apps/OBJViewer/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/apps/OBJViewer/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/apps/OBJViewer/assets/al.gles b/apps/OBJViewer/assets/al.gles
new file mode 100644
index 0000000..086de08
--- /dev/null
+++ b/apps/OBJViewer/assets/al.gles
Binary files differ
diff --git a/apps/OBJViewer/assets/apple.gles b/apps/OBJViewer/assets/apple.gles
new file mode 100644
index 0000000..41860a0
--- /dev/null
+++ b/apps/OBJViewer/assets/apple.gles
Binary files differ
diff --git a/apps/OBJViewer/assets/dolphins.gles b/apps/OBJViewer/assets/dolphins.gles
new file mode 100644
index 0000000..9066962
--- /dev/null
+++ b/apps/OBJViewer/assets/dolphins.gles
Binary files differ
diff --git a/apps/OBJViewer/assets/earth.raw b/apps/OBJViewer/assets/earth.raw
new file mode 100644
index 0000000..f884e75
--- /dev/null
+++ b/apps/OBJViewer/assets/earth.raw
Binary files differ
diff --git a/apps/OBJViewer/assets/f16.gles b/apps/OBJViewer/assets/f16.gles
new file mode 100644
index 0000000..51f3ef3
--- /dev/null
+++ b/apps/OBJViewer/assets/f16.gles
Binary files differ
diff --git a/apps/OBJViewer/assets/flowers.gles b/apps/OBJViewer/assets/flowers.gles
new file mode 100644
index 0000000..7726428
--- /dev/null
+++ b/apps/OBJViewer/assets/flowers.gles
Binary files differ
diff --git a/apps/OBJViewer/assets/porsche.gles b/apps/OBJViewer/assets/porsche.gles
new file mode 100644
index 0000000..383ed77
--- /dev/null
+++ b/apps/OBJViewer/assets/porsche.gles
Binary files differ
diff --git a/apps/OBJViewer/assets/rosevase.gles b/apps/OBJViewer/assets/rosevase.gles
new file mode 100644
index 0000000..e83fe07
--- /dev/null
+++ b/apps/OBJViewer/assets/rosevase.gles
Binary files differ
diff --git a/apps/OBJViewer/assets/shuttle.gles b/apps/OBJViewer/assets/shuttle.gles
new file mode 100644
index 0000000..e12e3e0
--- /dev/null
+++ b/apps/OBJViewer/assets/shuttle.gles
Binary files differ
diff --git a/apps/OBJViewer/assets/skin.raw b/apps/OBJViewer/assets/skin.raw
new file mode 100644
index 0000000..2c0f9dd
--- /dev/null
+++ b/apps/OBJViewer/assets/skin.raw
Binary files differ
diff --git a/apps/OBJViewer/assets/soccerball.gles b/apps/OBJViewer/assets/soccerball.gles
new file mode 100644
index 0000000..08a7f84
--- /dev/null
+++ b/apps/OBJViewer/assets/soccerball.gles
Binary files differ
diff --git a/apps/OBJViewer/assets/stem_color.raw b/apps/OBJViewer/assets/stem_color.raw
new file mode 100644
index 0000000..1aada90
--- /dev/null
+++ b/apps/OBJViewer/assets/stem_color.raw
Binary files differ
diff --git a/apps/OBJViewer/assets/world.gles b/apps/OBJViewer/assets/world.gles
new file mode 100644
index 0000000..654692c
--- /dev/null
+++ b/apps/OBJViewer/assets/world.gles
Binary files differ
diff --git a/apps/OBJViewer/com/android/objviewer/OBJViewer.java b/apps/OBJViewer/com/android/objviewer/OBJViewer.java
new file mode 100644
index 0000000..3929a87
--- /dev/null
+++ b/apps/OBJViewer/com/android/objviewer/OBJViewer.java
@@ -0,0 +1,334 @@
+/*
+ * 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.
+ */
+
+package com.android.objviewer;
+
+import android.app.Activity;
+import android.content.AssetManager;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.OpenGLContext;
+import android.graphics.Paint;
+import android.graphics.glutils.GLView;
+import android.graphics.glutils.Object3D;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.Window;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.microedition.khronos.opengles.GL10;
+
+class OBJView extends View {
+
+    // Mathematical constants
+    private static final float PI = (float)Math.PI;
+    private static final float TWO_PI = (float)(2.0*Math.PI);
+    private static final float PI_OVER_TWO = (float)(Math.PI/2.0);
+
+    // Ambient light to apply
+    // private float[] lightModelAmbient = { 0.0f, 0.0f, 0.0f, 1.0f };
+    private float[] lightModelAmbient = { 0.2f, 0.2f, 0.2f, 1.0f };
+
+    // Paint object for drawing the FPS display
+    private Paint paint = new Paint();
+
+    // GLView object to manage drawing    
+    private GLView glView = new GLView();
+
+    private boolean         initialized = false;
+
+    private OpenGLContext   mGLContext;
+
+    // Next time to draw
+    private long            mNextTime;
+
+    // View transformation controlled by UI
+    private float           mRotAngle = 0.0f;
+    private float           mRotVelocity = 1.0f;
+    private float           mTiltAngle = 0.0f;
+
+    // Object bounds
+    private float           mCenterX = 0.0f;
+    private float           mCenterY = 0.0f;
+    private float           mCenterZ = 0.0f;
+    private float           mScale   = 1.0f;
+
+    // Light direction
+    private float[] mLightDir = { 0.0f, 0.0f, 1.0f, 0.0f };
+
+    public OBJView(Context context) {
+        super(context);
+
+        mGLContext = new OpenGLContext(OpenGLContext.DEPTH_BUFFER);
+
+        Message msg = mHandler.obtainMessage(INVALIDATE);
+        mNextTime = SystemClock.uptimeMillis() + 100;
+        mHandler.sendMessageAtTime(msg, mNextTime);
+
+        requestFocus();
+    }
+
+    public void reset() {
+        initialized = false;
+
+        mRotAngle = 0.0f;
+        mRotVelocity = 1.0f;
+        mTiltAngle = 0.0f;
+
+        mCenterX = 0.0f;
+        mCenterY = 0.0f;
+        mCenterZ = 0.0f;
+        mScale   = 1.0f;
+    }
+
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        // Hand the key to the GLView object first
+        if (glView.processKey(keyCode)) {
+            return true;
+        }
+
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                mRotVelocity -= 1.0f;
+                break;
+
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                mRotVelocity += 1.0f;
+                break;
+
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+                mRotVelocity = 0.0f;
+                break;
+
+            case KeyEvent.KEYCODE_DPAD_UP:	
+                mTiltAngle -= 360.0f/24.0f;
+                break;
+
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                mTiltAngle += 360.0f/24.0f;
+                break;
+
+            case KeyEvent.KEYCODE_U:
+                OBJViewer.nextObject();
+                reset();
+                break;
+
+            default:
+                return super.onKeyDown(keyCode, event);
+        }
+
+        return true;
+    }
+
+    private void init(GL10 gl) {
+        glView.reset();
+
+        paint.setColor(0xffffffff);
+
+        gl.glEnable(gl.GL_DEPTH_TEST);
+
+        gl.glDisable(gl.GL_SCISSOR_TEST);
+
+        // Some quality settings...
+        gl.glEnable(gl.GL_DITHER);
+
+        gl.glShadeModel(gl.GL_SMOOTH);
+
+        gl.glEnable(gl.GL_CULL_FACE);
+        gl.glFrontFace(gl.GL_CCW);
+
+        gl.glClearColor(0, 0, 0, 1);
+
+        gl.glLightModelf(gl.GL_LIGHT_MODEL_TWO_SIDE, 0);
+        gl.glLightModelfv(gl.GL_LIGHT_MODEL_AMBIENT, lightModelAmbient, 0);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        GL10 gl = (GL10)mGLContext.getGL();
+        mGLContext.makeCurrent(this);
+
+        if (!initialized) {
+            init(gl);
+            initialized = true;
+
+            // Load the object
+            Object3D obj = OBJViewer.getObject();
+
+            // Compute a scale factor and translation to bring it
+            // into view
+            mCenterX = (obj.getBoundsMinX() + obj.getBoundsMaxX())/2.0f;
+            mCenterY = (obj.getBoundsMinY() + obj.getBoundsMaxY())/2.0f;
+            mCenterZ = (obj.getBoundsMinZ() + obj.getBoundsMaxZ())/2.0f;
+            float spanX = obj.getBoundsMaxX() - obj.getBoundsMinX();
+            float spanY = obj.getBoundsMaxY() - obj.getBoundsMinY();
+            float spanZ = obj.getBoundsMaxZ() - obj.getBoundsMinZ();
+            float maxSpan = Math.max(spanX, spanY);
+            maxSpan = Math.max(maxSpan, spanZ);
+            mScale = 2.0f/maxSpan;
+        }
+
+        int w = getWidth();
+        int h = getHeight();
+        gl.glViewport(0, 0, w, h);
+
+        float ratio = (float)w/h;
+        glView.setAspectRatio(ratio);
+
+        // Clear buffers
+        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);
+
+        // Set up the projection and view
+        glView.setProjection(gl);
+        glView.setView(gl);
+
+        // Set up lighting
+        gl.glMatrixMode(gl.GL_MODELVIEW);
+        gl.glEnable(gl.GL_LIGHTING);
+        gl.glEnable(gl.GL_LIGHT0);
+        gl.glLightfv(gl.GL_LIGHT0, gl.GL_POSITION, mLightDir, 0);
+        glView.setLights(gl, gl.GL_LIGHT0);
+
+        // Rotate the viewpoint around the model
+        gl.glRotatef(mTiltAngle, 1, 0, 0);
+        gl.glRotatef(mRotAngle, 0, 1, 0);
+
+        // Scale object to fit in [-1, 1]
+        gl.glScalef(mScale, mScale, mScale);
+
+        // Center the object at the origin
+        gl.glTranslatef(-mCenterX, -mCenterY, -mCenterZ);
+
+        // Increment the rotation angle
+        mRotAngle += mRotVelocity;
+        if (mRotAngle < 0.0f) {
+            mRotAngle += 360.0f;
+        }
+        if (mRotAngle > 360.0f) {
+            mRotAngle -= 360.0f;
+        }
+
+        // Draw the object
+        Object3D object = OBJViewer.getObject();
+        object.draw(gl);
+
+        // Allow GL to complete
+        mGLContext.post();
+
+        // Draw GLView messages and/or FPS
+        glView.showMessages(canvas);
+        glView.setNumTriangles(object.getNumTriangles());
+        glView.showStatistics(canvas, w);
+    }
+
+    private static final int INVALIDATE = 1;
+
+    private final Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            if (msg.what == INVALIDATE) {
+                invalidate();
+                msg = obtainMessage(INVALIDATE);
+                long current = SystemClock.uptimeMillis();
+                if (mNextTime < current) {
+                    mNextTime = current + 20;
+                }
+                sendMessageAtTime(msg, mNextTime);
+                mNextTime += 20;
+            }
+        }
+    };
+}
+
+
+public class OBJViewer extends Activity {
+
+    private static Object3D object = null;
+
+    private static List<String> objectFiles = new ArrayList<String>();
+    private static int objectIndex = 0;
+
+    static {
+        objectFiles.add("world.gles");
+        objectFiles.add("al.gles");
+        objectFiles.add("apple.gles");
+        objectFiles.add("dolphins.gles");
+        objectFiles.add("f16.gles");
+        objectFiles.add("flowers.gles");
+        objectFiles.add("porsche.gles");
+        objectFiles.add("rosevase.gles");
+        objectFiles.add("shuttle.gles");
+        objectFiles.add("soccerball.gles");
+    }
+
+    private int readInt16(InputStream is) throws Exception {
+        return is.read() | (is.read() << 8);
+    }
+
+    public static Object3D getObject() {
+        return object;
+    }
+
+    public static void nextObject() {
+        try {
+            objectIndex = (objectIndex + 1) % objectFiles.size();
+            object.load(objectFiles.get(objectIndex));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // Get rid of the title
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        // Make sure we're not drawing a background
+        setTheme(R.style.Theme);
+        setContentView(new OBJView((Context)getApplication()));
+
+        if (object == null) {
+            try {
+                final AssetManager am = getAssets();
+                this.object = new Object3D() {
+                    public InputStream readFile(String filename)
+                    throws IOException {
+                        return am.open(filename);
+
+                    }
+                };
+                object.load(objectFiles.get(0));
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    @Override protected void onResume() {
+        super.onResume();
+    }
+
+    @Override protected void onStop() {
+        super.onStop();
+    }
+}
diff --git a/apps/OBJViewer/res/values/styles.xml b/apps/OBJViewer/res/values/styles.xml
new file mode 100644
index 0000000..62f4684
--- /dev/null
+++ b/apps/OBJViewer/res/values/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/Calendar/assets/res/any/styles.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>
+    <style name="Theme" parent="android:Theme">
+        <item name="android:windowBackground">@null</item>
+    </style>
+</resources>
diff --git a/apps/SdkSetup/Android.mk b/apps/SdkSetup/Android.mk
new file mode 100644
index 0000000..538c2cb
--- /dev/null
+++ b/apps/SdkSetup/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SdkSetup
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/apps/SdkSetup/AndroidManifest.xml b/apps/SdkSetup/AndroidManifest.xml
new file mode 100644
index 0000000..966eeb1
--- /dev/null
+++ b/apps/SdkSetup/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?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.sdksetup">
+
+    <!-- For miscellaneous settings -->
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+
+    <application>
+        <activity android:name="DefaultActivity"
+                android:excludeFromRecents="true">
+            <intent-filter android:priority="1">
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.HOME" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
+
diff --git a/apps/SdkSetup/src/com/android/sdksetup/DefaultActivity.java b/apps/SdkSetup/src/com/android/sdksetup/DefaultActivity.java
new file mode 100644
index 0000000..db6385c
--- /dev/null
+++ b/apps/SdkSetup/src/com/android/sdksetup/DefaultActivity.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdksetup;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.provider.Settings;
+
+/**
+ * Entry point for SDK SetupWizard.
+ *
+ */
+public class DefaultActivity extends Activity {
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        // Add a persistent setting to allow other apps to know the device has been provisioned.
+        Settings.Secure.putInt(getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 1);
+
+        // Enable the GPS.
+        // Not needed since this SDK will contain the Settings app.
+        LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
+        Settings.Secure.putString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED, LocationManager.GPS_PROVIDER);
+        locationManager.updateProviders();
+        
+        // enable install from non market
+        Settings.Secure.putInt(getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS, 1);
+
+        // remove this activity from the package manager.
+        PackageManager pm = getPackageManager();
+        ComponentName name = new ComponentName(this, DefaultActivity.class);
+        pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
+
+        // terminate the activity.
+        finish();
+    }
+}
+
diff --git a/apps/SpareParts/Android.mk b/apps/SpareParts/Android.mk
new file mode 100644
index 0000000..ccf6c6d
--- /dev/null
+++ b/apps/SpareParts/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := eng development
+
+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
new file mode 100644
index 0000000..85de7a4
--- /dev/null
+++ b/apps/SpareParts/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?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="@drawable/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/drawable/app_icon.png b/apps/SpareParts/res/drawable/app_icon.png
new file mode 100644
index 0000000..cb40a19
--- /dev/null
+++ b/apps/SpareParts/res/drawable/app_icon.png
Binary files differ
diff --git a/apps/SpareParts/res/layout/spare_parts.xml b/apps/SpareParts/res/layout/spare_parts.xml
new file mode 100644
index 0000000..f39298b
--- /dev/null
+++ b/apps/SpareParts/res/layout/spare_parts.xml
@@ -0,0 +1,51 @@
+<?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="fill_parent"
+    android:layout_height="fill_parent">
+
+    <RelativeLayout 
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+        <Spinner android:id="@+id/window_animation_scale"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true">
+        </Spinner>
+
+        <Spinner android:id="@+id/transition_animation_scale"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/window_animation_scale"
+            android:layout_alignParentLeft="true">
+        </Spinner>
+
+        <CheckBox android:id="@+id/show_maps_compass"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/transition_animation_scale"
+            android:layout_alignParentLeft="true"
+            android:text="@string/development_settings_show_maps_compass_text" />
+            
+    </RelativeLayout>
+
+</ScrollView>
+
diff --git a/apps/SpareParts/res/values/arrays.xml b/apps/SpareParts/res/values/arrays.xml
new file mode 100644
index 0000000..e6026da
--- /dev/null
+++ b/apps/SpareParts/res/values/arrays.xml
@@ -0,0 +1,68 @@
+<?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
new file mode 100644
index 0000000..21c2df9
--- /dev/null
+++ b/apps/SpareParts/res/values/strings.xml
@@ -0,0 +1,71 @@
+<?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="title_accelerometer">Display rotation</string>
+    <string name="summary_on_accelerometer">Display rotates from orientation</string>
+    <string name="summary_off_accelerometer">Display rotates from orientation</string>
+    
+    <string name="applications_title">Applications</string>
+    
+    <string name="title_maps_compass">Show compass in Maps</string>
+    <string name="summary_on_maps_compass">Compass is displayed in Maps</string>
+    <string name="summary_off_maps_compass">Compass is not displayed in Maps</string>
+    
+    <string name="development_settings_show_maps_compass_text">Show compass in Maps</string>
+</resources>
diff --git a/apps/SpareParts/res/xml/spare_parts.xml b/apps/SpareParts/res/xml/spare_parts.xml
new file mode 100644
index 0000000..5141e22
--- /dev/null
+++ b/apps/SpareParts/res/xml/spare_parts.xml
@@ -0,0 +1,116 @@
+<?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.battery_history.BatteryHistory" />
+        </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="accelerometer" 
+            android:title="@string/title_accelerometer" 
+            android:summaryOn="@string/summary_on_accelerometer"
+            android:summaryOff="@string/summary_off_accelerometer"/>
+        
+        <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"/>
+        
+    </PreferenceCategory>
+            
+    <PreferenceCategory
+        android:title="@string/applications_title">
+                
+        <CheckBoxPreference 
+            android:key="maps_compass" 
+            android:title="@string/title_maps_compass" 
+            android:summaryOn="@string/summary_on_maps_compass"
+            android:summaryOff="@string/summary_off_maps_compass"/>
+        
+    </PreferenceCategory>
+        
+</PreferenceScreen>
diff --git a/apps/SpareParts/src/com/android/spare_parts/SpareParts.java b/apps/SpareParts/src/com/android/spare_parts/SpareParts.java
new file mode 100644
index 0000000..4852ec2
--- /dev/null
+++ b/apps/SpareParts/src/com/android/spare_parts/SpareParts.java
@@ -0,0 +1,281 @@
+/* //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 ACCELEROMETER_PREF = "accelerometer";
+    private static final String MAPS_COMPASS_PREF = "maps_compass";
+    
+    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 mAccelerometerPref;
+    private CheckBoxPreference mShowMapsCompassPref;
+    
+    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);
+        mAccelerometerPref = (CheckBoxPreference) prefSet.findPreference(ACCELEROMETER_PREF);
+        mShowMapsCompassPref = (CheckBoxPreference) prefSet.findPreference(MAPS_COMPASS_PREF);
+        
+        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() {
+        try {
+            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);
+            mAccelerometerPref.setChecked(Settings.System.getInt(
+                    getContentResolver(), 
+                    Settings.System.ACCELEROMETER_ROTATION, 0) != 0);
+            Context c = createPackageContext("com.google.android.apps.maps", 0);
+            mShowMapsCompassPref.setChecked(c.getSharedPreferences("extra-features", MODE_WORLD_READABLE)
+                .getBoolean("compass", false));
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Failed reading maps compass");
+            e.printStackTrace();
+        }
+    }
+    
+    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;
+    }
+    
+    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 (ACCELEROMETER_PREF.equals(key)) {
+            Settings.System.putInt(getContentResolver(),
+                    Settings.System.ACCELEROMETER_ROTATION,
+                    mAccelerometerPref.isChecked() ? 1 : 0);
+        } else 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);
+        } else if (MAPS_COMPASS_PREF.equals(key)) {
+            try {
+                Context c = createPackageContext("com.google.android.apps.maps", 0);
+                c.getSharedPreferences("extra-features", MODE_WORLD_WRITEABLE)
+                    .edit()
+                    .putBoolean("compass", mShowMapsCompassPref.isChecked())
+                    .commit();
+            } catch (NameNotFoundException e) {
+                Log.w(TAG, "Failed setting maps compass");
+                e.printStackTrace();
+            }
+        }
+    }
+    
+    @Override
+    public void onResume() {
+        super.onResume();
+        readAnimationPreference(0, mWindowAnimationsPref);
+        readAnimationPreference(1, mTransitionAnimationsPref);
+        readFontSizePreference(mFontSizePref);
+        readEndButtonPreference(mEndButtonPref);
+        updateToggles();
+    }
+}
diff --git a/apps/Term/Android.mk b/apps/Term/Android.mk
new file mode 100644
index 0000000..843aec5
--- /dev/null
+++ b/apps/Term/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := eng
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := Term
+
+include $(BUILD_PACKAGE)
diff --git a/apps/Term/AndroidManifest.xml b/apps/Term/AndroidManifest.xml
new file mode 100644
index 0000000..7084d2c
--- /dev/null
+++ b/apps/Term/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.term">
+    <application android:icon="@drawable/app_terminal"
+                android:label="@string/application_terminal">
+        <activity android:name="Term"
+                android:theme="@style/Theme"
+                android:launchMode="singleInstance"
+                android:configChanges="keyboard|keyboardHidden|orientation"
+                android:windowSoftInputMode="adjustResize|stateVisible">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+        <activity android:name="TermPreferences"/>
+    </application>
+</manifest> 
diff --git a/apps/Term/MODULE_LICENSE_APACHE2 b/apps/Term/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/Term/MODULE_LICENSE_APACHE2
diff --git a/apps/Term/NOTICE b/apps/Term/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/apps/Term/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/apps/Term/res/drawable/app_terminal.png b/apps/Term/res/drawable/app_terminal.png
new file mode 100644
index 0000000..1ec3b4b
--- /dev/null
+++ b/apps/Term/res/drawable/app_terminal.png
Binary files differ
diff --git a/apps/Term/res/drawable/atari_small.png b/apps/Term/res/drawable/atari_small.png
new file mode 100644
index 0000000..535e295
--- /dev/null
+++ b/apps/Term/res/drawable/atari_small.png
Binary files differ
diff --git a/apps/Term/res/drawable/atari_small_notice.txt b/apps/Term/res/drawable/atari_small_notice.txt
new file mode 100644
index 0000000..afa8539
--- /dev/null
+++ b/apps/Term/res/drawable/atari_small_notice.txt
@@ -0,0 +1,11 @@
+COMMENT  Copyright (c) 1999, Thomas A. Fine
+COMMENT
+COMMENT  License to copy, modify, and distribute for both commercial and
+COMMENT  non-commercial use is herby granted, provided this notice
+COMMENT  is preserved.
+COMMENT
+COMMENT  Email to my last name at head.cfa.harvard.edu
+COMMENT  http://hea-www.harvard.edu/~fine/
+COMMENT
+COMMENT  Produced with bdfedit, a tcl/tk font editing program
+COMMENT  written by Thomas A. Fine
\ No newline at end of file
diff --git a/apps/Term/res/layout/term_activity.xml b/apps/Term/res/layout/term_activity.xml
new file mode 100644
index 0000000..7d93d16
--- /dev/null
+++ b/apps/Term/res/layout/term_activity.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent" 
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+
+    <com.android.term.EmulatorView android:id="@+id/emulatorView"
+	      android:layout_width="wrap_content"
+	      android:layout_height="wrap_content"
+	      android:layout_alignParentLeft="true"
+	      />
+   
+</LinearLayout>
diff --git a/apps/Term/res/menu/main.xml b/apps/Term/res/menu/main.xml
new file mode 100644
index 0000000..5f6e9d8
--- /dev/null
+++ b/apps/Term/res/menu/main.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_preferences"
+    	android:title="@string/preferences" />
+    <item android:id="@+id/menu_reset"
+    	android:title="@string/reset" />
+    <item android:id="@+id/menu_send_email"
+    	android:title="@string/send_email" />
+    <item android:id="@+id/menu_special_keys"
+    	android:title="@string/special_keys" />
+</menu>
diff --git a/apps/Term/res/values/arrays.xml b/apps/Term/res/values/arrays.xml
new file mode 100644
index 0000000..b4857a2
--- /dev/null
+++ b/apps/Term/res/values/arrays.xml
@@ -0,0 +1,73 @@
+<?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_fontsize_preference">
+        <item>4 x 8 pixels</item>
+        <item>6 pt</item>
+        <item>7 pt</item>
+        <item>8 pt</item>
+        <item>9 pt</item>
+        <item>10 pt</item>
+        <item>12 pt</item>
+        <item>14 pt</item>
+        <item>16 pt</item>
+        <item>20 pt</item>
+    </string-array>
+
+	<!-- Do not localize entryvalues -->
+    <string-array name="entryvalues_fontsize_preference">
+        <item>0</item>
+        <item>6</item>
+        <item>7</item>
+        <item>8</item>
+        <item>9</item>
+        <item>10</item>
+        <item>12</item>
+        <item>14</item>
+        <item>16</item>
+        <item>20</item>  
+    </string-array>
+
+    <string-array name="entries_color_preference">
+        <item>Black text on white</item>
+        <item>White text on black</item>
+        <item>White text on blue</item>  
+    </string-array>
+
+	<!-- Do not localize entryvalues -->
+    <string-array name="entryvalues_color_preference">
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>  
+    </string-array>
+    
+    <string-array name="entries_controlkey_preference">
+        <item>Jog ball</item>
+        <item>\@ key</item>
+        <item>Left Alt key</item>
+        <item>Right Alt key</item>
+    </string-array>
+
+	<!-- Do not localize entryvalues -->
+    <string-array name="entryvalues_controlkey_preference">
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+    </string-array>
+</resources>
diff --git a/apps/Term/res/values/attrs.xml b/apps/Term/res/values/attrs.xml
new file mode 100644
index 0000000..3787d7e
--- /dev/null
+++ b/apps/Term/res/values/attrs.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<resources>
+     <declare-styleable name="EmulatorView">
+    </declare-styleable>
+</resources>
diff --git a/apps/Term/res/values/strings.xml b/apps/Term/res/values/strings.xml
new file mode 100644
index 0000000..e3f8fcf
--- /dev/null
+++ b/apps/Term/res/values/strings.xml
@@ -0,0 +1,55 @@
+<?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.
+-->
+<resources>
+   <string name="application_terminal">Terminal Emulator</string>
+   <string name="preferences">Preferences</string>
+   <string name="reset">Reset term</string>
+   <string name="send_email">Email to</string>
+   <string name="special_keys">Special keys</string>
+
+   <!-- Preference dialog -->
+   <string name="text_preferences">Text</string>
+
+   <string name="title_fontsize_preference">Font size</string>
+   <string name="summary_fontsize_preference">Choose character height in pixels.</string>
+   <string name="dialog_title_fontsize_preference">Font size</string>
+
+   <string name="title_color_preference">Colors</string>
+   <string name="summary_color_preference">Choose text color.</string>
+   <string name="dialog_title_color_preference">Text color</string>
+
+   <string name="keyboard_preferences">Keyboard</string>
+   <string name="title_controlkey_preference">Control key</string>
+   <string name="summary_controlkey_preference">Choose control key.</string>
+   <string name="dialog_title_controlkey_preference">Control key</string>
+
+   <string name="shell_preferences">Shell</string>
+   <string name="title_shell_preference">Command line</string>
+   <string name="summary_shell_preference">Specify the shell command line.</string>
+   <string name="dialog_title_shell_preference">Shell</string>
+
+   <string name="title_initialcommand_preference">Initial command</string>
+   <string name="summary_initialcommand_preference">Sent to the shell when it starts.</string>
+   <string name="dialog_title_initialcommand_preference">Initial Command</string>
+
+   <!-- Don't localize these default values -->
+   <string name="default_value_fontsize_preference">10</string>
+   <string name="default_value_color_preference">2</string>
+   <string name="default_value_controlkey_preference">0</string>
+   <string name="default_value_shell_preference">/system/bin/sh -</string>
+   <string name="default_value_initialcommand_preference">export PATH=/data/local/bin:$PATH</string>
+</resources>
diff --git a/apps/Term/res/values/styles.xml b/apps/Term/res/values/styles.xml
new file mode 100644
index 0000000..0e59f4a
--- /dev/null
+++ b/apps/Term/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?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>
+    <style name="Theme" parent="@android:style/Theme.Light">
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowFrame">@null</item>
+    </style>
+</resources>
+
diff --git a/apps/Term/res/xml/preferences.xml b/apps/Term/res/xml/preferences.xml
new file mode 100644
index 0000000..7792153
--- /dev/null
+++ b/apps/Term/res/xml/preferences.xml
@@ -0,0 +1,73 @@
+<?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.
+-->
+
+<PreferenceScreen
+        xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <PreferenceCategory
+            android:title="@string/text_preferences">
+
+        <ListPreference
+                android:key="fontsize"
+                android:defaultValue="@string/default_value_fontsize_preference"
+                android:title="@string/title_fontsize_preference"
+                android:summary="@string/summary_fontsize_preference"
+                android:entries="@array/entries_fontsize_preference"
+                android:entryValues="@array/entryvalues_fontsize_preference"
+                android:dialogTitle="@string/dialog_title_fontsize_preference" />
+
+        <ListPreference
+                android:key="color"
+                android:defaultValue="@string/default_value_color_preference"
+                android:title="@string/title_color_preference"
+                android:summary="@string/summary_color_preference"
+                android:entries="@array/entries_color_preference"
+                android:entryValues="@array/entryvalues_color_preference"
+                android:dialogTitle="@string/dialog_title_color_preference" />
+
+    </PreferenceCategory>
+
+    <PreferenceCategory
+            android:title="@string/keyboard_preferences">
+
+        <ListPreference
+                android:key="controlkey"
+                android:defaultValue="@string/default_value_controlkey_preference"
+                android:title="@string/title_controlkey_preference"
+                android:summary="@string/summary_controlkey_preference"
+                android:entries="@array/entries_controlkey_preference"
+                android:entryValues="@array/entryvalues_controlkey_preference"
+                android:dialogTitle="@string/dialog_title_controlkey_preference" />
+
+    </PreferenceCategory>
+
+    <PreferenceCategory
+        android:title="@string/shell_preferences">
+
+    <EditTextPreference
+            android:key="shell"
+            android:defaultValue="@string/default_value_shell_preference"
+            android:title="@string/title_shell_preference"
+            android:summary="@string/summary_shell_preference"
+            android:dialogTitle="@string/dialog_title_shell_preference" />
+    <EditTextPreference
+            android:key="initialcommand"
+            android:defaultValue="@string/default_value_initialcommand_preference"
+            android:title="@string/title_initialcommand_preference"
+            android:summary="@string/summary_initialcommand_preference"
+            android:dialogTitle="@string/dialog_title_initialcommand_preference" />
+    </PreferenceCategory>
+</PreferenceScreen>
diff --git a/apps/Term/src/com/android/term/Term.java b/apps/Term/src/com/android/term/Term.java
new file mode 100644
index 0000000..d74159b
--- /dev/null
+++ b/apps/Term/src/com/android/term/Term.java
@@ -0,0 +1,3262 @@
+/*
+ * 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.
+ */
+
+package com.android.term;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Exec;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.preference.PreferenceManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * A terminal emulator activity.
+ */
+
+public class Term extends Activity {
+    /**
+     * Set to true to add debugging code and logging.
+     */
+    public static final boolean DEBUG = false;
+
+    /**
+     * Set to true to log each character received from the remote process to the
+     * android log, which makes it easier to debug some kinds of problems with
+     * emulating escape sequences and control codes.
+     */
+    public static final boolean LOG_CHARACTERS_FLAG = DEBUG && false;
+
+    /**
+     * Set to true to log unknown escape sequences.
+     */
+    public static final boolean LOG_UNKNOWN_ESCAPE_SEQUENCES = DEBUG && false;
+
+    /**
+     * The tag we use when logging, so that our messages can be distinguished
+     * from other messages in the log. Public because it's used by several
+     * classes.
+     */
+    public static final String LOG_TAG = "Term";
+
+    /**
+     * Our main view. Displays the emulated terminal screen.
+     */
+    private EmulatorView mEmulatorView;
+
+    /**
+     * The pseudo-teletype (pty) file descriptor that we use to communicate with
+     * another process, typically a shell. Currently we just use this to get the
+     * mTermIn / mTermOut file descriptors, but when we implement resizing of
+     * the terminal we will need it to issue the ioctl to inform the other
+     * process that we've changed the terminal size.
+     */
+    private FileDescriptor mTermFd;
+
+    private boolean mShellRunning;
+
+    /**
+     * Used to send data to the remote process.
+     */
+    private FileOutputStream mTermOut;
+
+    /**
+     * A key listener that tracks the modifier keys and allows the full ASCII
+     * character set to be entered.
+     */
+    private TermKeyListener mKeyListener;
+
+    /**
+     * The name of our emulator view in the view resource.
+     */
+    private static final int EMULATOR_VIEW = R.id.emulatorView;
+
+    private int mFontSize = 9;
+    private int mColorId = 2;
+    private int mControlKeyId = 0;
+
+    private static final String FONTSIZE_KEY = "fontsize";
+    private static final String COLOR_KEY = "color";
+    private static final String CONTROLKEY_KEY = "controlkey";
+    private static final String SHELL_KEY = "shell";
+    private static final String INITIALCOMMAND_KEY = "initialcommand";
+
+    public static final int WHITE = 0xffffffff;
+    public static final int BLACK = 0xff000000;
+    public static final int BLUE = 0xff344ebd;
+
+    private static final int[][] COLOR_SCHEMES = {
+        {BLACK, WHITE}, {WHITE, BLACK}, {WHITE, BLUE}};
+
+    private static final int[] CONTROL_KEY_SCHEMES = {
+        KeyEvent.KEYCODE_DPAD_CENTER,
+        KeyEvent.KEYCODE_AT,
+        KeyEvent.KEYCODE_ALT_LEFT,
+        KeyEvent.KEYCODE_ALT_RIGHT
+    };
+    private static final String[] CONTROL_KEY_NAME = {
+        "Ball", "@", "Left-Alt", "Right-Alt"
+    };
+
+    private int mControlKeyCode;
+
+    private final static String DEFAULT_SHELL = "/system/bin/sh -";
+    private String mShell;
+
+    private final static String DEFAULT_INITIAL_COMMAND =
+        "export PATH=/data/local/bin:$PATH";
+    private String mInitialCommand;
+
+    private SharedPreferences mPrefs;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.e(Term.LOG_TAG, "onCreate");
+        mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+        mPrefs.registerOnSharedPreferenceChangeListener(
+                new SharedPreferences.OnSharedPreferenceChangeListener(){
+
+                    public void onSharedPreferenceChanged(
+                            SharedPreferences sharedPreferences, String key) {
+                        readPrefs();
+                        updatePrefs();
+                    }});
+        readPrefs();
+
+        setContentView(R.layout.term_activity);
+
+        mEmulatorView = (EmulatorView) findViewById(EMULATOR_VIEW);
+
+        startListening();
+
+        mKeyListener = new TermKeyListener();
+
+        mEmulatorView.setFocusable(true);
+        mEmulatorView.requestFocus();
+
+        updatePrefs();
+    }
+
+    private void startListening() {
+        int[] processId = new int[1];
+
+        createSubprocess(processId);
+        mShellRunning = true;
+
+        final int procId = processId[0];
+
+        final Handler handler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                mShellRunning = false;
+            }
+        };
+
+        Runnable watchForDeath = new Runnable() {
+
+            public void run() {
+                Log.i(Term.LOG_TAG, "waiting for: " + procId);
+               int result = Exec.waitFor(procId);
+                Log.i(Term.LOG_TAG, "Subprocess exited: " + result);
+                handler.sendEmptyMessage(result);
+             }
+
+        };
+        Thread watcher = new Thread(watchForDeath);
+        watcher.start();
+
+        mTermOut = new FileOutputStream(mTermFd);
+
+        mEmulatorView.initialize(mTermFd, mTermOut);
+
+        sendInitialCommand();
+    }
+
+    private void sendInitialCommand() {
+        String initialCommand = mInitialCommand;
+        if (initialCommand == null) {
+            initialCommand = DEFAULT_INITIAL_COMMAND;
+        }
+        if (initialCommand.length() > 0) {
+            write(initialCommand + '\r');
+        }
+    }
+
+    private void restart() {
+        startActivity(getIntent());
+        finish();
+    }
+
+    private void write(String data) {
+        try {
+            mTermOut.write(data.getBytes());
+            mTermOut.flush();
+        } catch (IOException e) {
+            // Ignore exception
+            // We don't really care if the receiver isn't listening.
+            // We just make a best effort to answer the query.
+        }
+    }
+
+    private void createSubprocess(int[] processId) {
+        String shell = mShell;
+        if (shell == null) {
+            shell = DEFAULT_SHELL;
+        }
+        ArrayList<String> args = parse(shell);
+        String arg0 = args.get(0);
+        String arg1 = null;
+        String arg2 = null;
+        if (args.size() >= 2) {
+            arg1 = args.get(1);
+        }
+        if (args.size() >= 3) {
+            arg2 = args.get(2);
+        }
+        mTermFd = Exec.createSubprocess(arg0, arg1, arg2, processId);
+    }
+
+    private ArrayList<String> parse(String cmd) {
+        final int PLAIN = 0;
+        final int WHITESPACE = 1;
+        final int INQUOTE = 2;
+        int state = WHITESPACE;
+        ArrayList<String> result =  new ArrayList<String>();
+        int cmdLen = cmd.length();
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < cmdLen; i++) {
+            char c = cmd.charAt(i);
+            if (state == PLAIN) {
+                if (Character.isWhitespace(c)) {
+                    result.add(builder.toString());
+                    builder.delete(0,builder.length());
+                    state = WHITESPACE;
+                } else if (c == '"') {
+                    state = INQUOTE;
+                } else {
+                    builder.append(c);
+                }
+            } else if (state == WHITESPACE) {
+                if (Character.isWhitespace(c)) {
+                    // do nothing
+                } else if (c == '"') {
+                    state = INQUOTE;
+                } else {
+                    state = PLAIN;
+                    builder.append(c);
+                }
+            } else if (state == INQUOTE) {
+                if (c == '\\') {
+                    if (i + 1 < cmdLen) {
+                        i += 1;
+                        builder.append(cmd.charAt(i));
+                    }
+                } else if (c == '"') {
+                    state = PLAIN;
+                } else {
+                    builder.append(c);
+                }
+            }
+        }
+        if (builder.length() > 0) {
+            result.add(builder.toString());
+        }
+        return result;
+    }
+
+    private void readPrefs() {
+        mFontSize = readIntPref(FONTSIZE_KEY, mFontSize, 20);
+        mColorId = readIntPref(COLOR_KEY, mColorId, COLOR_SCHEMES.length - 1);
+        mControlKeyId = readIntPref(CONTROLKEY_KEY, mControlKeyId,
+                CONTROL_KEY_SCHEMES.length - 1);
+        {
+            String newShell = readStringPref(SHELL_KEY, mShell);
+            if ((newShell == null) || ! newShell.equals(mShell)) {
+                if (mShell != null) {
+                    Log.i(Term.LOG_TAG, "New shell set. Restarting.");
+                    restart();
+                }
+                mShell = newShell;
+            }
+        }
+        {
+            String newInitialCommand = readStringPref(INITIALCOMMAND_KEY,
+                    mInitialCommand);
+            if ((newInitialCommand == null)
+                    || ! newInitialCommand.equals(mInitialCommand)) {
+                if (mInitialCommand != null) {
+                    Log.i(Term.LOG_TAG, "New initial command set. Restarting.");
+                    restart();
+                }
+                mInitialCommand = newInitialCommand;
+            }
+        }
+    }
+
+    private void updatePrefs() {
+        mEmulatorView.setTextSize(mFontSize);
+        setColors();
+        mControlKeyCode = CONTROL_KEY_SCHEMES[mControlKeyId];
+    }
+
+    private int readIntPref(String key, int defaultValue, int maxValue) {
+        int val;
+        try {
+            val = Integer.parseInt(
+                mPrefs.getString(key, Integer.toString(defaultValue)));
+        } catch (NumberFormatException e) {
+            val = defaultValue;
+        }
+        val = Math.max(0, Math.min(val, maxValue));
+        return val;
+    }
+
+    private String readStringPref(String key, String defaultValue) {
+        return mPrefs.getString(key, defaultValue);
+    }
+
+    @Override
+    public void onPause() {
+        SharedPreferences.Editor e = mPrefs.edit();
+        e.clear();
+        e.putString(FONTSIZE_KEY, Integer.toString(mFontSize));
+        e.putString(COLOR_KEY, Integer.toString(mColorId));
+        e.putString(CONTROLKEY_KEY, Integer.toString(mControlKeyId));
+        e.putString(SHELL_KEY, mShell);
+        e.putString(INITIALCOMMAND_KEY, mInitialCommand);
+        e.commit();
+
+        super.onPause();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        mEmulatorView.updateSize();
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (handleControlKey(keyCode, true)) {
+            return true;
+        } else if (isSystemKey(keyCode, event)) {
+            // Don't intercept the system keys
+            return super.onKeyDown(keyCode, event);
+        } else if (handleDPad(keyCode, true)) {
+            return true;
+        }
+
+        // Translate the keyCode into an ASCII character.
+        int letter = mKeyListener.keyDown(keyCode, event);
+
+        if (letter >= 0) {
+            try {
+                mTermOut.write(letter);
+            } catch (IOException e) {
+                // Ignore I/O exceptions
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (handleControlKey(keyCode, false)) {
+            return true;
+        } else if (isSystemKey(keyCode, event)) {
+            // Don't intercept the system keys
+            return super.onKeyUp(keyCode, event);
+        } else if (handleDPad(keyCode, false)) {
+            return true;
+        }
+
+        mKeyListener.keyUp(keyCode);
+        return true;
+    }
+
+    private boolean handleControlKey(int keyCode, boolean down) {
+        if (keyCode == mControlKeyCode) {
+            mKeyListener.handleControlKey(down);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Handle dpad left-right-up-down events. Don't handle
+     * dpad-center, that's our control key.
+     * @param keyCode
+     * @param down
+     */
+    private boolean handleDPad(int keyCode, boolean down) {
+        if (keyCode < KeyEvent.KEYCODE_DPAD_UP ||
+                keyCode > KeyEvent.KEYCODE_DPAD_CENTER) {
+            return false;
+        }
+
+        if (down) {
+            try {
+                if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+                    mTermOut.write('\r');
+                } else {
+                    char code;
+                    switch (keyCode) {
+                    case KeyEvent.KEYCODE_DPAD_UP:
+                        code = 'A';
+                        break;
+                    case KeyEvent.KEYCODE_DPAD_DOWN:
+                        code = 'B';
+                        break;
+                    case KeyEvent.KEYCODE_DPAD_LEFT:
+                        code = 'D';
+                        break;
+                    default:
+                    case KeyEvent.KEYCODE_DPAD_RIGHT:
+                        code = 'C';
+                        break;
+                    }
+                    mTermOut.write(27); // ESC
+                    if (mEmulatorView.getKeypadApplicationMode()) {
+                        mTermOut.write('O');
+                    } else {
+                        mTermOut.write('[');
+                    }
+                    mTermOut.write(code);
+                }
+            } catch (IOException e) {
+                // Ignore
+            }
+        }
+        return true;
+    }
+
+    private boolean isSystemKey(int keyCode, KeyEvent event) {
+        return event.isSystem();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        int id = item.getItemId();
+        if (id == R.id.menu_preferences) {
+            doPreferences();
+        } else if (id == R.id.menu_reset) {
+            doResetTerminal();
+        } else if (id == R.id.menu_send_email) {
+            doEmailTranscript();
+        } else if (id == R.id.menu_special_keys) {
+            doDocumentKeys();
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void doPreferences() {
+        startActivity(new Intent(this, TermPreferences.class));
+    }
+
+    private void setColors() {
+        int[] scheme = COLOR_SCHEMES[mColorId];
+        mEmulatorView.setColors(scheme[0], scheme[1]);
+    }
+
+    private void doResetTerminal() {
+        restart();
+    }
+
+    private void doEmailTranscript() {
+        // Don't really want to supply an address, but
+        // currently it's required, otherwise we get an
+        // exception.
+        String addr = "user@example.com";
+        Intent intent =
+                new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"
+                        + addr));
+
+        intent.putExtra("body", mEmulatorView.getTranscriptText());
+        startActivity(intent);
+    }
+
+    private void doDocumentKeys() {
+        String controlKey = CONTROL_KEY_NAME[mControlKeyId];
+        new AlertDialog.Builder(this).
+            setTitle("Press " + controlKey + " and Key").
+            setMessage(controlKey + " Space ==> Control-@ (NUL)\n"
+                    + controlKey + " A..Z ==> Control-A..Z\n"
+                    + controlKey + " 1 ==> Control-[ (ESC)\n"
+                    + controlKey + " 5 ==> Control-_\n"
+                    + controlKey + " . ==> Control-\\\n"
+                    + controlKey + " 0 ==> Control-]\n"
+                    + controlKey + " 6 ==> Control-^").
+            show();
+     }
+
+    private void print(String msg) {
+        char[] chars = msg.toCharArray();
+        int len = chars.length;
+        byte[] bytes = new byte[len];
+        for (int i = 0; i < len; i++) {
+            bytes[i] = (byte) chars[i];
+        }
+        mEmulatorView.append(bytes, 0, len);
+    }
+}
+
+
+/**
+ * An abstract screen interface. A terminal screen stores lines of text. (The
+ * reason to abstract it is to allow different implementations, and to hide
+ * implementation details from clients.)
+ */
+interface Screen {
+
+    /**
+     * Set line wrap flag for a given row. Affects how lines are logically
+     * wrapped when changing screen size or converting to a transcript.
+     */
+    void setLineWrap(int row);
+
+    /**
+     * Store byte b into the screen at location (x, y)
+     *
+     * @param x X coordinate (also known as column)
+     * @param y Y coordinate (also known as row)
+     * @param b ASCII character to store
+     * @param foreColor the foreground color
+     * @param backColor the background color
+     */
+    void set(int x, int y, byte b, int foreColor, int backColor);
+
+    /**
+     * Scroll the screen down one line. To scroll the whole screen of a 24 line
+     * screen, the arguments would be (0, 24).
+     *
+     * @param topMargin First line that is scrolled.
+     * @param bottomMargin One line after the last line that is scrolled.
+     */
+    void scroll(int topMargin, int bottomMargin, int foreColor, int backColor);
+
+    /**
+     * Block copy characters from one position in the screen to another. The two
+     * positions can overlap. All characters of the source and destination must
+     * be within the bounds of the screen, or else an InvalidParemeterException
+     * will be thrown.
+     *
+     * @param sx source X coordinate
+     * @param sy source Y coordinate
+     * @param w width
+     * @param h height
+     * @param dx destination X coordinate
+     * @param dy destination Y coordinate
+     */
+    void blockCopy(int sx, int sy, int w, int h, int dx, int dy);
+
+    /**
+     * Block set characters. All characters must be within the bounds of the
+     * screen, or else and InvalidParemeterException will be thrown. Typically
+     * this is called with a "val" argument of 32 to clear a block of
+     * characters.
+     *
+     * @param sx source X
+     * @param sy source Y
+     * @param w width
+     * @param h height
+     * @param val value to set.
+     * @param foreColor the foreground color
+     * @param backColor the background color
+     */
+    void blockSet(int sx, int sy, int w, int h, int val, int foreColor, int
+            backColor);
+
+    /**
+     * Get the contents of the transcript buffer as a text string.
+     *
+     * @return the contents of the transcript buffer.
+     */
+    String getTranscriptText();
+
+    /**
+     * Resize the screen
+     * @param columns
+     * @param rows
+     */
+    void resize(int columns, int rows, int foreColor, int backColor);
+}
+
+
+/**
+ * A TranscriptScreen is a screen that remembers data that's been scrolled. The
+ * old data is stored in a ring buffer to minimize the amount of copying that
+ * needs to be done. The transcript does its own drawing, to avoid having to
+ * expose its internal data structures.
+ */
+class TranscriptScreen implements Screen {
+
+    /**
+     * The width of the transcript, in characters. Fixed at initialization.
+     */
+    private int mColumns;
+
+    /**
+     * The total number of rows in the transcript and the screen. Fixed at
+     * initialization.
+     */
+    private int mTotalRows;
+
+    /**
+     * The number of rows in the active portion of the transcript. Doesn't
+     * include the screen.
+     */
+    private int mActiveTranscriptRows;
+
+    /**
+     * Which row is currently the topmost line of the transcript. Used to
+     * implement a circular buffer.
+     */
+    private int mHead;
+
+    /**
+     * The number of active rows, includes both the transcript and the screen.
+     */
+    private int mActiveRows;
+
+    /**
+     * The number of rows in the screen.
+     */
+    private int mScreenRows;
+
+    /**
+     * The data for both the screen and the transcript. The first mScreenRows *
+     * mLineWidth characters are the screen, the rest are the transcript.
+     * The low byte encodes the ASCII character, the high byte encodes the
+     * foreground and background colors, plus underline and bold.
+     */
+    private char[] mData;
+
+    /**
+     * The data's stored as color-encoded chars, but the drawing routines require chars, so we
+     * need a temporary buffer to hold a row's worth of characters.
+     */
+    private char[] mRowBuffer;
+
+    /**
+     * Flags that keep track of whether the current line logically wraps to the
+     * next line. This is used when resizing the screen and when copying to the
+     * clipboard or an email attachment
+     */
+
+    private boolean[] mLineWrap;
+
+    /**
+     * Create a transcript screen.
+     *
+     * @param columns the width of the screen in characters.
+     * @param totalRows the height of the entire text area, in rows of text.
+     * @param screenRows the height of just the screen, not including the
+     *        transcript that holds lines that have scrolled off the top of the
+     *        screen.
+     */
+    public TranscriptScreen(int columns, int totalRows, int screenRows,
+            int foreColor, int backColor) {
+        init(columns, totalRows, screenRows, foreColor, backColor);
+    }
+
+    private void init(int columns, int totalRows, int screenRows, int foreColor, int backColor) {
+        mColumns = columns;
+        mTotalRows = totalRows;
+        mActiveTranscriptRows = 0;
+        mHead = 0;
+        mActiveRows = screenRows;
+        mScreenRows = screenRows;
+        int totalSize = columns * totalRows;
+        mData = new char[totalSize];
+        blockSet(0, 0, mColumns, mScreenRows, ' ', foreColor, backColor);
+        mRowBuffer = new char[columns];
+        mLineWrap = new boolean[totalRows];
+        consistencyCheck();
+   }
+
+    /**
+     * Convert a row value from the public external coordinate system to our
+     * internal private coordinate system. External coordinate system:
+     * -mActiveTranscriptRows to mScreenRows-1, with the screen being
+     * 0..mScreenRows-1 Internal coordinate system: 0..mScreenRows-1 rows of
+     * mData are the visible rows. mScreenRows..mActiveRows - 1 are the
+     * transcript, stored as a circular buffer.
+     *
+     * @param row a row in the external coordinate system.
+     * @return The row corresponding to the input argument in the private
+     *         coordinate system.
+     */
+    private int externalToInternalRow(int row) {
+        if (row < -mActiveTranscriptRows || row >= mScreenRows) {
+            throw new IllegalArgumentException();
+        }
+        if (row >= 0) {
+            return row; // This is a visible row.
+        }
+        return mScreenRows
+                + ((mHead + mActiveTranscriptRows + row) % mActiveTranscriptRows);
+    }
+
+    private int getOffset(int externalLine) {
+        return externalToInternalRow(externalLine) * mColumns;
+    }
+
+    private int getOffset(int x, int y) {
+        return getOffset(y) + x;
+    }
+
+    public void setLineWrap(int row) {
+        mLineWrap[externalToInternalRow(row)] = true;
+    }
+
+    /**
+     * Store byte b into the screen at location (x, y)
+     *
+     * @param x X coordinate (also known as column)
+     * @param y Y coordinate (also known as row)
+     * @param b ASCII character to store
+     * @param foreColor the foreground color
+     * @param backColor the background color
+     */
+    public void set(int x, int y, byte b, int foreColor, int backColor) {
+        mData[getOffset(x, y)] = encode(b, foreColor, backColor);
+    }
+
+    private char encode(int b, int foreColor, int backColor) {
+        return (char) ((foreColor << 12) | (backColor << 8) | b);
+    }
+
+    /**
+     * Scroll the screen down one line. To scroll the whole screen of a 24 line
+     * screen, the arguments would be (0, 24).
+     *
+     * @param topMargin First line that is scrolled.
+     * @param bottomMargin One line after the last line that is scrolled.
+     */
+    public void scroll(int topMargin, int bottomMargin, int foreColor,
+            int backColor) {
+        if (topMargin > bottomMargin - 2 || topMargin > mScreenRows - 2
+                || bottomMargin > mScreenRows) {
+            throw new IllegalArgumentException();
+        }
+
+        // Adjust the transcript so that the last line of the transcript
+        // is ready to receive the newly scrolled data
+        consistencyCheck();
+        int expansionRows = Math.min(1, mTotalRows - mActiveRows);
+        int rollRows = 1 - expansionRows;
+        mActiveRows += expansionRows;
+        mActiveTranscriptRows += expansionRows;
+        if (mActiveTranscriptRows > 0) {
+            mHead = (mHead + rollRows) % mActiveTranscriptRows;
+        }
+        consistencyCheck();
+
+        // Block move the scroll line to the transcript
+        int topOffset = getOffset(topMargin);
+        int destOffset = getOffset(-1);
+        System.arraycopy(mData, topOffset, mData, destOffset, mColumns);
+
+        int topLine = externalToInternalRow(topMargin);
+        int destLine = externalToInternalRow(-1);
+        System.arraycopy(mLineWrap, topLine, mLineWrap, destLine, 1);
+
+        // Block move the scrolled data up
+        int numScrollChars = (bottomMargin - topMargin - 1) * mColumns;
+        System.arraycopy(mData, topOffset + mColumns, mData, topOffset,
+                numScrollChars);
+        int numScrollLines = (bottomMargin - topMargin - 1);
+        System.arraycopy(mLineWrap, topLine + 1, mLineWrap, topLine,
+                numScrollLines);
+
+        // Erase the bottom line of the scroll region
+        blockSet(0, bottomMargin - 1, mColumns, 1, ' ', foreColor, backColor);
+        mLineWrap[externalToInternalRow(bottomMargin-1)] = false;
+    }
+
+    private void consistencyCheck() {
+        checkPositive(mColumns);
+        checkPositive(mTotalRows);
+        checkRange(0, mActiveTranscriptRows, mTotalRows);
+        if (mActiveTranscriptRows == 0) {
+            checkEqual(mHead, 0);
+        } else {
+            checkRange(0, mHead, mActiveTranscriptRows-1);
+        }
+        checkEqual(mScreenRows + mActiveTranscriptRows, mActiveRows);
+        checkRange(0, mScreenRows, mTotalRows);
+
+        checkEqual(mTotalRows, mLineWrap.length);
+        checkEqual(mTotalRows*mColumns, mData.length);
+        checkEqual(mColumns, mRowBuffer.length);
+    }
+
+    private void checkPositive(int n) {
+        if (n < 0) {
+            throw new IllegalArgumentException("checkPositive " + n);
+        }
+    }
+
+    private void checkRange(int a, int b, int c) {
+        if (a > b || b > c) {
+            throw new IllegalArgumentException("checkRange " + a + " <= " + b + " <= " + c);
+        }
+    }
+
+    private void checkEqual(int a, int b) {
+        if (a != b) {
+            throw new IllegalArgumentException("checkEqual " + a + " == " + b);
+        }
+    }
+
+    /**
+     * Block copy characters from one position in the screen to another. The two
+     * positions can overlap. All characters of the source and destination must
+     * be within the bounds of the screen, or else an InvalidParemeterException
+     * will be thrown.
+     *
+     * @param sx source X coordinate
+     * @param sy source Y coordinate
+     * @param w width
+     * @param h height
+     * @param dx destination X coordinate
+     * @param dy destination Y coordinate
+     */
+    public void blockCopy(int sx, int sy, int w, int h, int dx, int dy) {
+        if (sx < 0 || sx + w > mColumns || sy < 0 || sy + h > mScreenRows
+                || dx < 0 || dx + w > mColumns || dy < 0
+                || dy + h > mScreenRows) {
+            throw new IllegalArgumentException();
+        }
+        if (sy <= dy) {
+            // Move in increasing order
+            for (int y = 0; y < h; y++) {
+                int srcOffset = getOffset(sx, sy + y);
+                int dstOffset = getOffset(dx, dy + y);
+                System.arraycopy(mData, srcOffset, mData, dstOffset, w);
+            }
+        } else {
+            // Move in decreasing order
+            for (int y = 0; y < h; y++) {
+                int y2 = h - (y + 1);
+                int srcOffset = getOffset(sx, sy + y2);
+                int dstOffset = getOffset(dx, dy + y2);
+                System.arraycopy(mData, srcOffset, mData, dstOffset, w);
+            }
+        }
+    }
+
+    /**
+     * Block set characters. All characters must be within the bounds of the
+     * screen, or else and InvalidParemeterException will be thrown. Typically
+     * this is called with a "val" argument of 32 to clear a block of
+     * characters.
+     *
+     * @param sx source X
+     * @param sy source Y
+     * @param w width
+     * @param h height
+     * @param val value to set.
+     */
+    public void blockSet(int sx, int sy, int w, int h, int val,
+            int foreColor, int backColor) {
+        if (sx < 0 || sx + w > mColumns || sy < 0 || sy + h > mScreenRows) {
+            throw new IllegalArgumentException();
+        }
+        char[] data = mData;
+        char encodedVal = encode(val, foreColor, backColor);
+        for (int y = 0; y < h; y++) {
+            int offset = getOffset(sx, sy + y);
+            for (int x = 0; x < w; x++) {
+                data[offset + x] = encodedVal;
+            }
+        }
+    }
+
+    /**
+     * Draw a row of text. Out-of-bounds rows are blank, not errors.
+     *
+     * @param row The row of text to draw.
+     * @param canvas The canvas to draw to.
+     * @param x The x coordinate origin of the drawing
+     * @param y The y coordinate origin of the drawing
+     * @param renderer The renderer to use to draw the text
+     * @param cx the cursor X coordinate, -1 means don't draw it
+     */
+    public final void drawText(int row, Canvas canvas, float x, float y,
+            TextRenderer renderer, int cx) {
+
+        // Out-of-bounds rows are blank.
+        if (row < -mActiveTranscriptRows || row >= mScreenRows) {
+            return;
+        }
+
+        // Copy the data from the byte array to a char array so they can
+        // be drawn.
+
+        int offset = getOffset(row);
+        char[] rowBuffer = mRowBuffer;
+        char[] data = mData;
+        int columns = mColumns;
+        int lastColors = 0;
+        int lastRunStart = -1;
+        final int CURSOR_MASK = 0x10000;
+        for (int i = 0; i < columns; i++) {
+            char c = data[offset + i];
+            int colors = (char) (c & 0xff00);
+            if (cx == i) {
+                // Set cursor background color:
+                colors |= CURSOR_MASK;
+            }
+            rowBuffer[i] = (char) (c & 0x00ff);
+            if (colors != lastColors) {
+                if (lastRunStart >= 0) {
+                    renderer.drawTextRun(canvas, x, y, lastRunStart, rowBuffer,
+                            lastRunStart, i - lastRunStart,
+                            (lastColors & CURSOR_MASK) != 0,
+                            0xf & (lastColors >> 12), 0xf & (lastColors >> 8));
+                }
+                lastColors = colors;
+                lastRunStart = i;
+            }
+        }
+        if (lastRunStart >= 0) {
+            renderer.drawTextRun(canvas, x, y, lastRunStart, rowBuffer,
+                    lastRunStart, columns - lastRunStart,
+                    (lastColors & CURSOR_MASK) != 0,
+                    0xf & (lastColors >> 12), 0xf & (lastColors >> 8));
+        }
+     }
+
+    /**
+     * Get the count of active rows.
+     *
+     * @return the count of active rows.
+     */
+    public int getActiveRows() {
+        return mActiveRows;
+    }
+
+    /**
+     * Get the count of active transcript rows.
+     *
+     * @return the count of active transcript rows.
+     */
+    public int getActiveTranscriptRows() {
+        return mActiveTranscriptRows;
+    }
+
+    public String getTranscriptText() {
+        return internalGetTranscriptText(true);
+    }
+
+    private String internalGetTranscriptText(boolean stripColors) {
+        StringBuilder builder = new StringBuilder();
+        char[] rowBuffer = mRowBuffer;
+        char[] data = mData;
+        int columns = mColumns;
+        for (int row = -mActiveTranscriptRows; row < mScreenRows; row++) {
+            int offset = getOffset(row);
+            int lastPrintingChar = -1;
+            for (int column = 0; column < columns; column++) {
+                char c = data[offset + column];
+                if (stripColors) {
+                    c = (char) (c & 0xff);
+                }
+                if ((c & 0xff) != ' ') {
+                    lastPrintingChar = column;
+                }
+                rowBuffer[column] = c;
+            }
+            if (mLineWrap[externalToInternalRow(row)]) {
+                builder.append(rowBuffer, 0, columns);
+            } else {
+                builder.append(rowBuffer, 0, lastPrintingChar + 1);
+                builder.append('\n');
+            }
+        }
+        return builder.toString();
+    }
+
+    public void resize(int columns, int rows, int foreColor, int backColor) {
+        init(columns, mTotalRows, rows, foreColor, backColor);
+    }
+}
+
+/**
+ * Renders text into a screen. Contains all the terminal-specific knowlege and
+ * state. Emulates a subset of the X Window System xterm terminal, which in turn
+ * is an emulator for a subset of the Digital Equipment Corporation vt100
+ * terminal. Missing functionality: text attributes (bold, underline, reverse
+ * video, color) alternate screen cursor key and keypad escape sequences.
+ */
+class TerminalEmulator {
+
+    /**
+     * The cursor row. Numbered 0..mRows-1.
+     */
+    private int mCursorRow;
+
+    /**
+     * The cursor column. Numbered 0..mColumns-1.
+     */
+    private int mCursorCol;
+
+    /**
+     * The number of character rows in the terminal screen.
+     */
+    private int mRows;
+
+    /**
+     * The number of character columns in the terminal screen.
+     */
+    private int mColumns;
+
+    /**
+     * Used to send data to the remote process. Needed to implement the various
+     * "report" escape sequences.
+     */
+    private FileOutputStream mTermOut;
+
+    /**
+     * Stores the characters that appear on the screen of the emulated terminal.
+     */
+    private Screen mScreen;
+
+    /**
+     * Keeps track of the current argument of the current escape sequence.
+     * Ranges from 0 to MAX_ESCAPE_PARAMETERS-1. (Typically just 0 or 1.)
+     */
+    private int mArgIndex;
+
+    /**
+     * The number of parameter arguments. This name comes from the ANSI standard
+     * for terminal escape codes.
+     */
+    private static final int MAX_ESCAPE_PARAMETERS = 16;
+
+    /**
+     * Holds the arguments of the current escape sequence.
+     */
+    private int[] mArgs = new int[MAX_ESCAPE_PARAMETERS];
+
+    // Escape processing states:
+
+    /**
+     * Escape processing state: Not currently in an escape sequence.
+     */
+    private static final int ESC_NONE = 0;
+
+    /**
+     * Escape processing state: Have seen an ESC character
+     */
+    private static final int ESC = 1;
+
+    /**
+     * Escape processing state: Have seen ESC POUND
+     */
+    private static final int ESC_POUND = 2;
+
+    /**
+     * Escape processing state: Have seen ESC and a character-set-select char
+     */
+    private static final int ESC_SELECT_LEFT_PAREN = 3;
+
+    /**
+     * Escape processing state: Have seen ESC and a character-set-select char
+     */
+    private static final int ESC_SELECT_RIGHT_PAREN = 4;
+
+    /**
+     * Escape processing state: ESC [
+     */
+    private static final int ESC_LEFT_SQUARE_BRACKET = 5;
+
+    /**
+     * Escape processing state: ESC [ ?
+     */
+    private static final int ESC_LEFT_SQUARE_BRACKET_QUESTION_MARK = 6;
+
+    /**
+     * True if the current escape sequence should continue, false if the current
+     * escape sequence should be terminated. Used when parsing a single
+     * character.
+     */
+    private boolean mContinueSequence;
+
+    /**
+     * The current state of the escape sequence state machine.
+     */
+    private int mEscapeState;
+
+    /**
+     * Saved state of the cursor row, Used to implement the save/restore cursor
+     * position escape sequences.
+     */
+    private int mSavedCursorRow;
+
+    /**
+     * Saved state of the cursor column, Used to implement the save/restore
+     * cursor position escape sequences.
+     */
+    private int mSavedCursorCol;
+
+    // DecSet booleans
+
+    /**
+     * This mask indicates 132-column mode is set. (As opposed to 80-column
+     * mode.)
+     */
+    private static final int K_132_COLUMN_MODE_MASK = 1 << 3;
+
+    /**
+     * This mask indicates that origin mode is set. (Cursor addressing is
+     * relative to the absolute screen size, rather than the currently set top
+     * and bottom margins.)
+     */
+    private static final int K_ORIGIN_MODE_MASK = 1 << 6;
+
+    /**
+     * This mask indicates that wraparound mode is set. (As opposed to
+     * stop-at-right-column mode.)
+     */
+    private static final int K_WRAPAROUND_MODE_MASK = 1 << 7;
+
+    /**
+     * Holds multiple DECSET flags. The data is stored this way, rather than in
+     * separate booleans, to make it easier to implement the save-and-restore
+     * semantics. The various k*ModeMask masks can be used to extract and modify
+     * the individual flags current states.
+     */
+    private int mDecFlags;
+
+    /**
+     * Saves away a snapshot of the DECSET flags. Used to implement save and
+     * restore escape sequences.
+     */
+    private int mSavedDecFlags;
+
+    // Modes set with Set Mode / Reset Mode
+
+    /**
+     * True if insert mode (as opposed to replace mode) is active. In insert
+     * mode new characters are inserted, pushing existing text to the right.
+     */
+    private boolean mInsertMode;
+
+    /**
+     * Automatic newline mode. Configures whether pressing return on the
+     * keyboard automatically generates a return as well. Not currently
+     * implemented.
+     */
+    private boolean mAutomaticNewlineMode;
+
+    /**
+     * An array of tab stops. mTabStop[i] is true if there is a tab stop set for
+     * column i.
+     */
+    private boolean[] mTabStop;
+
+    // The margins allow portions of the screen to be locked.
+
+    /**
+     * The top margin of the screen, for scrolling purposes. Ranges from 0 to
+     * mRows-2.
+     */
+    private int mTopMargin;
+
+    /**
+     * The bottom margin of the screen, for scrolling purposes. Ranges from
+     * mTopMargin + 2 to mRows. (Defines the first row after the scrolling
+     * region.
+     */
+    private int mBottomMargin;
+
+    /**
+     * True if the next character to be emitted will be automatically wrapped to
+     * the next line. Used to disambiguate the case where the cursor is
+     * positioned on column mColumns-1.
+     */
+    private boolean mAboutToAutoWrap;
+
+    /**
+     * Used for debugging, counts how many chars have been processed.
+     */
+    private int mProcessedCharCount;
+
+    /**
+     * Foreground color, 0..7, mask with 8 for bold
+     */
+    private int mForeColor;
+
+    /**
+     * Background color, 0..7, mask with 8 for underline
+     */
+    private int mBackColor;
+
+    private boolean mInverseColors;
+
+    private boolean mbKeypadApplicationMode;
+
+    private boolean mAlternateCharSet;
+
+    /**
+     * Construct a terminal emulator that uses the supplied screen
+     *
+     * @param screen the screen to render characters into.
+     * @param columns the number of columns to emulate
+     * @param rows the number of rows to emulate
+     * @param termOut the output file descriptor that talks to the pseudo-tty.
+     */
+    public TerminalEmulator(Screen screen, int columns, int rows,
+            FileOutputStream termOut) {
+        mScreen = screen;
+        mRows = rows;
+        mColumns = columns;
+        mTabStop = new boolean[mColumns];
+        mTermOut = termOut;
+        reset();
+    }
+
+    public void updateSize(int columns, int rows) {
+        if (mRows == rows && mColumns == columns) {
+            return;
+        }
+        String transcriptText = mScreen.getTranscriptText();
+
+        mScreen.resize(columns, rows, mForeColor, mBackColor);
+
+        if (mRows != rows) {
+            mRows = rows;
+            mTopMargin = 0;
+            mBottomMargin = mRows;
+        }
+        if (mColumns != columns) {
+            int oldColumns = mColumns;
+            mColumns = columns;
+            boolean[] oldTabStop = mTabStop;
+            mTabStop = new boolean[mColumns];
+            int toTransfer = Math.min(oldColumns, columns);
+            System.arraycopy(oldTabStop, 0, mTabStop, 0, toTransfer);
+            while (mCursorCol >= columns) {
+                mCursorCol -= columns;
+                mCursorRow = Math.min(mBottomMargin-1, mCursorRow + 1);
+            }
+        }
+        mCursorRow = 0;
+        mCursorCol = 0;
+        mAboutToAutoWrap = false;
+
+        int end = transcriptText.length()-1;
+        while ((end >= 0) && transcriptText.charAt(end) == '\n') {
+            end--;
+        }
+        for(int i = 0; i <= end; i++) {
+            byte c = (byte) transcriptText.charAt(i);
+            if (c == '\n') {
+                setCursorCol(0);
+                doLinefeed();
+            } else {
+                emit(c);
+            }
+        }
+    }
+
+    /**
+     * Get the cursor's current row.
+     *
+     * @return the cursor's current row.
+     */
+    public final int getCursorRow() {
+        return mCursorRow;
+    }
+
+    /**
+     * Get the cursor's current column.
+     *
+     * @return the cursor's current column.
+     */
+    public final int getCursorCol() {
+        return mCursorCol;
+    }
+
+    public final boolean getKeypadApplicationMode() {
+        return mbKeypadApplicationMode;
+    }
+
+    private void setDefaultTabStops() {
+        for (int i = 0; i < mColumns; i++) {
+            mTabStop[i] = (i & 7) == 0 && i != 0;
+        }
+    }
+
+    /**
+     * Accept bytes (typically from the pseudo-teletype) and process them.
+     *
+     * @param buffer a byte array containing the bytes to be processed
+     * @param base the first index of the array to process
+     * @param length the number of bytes in the array to process
+     */
+    public void append(byte[] buffer, int base, int length) {
+        for (int i = 0; i < length; i++) {
+            byte b = buffer[base + i];
+            try {
+                if (Term.LOG_CHARACTERS_FLAG) {
+                    char printableB = (char) b;
+                    if (b < 32 || b > 126) {
+                        printableB = ' ';
+                    }
+                    Log.w(Term.LOG_TAG, "'" + Character.toString(printableB)
+                            + "' (" + Integer.toString((int) b) + ")");
+                }
+                process(b);
+                mProcessedCharCount++;
+            } catch (Exception e) {
+                Log.e(Term.LOG_TAG, "Exception while processing character "
+                        + Integer.toString(mProcessedCharCount) + " code "
+                        + Integer.toString(b), e);
+            }
+        }
+    }
+
+    private void process(byte b) {
+        switch (b) {
+        case 0: // NUL
+            // Do nothing
+            break;
+
+        case 7: // BEL
+            // Do nothing
+            break;
+
+        case 8: // BS
+            setCursorCol(Math.max(0, mCursorCol - 1));
+            break;
+
+        case 9: // HT
+            // Move to next tab stop, but not past edge of screen
+            setCursorCol(nextTabStop(mCursorCol));
+            break;
+
+        case 13:
+            setCursorCol(0);
+            break;
+
+        case 10: // CR
+        case 11: // VT
+        case 12: // LF
+            doLinefeed();
+            break;
+
+        case 14: // SO:
+            setAltCharSet(true);
+            break;
+
+        case 15: // SI:
+            setAltCharSet(false);
+            break;
+
+
+        case 24: // CAN
+        case 26: // SUB
+            if (mEscapeState != ESC_NONE) {
+                mEscapeState = ESC_NONE;
+                emit((byte) 127);
+            }
+            break;
+
+        case 27: // ESC
+            // Always starts an escape sequence
+            startEscapeSequence(ESC);
+            break;
+
+        case (byte) 0x9b: // CSI
+            startEscapeSequence(ESC_LEFT_SQUARE_BRACKET);
+            break;
+
+        default:
+            mContinueSequence = false;
+            switch (mEscapeState) {
+            case ESC_NONE:
+                if (b >= 32) {
+                    emit(b);
+                }
+                break;
+
+            case ESC:
+                doEsc(b);
+                break;
+
+            case ESC_POUND:
+                doEscPound(b);
+                break;
+
+            case ESC_SELECT_LEFT_PAREN:
+                doEscSelectLeftParen(b);
+                break;
+
+            case ESC_SELECT_RIGHT_PAREN:
+                doEscSelectRightParen(b);
+                break;
+
+            case ESC_LEFT_SQUARE_BRACKET:
+                doEscLeftSquareBracket(b);
+                break;
+
+            case ESC_LEFT_SQUARE_BRACKET_QUESTION_MARK:
+                doEscLSBQuest(b);
+                break;
+
+            default:
+                unknownSequence(b);
+                break;
+            }
+            if (!mContinueSequence) {
+                mEscapeState = ESC_NONE;
+            }
+            break;
+        }
+    }
+
+    private void setAltCharSet(boolean alternateCharSet) {
+        mAlternateCharSet = alternateCharSet;
+    }
+
+    private int nextTabStop(int cursorCol) {
+        for (int i = cursorCol; i < mColumns; i++) {
+            if (mTabStop[i]) {
+                return i;
+            }
+        }
+        return mColumns - 1;
+    }
+
+    private void doEscLSBQuest(byte b) {
+        int mask = getDecFlagsMask(getArg0(0));
+        switch (b) {
+        case 'h': // Esc [ ? Pn h - DECSET
+            mDecFlags |= mask;
+            break;
+
+        case 'l': // Esc [ ? Pn l - DECRST
+            mDecFlags &= ~mask;
+            break;
+
+        case 'r': // Esc [ ? Pn r - restore
+            mDecFlags = (mDecFlags & ~mask) | (mSavedDecFlags & mask);
+            break;
+
+        case 's': // Esc [ ? Pn s - save
+            mSavedDecFlags = (mSavedDecFlags & ~mask) | (mDecFlags & mask);
+            break;
+
+        default:
+            parseArg(b);
+            break;
+        }
+
+        // 132 column mode
+        if ((mask & K_132_COLUMN_MODE_MASK) != 0) {
+            // We don't actually set 132 cols, but we do want the
+            // side effect of clearing the screen and homing the cursor.
+            blockClear(0, 0, mColumns, mRows);
+            setCursorRowCol(0, 0);
+        }
+
+        // origin mode
+        if ((mask & K_ORIGIN_MODE_MASK) != 0) {
+            // Home the cursor.
+            setCursorPosition(0, 0);
+        }
+    }
+
+    private int getDecFlagsMask(int argument) {
+        if (argument >= 1 && argument <= 9) {
+            return (1 << argument);
+        }
+
+        return 0;
+    }
+
+    private void startEscapeSequence(int escapeState) {
+        mEscapeState = escapeState;
+        mArgIndex = 0;
+        for (int j = 0; j < MAX_ESCAPE_PARAMETERS; j++) {
+            mArgs[j] = -1;
+        }
+    }
+
+    private void doLinefeed() {
+        int newCursorRow = mCursorRow + 1;
+        if (newCursorRow >= mBottomMargin) {
+            scroll();
+            newCursorRow = mBottomMargin - 1;
+        }
+        setCursorRow(newCursorRow);
+    }
+
+    private void continueSequence() {
+        mContinueSequence = true;
+    }
+
+    private void continueSequence(int state) {
+        mEscapeState = state;
+        mContinueSequence = true;
+    }
+
+    private void doEscSelectLeftParen(byte b) {
+        doSelectCharSet(true, b);
+    }
+
+    private void doEscSelectRightParen(byte b) {
+        doSelectCharSet(false, b);
+    }
+
+    private void doSelectCharSet(boolean isG0CharSet, byte b) {
+        switch (b) {
+        case 'A': // United Kingdom character set
+            break;
+        case 'B': // ASCII set
+            break;
+        case '0': // Special Graphics
+            break;
+        case '1': // Alternate character set
+            break;
+        case '2':
+            break;
+        default:
+            unknownSequence(b);
+        }
+    }
+
+    private void doEscPound(byte b) {
+        switch (b) {
+        case '8': // Esc # 8 - DECALN alignment test
+            mScreen.blockSet(0, 0, mColumns, mRows, 'E',
+                    getForeColor(), getBackColor());
+            break;
+
+        default:
+            unknownSequence(b);
+            break;
+        }
+    }
+
+    private void doEsc(byte b) {
+        switch (b) {
+        case '#':
+            continueSequence(ESC_POUND);
+            break;
+
+        case '(':
+            continueSequence(ESC_SELECT_LEFT_PAREN);
+            break;
+
+        case ')':
+            continueSequence(ESC_SELECT_RIGHT_PAREN);
+            break;
+
+        case '7': // DECSC save cursor
+            mSavedCursorRow = mCursorRow;
+            mSavedCursorCol = mCursorCol;
+            break;
+
+        case '8': // DECRC restore cursor
+            setCursorRowCol(mSavedCursorRow, mSavedCursorCol);
+            break;
+
+        case 'D': // INDEX
+            doLinefeed();
+            break;
+
+        case 'E': // NEL
+            setCursorCol(0);
+            doLinefeed();
+            break;
+
+        case 'F': // Cursor to lower-left corner of screen
+            setCursorRowCol(0, mBottomMargin - 1);
+            break;
+
+        case 'H': // Tab set
+            mTabStop[mCursorCol] = true;
+            break;
+
+        case 'M': // Reverse index
+            if (mCursorRow == 0) {
+                mScreen.blockCopy(0, mTopMargin + 1, mColumns, mBottomMargin
+                        - (mTopMargin + 1), 0, mTopMargin);
+                blockClear(0, mBottomMargin - 1, mColumns);
+            } else {
+                mCursorRow--;
+            }
+
+            break;
+
+        case 'N': // SS2
+            unimplementedSequence(b);
+            break;
+
+        case '0': // SS3
+            unimplementedSequence(b);
+            break;
+
+        case 'P': // Device control string
+            unimplementedSequence(b);
+            break;
+
+        case 'Z': // return terminal ID
+            sendDeviceAttributes();
+            break;
+
+        case '[':
+            continueSequence(ESC_LEFT_SQUARE_BRACKET);
+            break;
+
+        case '=': // DECKPAM
+            mbKeypadApplicationMode = true;
+            break;
+
+        case '>' : // DECKPNM
+            mbKeypadApplicationMode = false;
+            break;
+
+        default:
+            unknownSequence(b);
+            break;
+        }
+    }
+
+    private void doEscLeftSquareBracket(byte b) {
+        switch (b) {
+        case '@': // ESC [ Pn @ - ICH Insert Characters
+        {
+            int charsAfterCursor = mColumns - mCursorCol;
+            int charsToInsert = Math.min(getArg0(1), charsAfterCursor);
+            int charsToMove = charsAfterCursor - charsToInsert;
+            mScreen.blockCopy(mCursorCol, mCursorRow, charsToMove, 1,
+                    mCursorCol + charsToInsert, mCursorRow);
+            blockClear(mCursorCol, mCursorRow, charsToInsert);
+        }
+            break;
+
+        case 'A': // ESC [ Pn A - Cursor Up
+            setCursorRow(Math.max(mTopMargin, mCursorRow - getArg0(1)));
+            break;
+
+        case 'B': // ESC [ Pn B - Cursor Down
+            setCursorRow(Math.min(mBottomMargin - 1, mCursorRow + getArg0(1)));
+            break;
+
+        case 'C': // ESC [ Pn C - Cursor Right
+            setCursorCol(Math.min(mColumns - 1, mCursorCol + getArg0(1)));
+            break;
+
+        case 'D': // ESC [ Pn D - Cursor Left
+            setCursorCol(Math.max(0, mCursorCol - getArg0(1)));
+            break;
+
+        case 'G': // ESC [ Pn G - Cursor Horizontal Absolute
+            setCursorCol(Math.min(Math.max(1, getArg0(1)), mColumns) - 1);
+            break;
+
+        case 'H': // ESC [ Pn ; H - Cursor Position
+            setHorizontalVerticalPosition();
+            break;
+
+        case 'J': // ESC [ Pn J - Erase in Display
+            switch (getArg0(0)) {
+            case 0: // Clear below
+                blockClear(mCursorCol, mCursorRow, mColumns - mCursorCol);
+                blockClear(0, mCursorRow + 1, mColumns,
+                        mBottomMargin - (mCursorRow + 1));
+                break;
+
+            case 1: // Erase from the start of the screen to the cursor.
+                blockClear(0, mTopMargin, mColumns, mCursorRow - mTopMargin);
+                blockClear(0, mCursorRow, mCursorCol + 1);
+                break;
+
+            case 2: // Clear all
+                blockClear(0, mTopMargin, mColumns, mBottomMargin - mTopMargin);
+                break;
+
+            default:
+                unknownSequence(b);
+                break;
+            }
+            break;
+
+        case 'K': // ESC [ Pn K - Erase in Line
+            switch (getArg0(0)) {
+            case 0: // Clear to right
+                blockClear(mCursorCol, mCursorRow, mColumns - mCursorCol);
+                break;
+
+            case 1: // Erase start of line to cursor (including cursor)
+                blockClear(0, mCursorRow, mCursorCol + 1);
+                break;
+
+            case 2: // Clear whole line
+                blockClear(0, mCursorRow, mColumns);
+                break;
+
+            default:
+                unknownSequence(b);
+                break;
+            }
+            break;
+
+        case 'L': // Insert Lines
+        {
+            int linesAfterCursor = mBottomMargin - mCursorRow;
+            int linesToInsert = Math.min(getArg0(1), linesAfterCursor);
+            int linesToMove = linesAfterCursor - linesToInsert;
+            mScreen.blockCopy(0, mCursorRow, mColumns, linesToMove, 0,
+                    mCursorRow + linesToInsert);
+            blockClear(0, mCursorRow, mColumns, linesToInsert);
+        }
+            break;
+
+        case 'M': // Delete Lines
+        {
+            int linesAfterCursor = mBottomMargin - mCursorRow;
+            int linesToDelete = Math.min(getArg0(1), linesAfterCursor);
+            int linesToMove = linesAfterCursor - linesToDelete;
+            mScreen.blockCopy(0, mCursorRow + linesToDelete, mColumns,
+                    linesToMove, 0, mCursorRow);
+            blockClear(0, mCursorRow + linesToMove, mColumns, linesToDelete);
+        }
+            break;
+
+        case 'P': // Delete Characters
+        {
+            int charsAfterCursor = mColumns - mCursorCol;
+            int charsToDelete = Math.min(getArg0(1), charsAfterCursor);
+            int charsToMove = charsAfterCursor - charsToDelete;
+            mScreen.blockCopy(mCursorCol + charsToDelete, mCursorRow,
+                    charsToMove, 1, mCursorCol, mCursorRow);
+            blockClear(mCursorCol + charsToMove, mCursorRow, charsToDelete);
+        }
+            break;
+
+        case 'T': // Mouse tracking
+            unimplementedSequence(b);
+            break;
+
+        case '?': // Esc [ ? -- start of a private mode set
+            continueSequence(ESC_LEFT_SQUARE_BRACKET_QUESTION_MARK);
+            break;
+
+        case 'c': // Send device attributes
+            sendDeviceAttributes();
+            break;
+
+        case 'd': // ESC [ Pn d - Vert Position Absolute
+            setCursorRow(Math.min(Math.max(1, getArg0(1)), mRows) - 1);
+            break;
+
+        case 'f': // Horizontal and Vertical Position
+            setHorizontalVerticalPosition();
+            break;
+
+        case 'g': // Clear tab stop
+            switch (getArg0(0)) {
+            case 0:
+                mTabStop[mCursorCol] = false;
+                break;
+
+            case 3:
+                for (int i = 0; i < mColumns; i++) {
+                    mTabStop[i] = false;
+                }
+                break;
+
+            default:
+                // Specified to have no effect.
+                break;
+            }
+            break;
+
+        case 'h': // Set Mode
+            doSetMode(true);
+            break;
+
+        case 'l': // Reset Mode
+            doSetMode(false);
+            break;
+
+        case 'm': // Esc [ Pn m - character attributes.
+            selectGraphicRendition();
+            break;
+
+        case 'r': // Esc [ Pn ; Pn r - set top and bottom margins
+        {
+            // The top margin defaults to 1, the bottom margin
+            // (unusually for arguments) defaults to mRows.
+            //
+            // The escape sequence numbers top 1..23, but we
+            // number top 0..22.
+            // The escape sequence numbers bottom 2..24, and
+            // so do we (because we use a zero based numbering
+            // scheme, but we store the first line below the
+            // bottom-most scrolling line.
+            // As a result, we adjust the top line by -1, but
+            // we leave the bottom line alone.
+            //
+            // Also require that top + 2 <= bottom
+
+            int top = Math.max(0, Math.min(getArg0(1) - 1, mRows - 2));
+            int bottom = Math.max(top + 2, Math.min(getArg1(mRows), mRows));
+            mTopMargin = top;
+            mBottomMargin = bottom;
+
+            // The cursor is placed in the home position
+            setCursorRowCol(mTopMargin, 0);
+        }
+            break;
+
+        default:
+            parseArg(b);
+            break;
+        }
+    }
+
+    private void selectGraphicRendition() {
+        for (int i = 0; i <= mArgIndex; i++) {
+            int code = mArgs[i];
+            if ( code < 0) {
+                if (mArgIndex > 0) {
+                    continue;
+                } else {
+                    code = 0;
+                }
+            }
+            if (code == 0) { // reset
+                mInverseColors = false;
+                mForeColor = 7;
+                mBackColor = 0;
+            } else if (code == 1) { // bold
+                mForeColor |= 0x8;
+            } else if (code == 4) { // underscore
+                mBackColor |= 0x8;
+            } else if (code == 7) { // inverse
+                mInverseColors = true;
+            } else if (code >= 30 && code <= 37) { // foreground color
+                mForeColor = (mForeColor & 0x8) | (code - 30);
+            } else if (code >= 40 && code <= 47) { // background color
+                mBackColor = (mBackColor & 0x8) | (code - 40);
+            } else {
+                if (Term.LOG_UNKNOWN_ESCAPE_SEQUENCES) {
+                    Log.w(Term.LOG_TAG, String.format("SGR unknown code %d", code));
+                }
+            }
+        }
+    }
+
+    private void blockClear(int sx, int sy, int w) {
+        blockClear(sx, sy, w, 1);
+    }
+
+    private void blockClear(int sx, int sy, int w, int h) {
+        mScreen.blockSet(sx, sy, w, h, ' ', getForeColor(), getBackColor());
+    }
+
+    private int getForeColor() {
+        return mInverseColors ?
+                ((mBackColor & 0x7) | (mForeColor & 0x8)) : mForeColor;
+    }
+
+    private int getBackColor() {
+        return mInverseColors ?
+                ((mForeColor & 0x7) | (mBackColor & 0x8)) : mBackColor;
+    }
+
+    private void doSetMode(boolean newValue) {
+        int modeBit = getArg0(0);
+        switch (modeBit) {
+        case 4:
+            mInsertMode = newValue;
+            break;
+
+        case 20:
+            mAutomaticNewlineMode = newValue;
+            break;
+
+        default:
+            unknownParameter(modeBit);
+            break;
+        }
+    }
+
+    private void setHorizontalVerticalPosition() {
+
+        // Parameters are Row ; Column
+
+        setCursorPosition(getArg1(1) - 1, getArg0(1) - 1);
+    }
+
+    private void setCursorPosition(int x, int y) {
+        int effectiveTopMargin = 0;
+        int effectiveBottomMargin = mRows;
+        if ((mDecFlags & K_ORIGIN_MODE_MASK) != 0) {
+            effectiveTopMargin = mTopMargin;
+            effectiveBottomMargin = mBottomMargin;
+        }
+        int newRow =
+                Math.max(effectiveTopMargin, Math.min(effectiveTopMargin + y,
+                        effectiveBottomMargin - 1));
+        int newCol = Math.max(0, Math.min(x, mColumns - 1));
+        setCursorRowCol(newRow, newCol);
+    }
+
+    private void sendDeviceAttributes() {
+        // This identifies us as a DEC vt100 with advanced
+        // video options. This is what the xterm terminal
+        // emulator sends.
+        byte[] attributes =
+                {
+                /* VT100 */
+                 (byte) 27, (byte) '[', (byte) '?', (byte) '1',
+                 (byte) ';', (byte) '2', (byte) 'c'
+
+                /* VT220
+                (byte) 27, (byte) '[', (byte) '?', (byte) '6',
+                (byte) '0',  (byte) ';',
+                (byte) '1',  (byte) ';',
+                (byte) '2',  (byte) ';',
+                (byte) '6',  (byte) ';',
+                (byte) '8',  (byte) ';',
+                (byte) '9',  (byte) ';',
+                (byte) '1',  (byte) '5', (byte) ';',
+                (byte) 'c'
+                */
+                };
+
+        write(attributes);
+    }
+
+    /**
+     * Send data to the shell process
+     * @param data
+     */
+    private void write(byte[] data) {
+        try {
+            mTermOut.write(data);
+            mTermOut.flush();
+        } catch (IOException e) {
+            // Ignore exception
+            // We don't really care if the receiver isn't listening.
+            // We just make a best effort to answer the query.
+        }
+    }
+
+    private void scroll() {
+        mScreen.scroll(mTopMargin, mBottomMargin,
+                getForeColor(), getBackColor());
+    }
+
+    /**
+     * Process the next ASCII character of a parameter.
+     *
+     * @param b The next ASCII character of the paramater sequence.
+     */
+    private void parseArg(byte b) {
+        if (b >= '0' && b <= '9') {
+            if (mArgIndex < mArgs.length) {
+                int oldValue = mArgs[mArgIndex];
+                int thisDigit = b - '0';
+                int value;
+                if (oldValue >= 0) {
+                    value = oldValue * 10 + thisDigit;
+                } else {
+                    value = thisDigit;
+                }
+                mArgs[mArgIndex] = value;
+            }
+            continueSequence();
+        } else if (b == ';') {
+            if (mArgIndex < mArgs.length) {
+                mArgIndex++;
+            }
+            continueSequence();
+        } else {
+            unknownSequence(b);
+        }
+    }
+
+    private int getArg0(int defaultValue) {
+        return getArg(0, defaultValue);
+    }
+
+    private int getArg1(int defaultValue) {
+        return getArg(1, defaultValue);
+    }
+
+    private int getArg(int index, int defaultValue) {
+        int result = mArgs[index];
+        if (result < 0) {
+            result = defaultValue;
+        }
+        return result;
+    }
+
+    private void unimplementedSequence(byte b) {
+        if (Term.LOG_UNKNOWN_ESCAPE_SEQUENCES) {
+            logError("unimplemented", b);
+        }
+        finishSequence();
+    }
+
+    private void unknownSequence(byte b) {
+        if (Term.LOG_UNKNOWN_ESCAPE_SEQUENCES) {
+            logError("unknown", b);
+        }
+        finishSequence();
+    }
+
+    private void unknownParameter(int parameter) {
+        if (Term.LOG_UNKNOWN_ESCAPE_SEQUENCES) {
+            StringBuilder buf = new StringBuilder();
+            buf.append("Unknown parameter");
+            buf.append(parameter);
+            logError(buf.toString());
+        }
+    }
+
+    private void logError(String errorType, byte b) {
+        if (Term.LOG_UNKNOWN_ESCAPE_SEQUENCES) {
+            StringBuilder buf = new StringBuilder();
+            buf.append(errorType);
+            buf.append(" sequence ");
+            buf.append(" EscapeState: ");
+            buf.append(mEscapeState);
+            buf.append(" char: '");
+            buf.append((char) b);
+            buf.append("' (");
+            buf.append((int) b);
+            buf.append(")");
+            boolean firstArg = true;
+            for (int i = 0; i <= mArgIndex; i++) {
+                int value = mArgs[i];
+                if (value >= 0) {
+                    if (firstArg) {
+                        firstArg = false;
+                        buf.append("args = ");
+                    }
+                    buf.append(String.format("%d; ", value));
+                }
+            }
+            logError(buf.toString());
+        }
+    }
+
+    private void logError(String error) {
+        if (Term.LOG_UNKNOWN_ESCAPE_SEQUENCES) {
+            Log.e(Term.LOG_TAG, error);
+        }
+        finishSequence();
+    }
+
+    private void finishSequence() {
+        mEscapeState = ESC_NONE;
+    }
+
+    private boolean autoWrapEnabled() {
+        // Always enable auto wrap, because it's useful on a small screen
+        return true;
+        // return (mDecFlags & K_WRAPAROUND_MODE_MASK) != 0;
+    }
+
+    /**
+     * Send an ASCII character to the screen.
+     *
+     * @param b the ASCII character to display.
+     */
+    private void emit(byte b) {
+        boolean autoWrap = autoWrapEnabled();
+
+        if (autoWrap) {
+            if (mCursorCol == mColumns - 1 && mAboutToAutoWrap) {
+                mScreen.setLineWrap(mCursorRow);
+                mCursorCol = 0;
+                if (mCursorRow + 1 < mBottomMargin) {
+                    mCursorRow++;
+                } else {
+                    scroll();
+                }
+            }
+        }
+
+        if (mInsertMode) { // Move character to right one space
+            int destCol = mCursorCol + 1;
+            if (destCol < mColumns) {
+                mScreen.blockCopy(mCursorCol, mCursorRow, mColumns - destCol,
+                        1, destCol, mCursorRow);
+            }
+        }
+
+        mScreen.set(mCursorCol, mCursorRow, b, getForeColor(), getBackColor());
+
+        if (autoWrap) {
+            mAboutToAutoWrap = (mCursorCol == mColumns - 1);
+        }
+
+        mCursorCol = Math.min(mCursorCol + 1, mColumns - 1);
+    }
+
+    private void setCursorRow(int row) {
+        mCursorRow = row;
+        mAboutToAutoWrap = false;
+    }
+
+    private void setCursorCol(int col) {
+        mCursorCol = col;
+        mAboutToAutoWrap = false;
+    }
+
+    private void setCursorRowCol(int row, int col) {
+        mCursorRow = Math.min(row, mRows-1);
+        mCursorCol = Math.min(col, mColumns-1);
+        mAboutToAutoWrap = false;
+    }
+
+    /**
+     * Reset the terminal emulator to its initial state.
+     */
+    public void reset() {
+        mCursorRow = 0;
+        mCursorCol = 0;
+        mArgIndex = 0;
+        mContinueSequence = false;
+        mEscapeState = ESC_NONE;
+        mSavedCursorRow = 0;
+        mSavedCursorCol = 0;
+        mDecFlags = 0;
+        mSavedDecFlags = 0;
+        mInsertMode = false;
+        mAutomaticNewlineMode = false;
+        mTopMargin = 0;
+        mBottomMargin = mRows;
+        mAboutToAutoWrap = false;
+        mForeColor = 7;
+        mBackColor = 0;
+        mInverseColors = false;
+        mbKeypadApplicationMode = false;
+        mAlternateCharSet = false;
+        // mProcessedCharCount is preserved unchanged.
+        setDefaultTabStops();
+        blockClear(0, 0, mColumns, mRows);
+    }
+
+    public String getTranscriptText() {
+        return mScreen.getTranscriptText();
+    }
+}
+
+/**
+ * Text renderer interface
+ */
+
+interface TextRenderer {
+    int getCharacterWidth();
+    int getCharacterHeight();
+    void drawTextRun(Canvas canvas, float x, float y,
+            int lineOffset, char[] text,
+            int index, int count, boolean cursor, int foreColor, int backColor);
+}
+
+abstract class BaseTextRenderer implements TextRenderer {
+    protected int[] mForePaint = {
+            0xff000000, // Black
+            0xffff0000, // Red
+            0xff00ff00, // green
+            0xffffff00, // yellow
+            0xff0000ff, // blue
+            0xffff00ff, // magenta
+            0xff00ffff, // cyan
+            0xffffffff  // white -- is overridden by constructor
+    };
+    protected int[] mBackPaint = {
+            0xff000000, // Black -- is overridden by constructor
+            0xffcc0000, // Red
+            0xff00cc00, // green
+            0xffcccc00, // yellow
+            0xff0000cc, // blue
+            0xffff00cc, // magenta
+            0xff00cccc, // cyan
+            0xffffffff  // white
+    };
+    protected final static int mCursorPaint = 0xff808080;
+
+    public BaseTextRenderer(int forePaintColor, int backPaintColor) {
+        mForePaint[7] = forePaintColor;
+        mBackPaint[0] = backPaintColor;
+
+    }
+}
+
+class Bitmap4x8FontRenderer extends BaseTextRenderer {
+    private final static int kCharacterWidth = 4;
+    private final static int kCharacterHeight = 8;
+    private Bitmap mFont;
+    private int mCurrentForeColor;
+    private int mCurrentBackColor;
+    private float[] mColorMatrix;
+    private Paint mPaint;
+    private static final float BYTE_SCALE = 1.0f / 255.0f;
+
+    public Bitmap4x8FontRenderer(Resources resources,
+            int forePaintColor, int backPaintColor) {
+        super(forePaintColor, backPaintColor);
+        mFont = BitmapFactory.decodeResource(resources,
+                R.drawable.atari_small);
+        mPaint = new Paint();
+        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+    }
+
+    public int getCharacterWidth() {
+        return kCharacterWidth;
+    }
+
+    public int getCharacterHeight() {
+        return kCharacterHeight;
+    }
+
+    public void drawTextRun(Canvas canvas, float x, float y,
+            int lineOffset, char[] text, int index, int count,
+            boolean cursor, int foreColor, int backColor) {
+        setColorMatrix(mForePaint[foreColor & 7],
+                cursor ? mCursorPaint : mBackPaint[backColor & 7]);
+        int destX = (int) x + kCharacterWidth * lineOffset;
+        int destY = (int) y;
+        Rect srcRect = new Rect();
+        Rect destRect = new Rect();
+        destRect.top = (destY - kCharacterHeight);
+        destRect.bottom = destY;
+        for(int i = 0; i < count; i++) {
+            char c = text[i + index];
+            if ((cursor || (c != 32)) && (c < 128)) {
+                int cellX = c & 31;
+                int cellY = (c >> 5) & 3;
+                int srcX = cellX * kCharacterWidth;
+                int srcY = cellY * kCharacterHeight;
+                srcRect.set(srcX, srcY,
+                        srcX + kCharacterWidth, srcY + kCharacterHeight);
+                destRect.left = destX;
+                destRect.right = destX + kCharacterWidth;
+                canvas.drawBitmap(mFont, srcRect, destRect, mPaint);
+            }
+            destX += kCharacterWidth;
+        }
+    }
+
+    private void setColorMatrix(int foreColor, int backColor) {
+        if ((foreColor != mCurrentForeColor)
+                || (backColor != mCurrentBackColor)
+                || (mColorMatrix == null)) {
+            mCurrentForeColor = foreColor;
+            mCurrentBackColor = backColor;
+            if (mColorMatrix == null) {
+                mColorMatrix = new float[20];
+                mColorMatrix[18] = 1.0f; // Just copy Alpha
+            }
+            for (int component = 0; component < 3; component++) {
+                int rightShift = (2 - component) << 3;
+                int fore = 0xff & (foreColor >> rightShift);
+                int back = 0xff & (backColor >> rightShift);
+                int delta = back - fore;
+                mColorMatrix[component * 6] = delta * BYTE_SCALE;
+                mColorMatrix[component * 5 + 4] = fore;
+            }
+            mPaint.setColorFilter(new ColorMatrixColorFilter(mColorMatrix));
+        }
+    }
+}
+
+class PaintRenderer extends BaseTextRenderer {
+    public PaintRenderer(int fontSize, int forePaintColor, int backPaintColor) {
+        super(forePaintColor, backPaintColor);
+        mTextPaint = new Paint();
+        mTextPaint.setTypeface(Typeface.MONOSPACE);
+        mTextPaint.setAntiAlias(true);
+        mTextPaint.setTextSize(fontSize);
+
+        mCharHeight = (int) Math.ceil(mTextPaint.getFontSpacing());
+        mCharAscent = (int) Math.ceil(mTextPaint.ascent());
+        mCharDescent = mCharHeight + mCharAscent;
+        mCharWidth = (int) mTextPaint.measureText(EXAMPLE_CHAR, 0, 1);
+    }
+
+    public void drawTextRun(Canvas canvas, float x, float y, int lineOffset,
+            char[] text, int index, int count,
+            boolean cursor, int foreColor, int backColor) {
+        if (cursor) {
+            mTextPaint.setColor(mCursorPaint);
+        } else {
+            mTextPaint.setColor(mBackPaint[backColor & 0x7]);
+        }
+        float left = x + lineOffset * mCharWidth;
+        canvas.drawRect(left, y + mCharAscent,
+                left + count * mCharWidth, y + mCharDescent,
+                mTextPaint);
+        boolean bold = ( foreColor & 0x8 ) != 0;
+        boolean underline = (backColor & 0x8) != 0;
+        if (bold) {
+            mTextPaint.setFakeBoldText(true);
+        }
+        if (underline) {
+            mTextPaint.setUnderlineText(true);
+        }
+        mTextPaint.setColor(mForePaint[foreColor & 0x7]);
+        canvas.drawText(text, index, count, left, y, mTextPaint);
+        if (bold) {
+            mTextPaint.setFakeBoldText(false);
+        }
+        if (underline) {
+            mTextPaint.setUnderlineText(false);
+        }
+    }
+
+    public int getCharacterHeight() {
+        return mCharHeight;
+    }
+
+    public int getCharacterWidth() {
+        return mCharWidth;
+    }
+
+
+    private Paint mTextPaint;
+    private int mCharWidth;
+    private int mCharHeight;
+    private int mCharAscent;
+    private int mCharDescent;
+    private static final char[] EXAMPLE_CHAR = {'X'};
+    }
+
+/**
+ * A multi-thread-safe produce-consumer byte array.
+ * Only allows one producer and one consumer.
+ */
+
+class ByteQueue {
+    public ByteQueue(int size) {
+        mBuffer = new byte[size];
+    }
+
+    public int getBytesAvailable() {
+        synchronized(this) {
+            return mStoredBytes;
+        }
+    }
+
+    public int read(byte[] buffer, int offset, int length)
+        throws InterruptedException {
+        if (length + offset > buffer.length) {
+            throw
+                new IllegalArgumentException("length + offset > buffer.length");
+        }
+        if (length < 0) {
+            throw
+            new IllegalArgumentException("length < 0");
+
+        }
+        if (length == 0) {
+            return 0;
+        }
+        synchronized(this) {
+            while (mStoredBytes == 0) {
+                wait();
+            }
+            int totalRead = 0;
+            int bufferLength = mBuffer.length;
+            boolean wasFull = bufferLength == mStoredBytes;
+            while (length > 0 && mStoredBytes > 0) {
+                int oneRun = Math.min(bufferLength - mHead, mStoredBytes);
+                int bytesToCopy = Math.min(length, oneRun);
+                System.arraycopy(mBuffer, mHead, buffer, offset, bytesToCopy);
+                mHead += bytesToCopy;
+                if (mHead >= bufferLength) {
+                    mHead = 0;
+                }
+                mStoredBytes -= bytesToCopy;
+                length -= bytesToCopy;
+                offset += bytesToCopy;
+                totalRead += bytesToCopy;
+            }
+            if (wasFull) {
+                notify();
+            }
+            return totalRead;
+        }
+    }
+
+    public void write(byte[] buffer, int offset, int length)
+    throws InterruptedException {
+        if (length + offset > buffer.length) {
+            throw
+                new IllegalArgumentException("length + offset > buffer.length");
+        }
+        if (length < 0) {
+            throw
+            new IllegalArgumentException("length < 0");
+
+        }
+        if (length == 0) {
+            return;
+        }
+        synchronized(this) {
+            int bufferLength = mBuffer.length;
+            boolean wasEmpty = mStoredBytes == 0;
+            while (length > 0) {
+                while(bufferLength == mStoredBytes) {
+                    wait();
+                }
+                int tail = mHead + mStoredBytes;
+                int oneRun;
+                if (tail >= bufferLength) {
+                    tail = tail - bufferLength;
+                    oneRun = mHead - tail;
+                } else {
+                    oneRun = bufferLength - tail;
+                }
+                int bytesToCopy = Math.min(oneRun, length);
+                System.arraycopy(buffer, offset, mBuffer, tail, bytesToCopy);
+                offset += bytesToCopy;
+                mStoredBytes += bytesToCopy;
+                length -= bytesToCopy;
+            }
+            if (wasEmpty) {
+                notify();
+            }
+        }
+    }
+
+    private byte[] mBuffer;
+    private int mHead;
+    private int mStoredBytes;
+}
+/**
+ * A view on a transcript and a terminal emulator. Displays the text of the
+ * transcript and the current cursor position of the terminal emulator.
+ */
+class EmulatorView extends View implements GestureDetector.OnGestureListener {
+
+    /**
+     * We defer some initialization until we have been layed out in the view
+     * hierarchy. The boolean tracks when we know what our size is.
+     */
+    private boolean mKnownSize;
+
+    /**
+     * Our transcript. Contains the screen and the transcript.
+     */
+    private TranscriptScreen mTranscriptScreen;
+
+    /**
+     * Number of rows in the transcript.
+     */
+    private static final int TRANSCRIPT_ROWS = 10000;
+
+    /**
+     * Total width of each character, in pixels
+     */
+    private int mCharacterWidth;
+
+    /**
+     * Total height of each character, in pixels
+     */
+    private int mCharacterHeight;
+
+    /**
+     * Used to render text
+     */
+    private TextRenderer mTextRenderer;
+
+    /**
+     * Text size. Zero means 4 x 8 font.
+     */
+    private int mTextSize;
+
+    /**
+     * Foreground color.
+     */
+    private int mForeground;
+
+    /**
+     * Background color.
+     */
+    private int mBackground;
+
+    /**
+     * Used to paint the cursor
+     */
+    private Paint mCursorPaint;
+
+    private Paint mBackgroundPaint;
+
+    /**
+     * Our terminal emulator. We use this to get the current cursor position.
+     */
+    private TerminalEmulator mEmulator;
+
+    /**
+     * The number of rows of text to display.
+     */
+    private int mRows;
+
+    /**
+     * The number of columns of text to display.
+     */
+    private int mColumns;
+
+    /**
+     * The number of columns that are visible on the display.
+     */
+
+    private int mVisibleColumns;
+
+    /**
+     * The top row of text to display. Ranges from -activeTranscriptRows to 0
+     */
+    private int mTopRow;
+
+    private int mLeftColumn;
+
+    private FileDescriptor mTermFd;
+    /**
+     * Used to receive data from the remote process.
+     */
+    private FileInputStream mTermIn;
+
+    private FileOutputStream mTermOut;
+
+    private ByteQueue mByteQueue;
+
+    /**
+     * Used to temporarily hold data received from the remote process. Allocated
+     * once and used permanently to minimize heap thrashing.
+     */
+    private byte[] mReceiveBuffer;
+
+    /**
+     * Our private message id, which we use to receive new input from the
+     * remote process.
+     */
+    private static final int UPDATE = 1;
+
+    /**
+     * Thread that polls for input from the remote process
+     */
+
+    private Thread mPollingThread;
+
+    private GestureDetector mGestureDetector;
+    private float mScrollRemainder;
+
+    /**
+     * Our message handler class. Implements a periodic callback.
+     */
+    private final Handler mHandler = new Handler() {
+        /**
+         * Handle the callback message. Call our enclosing class's update
+         * method.
+         *
+         * @param msg The callback message.
+         */
+        public void handleMessage(Message msg) {
+            if (msg.what == UPDATE) {
+                update();
+            }
+        }
+    };
+
+    public EmulatorView(Context context) {
+        super(context);
+        commonConstructor();
+    }
+
+    public void setColors(int foreground, int background) {
+        mForeground = foreground;
+        mBackground = background;
+        updateText();
+    }
+
+    public String getTranscriptText() {
+        return mEmulator.getTranscriptText();
+    }
+
+    public void resetTerminal() {
+        mEmulator.reset();
+        invalidate();
+    }
+
+    @Override
+    public boolean onCheckIsTextEditor() {
+        return true;
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        return new BaseInputConnection(this, false) {
+
+            public boolean beginBatchEdit() {
+                return true;
+            }
+
+            public boolean clearMetaKeyStates(int states) {
+                return true;
+            }
+
+            public boolean commitCompletion(CompletionInfo text) {
+                return true;
+            }
+
+            public boolean commitText(CharSequence text, int newCursorPosition) {
+                sendText(text);
+                return true;
+            }
+
+            public boolean deleteSurroundingText(int leftLength, int rightLength) {
+                return true;
+            }
+
+            public boolean endBatchEdit() {
+                return true;
+            }
+
+            public boolean finishComposingText() {
+                return true;
+            }
+
+            public int getCursorCapsMode(int reqModes) {
+                return 0;
+            }
+
+            public ExtractedText getExtractedText(ExtractedTextRequest request,
+                    int flags) {
+                return null;
+            }
+
+            public CharSequence getTextAfterCursor(int n, int flags) {
+                return null;
+            }
+
+            public CharSequence getTextBeforeCursor(int n, int flags) {
+                return null;
+            }
+
+            public boolean hideStatusIcon() {
+                return true;
+            }
+
+            public boolean performContextMenuAction(int id) {
+                return true;
+            }
+
+            public boolean performPrivateCommand(String action, Bundle data) {
+                return true;
+            }
+
+            public boolean sendKeyEvent(KeyEvent event) {
+                switch(event.getKeyCode()) {
+                case KeyEvent.KEYCODE_ENTER:
+                    sendChar('\r');
+                    break;
+                case KeyEvent.KEYCODE_DEL:
+                    sendChar(127);
+                    break;
+                }
+                return true;
+            }
+
+            public boolean setComposingText(CharSequence text, int newCursorPosition) {
+                return true;
+            }
+
+            public boolean setSelection(int start, int end) {
+                return true;
+            }
+
+            public boolean showStatusIcon(String packageName, int resId) {
+                return true;
+            }
+
+            private void sendChar(int c) {
+                try {
+                    mTermOut.write(c);
+                } catch (IOException ex) {
+
+                }
+            }
+            private void sendText(CharSequence text) {
+                int n = text.length();
+                try {
+                    for(int i = 0; i < n; i++) {
+                        char c = text.charAt(i);
+                        mTermOut.write(c);
+                    }
+                } catch (IOException e) {
+                }
+            }
+        };
+    }
+
+    public boolean getKeypadApplicationMode() {
+        return mEmulator.getKeypadApplicationMode();
+    }
+
+    public EmulatorView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public EmulatorView(Context context, AttributeSet attrs,
+            int defStyle) {
+        super(context, attrs, defStyle);
+        TypedArray a =
+                context.obtainStyledAttributes(android.R.styleable.View);
+        initializeScrollbars(a);
+        a.recycle();
+        commonConstructor();
+    }
+
+    private void commonConstructor() {
+        mTextRenderer = null;
+        mCursorPaint = new Paint();
+        mCursorPaint.setARGB(255,128,128,128);
+        mBackgroundPaint = new Paint();
+        mTopRow = 0;
+        mLeftColumn = 0;
+        mGestureDetector = new GestureDetector(this);
+        mGestureDetector.setIsLongpressEnabled(false);
+        setVerticalScrollBarEnabled(true);
+    }
+
+    @Override
+    protected int computeVerticalScrollRange() {
+        return mTranscriptScreen.getActiveRows();
+    }
+
+    @Override
+    protected int computeVerticalScrollExtent() {
+        return mRows;
+    }
+
+    @Override
+    protected int computeVerticalScrollOffset() {
+        return mTranscriptScreen.getActiveRows() + mTopRow - mRows;
+    }
+
+    /**
+     * Call this to initialize the view.
+     *
+     * @param termFd the file descriptor
+     * @param termOut the output stream for the pseudo-teletype
+     */
+    public void initialize(FileDescriptor termFd, FileOutputStream termOut) {
+        mTermOut = termOut;
+        mTermFd = termFd;
+        mTextSize = 10;
+        mForeground = Term.WHITE;
+        mBackground = Term.BLACK;
+        updateText();
+        mTermIn = new FileInputStream(mTermFd);
+        mReceiveBuffer = new byte[4 * 1024];
+        mByteQueue = new ByteQueue(4 * 1024);
+    }
+
+    /**
+     * Accept a sequence of bytes (typically from the pseudo-tty) and process
+     * them.
+     *
+     * @param buffer a byte array containing bytes to be processed
+     * @param base the index of the first byte in the buffer to process
+     * @param length the number of bytes to process
+     */
+    public void append(byte[] buffer, int base, int length) {
+        mEmulator.append(buffer, base, length);
+        ensureCursorVisible();
+        invalidate();
+    }
+
+    /**
+     * Page the terminal view (scroll it up or down by delta screenfulls.)
+     *
+     * @param delta the number of screens to scroll. Positive means scroll down,
+     *        negative means scroll up.
+     */
+    public void page(int delta) {
+        mTopRow =
+                Math.min(0, Math.max(-(mTranscriptScreen
+                        .getActiveTranscriptRows()), mTopRow + mRows * delta));
+        invalidate();
+    }
+
+    /**
+     * Page the terminal view horizontally.
+     *
+     * @param deltaColumns the number of columns to scroll. Positive scrolls to
+     *        the right.
+     */
+    public void pageHorizontal(int deltaColumns) {
+        mLeftColumn =
+                Math.max(0, Math.min(mLeftColumn + deltaColumns, mColumns
+                        - mVisibleColumns));
+        invalidate();
+    }
+
+    /**
+     * Sets the text size, which in turn sets the number of rows and columns
+     *
+     * @param fontSize the new font size, in pixels.
+     */
+    public void setTextSize(int fontSize) {
+        mTextSize = fontSize;
+        updateText();
+    }
+
+    // Begin GestureDetector.OnGestureListener methods
+
+    public boolean onSingleTapUp(MotionEvent e) {
+        return true;
+    }
+
+    public void onLongPress(MotionEvent e) {
+    }
+
+    public boolean onScroll(MotionEvent e1, MotionEvent e2,
+            float distanceX, float distanceY) {
+        distanceY += mScrollRemainder;
+        int deltaRows = (int) (distanceY / mCharacterHeight);
+        mScrollRemainder = distanceY - deltaRows * mCharacterHeight;
+        mTopRow =
+            Math.min(0, Math.max(-(mTranscriptScreen
+                    .getActiveTranscriptRows()), mTopRow + deltaRows));
+        invalidate();
+
+        return true;
+   }
+
+    public void onSingleTapConfirmed(MotionEvent e) {
+    }
+
+    public boolean onJumpTapDown(MotionEvent e1, MotionEvent e2) {
+       // Scroll to bottom
+       mTopRow = 0;
+       invalidate();
+       return true;
+    }
+
+    public boolean onJumpTapUp(MotionEvent e1, MotionEvent e2) {
+        // Scroll to top
+        mTopRow = -mTranscriptScreen.getActiveTranscriptRows();
+        invalidate();
+        return true;
+    }
+
+    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+            float velocityY) {
+        // TODO: add animation man's (non animated) fling
+        mScrollRemainder = 0.0f;
+        onScroll(e1, e2, 2 * velocityX, -2 * velocityY);
+        return true;
+    }
+
+    public void onShowPress(MotionEvent e) {
+    }
+
+    public boolean onDown(MotionEvent e) {
+        mScrollRemainder = 0.0f;
+        return true;
+    }
+
+    // End GestureDetector.OnGestureListener methods
+
+    @Override public boolean onTouchEvent(MotionEvent ev) {
+        return mGestureDetector.onTouchEvent(ev);
+    }
+
+    private void updateText() {
+        if (mTextSize > 0) {
+            mTextRenderer = new PaintRenderer(mTextSize, mForeground,
+                    mBackground);
+        }
+        else {
+            mTextRenderer = new Bitmap4x8FontRenderer(getResources(),
+                    mForeground, mBackground);
+        }
+        mBackgroundPaint.setColor(mBackground);
+        mCharacterWidth = mTextRenderer.getCharacterWidth();
+        mCharacterHeight = mTextRenderer.getCharacterHeight();
+
+        if (mKnownSize) {
+            updateSize(getWidth(), getHeight());
+        }
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        updateSize(w, h);
+        if (!mKnownSize) {
+            mKnownSize = true;
+
+            // Set up a thread to read input from the
+            // pseudo-teletype:
+
+            mPollingThread = new Thread(new Runnable() {
+
+                public void run() {
+                    try {
+                        while(true) {
+                            int read = mTermIn.read(mBuffer);
+                            mByteQueue.write(mBuffer, 0, read);
+                            mHandler.sendMessage(
+                                    mHandler.obtainMessage(UPDATE));
+                        }
+                    } catch (IOException e) {
+                    } catch (InterruptedException e) {
+                    }
+                }
+                private byte[] mBuffer = new byte[4096];
+            });
+            mPollingThread.setName("Input reader");
+            mPollingThread.start();
+        }
+    }
+
+    private void updateSize(int w, int h) {
+        mColumns = w / mCharacterWidth;
+        mRows = h / mCharacterHeight;
+
+        // Inform the attached pty of our new size:
+        Exec.setPtyWindowSize(mTermFd, mRows, mColumns, w, h);
+
+
+        if (mTranscriptScreen != null) {
+            mEmulator.updateSize(mColumns, mRows);
+        } else {
+            mTranscriptScreen =
+                    new TranscriptScreen(mColumns, TRANSCRIPT_ROWS, mRows, 0, 7);
+            mEmulator =
+                    new TerminalEmulator(mTranscriptScreen, mColumns, mRows,
+                            mTermOut);
+        }
+
+        // Reset our paging:
+        mTopRow = 0;
+        mLeftColumn = 0;
+
+        invalidate();
+    }
+
+    void updateSize() {
+        if (mKnownSize) {
+            updateSize(getWidth(), getHeight());
+        }
+    }
+
+    /**
+     * Look for new input from the ptty, send it to the terminal emulator.
+     */
+    private void update() {
+        int bytesAvailable = mByteQueue.getBytesAvailable();
+        int bytesToRead = Math.min(bytesAvailable, mReceiveBuffer.length);
+        try {
+            int bytesRead = mByteQueue.read(mReceiveBuffer, 0, bytesToRead);
+            append(mReceiveBuffer, 0, bytesRead);
+        } catch (InterruptedException e) {
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        int w = getWidth();
+        int h = getHeight();
+        canvas.drawRect(0, 0, w, h, mBackgroundPaint);
+        mVisibleColumns = w / mCharacterWidth;
+        float x = -mLeftColumn * mCharacterWidth;
+        float y = mCharacterHeight;
+        int endLine = mTopRow + mRows;
+        int cx = mEmulator.getCursorCol();
+        int cy = mEmulator.getCursorRow();
+        for (int i = mTopRow; i < endLine; i++) {
+            int cursorX = -1;
+            if (i == cy) {
+                cursorX = cx;
+            }
+            mTranscriptScreen.drawText(i, canvas, x, y, mTextRenderer, cursorX);
+            y += mCharacterHeight;
+        }
+    }
+
+    private void ensureCursorVisible() {
+        mTopRow = 0;
+        if (mVisibleColumns > 0) {
+            int cx = mEmulator.getCursorCol();
+            int visibleCursorX = mEmulator.getCursorCol() - mLeftColumn;
+            if (visibleCursorX < 0) {
+                mLeftColumn = cx;
+            } else if (visibleCursorX >= mVisibleColumns) {
+                mLeftColumn = (cx - mVisibleColumns) + 1;
+            }
+        }
+    }
+}
+
+
+/**
+ * An ASCII key listener. Supports control characters and escape. Keeps track of
+ * the current state of the alt, shift, and control keys.
+ */
+class TermKeyListener {
+    /**
+     * The state engine for a modifier key. Can be pressed, released, locked,
+     * and so on.
+     *
+     */
+    private class ModifierKey {
+
+        private int mState;
+
+        private static final int UNPRESSED = 0;
+
+        private static final int PRESSED = 1;
+
+        private static final int RELEASED = 2;
+
+        private static final int USED = 3;
+
+        private static final int LOCKED = 4;
+
+        /**
+         * Construct a modifier key. UNPRESSED by default.
+         *
+         */
+        public ModifierKey() {
+            mState = UNPRESSED;
+        }
+
+        public void onPress() {
+            switch (mState) {
+            case PRESSED:
+                // This is a repeat before use
+                break;
+            case RELEASED:
+                mState = LOCKED;
+                break;
+            case USED:
+                // This is a repeat after use
+                break;
+            case LOCKED:
+                mState = UNPRESSED;
+                break;
+            default:
+                mState = PRESSED;
+                break;
+            }
+        }
+
+        public void onRelease() {
+            switch (mState) {
+            case USED:
+                mState = UNPRESSED;
+                break;
+            case PRESSED:
+                mState = RELEASED;
+                break;
+            default:
+                // Leave state alone
+                break;
+            }
+        }
+
+        public void adjustAfterKeypress() {
+            switch (mState) {
+            case PRESSED:
+                mState = USED;
+                break;
+            case RELEASED:
+                mState = UNPRESSED;
+                break;
+            default:
+                // Leave state alone
+                break;
+            }
+        }
+
+        public boolean isActive() {
+            return mState != UNPRESSED;
+        }
+    }
+
+    private ModifierKey mAltKey = new ModifierKey();
+
+    private ModifierKey mCapKey = new ModifierKey();
+
+    private ModifierKey mControlKey = new ModifierKey();
+
+    /**
+     * Construct a term key listener.
+     *
+     */
+    public TermKeyListener() {
+    }
+
+    public void handleControlKey(boolean down) {
+        if (down) {
+            mControlKey.onPress();
+        } else {
+            mControlKey.onRelease();
+        }
+    }
+
+    /**
+     * Handle a keyDown event.
+     *
+     * @param keyCode the keycode of the keyDown event
+     * @return the ASCII byte to transmit to the pseudo-teletype, or -1 if this
+     *         event does not produce an ASCII byte.
+     */
+    public int keyDown(int keyCode, KeyEvent event) {
+        int result = -1;
+        switch (keyCode) {
+        case KeyEvent.KEYCODE_ALT_RIGHT:
+        case KeyEvent.KEYCODE_ALT_LEFT:
+            mAltKey.onPress();
+            break;
+
+        case KeyEvent.KEYCODE_SHIFT_LEFT:
+        case KeyEvent.KEYCODE_SHIFT_RIGHT:
+            mCapKey.onPress();
+            break;
+
+        case KeyEvent.KEYCODE_ENTER:
+            // Convert newlines into returns. The vt100 sends a
+            // '\r' when the 'Return' key is pressed, but our
+            // KeyEvent translates this as a '\n'.
+            result = '\r';
+            break;
+
+        case KeyEvent.KEYCODE_DEL:
+            // Convert DEL into 127 (instead of 8)
+            result = 127;
+            break;
+
+        default: {
+            result = event.getUnicodeChar(
+                   (mCapKey.isActive() ? KeyEvent.META_SHIFT_ON : 0) |
+                   (mAltKey.isActive() ? KeyEvent.META_ALT_ON : 0));
+            break;
+            }
+        }
+
+        if (mControlKey.isActive()) {
+            // Search is the control key.
+            if (result >= 'a' && result <= 'z') {
+                result = (char) (result - 'a' + '\001');
+            } else if (result == ' ') {
+                result = 0;
+            } else if ((result == '[') || (result == '1')) {
+                result = 27;
+            } else if ((result == '\\') || (result == '.')) {
+                result = 28;
+            } else if ((result == ']') || (result == '0')) {
+                result = 29;
+            } else if ((result == '^') || (result == '6')) {
+                result = 30; // control-^
+            } else if ((result == '_') || (result == '5')) {
+                result = 31;
+            }
+        }
+
+        if (result > -1) {
+            mAltKey.adjustAfterKeypress();
+            mCapKey.adjustAfterKeypress();
+            mControlKey.adjustAfterKeypress();
+        }
+
+        return result;
+    }
+
+    /**
+     * Handle a keyUp event.
+     *
+     * @param keyCode the keyCode of the keyUp event
+     */
+    public void keyUp(int keyCode) {
+        switch (keyCode) {
+        case KeyEvent.KEYCODE_ALT_LEFT:
+        case KeyEvent.KEYCODE_ALT_RIGHT:
+            mAltKey.onRelease();
+            break;
+        case KeyEvent.KEYCODE_SHIFT_LEFT:
+        case KeyEvent.KEYCODE_SHIFT_RIGHT:
+            mCapKey.onRelease();
+            break;
+        default:
+            // Ignore other keyUps
+            break;
+        }
+    }
+}
diff --git a/apps/Term/src/com/android/term/TermPreferences.java b/apps/Term/src/com/android/term/TermPreferences.java
new file mode 100644
index 0000000..3102963
--- /dev/null
+++ b/apps/Term/src/com/android/term/TermPreferences.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package com.android.term;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+public class TermPreferences extends PreferenceActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Load the preferences from an XML resource
+        addPreferencesFromResource(R.xml.preferences);
+    }
+
+}
diff --git a/apps/launchperf/Android.mk b/apps/launchperf/Android.mk
new file mode 100644
index 0000000..f3d29bb
--- /dev/null
+++ b/apps/launchperf/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := launchperf
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/apps/launchperf/AndroidManifest.xml b/apps/launchperf/AndroidManifest.xml
new file mode 100644
index 0000000..8cf53c4
--- /dev/null
+++ b/apps/launchperf/AndroidManifest.xml
@@ -0,0 +1,64 @@
+<?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.launchperf">
+  <application android:label="Launch Performance">
+      <uses-library android:name="android.test.runner" />
+
+    <activity android:name="SimpleActivity" android:label="Simple Activity">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.DEFAULT" />
+      </intent-filter>
+    </activity>
+
+    <activity android:name="EmptyActivity" android:label="Empty Activity">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.DEFAULT" />
+      </intent-filter>
+    </activity>
+
+    <activity android:name="ComplexActivity" android:label="Complex Activity">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.DEFAULT" />
+      </intent-filter>
+    </activity>
+
+  </application>
+
+  <instrumentation android:name="SimpleActivityLaunchPerformance"
+    android:targetPackage="com.android.launchperf"
+    android:label="Simple Activity Launch Performance">
+  </instrumentation>
+
+  <instrumentation android:name="ComplexActivityLaunchPerformance"
+    android:targetPackage="com.android.launchperf"
+    android:label="Complex Activity Launch Performance">
+  </instrumentation>
+
+  <instrumentation android:name="EmptyActivityLaunchPerformance"
+    android:targetPackage="com.android.launchperf"
+    android:label="Empty Activity Launch Performance">
+  </instrumentation>
+
+  <instrumentation android:name="HelloWorldLaunchPerformance"
+    android:targetPackage="com.example.android.apis"
+    android:label="Hello World Launch Performance">
+  </instrumentation>
+
+</manifest>
diff --git a/apps/launchperf/res/layout/complex_layout.xml b/apps/launchperf/res/layout/complex_layout.xml
new file mode 100644
index 0000000..4e585b9
--- /dev/null
+++ b/apps/launchperf/res/layout/complex_layout.xml
@@ -0,0 +1,288 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/tests/ComplexLayout/res/layout/complex_layout.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This file describes the layout of the main ComplexLayout activity
+     user interface.
+ -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+<!--    <TabHost
+        android:layout_width="fill_parent"
+        android:layout_height="200dip">
+    </TabHost>
+
+    <GridView
+        android:layout_width="fill_parent"
+        android:layout_height="200dip"
+        android:numColumns="5">
+    </GridView> -->
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="200dip"
+        android:orientation="vertical">
+        
+        <TextView
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/header_absolute"/>
+
+        <AbsoluteLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_x="0dip"
+                android:layout_y="0dip"
+                android:background="@color/red"
+                android:text="@string/test_short_paragraph"/>
+            
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="0dip"
+                android:layout_y="0dip"
+                android:background="@color/gray0"
+                android:text="@string/test_word"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="8dip"
+                android:layout_y="4dip"
+                android:background="@color/gray1"
+                android:text="@string/test_word"/>
+             <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="16dip"
+                android:layout_y="8dip"
+                android:background="@color/gray2"
+                android:text="@string/test_word"/>
+             <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="24dip"
+                android:layout_y="12dip"
+                android:background="@color/gray3"
+                android:text="@string/test_word"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="32dip"
+                android:layout_y="16dip"
+                android:background="@color/gray4"
+                android:text="@string/test_word"/>
+             <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="40dip"
+                android:layout_y="20dip"
+                android:background="@color/gray5"
+                android:text="@string/test_word"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="48dip"
+                android:layout_y="24dip"
+                android:background="@color/gray6"
+                android:text="@string/test_word"/>
+             <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="56dip"
+                android:layout_y="28dip"
+                android:background="@color/gray7"
+                android:text="@string/test_word"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="64dip"
+                android:layout_y="32dip"
+                android:background="@color/gray8"
+                android:text="@string/test_word"/>
+             <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="72dip"
+                android:layout_y="36dip"
+                android:background="@color/gray9"
+                android:text="@string/test_word"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="80dip"
+                android:layout_y="40dip"
+                android:background="@color/grayA"
+                android:text="@string/test_word"/>
+             <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="88dip"
+                android:layout_y="44dip"
+                android:background="@color/grayB"
+                android:text="@string/test_word"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="96dip"
+                android:layout_y="48dip"
+                android:background="@color/grayC"
+                android:text="@string/test_word"/>
+             <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="104dip"
+                android:layout_y="52dip"
+                android:background="@color/grayD"
+                android:text="@string/test_word"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="112dip"
+                android:layout_y="56dip"
+                android:background="@color/grayE"
+                android:text="@string/test_word"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_x="120dip"
+                android:layout_y="60dip"
+                android:background="@color/grayF"
+                android:text="@string/test_word"/>
+
+        </AbsoluteLayout>
+
+        <TextView
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/header_relative"/>
+
+        <RelativeLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content">
+
+            <Button android:id="@+id/relative_button1"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/relative_button1"/>
+            <Button android:id="@+id/relative_button2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/relative_button1"
+                android:text="@string/relative_button2"/>
+            <Button android:id="@+id/relative_button3"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/relative_button2"
+                android:text="@string/relative_button3"/>
+            <Button android:id="@+id/relative_button4"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/relative_button3"
+                android:text="@string/relative_button4"/>
+
+            <TextView android:id="@+id/relative_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_toRightOf="@id/relative_button1"
+                android:background="@color/green"
+                android:text="@string/test_short_paragraph"/>
+
+            <Button android:id="@+id/relative_button5"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/relative_text"
+                android:layout_alignParentRight="true"
+                android:text="@string/relative_button5"/>
+            <Button android:id="@+id/relative_button6"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/relative_text"
+                android:layout_toLeftOf="@id/relative_button5"
+                android:text="@string/relative_button6"/>
+            <Button android:id="@+id/relative_button7"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/relative_text"
+                android:layout_toLeftOf="@id/relative_button6"
+                android:text="@string/relative_button7"/>
+            <Button android:id="@+id/relative_button8"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/relative_text"
+                android:layout_toLeftOf="@id/relative_button7"
+                android:text="@string/relative_button8"/>
+
+        </RelativeLayout>
+
+        <TextView
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/header_linear"/>
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/relative_button1"/>
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/relative_button2"/>
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/relative_button3"/>
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/relative_button4"/>
+
+            </LinearLayout>
+
+            <EditText
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"/>
+
+            <TextView
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:background="@color/blue"
+                android:text="@string/test_long_paragraph"/>
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</ScrollView>
diff --git a/apps/launchperf/res/layout/simple_layout.xml b/apps/launchperf/res/layout/simple_layout.xml
new file mode 100644
index 0000000..3a61724
--- /dev/null
+++ b/apps/launchperf/res/layout/simple_layout.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/tests/SimpleLayout/res/layout/simple_layout.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This file describes the layout of the main SimpleLayout activity
+     user interface.
+ -->
+
+<!-- The top view is a layout manager that places its child views into
+     a row, here set to be vertical (so the first is at the top) -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+    
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+
+        <RelativeLayout android:id="@+id/replay_pane"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="True"
+            android:background="@color/replay_background">
+
+            <TextView android:id="@+id/instructions"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/response" />
+
+            <EditText android:id="@+id/entry"
+                android:layout_width="fill_parent" 
+                android:layout_height="44dip" 
+                android:layout_below="@id/instructions"/>
+  
+            <Button android:id="@+id/ok" 
+                android:layout_width="wrap_content" 
+                android:layout_height="wrap_content" 
+                android:layout_below="@id/entry"
+                android:layout_alignParentRight="true"
+                android:text="@string/ok" />
+
+            <Button android:id="@+id/cancel"
+                android:layout_width="wrap_content" 
+                android:layout_height="wrap_content"
+                android:layout_toLeftOf="@id/ok"
+                android:layout_alignTop="@id/ok"
+                android:text="@string/cancel" />
+
+        </RelativeLayout>
+
+        <ScrollView android:id="@+id/scroll_pane"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_above="@id/replay_pane">
+
+            <TextView android:id="@+id/text_field"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:text="@string/text"/>
+            
+            <requestFocus/>
+
+        </ScrollView>
+
+    </RelativeLayout>
+    
+</LinearLayout>
diff --git a/apps/launchperf/res/values/colors.xml b/apps/launchperf/res/values/colors.xml
new file mode 100644
index 0000000..9510c25
--- /dev/null
+++ b/apps/launchperf/res/values/colors.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/tests/ComplexLayout/res/values/colors.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+     them to be changed based on the locale and options. -->
+
+<resources>
+    <color name="gray0">#F000</color>
+    <color name="gray1">#E111</color>
+    <color name="gray2">#D222</color>
+    <color name="gray3">#C333</color>
+    <color name="gray4">#B444</color>
+    <color name="gray5">#A555</color>
+    <color name="gray6">#9666</color>
+    <color name="gray7">#8777</color>
+    <color name="gray8">#7888</color>
+    <color name="gray9">#6999</color>
+    <color name="grayA">#5AAA</color>
+    <color name="grayB">#4BBB</color>
+    <color name="grayC">#3CCC</color>
+    <color name="grayD">#2DDD</color>
+    <color name="grayE">#1EEE</color>
+    <color name="grayF">#0FFF</color>
+    <color name="red">#F00</color>
+    <color name="green">#0F0</color>
+    <color name="blue">#00F</color>
+    <color name="replay_background">#e0eaff</color>
+</resources>
diff --git a/apps/launchperf/res/values/strings.xml b/apps/launchperf/res/values/strings.xml
new file mode 100644
index 0000000..21c406c
--- /dev/null
+++ b/apps/launchperf/res/values/strings.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/tests/ComplexLayout/res/values/strings.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+     them to be changed based on the locale and options. -->
+
+<resources>
+    <string name="test_word">test</string>
+    <string name="test_sentence">This is a test sentence.</string>
+    <string name="test_short_paragraph">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras consectetuer dolor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent nec sapien nec orci feugiat sodales.</string>
+    <string name="test_long_paragraph">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras consectetuer dolor. Vivamus bibendum semper lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent nec sapien nec orci feugiat sodales. Praesent ut tortor. Suspendisse sed magna quis ante pellentesque faucibus. Nunc feugiat. Quisque porta. Nunc velit magna, varius in, fringilla quis, ornare eget, magna. Suspendisse potenti. Nam eu felis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque vulputate suscipit magna. Nunc vestibulum lorem ac odio.</string>
+    <string name="header_absolute">Absolute view</string>
+
+    <string name="header_relative">Relative layout</string>
+    <string name="header_linear">Linear layout</string>
+
+    <string name="relative_button1">Button1</string>
+    <string name="relative_button2">Button2</string>
+    <string name="relative_button3">Button3</string>
+    <string name="relative_button4">Button4</string>
+    <string name="relative_button5">Button5</string>
+    <string name="relative_button6">Button6</string>
+    <string name="relative_button7">Button7</string>
+    <string name="relative_button8">Button8</string>
+    <string name="response">Type Response:</string>
+    <string name="ok">OK</string>
+    <string name="cancel">Cancel</string>
+    <string name="text">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In congue varius tortor. Etiam dolor nisl, lacinia et, venenatis vitae, nonummy ut, mi. Praesent a risus. Ut nisi. Nullam nonummy, lorem vel bibendum pellentesque, dolor massa egestas risus, luctus vehicula metus metus non nibh. Suspendisse potenti. In malesuada dolor. Fusce sodales fermentum metus. Mauris bibendum. Morbi faucibus eros sed enim. Pellentesque bibendum diam a justo. Suspendisse condimentum. Nam luctus, turpis molestie aliquet congue, nulla ante vulputate ipsum, nec nonummy neque tellus eu mi. Phasellus semper. Aenean adipiscing erat nec turpis. Curabitur euismod sapien quis nisl. Pellentesque tempor tristique lectus. Praesent fermentum.</string>
+</resources>
diff --git a/apps/launchperf/src/com/android/launchperf/ComplexActivity.java b/apps/launchperf/src/com/android/launchperf/ComplexActivity.java
new file mode 100644
index 0000000..b909bd3
--- /dev/null
+++ b/apps/launchperf/src/com/android/launchperf/ComplexActivity.java
@@ -0,0 +1,35 @@
+/* //device/tests/ComplexLayout/src/com/android/complexlayout/ComplexLayout.java
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.launchperf;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class ComplexActivity extends Activity {
+   
+    /** Called with the activity is first created. */
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        // Inflate our UI from its XML layout description.
+        setContentView(R.layout.complex_layout);
+    }
+}
diff --git a/apps/launchperf/src/com/android/launchperf/ComplexActivityLaunchPerformance.java b/apps/launchperf/src/com/android/launchperf/ComplexActivityLaunchPerformance.java
new file mode 100644
index 0000000..0030f6b
--- /dev/null
+++ b/apps/launchperf/src/com/android/launchperf/ComplexActivityLaunchPerformance.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package com.android.launchperf;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.test.LaunchPerformanceBase;
+import android.os.Bundle;
+
+import java.util.Map;
+
+/**
+ * Instrumentation class for Complex Activity launch performance testing.
+ */
+public class ComplexActivityLaunchPerformance extends LaunchPerformanceBase {
+ 
+    public static final String LOG_TAG = "ComplexActivityLaunchPerformance";
+
+    public ComplexActivityLaunchPerformance() {
+        super();
+    }
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+
+        mIntent.setClassName(getContext(), "com.android.launchperf.ComplexActivity");
+        start();
+    }
+
+    /**
+     * Calls LaunchApp and finish.
+     */
+    @Override
+    public void onStart() {
+        super.onStart();
+        LaunchApp();
+        finish(Activity.RESULT_OK, mResults);
+    }
+}
diff --git a/apps/launchperf/src/com/android/launchperf/EmptyActivity.java b/apps/launchperf/src/com/android/launchperf/EmptyActivity.java
new file mode 100644
index 0000000..b431ea4
--- /dev/null
+++ b/apps/launchperf/src/com/android/launchperf/EmptyActivity.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package com.android.launchperf;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import java.util.Map;
+
+public class EmptyActivity extends Activity {
+    
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+    }
+
+}
diff --git a/apps/launchperf/src/com/android/launchperf/EmptyActivityLaunchPerformance.java b/apps/launchperf/src/com/android/launchperf/EmptyActivityLaunchPerformance.java
new file mode 100644
index 0000000..5dc586b
--- /dev/null
+++ b/apps/launchperf/src/com/android/launchperf/EmptyActivityLaunchPerformance.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launchperf;
+
+import android.app.Activity;
+import android.test.LaunchPerformanceBase;
+import android.os.Bundle;
+
+import java.util.Map;
+
+/**
+ * Instrumentation class for Empty Activity launch performance testing.
+ */
+public class EmptyActivityLaunchPerformance extends LaunchPerformanceBase {
+ 
+    public static final String LOG_TAG = "EmptyActivityLaunchPerformance";
+
+    public EmptyActivityLaunchPerformance() {
+        super();
+    }
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+
+        mIntent.setClassName(getContext(), "com.android.launchperf.EmptyActivity");
+        start();
+    }
+
+    /**
+     * Calls LaunchApp and finish.
+     */
+    @Override
+    public void onStart() {
+        super.onStart();
+        LaunchApp();
+        finish(Activity.RESULT_OK, mResults);
+    }
+}
diff --git a/apps/launchperf/src/com/android/launchperf/HelloWorldLaunchPerformance.java b/apps/launchperf/src/com/android/launchperf/HelloWorldLaunchPerformance.java
new file mode 100644
index 0000000..0500165
--- /dev/null
+++ b/apps/launchperf/src/com/android/launchperf/HelloWorldLaunchPerformance.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launchperf;
+
+import android.app.Activity;
+import android.test.LaunchPerformanceBase;
+import android.os.Bundle;
+
+import java.util.Map;
+
+/**
+ * Instrumentation class for Hello World launch performance testing.
+ */
+public class HelloWorldLaunchPerformance extends LaunchPerformanceBase {
+ 
+    public static final String LOG_TAG = "HelloWorldLaunchPerformance";
+
+    public HelloWorldLaunchPerformance() {
+        super();
+    }
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+
+        mIntent.setClassName(getTargetContext(), "com.example.android.apis.app.HelloWorld");
+        start();
+    }
+
+    /**
+     * Calls LaunchApp and finish.
+     */
+    @Override
+    public void onStart() {
+        super.onStart();
+        LaunchApp();
+        finish(Activity.RESULT_OK, mResults);
+    }
+}
diff --git a/apps/launchperf/src/com/android/launchperf/NotePadLaunchPerformance.java b/apps/launchperf/src/com/android/launchperf/NotePadLaunchPerformance.java
new file mode 100644
index 0000000..a33fe63
--- /dev/null
+++ b/apps/launchperf/src/com/android/launchperf/NotePadLaunchPerformance.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launchperf;
+
+import android.app.Activity;
+import android.test.LaunchPerformanceBase;
+import android.os.Bundle;
+
+import java.util.Map;
+
+/**
+ * Instrumentation class for Notepad launch performance testing.
+ */
+public class NotePadLaunchPerformance extends LaunchPerformanceBase {
+ 
+    public static final String LOG_TAG = "NotePadLaunchPerformance";
+
+    public NotePadLaunchPerformance() {
+        super();
+    }
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+
+        mIntent.setClassName(getTargetContext(), "com.android.notepad.NotesList");
+        start();
+    }
+
+    /**
+     * Calls LaunchApp and finish.
+     */
+    @Override
+    public void onStart() {
+        super.onStart();
+        LaunchApp();
+        finish(Activity.RESULT_OK, mResults);
+    }
+}
diff --git a/apps/launchperf/src/com/android/launchperf/PhoneLaunchPerformance.java b/apps/launchperf/src/com/android/launchperf/PhoneLaunchPerformance.java
new file mode 100644
index 0000000..02e2a3b
--- /dev/null
+++ b/apps/launchperf/src/com/android/launchperf/PhoneLaunchPerformance.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launchperf;
+
+import android.app.Activity;
+import android.test.LaunchPerformanceBase;
+import android.os.Bundle;
+
+import java.util.Map;
+
+/**
+ * Instrumentation class for Phone launch performance testing.
+ */
+public class PhoneLaunchPerformance extends LaunchPerformanceBase {
+ 
+    public static final String LOG_TAG = "PhoneLaunchPerformance";
+   
+    public PhoneLaunchPerformance() {
+        super();
+    }
+    
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+
+        mIntent.setClassName(getTargetContext(), "com.android.phone.CallLogList");
+        start();
+    }
+
+    /**
+     * Calls LaunchApp and finish.
+     */
+    @Override
+    public void onStart() {
+        super.onStart();
+        LaunchApp();
+        finish(Activity.RESULT_OK, mResults);
+    }
+}
diff --git a/apps/launchperf/src/com/android/launchperf/SimpleActivity.java b/apps/launchperf/src/com/android/launchperf/SimpleActivity.java
new file mode 100644
index 0000000..e6425ab
--- /dev/null
+++ b/apps/launchperf/src/com/android/launchperf/SimpleActivity.java
@@ -0,0 +1,35 @@
+/* //device/tests/SimpleLayout/src/com/android/simplelayout/SimpleLayout.java
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.launchperf;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class SimpleActivity extends Activity {
+   
+    /** Called with the activity is first created. */
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        // Inflate our UI from its XML layout description.
+        setContentView(R.layout.simple_layout);
+    }
+}
diff --git a/apps/launchperf/src/com/android/launchperf/SimpleActivityLaunchPerformance.java b/apps/launchperf/src/com/android/launchperf/SimpleActivityLaunchPerformance.java
new file mode 100644
index 0000000..2f92500
--- /dev/null
+++ b/apps/launchperf/src/com/android/launchperf/SimpleActivityLaunchPerformance.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launchperf;
+
+import android.app.Activity;
+import android.test.LaunchPerformanceBase;
+import android.os.Bundle;
+
+import java.util.Map;
+
+/**
+ * Instrumentation class for Simple Activity launch performance testing.
+ */
+public class SimpleActivityLaunchPerformance extends LaunchPerformanceBase {
+ 
+    public static final String LOG_TAG = "SimpleActivityLaunchPerformance";
+
+    public SimpleActivityLaunchPerformance() {
+        super();
+    }
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+
+        mIntent.setClassName(getContext(), "com.android.launchperf.SimpleActivity");
+        start();
+    }
+
+    /**
+     * Calls LaunchApp and finish.
+     */
+    @Override
+    public void onStart() {
+        super.onStart();
+        LaunchApp();
+        finish(Activity.RESULT_OK, mResults);
+    }
+}