Code drop from //branches/cupcake/...@124589
diff --git a/core/java/android/accounts/AccountMonitor.java b/core/java/android/accounts/AccountMonitor.java
index 9bcc1e7..f21385e 100644
--- a/core/java/android/accounts/AccountMonitor.java
+++ b/core/java/android/accounts/AccountMonitor.java
@@ -42,31 +42,42 @@
     private final Context mContext;
     private final AccountMonitorListener mListener;
     private boolean mClosed = false;
+    private int pending = 0;
 
     // This thread runs in the background and runs the code to update accounts
     // in the listener.
     private class AccountUpdater extends Thread {
         private IBinder mService;
-        
+
         public AccountUpdater(IBinder service) {
             mService = service;
         }
-        
+
         @Override
         public void run() {
             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
             IAccountsService accountsService = IAccountsService.Stub.asInterface(mService);
-            String[] accounts;
-            try {
-                accounts = accountsService.getAccounts();
-            } catch (RemoteException e) {
-                // if the service was killed then the system will restart it and when it does we
-                // will get another onServiceConnected, at which point we will do a notify.
-                Log.w("AccountMonitor", "Remote exception when getting accounts", e);
-                return;
-            }
+            String[] accounts = null;
+            do {
+                try {
+                    accounts = accountsService.getAccounts();
+                } catch (RemoteException e) {
+                    // if the service was killed then the system will restart it and when it does we
+                    // will get another onServiceConnected, at which point we will do a notify.
+                    Log.w("AccountMonitor", "Remote exception when getting accounts", e);
+                    return;
+                }
+
+                synchronized (AccountMonitor.this) {
+                    --pending;
+                    if (pending == 0) {
+                        break;
+                    }
+                }
+            } while (true);
+
             mContext.unbindService(AccountMonitor.this);
-            
+
             try {
                 mListener.onAccountsUpdated(accounts);
             } catch (SQLException e) {
@@ -76,7 +87,7 @@
             }
         }
     }
-    
+
     /**
      * Initializes the AccountMonitor and initiates a bind to the
      * AccountsService to get the initial account list.  For 1.0,
@@ -93,7 +104,7 @@
         mContext = context;
         mListener = listener;
 
-        // Register an intent receiver to monitor account changes
+        // Register a broadcast receiver to monitor account changes
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(AccountsServiceConstants.LOGIN_ACCOUNTS_CHANGED_ACTION);
         intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);  // To recover from disk-full.
@@ -116,14 +127,27 @@
     public void onServiceDisconnected(ComponentName className) {
     }
 
-    private void notifyListener() {
-        // initiate the bind
-        if (!mContext.bindService(AccountsServiceConstants.SERVICE_INTENT, this,
-                Context.BIND_AUTO_CREATE)) {
-            // This is normal if GLS isn't part of this build.
-            Log.w("AccountMonitor",
-                    "Couldn't connect to the accounts service (Missing service?)");
+    private synchronized void notifyListener() {
+        if (pending == 0) {
+            // initiate the bind
+            if (!mContext.bindService(AccountsServiceConstants.SERVICE_INTENT,
+                                      this, Context.BIND_AUTO_CREATE)) {
+                // This is normal if GLS isn't part of this build.
+                Log.w("AccountMonitor",
+                      "Couldn't connect to "  +
+                      AccountsServiceConstants.SERVICE_INTENT +
+                      " (Missing service?)");
+            }
+        } else {
+            // already bound.  bindService will not trigger another
+            // call to onServiceConnected, so instead we make sure
+            // that the existing background thread will call
+            // getAccounts() after this function returns, by
+            // incrementing pending.
+            //
+            // Yes, this else clause contains only a comment.
         }
+        ++pending;
     }
 
     /**
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index fa310a5..eafb048 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -62,6 +62,7 @@
 import com.android.internal.policy.PolicyManager;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 
 /**
  * An activity is a single, focused thing that the user can do.  Almost all
@@ -613,7 +614,8 @@
     private ComponentName mComponent;
     /*package*/ ActivityInfo mActivityInfo;
     /*package*/ ActivityThread mMainThread;
-    private Object mLastNonConfigurationInstance;
+    /*package*/ Object mLastNonConfigurationInstance;
+    /*package*/ HashMap<String,Object> mLastNonConfigurationChildInstances;
     Activity mParent;
     boolean mCalled;
     private boolean mResumed;
@@ -1379,6 +1381,38 @@
         return null;
     }
     
+    /**
+     * Retrieve the non-configuration instance data that was previously
+     * returned by {@link #onRetainNonConfigurationChildInstances()}.  This will
+     * be available from the initial {@link #onCreate} and
+     * {@link #onStart} calls to the new instance, allowing you to extract
+     * any useful dynamic state from the previous instance.
+     * 
+     * <p>Note that the data you retrieve here should <em>only</em> be used
+     * as an optimization for handling configuration changes.  You should always
+     * be able to handle getting a null pointer back, and an activity must
+     * still be able to restore itself to its previous state (through the
+     * normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this
+     * function returns null.
+     * 
+     * @return Returns the object previously returned by
+     * {@link #onRetainNonConfigurationChildInstances()}
+     */
+    HashMap<String,Object> getLastNonConfigurationChildInstances() {
+        return mLastNonConfigurationChildInstances;
+    }
+    
+    /**
+     * This method is similar to {@link #onRetainNonConfigurationInstance()} except that
+     * it should return either a mapping from  child activity id strings to arbitrary objects,
+     * or null.  This method is intended to be used by Activity framework subclasses that control a
+     * set of child activities, such as ActivityGroup.  The same guarantees and restrictions apply
+     * as for {@link #onRetainNonConfigurationInstance()}.  The default implementation returns null.
+     */
+    HashMap<String,Object> onRetainNonConfigurationChildInstances() {
+        return null;
+    }
+    
     public void onLowMemory() {
         mCalled = true;
     }
@@ -1837,13 +1871,50 @@
      * Called when the current {@link Window} of the activity gains or loses
      * focus.  This is the best indicator of whether this activity is visible
      * to the user.
+     * 
+     * <p>Note that this provides information what global focus state, which
+     * is managed independently of activity lifecycles.  As such, while focus
+     * changes will generally have some relation to lifecycle changes (an
+     * activity that is stopped will not generally get window focus), you
+     * should not rely on any particular order between the callbacks here and
+     * those in the other lifecycle methods such as {@link #onResume}.
+     * 
+     * <p>As a general rule, however, a resumed activity will have window
+     * focus...  unless it has displayed other dialogs or popups that take
+     * input focus, in which case the activity itself will not have focus
+     * when the other windows have it.  Likewise, the system may display
+     * system-level windows (such as the status bar notification panel or
+     * a system alert) which will temporarily take window input focus without
+     * pausing the foreground activity.
      *
      * @param hasFocus Whether the window of this activity has focus.
+     * 
+     * @see #hasWindowFocus()
+     * @see #onResume
      */
     public void onWindowFocusChanged(boolean hasFocus) {
     }
     
     /**
+     * Returns true if this activity's <em>main</em> window currently has window focus.
+     * Note that this is not the same as the view itself having focus.
+     * 
+     * @return True if this activity's main window currently has window focus.
+     * 
+     * @see #onWindowAttributesChanged(android.view.WindowManager.LayoutParams)
+     */
+    public boolean hasWindowFocus() {
+        Window w = getWindow();
+        if (w != null) {
+            View d = w.getDecorView();
+            if (d != null) {
+                return d.hasWindowFocus();
+            }
+        }
+        return false;
+    }
+    
+    /**
      * Called to process key events.  You can override this to intercept all 
      * key events before they are dispatched to the window.  Be sure to call 
      * this implementation for key events that should be handled normally.
@@ -2160,6 +2231,15 @@
     }
     
     /**
+     * Programmatically closes the most recently opened context menu, if showing.
+     * 
+     * @hide pending API council
+     */
+    public void closeContextMenu() {
+        mWindow.closePanel(Window.FEATURE_CONTEXT_MENU);
+    }
+    
+    /**
      * This hook is called whenever an item in a context menu is selected. The
      * default implementation simply returns false to have the normal processing
      * happen (calling the item's Runnable or sending a message to its Handler
@@ -2910,6 +2990,7 @@
      * @param flags May be {@link PendingIntent#FLAG_ONE_SHOT PendingIntent.FLAG_ONE_SHOT},
      * {@link PendingIntent#FLAG_NO_CREATE PendingIntent.FLAG_NO_CREATE},
      * {@link PendingIntent#FLAG_CANCEL_CURRENT PendingIntent.FLAG_CANCEL_CURRENT},
+     * {@link PendingIntent#FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT},
      * or any of the flags as supported by
      * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
      * of the intent that can be supplied when the actual send happens.
@@ -3285,10 +3366,21 @@
             Application application, Intent intent, ActivityInfo info, CharSequence title, 
             Activity parent, String id, Object lastNonConfigurationInstance,
             Configuration config) {
+        attach(context, aThread, instr, token, application, intent, info, title, parent, id,
+            lastNonConfigurationInstance, null, config);
+    }
+    
+    final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token,
+        Application application, Intent intent, ActivityInfo info, CharSequence title, 
+        Activity parent, String id, Object lastNonConfigurationInstance,
+        HashMap<String,Object> lastNonConfigurationChildInstances, Configuration config) {
         attachBaseContext(context);
 
         mWindow = PolicyManager.makeNewWindow(this);
         mWindow.setCallback(this);
+        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
+            mWindow.setSoftInputMode(info.softInputMode);
+        }
         mUiThread = Thread.currentThread();
 
         mMainThread = aThread;
@@ -3302,6 +3394,7 @@
         mParent = parent;
         mEmbeddedID = id;
         mLastNonConfigurationInstance = lastNonConfigurationInstance;
+        mLastNonConfigurationChildInstances = lastNonConfigurationChildInstances;
 
         mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
         if (mParent != null) {
@@ -3375,6 +3468,10 @@
         }
     }
 
+    final void performPause() {
+        onPause();
+    }
+    
     final void performStop() {
         if (!mStopped) {
             if (mWindow != null) {
diff --git a/core/java/android/app/ActivityGroup.java b/core/java/android/app/ActivityGroup.java
index 96bb475..f1216f9 100644
--- a/core/java/android/app/ActivityGroup.java
+++ b/core/java/android/app/ActivityGroup.java
@@ -16,14 +16,19 @@
 
 package android.app;
 
+import java.util.HashMap;
+
 import android.content.Intent;
 import android.os.Bundle;
+import android.util.Log;
 
 /**
  * A screen that contains and runs multiple embedded activities.
  */
 public class ActivityGroup extends Activity {
+    private static final String TAG = "ActivityGroup";
     private static final String STATES_KEY = "android:states";
+    static final String PARENT_NON_CONFIG_INSTANCE_KEY = "android:parent_non_config_instance";
 
     /**
      * This field should be made private, so it is hidden from the SDK.
@@ -80,6 +85,17 @@
         mLocalActivityManager.dispatchDestroy(isFinishing());
     }
 
+    /**
+     * Returns a HashMap mapping from child activity ids to the return values
+     * from calls to their onRetainNonConfigurationInstance methods.
+     *
+     * {@hide}
+     */
+    @Override
+    public HashMap<String,Object> onRetainNonConfigurationChildInstances() {
+        return mLocalActivityManager.dispatchRetainNonConfigurationInstance();
+    }
+
     public Activity getCurrentActivity() {
         return mLocalActivityManager.getCurrentActivity();
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 6eb1102..f9b9221 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -29,7 +29,6 @@
 import android.os.Parcelable.Creator;
 import android.text.TextUtils;
 import android.util.Log;
-
 import java.util.List;
 
 /**
@@ -601,4 +600,75 @@
             return null;
         }
     }
+
+    /**
+     * Information you can retrieve about a running process.
+     */
+    public static class RunningAppProcessInfo implements Parcelable {        
+        /**
+         * The name of the process that this object is associated with
+         */
+        public String processName;
+
+        /**
+         * The pid of this process; 0 if none
+         */
+        public int pid;
+        
+        public String pkgList[];
+        
+        public RunningAppProcessInfo() {
+        }
+        
+        public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) {
+            processName = pProcessName;
+            pid = pPid;
+            pkgList = pArr;
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(processName);
+            dest.writeInt(pid);
+            dest.writeStringArray(pkgList);
+        }
+
+        public void readFromParcel(Parcel source) {
+            processName = source.readString();
+            pid = source.readInt();
+            pkgList = source.readStringArray();
+        }
+
+        public static final Creator<RunningAppProcessInfo> CREATOR = 
+            new Creator<RunningAppProcessInfo>() {
+            public RunningAppProcessInfo createFromParcel(Parcel source) {
+                return new RunningAppProcessInfo(source);
+            }
+            public RunningAppProcessInfo[] newArray(int size) {
+                return new RunningAppProcessInfo[size];
+            }
+        };
+
+        private RunningAppProcessInfo(Parcel source) {
+            readFromParcel(source);
+        }
+    }
+    
+    /**
+     * Returns a list of application processes that are running on the device.
+     * 
+     * @return Returns a list of RunningAppProcessInfo records, or null if there are no
+     * running processes (it will not return an empty list).  This list ordering is not
+     * specified.
+     */
+    public List<RunningAppProcessInfo> getRunningAppProcesses() {
+        try {
+            return ActivityManagerNative.getDefault().getRunningAppProcesses();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index e6f1b05..ae9f3bf 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -387,6 +387,14 @@
             reply.writeTypedList(list);
             return true;
         }
+        
+        case GET_RUNNING_APP_PROCESSES_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            List<ActivityManager.RunningAppProcessInfo> list = getRunningAppProcesses();
+            reply.writeNoException();
+            reply.writeTypedList(list);
+            return true;
+        }
 
         case MOVE_TASK_TO_FRONT_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
@@ -1314,6 +1322,19 @@
         reply.recycle();
         return list;
     }
+    public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses()
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_RUNNING_APP_PROCESSES_TRANSACTION, data, reply, 0);
+        reply.readException();
+        ArrayList<ActivityManager.RunningAppProcessInfo> list
+        = reply.createTypedArrayList(ActivityManager.RunningAppProcessInfo.CREATOR);
+        data.recycle();
+        reply.recycle();
+        return list;
+    }
     public void moveTaskToFront(int task) throws RemoteException
     {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d03a76f..3d448a6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -220,7 +220,8 @@
             mApplicationInfo = aInfo;
             mPackageName = aInfo.packageName;
             mAppDir = aInfo.sourceDir;
-            mResDir = aInfo.publicSourceDir;
+            mResDir = aInfo.uid == Process.myUid() ? aInfo.sourceDir
+                    : aInfo.publicSourceDir;
             mSharedLibraries = aInfo.sharedLibraryFiles;
             mDataDir = aInfo.dataDir;
             mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
@@ -1057,6 +1058,7 @@
         Activity parent;
         String embeddedID;
         Object lastNonConfigurationInstance;
+        HashMap<String,Object> lastNonConfigurationChildInstances;
         boolean paused;
         boolean stopped;
         boolean hideForNow;
@@ -1966,6 +1968,12 @@
     
     public final Activity startActivityNow(Activity parent, String id,
             Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state) {
+        return startActivityNow(parent, id, intent, activityInfo, token, state, null);
+    }
+
+    public final Activity startActivityNow(Activity parent, String id,
+        Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
+        Object lastNonConfigurationInstance) {
         ActivityRecord r = new ActivityRecord();
             r.token = token;
             r.intent = intent;
@@ -1973,6 +1981,7 @@
             r.parent = parent;
             r.embeddedID = id;
             r.activityInfo = activityInfo;
+            r.lastNonConfigurationInstance = lastNonConfigurationInstance;
         if (localLOGV) {
             ComponentName compname = intent.getComponent();
             String name;
@@ -2090,9 +2099,11 @@
                 Configuration config = new Configuration(mConfiguration);
                 activity.attach(appContext, this, getInstrumentation(), r.token, app, 
                         r.intent, r.activityInfo, title, r.parent, r.embeddedID,
-                        r.lastNonConfigurationInstance, config);
+                        r.lastNonConfigurationInstance, r.lastNonConfigurationChildInstances,
+                        config);
                 
                 r.lastNonConfigurationInstance = null;
+                r.lastNonConfigurationChildInstances = null;
                 activity.mStartedActivity = false;
                 int theme = r.activityInfo.getThemeResource();
                 if (theme != 0) {
@@ -2948,6 +2959,17 @@
                                 + ": " + e.toString(), e);
                     }
                 }
+                try {
+                    r.lastNonConfigurationChildInstances
+                            = r.activity.onRetainNonConfigurationChildInstances();
+                } catch (Exception e) {
+                    if (!mInstrumentation.onException(r.activity, e)) {
+                        throw new RuntimeException(
+                                "Unable to retain child activities "
+                                + r.intent.getComponent().toShortString()
+                                + ": " + e.toString(), e);
+                    }
+                }
                 
             }
             try {
@@ -3225,11 +3247,7 @@
                 Locale.setDefault(config.locale);
             }
 
-            if (mSystemContext != null) {
-                mSystemContext.getResources().updateConfiguration(config, null);
-                //Log.i(TAG, "Updated system resources " + mSystemContext.getResources()
-                //        + ": " + mSystemContext.getResources().getConfiguration());
-            }
+            Resources.updateSystemConfiguration(config, null);
 
             ApplicationContext.ApplicationPackageManager.configurationChanged();
             //Log.i(TAG, "Configuration changed in " + currentPackageName());
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 35c6ac1..b4c0e31 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -71,17 +71,13 @@
      */
     public static final int ELAPSED_REALTIME = 3;
 
-    private static IAlarmManager mService;
+    private final IAlarmManager mService;
 
-    static {
-        mService = IAlarmManager.Stub.asInterface(
-                    ServiceManager.getService(Context.ALARM_SERVICE));
-    }
-    
     /**
      * package private on purpose
      */
-    AlarmManager() {
+    AlarmManager(IAlarmManager service) {
+        mService = service;
     }
     
     /**
@@ -97,7 +93,7 @@
      * this one.
      *
      * <p>
-     * The alarm is an intent broadcast that goes to an intent receiver that
+     * The alarm is an intent broadcast that goes to a broadcast receiver that
      * you registered with {@link android.content.Context#registerReceiver}
      * or through the &lt;receiver&gt; tag in an AndroidManifest.xml file.
      *
@@ -189,6 +185,72 @@
     }
 
     /**
+     * Available inexact recurrence intervals recognized by
+     * {@link #setInexactRepeating(int, long, long, PendingIntent)} 
+     */
+    public static final long INTERVAL_FIFTEEN_MINUTES = 15 * 60 * 1000;
+    public static final long INTERVAL_HALF_HOUR = 2*INTERVAL_FIFTEEN_MINUTES;
+    public static final long INTERVAL_HOUR = 2*INTERVAL_HALF_HOUR;
+    public static final long INTERVAL_HALF_DAY = 12*INTERVAL_HOUR;
+    public static final long INTERVAL_DAY = 2*INTERVAL_HALF_DAY;
+    
+    /**
+     * Schedule a repeating alarm that has inexact trigger time requirements;
+     * for example, an alarm that repeats every hour, but not necessarily at
+     * the top of every hour.  These alarms are more power-efficient than
+     * the strict recurrences supplied by {@link #setRepeating}, since the
+     * system can adjust alarms' phase to cause them to fire simultaneously,
+     * avoiding waking the device from sleep more than necessary.
+     * 
+     * <p>Your alarm's first trigger will not be before the requested time,
+     * but it might not occur for almost a full interval after that time.  In
+     * addition, while the overall period of the repeating alarm will be as
+     * requested, the time between any two successive firings of the alarm
+     * may vary.  If your application demands very low jitter, use
+     * {@link #setRepeating} instead.
+     * 
+     * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP}, RTC or
+     *             RTC_WAKEUP.
+     * @param triggerAtTime Time the alarm should first go off, using the
+     *                      appropriate clock (depending on the alarm type).  This
+     *                      is inexact: the alarm will not fire before this time,
+     *                      but there may be a delay of almost an entire alarm
+     *                      interval before the first invocation of the alarm.
+     * @param interval Interval between subsequent repeats of the alarm.  If
+     *                 this is one of INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR,
+     *                 INTERVAL_HOUR, INTERVAL_HALF_DAY, or INTERVAL_DAY then the
+     *                 alarm will be phase-aligned with other alarms to reduce
+     *                 the number of wakeups.  Otherwise, the alarm will be set
+     *                 as though the application had called {@link #setRepeating}.
+     * @param operation Action to perform when the alarm goes off;
+     * typically comes from {@link PendingIntent#getBroadcast
+     * IntentSender.getBroadcast()}.
+     *
+     * @see android.os.Handler
+     * @see #set
+     * @see #cancel
+     * @see android.content.Context#sendBroadcast
+     * @see android.content.Context#registerReceiver
+     * @see android.content.Intent#filterEquals
+     * @see #ELAPSED_REALTIME
+     * @see #ELAPSED_REALTIME_WAKEUP
+     * @see #RTC
+     * @see #RTC_WAKEUP
+     * @see #INTERVAL_FIFTEEN_MINUTES
+     * @see #INTERVAL_HALF_HOUR
+     * @see #INTERVAL_HOUR
+     * @see #INTERVAL_HALF_DAY
+     * @see #INTERVAL_DAY
+     */
+    public void setInexactRepeating(int type, long triggerAtTime, long interval,
+            PendingIntent operation) {
+        try {
+            mService.setInexactRepeating(type, triggerAtTime, interval, operation);
+        } catch (RemoteException ex) {
+        }
+    }
+    
+    /**
      * Remove any alarms with a matching {@link Intent}.
      * Any alarm, of any type, whose Intent matches this one (as defined by
      * {@link Intent#filterEquals}), will be canceled.
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index cc80ba4..a6981a5 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -25,6 +25,7 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.AdapterView;
+import android.widget.Button;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 
@@ -59,6 +60,29 @@
         setOnCancelListener(cancelListener);
         mAlert = new AlertController(context, this, getWindow());
     }
+
+    /**
+     * Gets one of the buttons used in the dialog.
+     * <p>
+     * If a button does not exist in the dialog, null will be returned.
+     * 
+     * @param whichButton The identifier of the button that should be returned.
+     *            For example, this can be
+     *            {@link DialogInterface#BUTTON_POSITIVE}.
+     * @return The button from the dialog, or null if a button does not exist.
+     */
+    public Button getButton(int whichButton) {
+        return mAlert.getButton(whichButton);
+    }
+    
+    /**
+     * Gets the list view used in the dialog.
+     *  
+     * @return The {@link ListView} from the dialog.
+     */
+    public ListView getListView() {
+        return mAlert.getListView();
+    }
     
     @Override
     public void setTitle(CharSequence title) {
@@ -83,44 +107,115 @@
     public void setView(View view) {
         mAlert.setView(view);
     }
+    
+    /**
+     * Set the view to display in that dialog, specifying the spacing to appear around that 
+     * view.
+     *
+     * @param view The view to show in the content area of the dialog
+     * @param viewSpacingLeft Extra space to appear to the left of {@code view}
+     * @param viewSpacingTop Extra space to appear above {@code view}
+     * @param viewSpacingRight Extra space to appear to the right of {@code view}
+     * @param viewSpacingBottom Extra space to appear below {@code view}
+     */
+    public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight,
+            int viewSpacingBottom) {
+        mAlert.setView(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight, viewSpacingBottom);
+    }
 
+    /**
+     * Set a message to be sent when a button is pressed.
+     * 
+     * @param whichButton Which button to set the message for, can be one of
+     *            {@link DialogInterface#BUTTON_POSITIVE},
+     *            {@link DialogInterface#BUTTON_NEGATIVE}, or
+     *            {@link DialogInterface#BUTTON_NEUTRAL}
+     * @param text The text to display in positive button.
+     * @param msg The {@link Message} to be sent when clicked.
+     */
+    public void setButton(int whichButton, CharSequence text, Message msg) {
+        mAlert.setButton(whichButton, text, null, msg);
+    }
+    
+    /**
+     * Set a listener to be invoked when the positive button of the dialog is pressed.
+     * 
+     * @param whichButton Which button to set the listener on, can be one of
+     *            {@link DialogInterface#BUTTON_POSITIVE},
+     *            {@link DialogInterface#BUTTON_NEGATIVE}, or
+     *            {@link DialogInterface#BUTTON_NEUTRAL}
+     * @param text The text to display in positive button.
+     * @param listener The {@link DialogInterface.OnClickListener} to use.
+     */
+    public void setButton(int whichButton, CharSequence text, OnClickListener listener) {
+        mAlert.setButton(whichButton, text, listener, null);
+    }
+
+    /**
+     * @deprecated Use {@link #setButton(int, CharSequence, Message)} with
+     *             {@link DialogInterface#BUTTON_POSITIVE}.
+     */
+    @Deprecated
     public void setButton(CharSequence text, Message msg) {
-        mAlert.setButton(text, msg);
+        setButton(BUTTON_POSITIVE, text, msg);
     }
-
+        
+    /**
+     * @deprecated Use {@link #setButton(int, CharSequence, Message)} with
+     *             {@link DialogInterface#BUTTON_NEGATIVE}.
+     */
+    @Deprecated
     public void setButton2(CharSequence text, Message msg) {
-        mAlert.setButton2(text, msg);
+        setButton(BUTTON_NEGATIVE, text, msg);
     }
 
+    /**
+     * @deprecated Use {@link #setButton(int, CharSequence, Message)} with
+     *             {@link DialogInterface#BUTTON_NEUTRAL}.
+     */
+    @Deprecated
     public void setButton3(CharSequence text, Message msg) {
-        mAlert.setButton3(text, msg);
+        setButton(BUTTON_NEUTRAL, text, msg);
     }
 
     /**
      * Set a listener to be invoked when button 1 of the dialog is pressed.
+     * 
      * @param text The text to display in button 1.
      * @param listener The {@link DialogInterface.OnClickListener} to use.
+     * @deprecated Use
+     *             {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)}
+     *             with {@link DialogInterface#BUTTON_POSITIVE}
      */
+    @Deprecated
     public void setButton(CharSequence text, final OnClickListener listener) {
-        mAlert.setButton(text, listener);
+        setButton(BUTTON_POSITIVE, text, listener);
     }
 
     /**
      * Set a listener to be invoked when button 2 of the dialog is pressed.
      * @param text The text to display in button 2.
      * @param listener The {@link DialogInterface.OnClickListener} to use.
+     * @deprecated Use
+     *             {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)}
+     *             with {@link DialogInterface#BUTTON_NEGATIVE}
      */
+    @Deprecated
     public void setButton2(CharSequence text, final OnClickListener listener) {
-        mAlert.setButton2(text, listener);
+        setButton(BUTTON_NEGATIVE, text, listener);
     }
 
     /**
      * Set a listener to be invoked when button 3 of the dialog is pressed.
      * @param text The text to display in button 3.
      * @param listener The {@link DialogInterface.OnClickListener} to use.
+     * @deprecated Use
+     *             {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)}
+     *             with {@link DialogInterface#BUTTON_POSITIVE}
      */
+    @Deprecated
     public void setButton3(CharSequence text, final OnClickListener listener) {
-        mAlert.setButton3(text, listener);
+        setButton(BUTTON_NEUTRAL, text, listener);
     }
 
     /**
@@ -170,6 +265,8 @@
         
         /**
          * Set the title using the given resource id.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setTitle(int titleId) {
             P.mTitle = P.mContext.getText(titleId);
@@ -178,6 +275,8 @@
         
         /**
          * Set the title displayed in the {@link Dialog}.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setTitle(CharSequence title) {
             P.mTitle = title;
@@ -192,6 +291,8 @@
          * via the other methods.
          * 
          * @param customTitleView The custom view to use as the title.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setCustomTitle(View customTitleView) {
             P.mCustomTitleView = customTitleView;
@@ -200,6 +301,8 @@
         
         /**
          * Set the message to display using the given resource id.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setMessage(int messageId) {
             P.mMessage = P.mContext.getText(messageId);
@@ -208,6 +311,8 @@
         
         /**
          * Set the message to display.
+          *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setMessage(CharSequence message) {
             P.mMessage = message;
@@ -216,6 +321,8 @@
         
         /**
          * Set the resource id of the {@link Drawable} to be used in the title.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setIcon(int iconId) {
             P.mIconId = iconId;
@@ -224,6 +331,8 @@
         
         /**
          * Set the {@link Drawable} to be used in the title.
+          *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setIcon(Drawable icon) {
             P.mIcon = icon;
@@ -234,6 +343,8 @@
          * Set a listener to be invoked when the positive button of the dialog is pressed.
          * @param textId The resource id of the text to display in the positive button
          * @param listener The {@link DialogInterface.OnClickListener} to use.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setPositiveButton(int textId, final OnClickListener listener) {
             P.mPositiveButtonText = P.mContext.getText(textId);
@@ -245,6 +356,8 @@
          * Set a listener to be invoked when the positive button of the dialog is pressed.
          * @param text The text to display in the positive button
          * @param listener The {@link DialogInterface.OnClickListener} to use.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
             P.mPositiveButtonText = text;
@@ -256,6 +369,8 @@
          * Set a listener to be invoked when the negative button of the dialog is pressed.
          * @param textId The resource id of the text to display in the negative button
          * @param listener The {@link DialogInterface.OnClickListener} to use.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setNegativeButton(int textId, final OnClickListener listener) {
             P.mNegativeButtonText = P.mContext.getText(textId);
@@ -267,6 +382,8 @@
          * Set a listener to be invoked when the negative button of the dialog is pressed.
          * @param text The text to display in the negative button
          * @param listener The {@link DialogInterface.OnClickListener} to use.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setNegativeButton(CharSequence text, final OnClickListener listener) {
             P.mNegativeButtonText = text;
@@ -278,6 +395,8 @@
          * Set a listener to be invoked when the neutral button of the dialog is pressed.
          * @param textId The resource id of the text to display in the neutral button
          * @param listener The {@link DialogInterface.OnClickListener} to use.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setNeutralButton(int textId, final OnClickListener listener) {
             P.mNeutralButtonText = P.mContext.getText(textId);
@@ -289,6 +408,8 @@
          * Set a listener to be invoked when the neutral button of the dialog is pressed.
          * @param text The text to display in the neutral button
          * @param listener The {@link DialogInterface.OnClickListener} to use.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setNeutralButton(CharSequence text, final OnClickListener listener) {
             P.mNeutralButtonText = text;
@@ -298,6 +419,8 @@
         
         /**
          * Sets whether the dialog is cancelable or not default is true.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setCancelable(boolean cancelable) {
             P.mCancelable = cancelable;
@@ -307,6 +430,8 @@
         /**
          * Sets the callback that will be called if the dialog is canceled.
          * @see #setCancelable(boolean)
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setOnCancelListener(OnCancelListener onCancelListener) {
             P.mOnCancelListener = onCancelListener;
@@ -315,6 +440,8 @@
         
         /**
          * Sets the callback that will be called if a key is dispatched to the dialog.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setOnKeyListener(OnKeyListener onKeyListener) {
             P.mOnKeyListener = onKeyListener;
@@ -324,6 +451,8 @@
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of the
          * selected item via the supplied listener. This should be an array type i.e. R.array.foo
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setItems(int itemsId, final OnClickListener listener) {
             P.mItems = P.mContext.getResources().getTextArray(itemsId);
@@ -334,6 +463,8 @@
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of the
          * selected item via the supplied listener.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setItems(CharSequence[] items, final OnClickListener listener) {
             P.mItems = items;
@@ -348,6 +479,8 @@
          * 
          * @param adapter The {@link ListAdapter} to supply the list of items
          * @param listener The listener that will be called when an item is clicked.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setAdapter(final ListAdapter adapter, final OnClickListener listener) {
             P.mAdapter = adapter;
@@ -364,6 +497,8 @@
          * @param listener The listener that will be called when an item is clicked.
          * @param labelColumn The column name on the cursor containing the string to display
          *          in the label.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setCursor(final Cursor cursor, final OnClickListener listener,
                 String labelColumn) {
@@ -388,6 +523,8 @@
          * @param listener notified when an item on the list is clicked. The dialog will not be
          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setMultiChoiceItems(int itemsId, boolean[] checkedItems, 
                 final OnMultiChoiceClickListener listener) {
@@ -412,6 +549,8 @@
          * @param listener notified when an item on the list is clicked. The dialog will not be
          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, 
                 final OnMultiChoiceClickListener listener) {
@@ -438,6 +577,8 @@
          * @param listener notified when an item on the list is clicked. The dialog will not be
          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, 
                 final OnMultiChoiceClickListener listener) {
@@ -461,6 +602,8 @@
          * @param listener notified when an item on the list is clicked. The dialog will not be
          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setSingleChoiceItems(int itemsId, int checkedItem, 
                 final OnClickListener listener) {
@@ -484,6 +627,8 @@
          * @param listener notified when an item on the list is clicked. The dialog will not be
          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn, 
                 final OnClickListener listener) {
@@ -506,6 +651,8 @@
          * @param listener notified when an item on the list is clicked. The dialog will not be
          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener) {
             P.mItems = items;
@@ -526,6 +673,8 @@
          * @param listener notified when an item on the list is clicked. The dialog will not be
          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setSingleChoiceItems(ListAdapter adapter, int checkedItem, final OnClickListener listener) {
             P.mAdapter = adapter;
@@ -540,6 +689,8 @@
          * 
          * @param listener The listener to be invoked.
          * @see AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
+         *
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setOnItemSelectedListener(final AdapterView.OnItemSelectedListener listener) {
             P.mOnItemSelectedListener = listener;
@@ -549,9 +700,44 @@
         /**
          * Set a custom view to be the contents of the Dialog. If the supplied view is an instance
          * of a {@link ListView} the light background will be used.
+         *
+         * @param view The view to use as the contents of the Dialog.
+         * 
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setView(View view) {
             P.mView = view;
+            P.mViewSpacingSpecified = false;
+            return this;
+        }
+        
+        /**
+         * Set a custom view to be the contents of the Dialog, specifying the
+         * spacing to appear around that view. If the supplied view is an
+         * instance of a {@link ListView} the light background will be used.
+         * 
+         * @param view The view to use as the contents of the Dialog.
+         * @param viewSpacingLeft Spacing between the left edge of the view and
+         *        the dialog frame
+         * @param viewSpacingTop Spacing between the top edge of the view and
+         *        the dialog frame
+         * @param viewSpacingRight Spacing between the right edge of the view
+         *        and the dialog frame
+         * @param viewSpacingBottom Spacing between the bottom edge of the view
+         *        and the dialog frame
+         * @return This Builder object to allow for chaining of calls to set
+         *         methods
+         *         
+         * @hide pending API review
+         */
+        public Builder setView(View view, int viewSpacingLeft, int viewSpacingTop,
+                int viewSpacingRight, int viewSpacingBottom) {
+            P.mView = view;
+            P.mViewSpacingSpecified = true;
+            P.mViewSpacingLeft = viewSpacingLeft;
+            P.mViewSpacingTop = viewSpacingTop;
+            P.mViewSpacingRight = viewSpacingRight;
+            P.mViewSpacingBottom = viewSpacingBottom;
             return this;
         }
         
@@ -560,7 +746,8 @@
          * contents is.
          * 
          * @param useInverseBackground Whether to use the inverse background
-         * @return This Builder object to allow for chaining of sets.
+         * 
+         * @return This Builder object to allow for chaining of calls to set methods
          */
         public Builder setInverseBackgroundForced(boolean useInverseBackground) {
             P.mForceInverseBackground = useInverseBackground;
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 342ffcf..0e41ae6 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -87,6 +87,7 @@
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.WindowManagerImpl;
+import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.policy.PolicyManager;
 
@@ -104,6 +105,8 @@
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 class ReceiverRestrictedContext extends ContextWrapper {
     ReceiverRestrictedContext(Context base) {
         super(base);
@@ -139,12 +142,12 @@
  * Common implementation of Context API, which Activity and other application
  * classes inherit.
  */
-@SuppressWarnings({"EmptyCatchBlock"})
 class ApplicationContext extends Context {
     private final static String TAG = "ApplicationContext";
     private final static boolean DEBUG_ICONS = false;
 
     private static final Object sSync = new Object();
+    private static AlarmManager sAlarmManager;
     private static PowerManager sPowerManager;
     private static ConnectivityManager sConnectivityManager;
     private static WifiManager sWifiManager;
@@ -288,12 +291,15 @@
         }
         throw new RuntimeException("Not supported in system context");
     }
+    
+    private static File makeBackupFile(File prefsFile) {
+        return new File(prefsFile.getPath() + ".bak");
+    }
 
     @Override
     public SharedPreferences getSharedPreferences(String name, int mode) {
-        File f;
-        f = makeFilename(getPreferencesDir(), name + ".xml");
         SharedPreferencesImpl sp;
+        File f = makeFilename(getPreferencesDir(), name + ".xml");
         synchronized (sSharedPrefs) {
             sp = sSharedPrefs.get(f);
             if (sp != null && !sp.hasFileChanged()) {
@@ -301,15 +307,27 @@
                 return sp;
             }
         }
+        
+        FileInputStream str = null;
+        File backup = makeBackupFile(f);
+        if (backup.exists()) {
+            f.delete();
+            backup.renameTo(f);
+        }
 
         Map map = null;
-        try {
-            FileInputStream str = new FileInputStream(f);
-            map = XmlUtils.readMapXml(str);
-            str.close();
-        } catch (org.xmlpull.v1.XmlPullParserException e) {
-        } catch (java.io.FileNotFoundException e) {
-        } catch (java.io.IOException e) {
+        if (f.exists()) {
+            try {
+                str = new FileInputStream(f);
+                map = XmlUtils.readMapXml(str);
+                str.close();
+            } catch (org.xmlpull.v1.XmlPullParserException e) {
+                Log.w(TAG, "getSharedPreferences", e);
+            } catch (FileNotFoundException e) {
+                Log.w(TAG, "getSharedPreferences", e);
+            } catch (IOException e) {
+                Log.w(TAG, "getSharedPreferences", e);
+            }
         }
 
         synchronized (sSharedPrefs) {
@@ -350,7 +368,7 @@
         File f = makeFilename(getFilesDir(), name);
         try {
             FileOutputStream fos = new FileOutputStream(f, append);
-            setFilePermissionsFromMode(f.toString(), mode, 0);
+            setFilePermissionsFromMode(f.getPath(), mode, 0);
             return fos;
         } catch (FileNotFoundException e) {
         }
@@ -358,11 +376,11 @@
         File parent = f.getParentFile();
         parent.mkdir();
         FileUtils.setPermissions(
-            parent.toString(),
+            parent.getPath(),
             FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
             -1, -1);
         FileOutputStream fos = new FileOutputStream(f, append);
-        setFilePermissionsFromMode(f.toString(), mode, 0);
+        setFilePermissionsFromMode(f.getPath(), mode, 0);
         return fos;
     }
 
@@ -378,6 +396,16 @@
             if (mFilesDir == null) {
                 mFilesDir = new File(getDataDirFile(), "files");
             }
+            if (!mFilesDir.exists()) {
+                if(!mFilesDir.mkdirs()) {
+                    Log.w(TAG, "Unable to create files directory");
+                    return null;
+                }
+                FileUtils.setPermissions(
+                        mFilesDir.getPath(),
+                        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+                        -1, -1);
+            }
             return mFilesDir;
         }
     }
@@ -394,7 +422,7 @@
                     return null;
                 }
                 FileUtils.setPermissions(
-                        mCacheDir.toString(),
+                        mCacheDir.getPath(),
                         FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
                         -1, -1);
             }
@@ -418,14 +446,14 @@
     public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
         File dir = getDatabasesDir();
         if (!dir.isDirectory() && dir.mkdir()) {
-            FileUtils.setPermissions(dir.toString(),
+            FileUtils.setPermissions(dir.getPath(),
                 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
                 -1, -1);
         }
 
         File f = makeFilename(dir, name);
         SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory);
-        setFilePermissionsFromMode(f.toString(), mode, 0);
+        setFilePermissionsFromMode(f.getPath(), mode, 0);
         return db;
     }
 
@@ -844,7 +872,7 @@
         } else if (ACTIVITY_SERVICE.equals(name)) {
             return getActivityManager();
         } else if (ALARM_SERVICE.equals(name)) {
-            return new AlarmManager();
+            return getAlarmManager();
         } else if (POWER_SERVICE.equals(name)) {
             return getPowerManager();
         } else if (CONNECTIVITY_SERVICE.equals(name)) {
@@ -878,6 +906,8 @@
             return getTelephonyManager();
         } else if (CLIPBOARD_SERVICE.equals(name)) {
             return getClipboardManager();
+        } else if (INPUT_METHOD_SERVICE.equals(name)) {
+            return InputMethodManager.getInstance(this);
         }
 
         return null;
@@ -893,6 +923,17 @@
         return mActivityManager;
     }
 
+    private AlarmManager getAlarmManager() {
+        synchronized (sSync) {
+            if (sAlarmManager == null) {
+                IBinder b = ServiceManager.getService(ALARM_SERVICE);
+                IAlarmManager service = IAlarmManager.Stub.asInterface(b);
+                sAlarmManager = new AlarmManager(service);
+            }
+        }
+        return sAlarmManager;
+    }
+
     private PowerManager getPowerManager() {
         synchronized (sSync) {
             if (sPowerManager == null) {
@@ -1299,7 +1340,7 @@
         File file = makeFilename(getDataDirFile(), name);
         if (!file.exists()) {
             file.mkdir();
-            setFilePermissionsFromMode(file.toString(), mode,
+            setFilePermissionsFromMode(file.getPath(), mode,
                     FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH);
         }
         return file;
@@ -1636,6 +1677,20 @@
                 throw new RuntimeException("Package manager has died", e);
             }
         }
+        
+        @Override
+        public int getUidForSharedUser(String sharedUserName) 
+                throws NameNotFoundException {
+            try {
+                int uid = mPM.getUidForSharedUser(sharedUserName);
+                if(uid != -1) {
+                    return uid;
+                }
+            } catch (RemoteException e) {
+                throw new RuntimeException("Package manager has died", e);
+            }
+            throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
+        }
 
         @Override
         public List<PackageInfo> getInstalledPackages(int flags) {
@@ -1899,7 +1954,9 @@
             if (app.packageName.equals("system")) {
                 return mContext.mMainThread.getSystemContext().getResources();
             }
-            Resources r = mContext.mMainThread.getTopLevelResources(app.publicSourceDir);
+            Resources r = mContext.mMainThread.getTopLevelResources(
+                    app.uid == Process.myUid() ? app.sourceDir
+                    : app.publicSourceDir);
             if (r != null) {
                 return r;
             }
@@ -2341,6 +2398,7 @@
     private static final class SharedPreferencesImpl implements SharedPreferences {
 
         private final File mFile;
+        private final File mBackupFile;
         private final int mMode;
         private Map mMap;
         private final FileStatus mFileStatus = new FileStatus();
@@ -2351,6 +2409,7 @@
         SharedPreferencesImpl(
             File file, int mode, Map initialContents) {
             mFile = file;
+            mBackupFile = makeBackupFile(file);
             mMode = mode;
             mMap = initialContents != null ? initialContents : new HashMap();
             if (FileUtils.getFileStatus(file.getPath(), mFileStatus)) {
@@ -2544,30 +2603,68 @@
         public Editor edit() {
             return new EditorImpl();
         }
+        
+        private FileOutputStream createFileOutputStream(File file) {
+            FileOutputStream str = null;
+            try {
+                str = new FileOutputStream(file);
+            } catch (FileNotFoundException e) {
+                File parent = file.getParentFile();
+                if (!parent.mkdir()) {
+                    Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file);
+                    return null;
+                }
+                FileUtils.setPermissions(
+                    parent.getPath(),
+                    FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+                    -1, -1);
+                try {
+                    str = new FileOutputStream(file);
+                } catch (FileNotFoundException e2) {
+                    Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2);
+                }
+            }
+            return str;
+        }
 
         private boolean writeFileLocked() {
+            // Rename the current file so it may be used as a backup during the next read
+            if (mFile.exists()) {
+                if (!mFile.renameTo(mBackupFile)) {
+                    Log.e(TAG, "Couldn't rename file " + mFile + " to backup file " + mBackupFile);
+                }
+            }
+            
+            // Attempt to write the file, delete the backup and return true as atomically as
+            // possible.  If any exception occurs, delete the new file; next time we will restore
+            // from the backup.
             try {
-                FileOutputStream str;
-                try {
-                    str = new FileOutputStream(mFile);
-                } catch (Exception e) {
-                    File parent = mFile.getParentFile();
-                    parent.mkdir();
-                    FileUtils.setPermissions(
-                        parent.toString(),
-                        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-                        -1, -1);
-                    str = new FileOutputStream(mFile);
+                FileOutputStream str = createFileOutputStream(mFile);
+                if (str == null) {
+                    return false;
                 }
                 XmlUtils.writeMapXml(mMap, str);
                 str.close();
-                setFilePermissionsFromMode(mFile.toString(), mMode, 0);
+                setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
                 if (FileUtils.getFileStatus(mFile.getPath(), mFileStatus)) {
                     mTimestamp = mFileStatus.mtime;
                 }
-            } catch (org.xmlpull.v1.XmlPullParserException e) {
-            } catch (java.io.FileNotFoundException e) {
-            } catch (java.io.IOException e) {
+                
+                // Writing was successful, delete the backup file
+                if (!mBackupFile.delete()) {
+                    Log.e(TAG, "Couldn't delete new backup file " + mBackupFile);
+                }
+                return true;
+            } catch (XmlPullParserException e) {
+                Log.w(TAG, "writeFileLocked: Got exception:", e);
+            } catch (IOException e) {
+                Log.w(TAG, "writeFileLocked: Got exception:", e);
+            }
+            // Clean up an unsuccessfully written file
+            if (mFile.exists()) {
+                if (!mFile.delete()) {
+                    Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
+                }
             }
             return false;
         }
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 7450559..ee5e0d5 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -20,8 +20,8 @@
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
 import android.os.Bundle;
-import android.pim.DateFormat;
 import android.text.TextUtils.TruncateAt;
+import android.text.format.DateFormat;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.DatePicker;
@@ -107,7 +107,7 @@
         DateFormatSymbols symbols = new DateFormatSymbols();
         mWeekDays = symbols.getShortWeekdays();
         
-        mDateFormat = DateFormat.getLongDateFormat(context);
+        mDateFormat = DateFormat.getMediumDateFormat(context);
         mCalendar = Calendar.getInstance();
         updateTitle(mInitialYear, mInitialMonth, mInitialDay);
         
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2de21ed..353500e9 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -213,6 +213,9 @@
      * SIGUSR1 is delivered. All others are ignored.
      */
     public void signalPersistentProcesses(int signal) throws RemoteException;
+    // Retrieve running application processes in the system
+    public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses()
+            throws RemoteException;
     
     /** Information you can retrieve about a particular application. */
     public static class ContentProviderHolder implements Parcelable {
@@ -350,4 +353,5 @@
     int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
     int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
     int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
+    int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82;
 }
diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl
index c7f20b9b..cb42236 100755
--- a/core/java/android/app/IAlarmManager.aidl
+++ b/core/java/android/app/IAlarmManager.aidl
@@ -26,6 +26,7 @@
 interface IAlarmManager {
     void set(int type, long triggerAtTime, in PendingIntent operation);
     void setRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation);
+    void setInexactRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation);
     void setTimeZone(String zone);
     void remove(in PendingIntent operation);
 }
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index f80c947..17618ff 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -40,6 +40,7 @@
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 import android.view.Window;
+import android.view.inputmethod.InputMethodManager;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -1262,7 +1263,7 @@
      * @param activity The activity being paused.
      */
     public void callActivityOnPause(Activity activity) {
-        activity.onPause();
+        activity.performPause();
     }
     
     /*
@@ -1392,8 +1393,8 @@
      * if there was no Activity found to run the given Intent.
      * 
      * @param who The Context from which the activity is being started.
-     * @param whoThread The main thread of the Context from which the activity
-     *                  is being started.
+     * @param contextThread The main thread of the Context from which the activity
+     *                      is being started.
      * @param token Internal token identifying to the system who is starting 
      *              the activity; may be null.
      * @param target Which activity is perform the start (and thus receiving 
@@ -1416,8 +1417,9 @@
      * {@hide}
      */
     public ActivityResult execStartActivity(
-        Context who, IApplicationThread whoThread, IBinder token, Activity target,
+        Context who, IBinder contextThread, IBinder token, Activity target,
         Intent intent, int requestCode) {
+        IApplicationThread whoThread = (IApplicationThread) contextThread;
         if (mActivityMonitors != null) {
             synchronized (mSync) {
                 final int N = mActivityMonitors.size();
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 12e70e3..a24fcae 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -22,9 +22,6 @@
 import android.os.Bundle;
 import android.util.Config;
 import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.view.Window;
 
 import java.util.ArrayList;
@@ -114,13 +111,21 @@
         }
         
         if (r.curState == INITIALIZING) {
+            // Get the lastNonConfigurationInstance for the activity
+            HashMap<String,Object> lastNonConfigurationInstances =
+                mParent.getLastNonConfigurationChildInstances();
+            Object instance = null;
+            if (lastNonConfigurationInstances != null) {
+                instance = lastNonConfigurationInstances.get(r.id);
+            }
+            
             // We need to have always created the activity.
             if (localLOGV) Log.v(TAG, r.id + ": starting " + r.intent);
             if (r.activityInfo == null) {
                 r.activityInfo = mActivityThread.resolveActivityInfo(r.intent);
             }
             r.activity = mActivityThread.startActivityNow(
-                    mParent, r.id, r.intent, r.activityInfo, r, r.instanceState);
+                    mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance);
             if (r.activity == null) {
                 return;
             }
@@ -288,7 +293,6 @@
             // It's a brand new world.
             mActivities.put(id, r);
             mActivityArray.add(r);
-            
         } else if (r.activityInfo != null) {
             // If the new activity is the same as the current one, then
             // we may be able to reuse it.
@@ -568,6 +572,32 @@
             moveToState(r, CREATED);
         }
     }
+    
+    /**
+     * Call onRetainNonConfigurationInstance on each child activity and store the
+     * results in a HashMap by id.  Only construct the HashMap if there is a non-null
+     * object to store.  Note that this does not support nested ActivityGroups.
+     * 
+     * {@hide}
+     */
+    public HashMap<String,Object> dispatchRetainNonConfigurationInstance() {
+        HashMap<String,Object> instanceMap = null;
+        
+        final int N = mActivityArray.size();
+        for (int i=0; i<N; i++) {
+            LocalActivityRecord r = mActivityArray.get(i);
+            if ((r != null) && (r.activity != null)) {
+                Object instance = r.activity.onRetainNonConfigurationInstance();
+                if (instance != null) {
+                    if (instanceMap == null) {
+                        instanceMap = new HashMap<String,Object>();
+                    }
+                    instanceMap.put(r.id, instance);
+                }
+            }
+        }
+        return instanceMap;
+    }
 
     /**
      * Remove all activities from this LocalActivityManager, performing an
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index cc56385..ea67cdb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -25,9 +25,9 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.pim.DateFormat;
-import android.pim.DateUtils;
 import android.text.TextUtils;
+import android.text.format.DateFormat;
+import android.text.format.DateUtils;
 import android.widget.RemoteViews;
 
 /**
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index ba84903..b59e9dc 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -73,9 +73,22 @@
      * {@link #getService}: if the described PendingIntent already exists,
      * the current one is canceled before generating a new one.  You can use
      * this to retrieve a new PendingIntent when you are only changing the
-     * extra data in the Intent.
+     * extra data in the Intent; by canceling the previous pending intent,
+     * this ensures that only entities given the new data will be able to
+     * launch it.  If this assurance is not an issue, consider
+     * {@link #FLAG_UPDATE_CURRENT}.
      */
     public static final int FLAG_CANCEL_CURRENT = 1<<28;
+    /**
+     * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and
+     * {@link #getService}: if the described PendingIntent already exists,
+     * then keep it but its replace its extra data with what is in this new
+     * Intent.  This can be used if you are creating intents where only the
+     * extras change, and don't care that any entities that received your
+     * previous PendingIntent will be able to launch it with your new
+     * extras even if they are not explicitly given to it.
+     */
+    public static final int FLAG_UPDATE_CURRENT = 1<<27;
 
     /**
      * Exception thrown when trying to send through a PendingIntent that
@@ -161,7 +174,8 @@
      * not used).
      * @param intent Intent of the activity to be launched.
      * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
-     * {@link #FLAG_CANCEL_CURRENT}, or any of the flags as supported by
+     * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
+     * or any of the flags as supported by
      * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
      * of the intent that can be supplied when the actual send happens.
      *
@@ -195,7 +209,8 @@
      * not used).
      * @param intent The Intent to be broadcast.
      * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
-     * {@link #FLAG_CANCEL_CURRENT}, or any of the flags as supported by
+     * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
+     * or any of the flags as supported by
      * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
      * of the intent that can be supplied when the actual send happens.
      *
@@ -230,7 +245,8 @@
      * not used).
      * @param intent An Intent describing the service to be started.
      * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
-     * {@link #FLAG_CANCEL_CURRENT}, or any of the flags as supported by
+     * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
+     * or any of the flags as supported by
      * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
      * of the intent that can be supplied when the actual send happens.
      *
diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java
index 8b60cfa..c87e398 100644
--- a/core/java/android/app/ProgressDialog.java
+++ b/core/java/android/app/ProgressDialog.java
@@ -262,7 +262,7 @@
     }
 
     public void setIndeterminate(boolean indeterminate) {
-        if (mHasStarted && (isIndeterminate() != indeterminate)) {
+        if (mProgress != null) {
             mProgress.setIndeterminate(indeterminate);
         } else {
             mIndeterminate = indeterminate;
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 5f3f9ef..2ce2db9 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -16,11 +16,14 @@
 
 package android.app;
 
+import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
@@ -48,10 +51,12 @@
 import android.view.View.OnFocusChangeListener;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.EditorInfo;
 import android.widget.AdapterView;
-import android.widget.Button;
 import android.widget.CursorAdapter;
 import android.widget.EditText;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListAdapter;
@@ -62,6 +67,7 @@
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
 
+import java.util.List;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -100,7 +106,7 @@
     private TextView mBadgeLabel;
     private LinearLayout mSearchEditLayout;
     private EditText mSearchTextField;
-    private Button mGoButton;
+    private ImageButton mGoButton;
     private ListView mSuggestionsList;
 
     private ViewTreeObserver mViewTreeObserver = null;
@@ -130,14 +136,14 @@
     private String mSuggestionAction = null;
     private Uri mSuggestionData = null;
     private String mSuggestionQuery = null;
-
+    
     /**
      * Constructor - fires it up and makes it look like the search UI.
      * 
      * @param context Application Context we can use for system acess
      */
     public SearchDialog(Context context) {
-        super(context, com.android.internal.R.style.Theme_Translucent);
+        super(context, com.android.internal.R.style.Theme_SearchBar);
     }
 
     /**
@@ -149,21 +155,15 @@
         super.onCreate(savedInstanceState);
 
         Window theWindow = getWindow();
-        theWindow.requestFeature(Window.FEATURE_NO_TITLE);
-        theWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
-                WindowManager.LayoutParams.FLAG_DIM_BEHIND);
         theWindow.setGravity(Gravity.TOP|Gravity.FILL_HORIZONTAL);
 
         setContentView(com.android.internal.R.layout.search_bar);
 
-        // Note:  theWindow.setBackgroundDrawable(null) does not work here - you get blackness
-        theWindow.setBackgroundDrawableResource(android.R.color.transparent);
-
         theWindow.setLayout(ViewGroup.LayoutParams.FILL_PARENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT);
         WindowManager.LayoutParams lp = theWindow.getAttributes();
-        lp.dimAmount = 0.5f;
         lp.setTitle("Search Dialog");
+        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE;
         theWindow.setAttributes(lp);
 
         // get the view elements for local access
@@ -171,14 +171,14 @@
         mBadgeLabel = (TextView) findViewById(com.android.internal.R.id.search_badge);
         mSearchEditLayout = (LinearLayout)findViewById(com.android.internal.R.id.search_edit_frame);
         mSearchTextField = (EditText) findViewById(com.android.internal.R.id.search_src_text);
-        mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn);
+        mGoButton = (ImageButton) findViewById(com.android.internal.R.id.search_go_btn);
         mSuggestionsList = (ListView) findViewById(com.android.internal.R.id.search_suggest_list);
         
         // attach listeners
         mSearchTextField.addTextChangedListener(mTextWatcher);
         mSearchTextField.setOnKeyListener(mTextKeyListener);
         mGoButton.setOnClickListener(mGoButtonClickListener);
-        mGoButton.setOnKeyListener(mGoButtonKeyListener);
+        mGoButton.setOnKeyListener(mButtonsKeyListener);
         mSuggestionsList.setOnItemClickListener(mSuggestionsListItemClickListener);
         mSuggestionsList.setOnKeyListener(mSuggestionsKeyListener);
         mSuggestionsList.setOnFocusChangeListener(mSuggestFocusListener);
@@ -241,6 +241,7 @@
         if (mSuggestionsList != null) {
             mSuggestionsList.setVisibility(View.GONE);      // prevent any flicker if was visible
         }
+        
         super.show();
 
         setupSearchableInfo();
@@ -266,6 +267,17 @@
             initialQuery = "";     // This forces the preload to happen, triggering suggestions
         }
         mSearchTextField.setText(initialQuery);
+        
+        // If it is not for global search, that means the search dialog is 
+        // launched to input a web address. 
+        if (!globalSearch) {
+            mSearchTextField.setRawInputType(EditorInfo.TYPE_CLASS_TEXT
+                    | EditorInfo.TYPE_TEXT_VARIATION_URI);
+        } else {
+            mSearchTextField.setRawInputType(EditorInfo.TYPE_CLASS_TEXT
+                    | EditorInfo.TYPE_TEXT_VARIATION_NORMAL);
+        }
+        
         if (selectInitialQuery) {
             mSearchTextField.selectAll();
         } else {
@@ -424,7 +436,6 @@
     public void onConfigurationChanged(Configuration newConfig) {
         if (isShowing()) {
             // Redraw (resources may have changed)
-            updateSearchButton();
             updateSearchBadge();
             updateQueryHint();
         } 
@@ -439,7 +450,6 @@
             mActivityContext = mSearchable.getActivityContext(getContext());
             mProviderContext = mSearchable.getProviderContext(getContext(), mActivityContext);
             
-            updateSearchButton();
             updateSearchBadge();
             updateQueryHint();
         }
@@ -459,18 +469,6 @@
     }
     
     /**
-     * Update the text in the search button
-     */
-    private void updateSearchButton() {
-        int textId = mSearchable.getSearchButtonText();
-        if (textId == 0) {
-            textId = com.android.internal.R.string.search_go;
-        }
-        String goText = mActivityContext.getResources().getString(textId);
-        mGoButton.setText(goText);
-    }
-    
-    /**
      * Setup the search "Badge" if request by mode flags.
      */
     private void updateSearchBadge() {
@@ -1031,9 +1029,10 @@
     }
 
     /**
-     * React to typing in the GO button by refocusing to EditText.  Continue typing the query.
+     * React to typing in the GO search button by refocusing to EditText. 
+     * Continue typing the query.
      */
-    View.OnKeyListener mGoButtonKeyListener = new View.OnKeyListener() {
+    View.OnKeyListener mButtonsKeyListener = new View.OnKeyListener() {
         public boolean onKey(View v, int keyCode, KeyEvent event) {
             // also guard against possible race conditions (late arrival after dismiss)
             if (mSearchable != null) {
@@ -1054,7 +1053,7 @@
             }
         }
     };
-
+    
     /**
      * React to the user typing "enter" or other hardwired keys while typing in the search box.
      * This handles these special keys while the edit box has focus.
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 01babc4..5f25b90 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -48,6 +48,7 @@
  * <li><a href="#ActionKeys">Action Keys</a>
  * <li><a href="#SearchabilityMetadata">Searchability Metadata</a>
  * <li><a href="#PassingSearchContext">Passing Search Context</a>
+ * <li><a href="#ProtectingUserPrivacy">Protecting User Privacy</a>
  * </ol>
  * 
  * <a name="DeveloperGuide"></a>
@@ -578,7 +579,7 @@
  * file.  Each element defines one of the keycodes you are interested in, 
  * defines the conditions under which they are sent, and provides details
  * on how to communicate the action key event back to your searchable activity.</li>
- * <li>In your intent receiver, if you wish, you can check for action keys by checking the 
+ * <li>In your broadcast receiver, if you wish, you can check for action keys by checking the 
  * extras field of the {@link android.content.Intent Intent}.</li>
  * </ul>
  * 
@@ -974,6 +975,36 @@
  *     appData.get...();
  *     appData.get...();
  * }</pre>
+ * 
+ * <a name="ProtectingUserPrivacy"></a>
+ * <h3>Protecting User Privacy</h3>
+ * 
+ * <p>Many users consider their activities on the phone, including searches, to be private 
+ * information.  Applications that implement search should take steps to protect users' privacy
+ * wherever possible.  This section covers two areas of concern, but you should consider your search
+ * design carefully and take any additional steps necessary.
+ * 
+ * <p><b>Don't send personal information to servers, and if you do, don't log it.</b>
+ * "Personal information" is information that can personally identify your users, such as name, 
+ * email address or billing information, or other data which can be reasonably linked to such 
+ * information.  If your application implements search with the assistance of a server, try to 
+ * avoid sending personal information with your searches.  For example, if you are searching for 
+ * businesses near a zip code, you don't need to send the user ID as well - just send the zip code
+ * to the server.  If you do need to send personal information, you should take steps to avoid 
+ * logging it.  If you must log it, you should protect that data very carefully, and erase it as 
+ * soon as possible.
+ * 
+ * <p><b>Provide the user with a way to clear their search history.</b>  The Search Manager helps
+ * your application provide context-specific suggestions.  Sometimes these suggestions are based
+ * on previous searches, or other actions taken by the user in an earlier session.  A user may not
+ * wish for previous searches to be revealed to other users, for instance if they share their phone
+ * with a friend.  If your application provides suggestions that can reveal previous activities,
+ * you should implement a "Clear History" menu, preference, or button.  If you are using 
+ * {@link android.provider.SearchRecentSuggestions}, you can simply call its 
+ * {@link android.provider.SearchRecentSuggestions#clearHistory() clearHistory()} method from
+ * your "Clear History" UI.  If you are implementing your own form of recent suggestions, you'll 
+ * need to provide a similar a "clear history" API in your provider, and call it from your
+ * "Clear History" UI.
  */
 public class SearchManager 
         implements DialogInterface.OnDismissListener, DialogInterface.OnCancelListener
@@ -1008,6 +1039,16 @@
      * activity that launched the search.
      */
     public final static String APP_DATA = "app_data";
+
+    /**
+     * Intent app_data bundle key: Use this key with the bundle from
+     * {@link android.content.Intent#getBundleExtra
+     * content.Intent.getBundleExtra(APP_DATA)} to obtain the source identifier
+     * set by the activity that launched the search.
+     *
+     * @hide
+     */
+    public final static String SOURCE = "source";
     
     /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 28b0615..6c08e75 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -163,7 +163,6 @@
 
     /**
      * Called by the system when the service is first created.  Do not call this method directly.
-     * If you override this method, be sure to call super.onCreate().
      */
     public void onCreate() {
     }
@@ -172,7 +171,6 @@
      * Called by the system every time a client explicitly starts the service by calling 
      * {@link android.content.Context#startService}, providing the arguments it supplied and a 
      * unique integer token representing the start request.  Do not call this method directly.
-     * If you override this method, be sure to call super.onStart().
      *  
      * @param intent The Intent supplied to {@link android.content.Context#startService}, 
      *                  as given.
@@ -189,7 +187,6 @@
      * service should clean up an resources it holds (threads, registered
      * receivers, etc) at this point.  Upon return, there will be no more calls
      * in to this Service object and it is effectively dead.  Do not call this method directly.
-     * If you override this method, be sure to call super.onDestroy().
      */
     public void onDestroy() {
     }
@@ -375,4 +372,3 @@
     private Application mApplication = null;
     private IActivityManager mActivityManager = null;
 }
-
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 107532e..002b01f 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -20,7 +20,7 @@
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
 import android.os.Bundle;
-import android.pim.DateFormat;
+import android.text.format.DateFormat;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.TimePicker;
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
new file mode 100644
index 0000000..d6ea889
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.server.BluetoothA2dpService;
+import android.content.Context;
+import android.os.ServiceManager;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Public API for controlling the Bluetooth A2DP Profile Service.
+ *
+ * BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
+ * Service via IPC.
+ *
+ * Creating a BluetoothA2dp object will initiate a binding with the
+ * BluetoothHeadset service. Users of this object should call close() when they
+ * are finished, so that this proxy object can unbind from the service.
+ *
+ * Currently the BluetoothA2dp service runs in the system server and this
+ * proxy object will be immediately bound to the service on construction.
+ * However this may change in future releases, and error codes such as
+ * BluetoothError.ERROR_IPC_NOT_READY will be returned from this API when the
+ * proxy object is not yet attached.
+ * 
+ * Currently this class provides methods to connect to A2DP audio sinks.
+ *
+ * @hide
+ */
+public class BluetoothA2dp {
+    private static final String TAG = "BluetoothA2dp";
+
+    /** int extra for SINK_STATE_CHANGED_ACTION */
+    public static final String SINK_STATE =
+        "android.bluetooth.a2dp.intent.SINK_STATE";
+    /** int extra for SINK_STATE_CHANGED_ACTION */
+    public static final String SINK_PREVIOUS_STATE =
+        "android.bluetooth.a2dp.intent.SINK_PREVIOUS_STATE";
+
+    /** Indicates the state of an A2DP audio sink has changed.
+     *  This intent will always contain SINK_STATE, SINK_PREVIOUS_STATE and
+     *  BluetoothIntent.ADDRESS extras.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String SINK_STATE_CHANGED_ACTION =
+        "android.bluetooth.a2dp.intent.action.SINK_STATE_CHANGED";
+
+    public static final int STATE_DISCONNECTED = 0;
+    public static final int STATE_CONNECTING   = 1;
+    public static final int STATE_CONNECTED    = 2;
+    public static final int STATE_DISCONNECTING = 3;
+    /** Playing implies connected */
+    public static final int STATE_PLAYING    = 4;
+
+    private final IBluetoothA2dp mService;
+    private final Context mContext;
+
+    /**
+     * Create a BluetoothA2dp proxy object for interacting with the local
+     * Bluetooth A2DP service.
+     * @param c Context
+     */
+    public BluetoothA2dp(Context c) {
+        mContext = c;
+        IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE);
+        if (b == null) {
+            throw new RuntimeException("Bluetooth A2DP service not available!");
+        }
+        mService = IBluetoothA2dp.Stub.asInterface(b);
+    }
+
+    /** Initiate a connection to an A2DP sink.
+     *  Listen for A2DP_SINK_STATE_CHANGED_ACTION to find out when the
+     *  connection is completed.
+     *  @param address Remote BT address.
+     *  @return Result code, negative indicates an immediate error.
+     *  @hide
+     */
+    public int connectSink(String address) {
+        try {
+            return mService.connectSink(address);
+        } catch (RemoteException e) {
+            Log.w(TAG, "", e);
+            return BluetoothError.ERROR_IPC;
+        }
+    }
+
+    /** Initiate disconnect from an A2DP sink.
+     *  Listen for A2DP_SINK_STATE_CHANGED_ACTION to find out when
+     *  disconnect is completed.
+     *  @param address Remote BT address.
+     *  @return Result code, negative indicates an immediate error.
+     *  @hide
+     */
+    public int disconnectSink(String address) {
+        try {
+            return mService.disconnectSink(address);
+        } catch (RemoteException e) {
+            Log.w(TAG, "", e);
+            return BluetoothError.ERROR_IPC;
+        }
+    }
+
+    /** Check if a specified A2DP sink is connected.
+     *  @param address Remote BT address.
+     *  @return True if connected (or playing), false otherwise and on error.
+     *  @hide
+     */
+    public boolean isSinkConnected(String address) {
+        int state = getSinkState(address);
+        return state == STATE_CONNECTED || state == STATE_PLAYING;
+    }
+
+    /** Check if any A2DP sink is connected.
+     * @return a List of connected A2DP sinks, or null on error.
+     * @hide
+     */
+    public List<String> listConnectedSinks() {
+        try {
+            return mService.listConnectedSinks();
+        } catch (RemoteException e) {
+            Log.w(TAG, "", e);
+            return null;
+        }
+    }
+
+    /** Get the state of an A2DP sink
+     *  @param address Remote BT address.
+     *  @return State code, or negative on error
+     *  @hide
+     */
+    public int getSinkState(String address) {
+        try {
+            return mService.getSinkState(address);
+        } catch (RemoteException e) {
+            Log.w(TAG, "", e);
+            return BluetoothError.ERROR_IPC;
+        }
+    }
+
+    /** Helper for converting a state to a string.
+     * For debug use only - strings are not internationalized.
+     * @hide
+     */
+    public static String stateToString(int state) {
+        switch (state) {
+        case STATE_DISCONNECTED:
+            return "disconnected";
+        case STATE_CONNECTING:
+            return "connecting";
+        case STATE_CONNECTED:
+            return "connected";
+        case STATE_DISCONNECTING:
+            return "disconnecting";
+        case STATE_PLAYING:
+            return "playing";
+        default:
+            return "<unknown state " + state + ">";
+        }
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
new file mode 100644
index 0000000..88ce18b
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+/**
+ * The Android Bluetooth API is not finalized, and *will* change. Use at your
+ * own risk.
+ *
+ * Static helper methods and constants to decode the device class bit vector
+ * returned by the Bluetooth API.
+ *
+ * The Android Bluetooth API returns a 32-bit integer to represent the class.
+ * The format of these bits is defined at
+ *   http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
+ * (login required). This class provides static helper methods and constants to
+ * determine what Service Class(es) and Device Class are encoded in the 32-bit
+ * class.
+ *
+ * Devices typically have zero or more service classes, and exactly one device
+ * class. The device class is encoded as a major and minor device class, the
+ * minor being a subset of the major.
+ *
+ * Class is useful to describe a device (for example to show an icon),
+ * but does not reliably describe what profiles a device supports. To determine
+ * profile support you usually need to perform SDP queries.
+ *
+ * Each of these helper methods takes the 32-bit integer class as an argument.
+ *
+ * @hide
+ */
+public class BluetoothClass {
+    /** Indicates the Bluetooth API could not retrieve the class */
+    public static final int ERROR = 0xFF000000;
+
+    /** Every Bluetooth device has zero or more service classes */
+    public static class Service {
+        public static final int BITMASK                 = 0xFFE000;
+
+        public static final int LIMITED_DISCOVERABILITY = 0x002000;
+        public static final int POSITIONING             = 0x010000;
+        public static final int NETWORKING              = 0x020000;
+        public static final int RENDER                  = 0x040000;
+        public static final int CAPTURE                 = 0x080000;
+        public static final int OBJECT_TRANSFER         = 0x100000;
+        public static final int AUDIO                   = 0x200000;
+        public static final int TELEPHONY               = 0x400000;
+        public static final int INFORMATION             = 0x800000;
+
+        /** Returns true if the given class supports the given Service Class.
+         * A bluetooth device can claim to support zero or more service classes.
+         * @param btClass The bluetooth class.
+         * @param serviceClass The service class constant to test for. For
+         *                     example, Service.AUDIO. Must be one of the
+         *                     Service.FOO constants.
+         * @return True if the service class is supported.
+         */
+        public static boolean hasService(int btClass, int serviceClass) {
+            if (btClass == ERROR) {
+                return false;
+            }
+            return ((btClass & Service.BITMASK & serviceClass) != 0);
+        }
+    }
+
+    /** Every Bluetooth device has exactly one device class, comprimised of
+     *  major and minor components. We have not included the minor classes for
+     *  major classes: NETWORKING, PERIPHERAL and IMAGING yet because they work
+     *  a little differently. */
+    public static class Device {
+        public static final int BITMASK               = 0x1FFC;
+
+        public static class Major {
+            public static final int BITMASK           = 0x1F00;
+
+            public static final int MISC              = 0x0000;
+            public static final int COMPUTER          = 0x0100;
+            public static final int PHONE             = 0x0200;
+            public static final int NETWORKING        = 0x0300;
+            public static final int AUDIO_VIDEO       = 0x0400;
+            public static final int PERIPHERAL        = 0x0500;
+            public static final int IMAGING           = 0x0600;
+            public static final int WEARABLE          = 0x0700;
+            public static final int TOY               = 0x0800;
+            public static final int HEALTH            = 0x0900;
+            public static final int UNCATEGORIZED     = 0x1F00;
+
+            /** Returns the Major Device Class component of a bluetooth class.
+             * Values returned from this function can be compared with the constants
+             * Device.Major.FOO. A bluetooth device can only be associated
+             * with one major class.
+             */
+            public static int getDeviceMajor(int btClass) {
+                if (btClass == ERROR) {
+                    return ERROR;
+                }
+                return (btClass & Device.Major.BITMASK);
+            }
+        }
+
+        // Devices in the COMPUTER major class
+        public static final int COMPUTER_UNCATEGORIZED              = 0x0100;
+        public static final int COMPUTER_DESKTOP                    = 0x0104;
+        public static final int COMPUTER_SERVER                     = 0x0108;
+        public static final int COMPUTER_LAPTOP                     = 0x010C;
+        public static final int COMPUTER_HANDHELD_PC_PDA            = 0x0110;
+        public static final int COMPUTER_PALM_SIZE_PC_PDA           = 0x0114;
+        public static final int COMPUTER_WEARABLE                   = 0x0118;
+
+        // Devices in the PHONE major class
+        public static final int PHONE_UNCATEGORIZED                 = 0x0200;
+        public static final int PHONE_CELLULAR                      = 0x0204;
+        public static final int PHONE_CORDLESS                      = 0x0208;
+        public static final int PHONE_SMART                         = 0x020C;
+        public static final int PHONE_MODEM_OR_GATEWAY              = 0x0210;
+        public static final int PHONE_ISDN                          = 0x0214;
+
+        // Minor classes for the AUDIO_VIDEO major class
+        public static final int AUDIO_VIDEO_UNCATEGORIZED           = 0x0400;
+        public static final int AUDIO_VIDEO_WEARABLE_HEADSET        = 0x0404;
+        public static final int AUDIO_VIDEO_HANDSFREE               = 0x0408;
+        //public static final int AUDIO_VIDEO_RESERVED              = 0x040C;
+        public static final int AUDIO_VIDEO_MICROPHONE              = 0x0410;
+        public static final int AUDIO_VIDEO_LOUDSPEAKER             = 0x0414;
+        public static final int AUDIO_VIDEO_HEADPHONES              = 0x0418;
+        public static final int AUDIO_VIDEO_PORTABLE_AUDIO          = 0x041C;
+        public static final int AUDIO_VIDEO_CAR_AUDIO               = 0x0420;
+        public static final int AUDIO_VIDEO_SET_TOP_BOX             = 0x0424;
+        public static final int AUDIO_VIDEO_HIFI_AUDIO              = 0x0428;
+        public static final int AUDIO_VIDEO_VCR                     = 0x042C;
+        public static final int AUDIO_VIDEO_VIDEO_CAMERA            = 0x0430;
+        public static final int AUDIO_VIDEO_CAMCORDER               = 0x0434;
+        public static final int AUDIO_VIDEO_VIDEO_MONITOR           = 0x0438;
+        public static final int AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER = 0x043C;
+        public static final int AUDIO_VIDEO_VIDEO_CONFERENCING      = 0x0440;
+        //public static final int AUDIO_VIDEO_RESERVED              = 0x0444;
+        public static final int AUDIO_VIDEO_VIDEO_GAMING_TOY        = 0x0448;
+
+        // Devices in the WEARABLE major class
+        public static final int WEARABLE_UNCATEGORIZED              = 0x0700;
+        public static final int WEARABLE_WRIST_WATCH                = 0x0704;
+        public static final int WEARABLE_PAGER                      = 0x0708;
+        public static final int WEARABLE_JACKET                     = 0x070C;
+        public static final int WEARABLE_HELMET                     = 0x0710;
+        public static final int WEARABLE_GLASSES                    = 0x0714;
+
+        // Devices in the TOY major class
+        public static final int TOY_UNCATEGORIZED                   = 0x0800;
+        public static final int TOY_ROBOT                           = 0x0804;
+        public static final int TOY_VEHICLE                         = 0x0808;
+        public static final int TOY_DOLL_ACTION_FIGURE              = 0x080C;
+        public static final int TOY_CONTROLLER                      = 0x0810;
+        public static final int TOY_GAME                            = 0x0814;
+
+        // Devices in the HEALTH major class
+        public static final int HEALTH_UNCATEGORIZED                = 0x0900;
+        public static final int HEALTH_BLOOD_PRESSURE               = 0x0904;
+        public static final int HEALTH_THERMOMETER                  = 0x0908;
+        public static final int HEALTH_WEIGHING                     = 0x090C;
+        public static final int HEALTH_GLUCOSE                      = 0x0910;
+        public static final int HEALTH_PULSE_OXIMETER               = 0x0914;
+        public static final int HEALTH_PULSE_RATE                   = 0x0918;
+        public static final int HEALTH_DATA_DISPLAY                 = 0x091C;
+
+        /** Returns the Device Class component of a bluetooth class. This includes
+         * both the major and minor device components. Values returned from this
+         * function can be compared with the constants Device.FOO. A bluetooth
+         * device can only be associated with one device class.
+         */
+        public static int getDevice(int btClass) {
+            if (btClass == ERROR) {
+                return ERROR;
+            }
+            return (btClass & Device.BITMASK);
+        }
+    }
+}
+
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 0b24db6..d1f71c5 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -514,7 +514,7 @@
         try {
             return mService.getRemoteClass(address);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return DeviceClass.CLASS_UNKNOWN;
+        return BluetoothClass.ERROR;
     }
     public byte[] getRemoteFeatures(String address) {
         try {
diff --git a/core/java/android/bluetooth/BluetoothError.java b/core/java/android/bluetooth/BluetoothError.java
new file mode 100644
index 0000000..2554bea
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothError.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+/**
+ * Bluetooth API error codes.
+ *
+ * Errors are always negative.
+ *
+ * @hide
+ */
+public class BluetoothError {
+    /** No error */
+    public static final int SUCCESS = 0;
+
+    /** Generic error */
+    public static final int ERROR = -1000;
+
+    /** Bluetooth currently disabled */
+    public static final int ERROR_DISABLED = -1001;
+
+    /** IPC is not ready, for example service is not yet bound */
+    public static final int ERROR_IPC_NOT_READY = -1011;
+
+    /** Some other IPC error, for example a RemoteException */
+    public static final int ERROR_IPC = -1012;
+
+}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 90db39b..905173e 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -28,35 +28,36 @@
  * The Android Bluetooth API is not finalized, and *will* change. Use at your
  * own risk.
  *
- * Public API for controlling the Bluetooth Headset Service.
+ * Public API for controlling the Bluetooth Headset Service. This includes both
+ * Bluetooth Headset and Handsfree (v1.5) profiles. The Headset service will
+ * attempt a handsfree connection first, and fall back to headset.
  *
  * BluetoothHeadset is a proxy object for controlling the Bluetooth Headset
- * Service.
+ * Service via IPC.
  *
  * Creating a BluetoothHeadset object will create a binding with the
  * BluetoothHeadset service. Users of this object should call close() when they
  * are finished with the BluetoothHeadset, so that this proxy object can unbind
  * from the service.
  *
- * BlueoothHeadset objects are not guarenteed to be connected to the
- * BluetoothHeadsetService at all times. Calls on this object while not
- * connected to the service will result in default error return values. Even
- * after object construction, there is a short delay (~10ms) before this proxy
- * object is actually connected to the Service.
+ * This BluetoothHeadset object is not immediately bound to the
+ * BluetoothHeadset service. Use the ServiceListener interface to obtain a
+ * notification when it is bound, this is especially important if you wish to
+ * immediately call methods on BluetootHeadset after construction.
  *
  * Android only supports one connected Bluetooth Headset at a time.
  *
- * Note that in this context, Headset includes both Bluetooth Headset's and
- * Handsfree devices.
- *
  * @hide
  */
 public class BluetoothHeadset {
 
-    private final static String TAG = "BluetoothHeadset";
+    private static final String TAG = "BluetoothHeadset";
+    private static final boolean DBG = false;
 
-    private final Context mContext;
     private IBluetoothHeadset mService;
+    private final Context mContext;
+    private final ServiceListener mServiceListener;
+    private ConnectHeadsetCallback mConnectHeadsetCallback;
 
     /** There was an error trying to obtain the state */
     public static final int STATE_ERROR        = -1;
@@ -72,25 +73,44 @@
     /** Connection cancelled before completetion. */
     public static final int RESULT_CANCELLED = 2;
 
-    private ServiceConnection mConnection = new ServiceConnection() {
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            mService = IBluetoothHeadset.Stub.asInterface(service);
-            Log.i(TAG, "Proxy object is now connected to Bluetooth Headset Service");
-        }
-        public void onServiceDisconnected(ComponentName className) {
-            mService = null;
-        }
-    };
+    /**
+     * An interface for notifying BluetoothHeadset IPC clients when they have
+     * been connected to the BluetoothHeadset service.
+     */
+    public interface ServiceListener {
+        /**
+         * Called to notify the client when this proxy object has been
+         * connected to the BluetoothHeadset service. Clients must wait for
+         * this callback before making IPC calls on the BluetoothHeadset
+         * service.
+         */
+        public void onServiceConnected();
+
+        /**
+         * Called to notify the client that this proxy object has been
+         * disconnected from the BluetoothHeadset service. Clients must not
+         * make IPC calls on the BluetoothHeadset service after this callback.
+         * This callback will currently only occur if the application hosting
+         * the BluetoothHeadset service, but may be called more often in future.
+         */
+        public void onServiceDisconnected();
+    }
+
+    /**
+     * Interface for connectHeadset() callback.
+     * This callback can occur in the Binder thread.
+     */
+    public interface ConnectHeadsetCallback {
+        public void onConnectHeadsetResult(String address, int resultCode);
+    }
 
     /**
      * Create a BluetoothHeadset proxy object.
-     * Remeber to call close() when you are done with this object, so that it
-     * can unbind from the BluetoothHeadsetService.
      */
-    public BluetoothHeadset(Context context) {
+    public BluetoothHeadset(Context context, ServiceListener l) {
         mContext = context;
-        if (!context.bindService(
-                new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) {
+        mServiceListener = l;
+        if (!context.bindService(new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) {
             Log.e(TAG, "Could not bind to Bluetooth Headset Service");
         }
     }
@@ -126,6 +146,9 @@
             try {
                 return mService.getState();
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
         }
         return BluetoothHeadset.STATE_ERROR;
     }
@@ -141,6 +164,9 @@
             try {
                 return mService.getHeadsetAddress();
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
         }
         return null;
     }
@@ -150,20 +176,29 @@
      * This call does not block. Fails if a headset is already connecting
      * or connected.
      * Will connect to the last connected headset if address is null.
+     * onConnectHeadsetResult() of your ConnectHeadsetCallback will be called
+     * on completition.
      * @param address The Bluetooth Address to connect to, or null to connect
      *                to the last connected headset.
-     * @param callback A callback with onCreateBondingResult() defined, or
-     *                 null.
+     * @param callback Callback on result. Not called if false is returned. Can
+     *                be null.
+     *                to the last connected headset.
      * @return        False if there was a problem initiating the connection
      *                procedure, and your callback will not be used. True if
      *                the connection procedure was initiated, in which case
      *                your callback is guarenteed to be called.
      */
-    public boolean connectHeadset(String address, IBluetoothHeadsetCallback callback) {
+    public boolean connectHeadset(String address, ConnectHeadsetCallback callback) {
         if (mService != null) {
             try {
-                return mService.connectHeadset(address, callback);
+                if (mService.connectHeadset(address, mHeadsetCallback)) {
+                    mConnectHeadsetCallback = callback;
+                    return true;
+                }
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
         }
         return false;
     }
@@ -178,6 +213,9 @@
             try {
                 return mService.isConnected(address);
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
         }
         return false;
     }
@@ -191,8 +229,72 @@
         if (mService != null) {
             try {
                 mService.disconnectHeadset();
+                return true;
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
         }
         return false;
     }
+
+    /**
+     * Start BT Voice Recognition mode, and set up Bluetooth audio path.
+     * Returns false if there is no headset connected, or if the
+     * connected headset does not support voice recognition, or on
+     * error.
+     */
+    public boolean startVoiceRecognition() {
+        if (mService != null) {
+            try {
+                return mService.startVoiceRecognition();
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return false;
+    }
+
+    /**
+     * Stop BT Voice Recognition mode, and shut down Bluetooth audio path.
+     * Returns false if there is no headset connected, or the connected
+     * headset is not in voice recognition mode, or on error.
+     */
+    public boolean stopVoiceRecognition() {
+        if (mService != null) {
+            try {
+                return mService.stopVoiceRecognition();
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return false;
+    }
+
+    private ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (DBG) Log.d(TAG, "Proxy object connected");
+            mService = IBluetoothHeadset.Stub.asInterface(service);
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected();
+            }
+        }
+        public void onServiceDisconnected(ComponentName className) {
+            if (DBG) Log.d(TAG, "Proxy object disconnected");
+            mService = null;
+            if (mServiceListener != null) {
+                mServiceListener.onServiceDisconnected();
+            }
+        }
+    };
+
+    private IBluetoothHeadsetCallback mHeadsetCallback = new IBluetoothHeadsetCallback.Stub() {
+        public void onConnectHeadsetResult(String address, int resultCode) {
+            if (mConnectHeadsetCallback != null) {
+                mConnectHeadsetCallback.onConnectHeadsetResult(address, resultCode);
+            }
+        }
+    };
 }
diff --git a/core/java/android/bluetooth/DeviceClass.java b/core/java/android/bluetooth/DeviceClass.java
deleted file mode 100644
index 36035ca..0000000
--- a/core/java/android/bluetooth/DeviceClass.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-/**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
- *
- * Static helper methods and constants to decode the device class bit vector
- * returned by the Bluetooth API.
- *
- * The Android Bluetooth API returns a 32-bit integer to represent the device
- * class. This is actually a bit vector, the format defined at
- *   http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
- * (login required). This class provides static helper methods and constants to
- * determine what Service Class(es), Major Class, and Minor Class are encoded
- * in a 32-bit device class.
- *
- * Each of the helper methods takes the 32-bit integer device class as an
- * argument.
- *
- * @hide
- */
-public class DeviceClass {
-
-    // Baseband class information
-    // See http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
-
-    public static final int SERVICE_CLASS_BITMASK                 = 0xFFE000;
-    public static final int SERVICE_CLASS_LIMITED_DISCOVERABILITY = 0x002000;
-    public static final int SERVICE_CLASS_POSITIONING             = 0x010000;
-    public static final int SERVICE_CLASS_NETWORKING              = 0x020000;
-    public static final int SERVICE_CLASS_RENDER                  = 0x040000;
-    public static final int SERVICE_CLASS_CAPTURE                 = 0x080000;
-    public static final int SERVICE_CLASS_OBJECT_TRANSFER         = 0x100000;
-    public static final int SERVICE_CLASS_AUDIO                   = 0x200000;
-    public static final int SERVICE_CLASS_TELEPHONY               = 0x400000;
-    public static final int SERVICE_CLASS_INFORMATION             = 0x800000;
-
-    public static final int MAJOR_CLASS_BITMASK           = 0x001F00;
-    public static final int MAJOR_CLASS_MISC              = 0x000000;
-    public static final int MAJOR_CLASS_COMPUTER          = 0x000100;
-    public static final int MAJOR_CLASS_PHONE             = 0x000200;
-    public static final int MAJOR_CLASS_NETWORKING        = 0x000300;
-    public static final int MAJOR_CLASS_AUDIO_VIDEO       = 0x000400;
-    public static final int MAJOR_CLASS_PERIPHERAL        = 0x000500;
-    public static final int MAJOR_CLASS_IMAGING           = 0x000600;
-    public static final int MAJOR_CLASS_WEARABLE          = 0x000700;
-    public static final int MAJOR_CLASS_TOY               = 0x000800;
-    public static final int MAJOR_CLASS_MEDICAL           = 0x000900;
-    public static final int MAJOR_CLASS_UNCATEGORIZED     = 0x001F00;
-
-    // Minor classes for the AUDIO_VIDEO major class
-    public static final int MINOR_CLASS_AUDIO_VIDEO_BITMASK                       = 0x0000FC;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_UNCATEGORIZED                 = 0x000000;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_HEADSET                       = 0x000004;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_HANDSFREE                     = 0x000008;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_MICROPHONE                    = 0x000010;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_LOUDSPEAKER                   = 0x000014;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_HEADPHONES                    = 0x000018;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_PORTABLE_AUDIO                = 0x00001C;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_CAR_AUDIO                     = 0x000020;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_SET_TOP_BOX                   = 0x000024;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_HIFI_AUDIO                    = 0x000028;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_VCR                           = 0x00002C;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_VIDEO_CAMERA                  = 0x000030;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_CAMCORDER                     = 0x000034;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_VIDEO_MONITOR                 = 0x000038;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER = 0x00003C;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_VIDEO_CONFERENCING            = 0x000040;
-    public static final int MINOR_CLASS_AUDIO_VIDEO_VIDEO_GAMING_TOY              = 0x000048;
-
-    // Indicates the Bluetooth API could not retrieve the class
-    public static final int CLASS_UNKNOWN = 0xFF000000;
-
-    /** Returns true if the given device class supports the given Service Class.
-     * A bluetooth device can claim to support zero or more service classes.
-     * @param deviceClass      The bluetooth device class.
-     * @param serviceClassType The service class constant to test for. For
-     *                         example, DeviceClass.SERVICE_CLASS_AUDIO. This
-     *                         must be one of the SERVICE_CLASS_xxx constants,
-     *                         results of this function are undefined
-     *                         otherwise.
-     * @return If the deviceClass claims to support the serviceClassType.
-     */
-    public static boolean hasServiceClass(int deviceClass, int serviceClassType) {
-        if (deviceClass == CLASS_UNKNOWN) {
-            return false;
-        }
-        return ((deviceClass & SERVICE_CLASS_BITMASK & serviceClassType) != 0);
-    }
-
-    /** Returns the Major Class of a bluetooth device class.
-     * Values returned from this function can be compared with the constants
-     * MAJOR_CLASS_xxx. A bluetooth device can only be associated
-     * with one major class.
-     */
-    public static int getMajorClass(int deviceClass) {
-        if (deviceClass == CLASS_UNKNOWN) {
-            return CLASS_UNKNOWN;
-        }
-        return (deviceClass & MAJOR_CLASS_BITMASK);
-    }
-
-    /** Returns the Minor Class of a bluetooth device class.
-     * Values returned from this function can be compared with the constants
-     * MINOR_CLASS_xxx_yyy, where xxx is the Major Class. A bluetooth
-     * device can only be associated with one minor class within its major
-     * class.
-     */
-    public static int getMinorClass(int deviceClass) {
-        if (deviceClass == CLASS_UNKNOWN) {
-            return CLASS_UNKNOWN;
-        }
-        return (deviceClass & MINOR_CLASS_AUDIO_VIDEO_BITMASK);
-    }
-}
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
new file mode 100644
index 0000000..7e0226d
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+/**
+ * System private API for Bluetooth A2DP service
+ *
+ * {@hide}
+ */
+interface IBluetoothA2dp {
+    int connectSink(in String address);
+    int disconnectSink(in String address);
+    List<String> listConnectedSinks();
+    int getSinkState(in String address);
+}
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 7b6030b..564861f 100644
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -36,7 +36,11 @@
     // returns true
     boolean connectHeadset(in String address, in IBluetoothHeadsetCallback callback);
 
+    void disconnectHeadset();
+
     boolean isConnected(in String address);
 
-    void disconnectHeadset();
+    boolean startVoiceRecognition();
+
+    boolean stopVoiceRecognition();
 }
diff --git a/core/java/android/bluetooth/package.html b/core/java/android/bluetooth/package.html
index ccd8fec..79abf0c 100644
--- a/core/java/android/bluetooth/package.html
+++ b/core/java/android/bluetooth/package.html
@@ -9,6 +9,5 @@
 channels/sockets on Android, and connect to specified sockets on other devices.
 </p>
 <p>Remember, not all Android devices are guaranteed to have Bluetooth functionality.</p>
-{@hide}
 </BODY>
 </HTML>
diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java
index 56e5d4a..e1a484e 100644
--- a/core/java/android/content/AbstractTableMerger.java
+++ b/core/java/android/content/AbstractTableMerger.java
@@ -548,7 +548,8 @@
         long numDeletedEntries = 0;
         if (mDeletedTable != null) {
             Cursor deletedCursor = mDb.query(mDeletedTable,
-                    syncIdAndVersionProjection, _SYNC_ACCOUNT + "=?", accountSelectionArgs,
+                    syncIdAndVersionProjection,
+                    _SYNC_ACCOUNT + "=? AND " + _SYNC_ID + " IS NOT NULL", accountSelectionArgs,
                     null, null, mDeletedTable + "." + _SYNC_ID);
 
             numDeletedEntries = deletedCursor.getCount();
diff --git a/core/java/android/content/AsyncQueryHandler.java b/core/java/android/content/AsyncQueryHandler.java
index 48f1bc7..2d651a7 100644
--- a/core/java/android/content/AsyncQueryHandler.java
+++ b/core/java/android/content/AsyncQueryHandler.java
@@ -24,6 +24,8 @@
 import android.os.Message;
 import android.util.Log;
 
+import java.lang.ref.WeakReference;
+
 /**
  * A helper class to help make handling asynchronous {@link ContentResolver}
  * queries easier.
@@ -37,7 +39,7 @@
     private static final int EVENT_ARG_UPDATE = 3;
     private static final int EVENT_ARG_DELETE = 4;
     
-    /* package */ ContentResolver mResolver;
+    /* package */ final WeakReference<ContentResolver> mResolver;
 
     private static Looper sLooper = null;
 
@@ -62,18 +64,26 @@
 
         @Override
         public void handleMessage(Message msg) {
+            final ContentResolver resolver = mResolver.get();
+            if (resolver == null) return;
+
             WorkerArgs args = (WorkerArgs) msg.obj;
 
             int token = msg.what;
             int event = msg.arg1;
-            
+
             switch (event) {
                 case EVENT_ARG_QUERY:
                     Cursor cursor;
                     try {
-                        cursor = mResolver.query(args.uri, args.projection,
+                        cursor = resolver.query(args.uri, args.projection,
                                 args.selection, args.selectionArgs,
                                 args.orderBy);
+                        // Calling getCount() causes the cursor window to be filled,
+                        // which will make the first access on the main thread a lot faster.
+                        if (cursor != null) {
+                            cursor.getCount();
+                        }
                     } catch (Exception e) {
                         cursor = null;
                     }
@@ -82,18 +92,16 @@
                     break;
 
                 case EVENT_ARG_INSERT:
-                    args.result = mResolver.insert(args.uri, args.values);
+                    args.result = resolver.insert(args.uri, args.values);
                     break;
 
                 case EVENT_ARG_UPDATE:
-                    int r = mResolver.update(args.uri, args.values, args.selection,
+                    args.result = resolver.update(args.uri, args.values, args.selection,
                             args.selectionArgs);
-                    args.result = new Integer(r);
                     break;
 
                 case EVENT_ARG_DELETE:
-                    int r2 = mResolver.delete(args.uri, args.selection, args.selectionArgs);
-                    args.result = new Integer(r2);
+                    args.result = resolver.delete(args.uri, args.selection, args.selectionArgs);
                     break;
 
             }
@@ -115,7 +123,7 @@
 
     public AsyncQueryHandler(ContentResolver cr) {
         super();
-        mResolver = cr;
+        mResolver = new WeakReference<ContentResolver>(cr);
         synchronized (AsyncQueryHandler.class) {
             if (sLooper == null) {
                 HandlerThread thread = new HandlerThread("AsyncQueryWorker");
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 6a6f4f9..cd92002 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -327,7 +327,7 @@
      * current broadcast; only works with broadcasts sent through
      * {@link Context#sendOrderedBroadcast(Intent, String)
      * Context.sendOrderedBroadcast}.  This will prevent
-     * any other intent receivers from receiving the broadcast. It will still
+     * any other broadcast receivers from receiving the broadcast. It will still
      * call {@link #onReceive} of the BroadcastReceiver that the caller of 
      * {@link Context#sendOrderedBroadcast(Intent, String)
      * Context.sendOrderedBroadcast} passed in.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 00a6d31..6da00df 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -982,10 +982,10 @@
             String profileFile, Bundle arguments);
 
     /**
-     * Return the handle to a system-level service by name.  The class of the
-     * returned object varies by the requested name.  Currently available names
+     * Return the handle to a system-level service by name. The class of the
+     * returned object varies by the requested name. Currently available names
      * are:
-     *
+     * 
      * <dl>
      *  <dt> {@link #WINDOW_SERVICE} ("window")
      *  <dd> The top-level window manager in which you can place custom
@@ -1021,6 +1021,9 @@
      *  <dt> {@link #WIFI_SERVICE} ("wifi")
      *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of
      * Wi-Fi connectivity.
+     * <dt> {@link #INPUT_METHOD_SERVICE} ("input_method")
+     * <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager}
+     * for management of input methods.
      * </dl>
      * 
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -1029,9 +1032,9 @@
      * Services, Providers, etc.)
      *
      * @param name The name of the desired service.
-     *
+     * 
      * @return The service or null if the name does not exist.
-     *
+     * 
      * @see #WINDOW_SERVICE
      * @see android.view.WindowManager
      * @see #LAYOUT_INFLATER_SERVICE
@@ -1062,6 +1065,8 @@
      * @see android.media.AudioManager
      * @see #TELEPHONY_SERVICE
      * @see android.internal.TelephonyManager
+     * @see #INPUT_METHOD_SERVICE
+     * @see android.view.inputmethod.InputMethodManager
      */
     public abstract Object getSystemService(String name);
 
@@ -1235,6 +1240,15 @@
     public static final String CLIPBOARD_SERVICE = "clipboard";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a 
+     * {@link android.view.inputmethod.InputMethodManager} for accessing input
+     * methods.
+     *
+     * @see #getSystemService
+     */
+    public static final String INPUT_METHOD_SERVICE = "input_method";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/DefaultDataHandler.java b/core/java/android/content/DefaultDataHandler.java
index 7dc71b8..863c9f6 100644
--- a/core/java/android/content/DefaultDataHandler.java
+++ b/core/java/android/content/DefaultDataHandler.java
@@ -28,42 +28,47 @@
 import java.util.Stack;
 
 /**
- * insert default data from InputStream, should be in XML format:
- * if the provider syncs data to the server, the imported data will be synced to the server
- * Samples:
- *  insert one row
- * <row uri="content://contacts/people">
- *  <Col column = "name" value = "foo feebe "/>
- *  <Col column = "addr" value = "Tx"/>
- * </row>
- * 
- * delete, it must be in order of uri, select and arg
- * <del uri="content://contacts/people" select="name=? and addr=?" 
- *  arg1 = "foo feebe" arg2 ="Tx"/>
+ * Inserts default data from InputStream, should be in XML format.
+ * If the provider syncs data to the server, the imported data will be synced to the server.
+ * <p>Samples:</p>
+ * <br/>
+ *  Insert one row:
+ * <pre>
+ * &lt;row uri="content://contacts/people">
+ *  &lt;Col column = "name" value = "foo feebe "/>
+ *  &lt;Col column = "addr" value = "Tx"/>
+ * &lt;/row></pre>
+ * <br/>
+ * Delete, it must be in order of uri, select, and arg:
+ * <pre>
+ * &lt;del uri="content://contacts/people" select="name=? and addr=?" 
+ *  arg1 = "foo feebe" arg2 ="Tx"/></pre>
+ * <br/>
+ *  Use first row's uri to insert into another table,
+ *  content://contacts/people/1/phones:
+ * <pre>
+ * &lt;row uri="content://contacts/people">
+ *  &lt;col column = "name" value = "foo feebe"/>
+ *  &lt;col column = "addr" value = "Tx"/>
+ *  &lt;row postfix="phones">
+ *    &lt;col column="number" value="512-514-6535"/>
+ *  &lt;/row>
+ *  &lt;row postfix="phones">
+ *    &lt;col column="cell" value="512-514-6535"/>
+ *  &lt;/row>  
+ * &lt;/row></pre>
+ * <br/>
+ *  Insert multiple rows in to same table and same attributes:
+ * <pre>
+ * &lt;row uri="content://contacts/people" >
+ *  &lt;row>
+ *   &lt;col column= "name" value = "foo feebe"/>
+ *   &lt;col column= "addr" value = "Tx"/>
+ *  &lt;/row>
+ *  &lt;row>
+ *  &lt;/row>
+ * &lt;/row></pre>
  *
- *  use first row's uri to insert into another table
- *  content://contacts/people/1/phones
- * <row uri="content://contacts/people">
- *  <col column = "name" value = "foo feebe"/>
- *  <col column = "addr" value = "Tx"/>
- *  <row postfix="phones">
- *    <col column="number" value="512-514-6535"/>
- *  </row>
- *  <row postfix="phones">
- *    <col column="cell" value="512-514-6535"/>
- *  </row>  
- * </row>
- * 
- *  insert multiple rows in to same table and same attributes:
- * <row uri="content://contacts/people" >
- *  <row>
- *   <col column= "name" value = "foo feebe"/>
- *   <col column= "addr" value = "Tx"/>
- *  </row>
- *  <row>
- *  </row>
- * </row> 
- * 
  * @hide
  */ 
 public class DefaultDataHandler implements ContentInsertHandler {
diff --git a/core/java/android/content/DialogInterface.java b/core/java/android/content/DialogInterface.java
index fc94aa6..4afa294 100644
--- a/core/java/android/content/DialogInterface.java
+++ b/core/java/android/content/DialogInterface.java
@@ -22,10 +22,39 @@
  * 
  */
 public interface DialogInterface {    
-    public static final int BUTTON1 = -1;
-    public static final int BUTTON2 = -2;
-    public static final int BUTTON3 = -3;
+    /**
+     * The identifier for the positive button.
+     */
+    public static final int BUTTON_POSITIVE = -1;
 
+    /**
+     * The identifier for the negative button. 
+     */
+    public static final int BUTTON_NEGATIVE = -2;
+
+    /**
+     * The identifier for the neutral button. 
+     */
+    public static final int BUTTON_NEUTRAL = -3;
+
+    /**
+     * @deprecated Use {@link #BUTTON_POSITIVE}
+     */
+    @Deprecated
+    public static final int BUTTON1 = BUTTON_POSITIVE;
+
+    /**
+     * @deprecated Use {@link #BUTTON_NEGATIVE}
+     */
+    @Deprecated
+    public static final int BUTTON2 = BUTTON_NEGATIVE;
+
+    /**
+     * @deprecated Use {@link #BUTTON_NEUTRAL}
+     */
+    @Deprecated
+    public static final int BUTTON3 = BUTTON_NEUTRAL;
+    
     public void cancel();
 
     public void dismiss();
@@ -71,9 +100,11 @@
          * This method will be invoked when a button in the dialog is clicked.
          * 
          * @param dialog The dialog that received the click.
-         * @param which The button that was clicked, i.e. BUTTON1 or BUTTON2 or
-         *            the position of the item clicked.
+         * @param which The button that was clicked (e.g.
+         *            {@link DialogInterface#BUTTON1}) or the position
+         *            of the item clicked.
          */
+        /* TODO: Change to use BUTTON_POSITIVE after API council */
         public void onClick(DialogInterface dialog, int which);
     }
     
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c76158c..4a92b4c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -33,7 +33,6 @@
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.TypedValue;
 import com.android.internal.util.XmlUtils;
 
 import java.io.IOException;
@@ -542,23 +541,8 @@
  * <h3>Flags</h3>
  *
  * <p>These are the possible flags that can be used in the Intent via
- * {@link #setFlags} and {@link #addFlags}.
- *
- * <ul>
- *     <li> {@link #FLAG_GRANT_READ_URI_PERMISSION}
- *     <li> {@link #FLAG_GRANT_WRITE_URI_PERMISSION}
- *     <li> {@link #FLAG_FROM_BACKGROUND}
- *     <li> {@link #FLAG_DEBUG_LOG_RESOLUTION}
- *     <li> {@link #FLAG_ACTIVITY_NO_HISTORY}
- *     <li> {@link #FLAG_ACTIVITY_SINGLE_TOP}
- *     <li> {@link #FLAG_ACTIVITY_NEW_TASK}
- *     <li> {@link #FLAG_ACTIVITY_MULTIPLE_TASK}
- *     <li> {@link #FLAG_ACTIVITY_FORWARD_RESULT}
- *     <li> {@link #FLAG_ACTIVITY_PREVIOUS_IS_TOP}
- *     <li> {@link #FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS}
- *     <li> {@link #FLAG_ACTIVITY_BROUGHT_TO_FRONT}
- *     <li> {@link #FLAG_RECEIVER_REGISTERED_ONLY}
- * </ul>
+ * {@link #setFlags} and {@link #addFlags}.  See {@link #setFlags} for a list
+ * of all possible flags.
  */
 public class Intent implements Parcelable {
     // ---------------------------------------------------------------------
@@ -573,6 +557,7 @@
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_MAIN = "android.intent.action.MAIN";
+
     /**
      * Activity Action: Display the data to the user.  This is the most common
      * action performed on data -- it is the generic action you can use on
@@ -586,11 +571,13 @@
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_VIEW = "android.intent.action.VIEW";
+
     /**
      * A synonym for {@link #ACTION_VIEW}, the "standard" action that is
      * performed on a piece of data.
      */
     public static final String ACTION_DEFAULT = ACTION_VIEW;
+
     /**
      * Used to indicate that some piece of data should be attached to some other
      * place.  For example, image data could be attached to a contact.  It is up
@@ -601,6 +588,7 @@
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
+
     /**
      * Activity Action: Provide explicit editable access to the given data.
      * <p>Input: {@link #getData} is URI of data to be edited.
@@ -608,6 +596,7 @@
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_EDIT = "android.intent.action.EDIT";
+
     /**
      * Activity Action: Pick an existing item, or insert a new item, and then edit it.
      * <p>Input: {@link #getType} is the desired MIME type of the item to create or edit.
@@ -618,6 +607,7 @@
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT";
+
     /**
      * Activity Action: Pick an item from the data, returning what was selected.
      * <p>Input: {@link #getData} is URI containing a directory of data
@@ -626,13 +616,15 @@
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PICK = "android.intent.action.PICK";
+
     /**
      * Activity Action: Creates a shortcut.
-     * <p>Input: Nothing.
+     * <p>Input: Nothing.</p>
      * <p>Output: An Intent representing the shortcut. The intent must contain three
      * extras: SHORTCUT_INTENT (value: Intent), SHORTCUT_NAME (value: String),
      * and SHORTCUT_ICON (value: Bitmap) or SHORTCUT_ICON_RESOURCE
-     * (value: ShortcutIconResource).
+     * (value: ShortcutIconResource).</p>
+     *
      * @see #EXTRA_SHORTCUT_INTENT
      * @see #EXTRA_SHORTCUT_NAME
      * @see #EXTRA_SHORTCUT_ICON
@@ -670,10 +662,12 @@
             "android.intent.extra.shortcut.ICON_RESOURCE";
 
     /**
-     * Represents a shortcut icon resource.
+     * Represents a shortcut/live folder icon resource.
      *
      * @see Intent#ACTION_CREATE_SHORTCUT
      * @see Intent#EXTRA_SHORTCUT_ICON_RESOURCE
+     * @see android.provider.LiveFolders#ACTION_CREATE_LIVE_FOLDER
+     * @see android.provider.LiveFolders#EXTRA_LIVE_FOLDER_ICON
      */
     public static class ShortcutIconResource implements Parcelable {
         /**
@@ -972,10 +966,13 @@
     public static final String ACTION_SEARCH = "android.intent.action.SEARCH";
     /**
      * Activity Action: Perform a web search.
-     * <p>Input: {@link #getData} is URI of data. If it is a url
-     * starts with http or https, the site will be opened. If it is plain text,
-     * Google search will be applied.
-     * <p>Output: nothing.
+     * <p>
+     * Input: {@link android.app.SearchManager#QUERY
+     * getStringExtra(SearchManager.QUERY)} is the text to search for. If it is
+     * a url starts with http or https, the site will be opened. If it is plain
+     * text, Google search will be applied.
+     * <p>
+     * Output: nothing.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
@@ -1027,7 +1024,7 @@
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
-
+    
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent broadcast actions (see action variable).
@@ -1318,6 +1315,14 @@
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_GTALK_SERVICE_DISCONNECTED =
             "android.intent.action.GTALK_DISCONNECTED";
+    
+    /**
+     * Broadcast Action: An input method has been changed.
+     * {@hide pending API Council approval}
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_INPUT_METHOD_CHANGED =
+            "android.intent.action.INPUT_METHOD_CHANGED";
 
     /**
      * <p>Broadcast Action: The user has switched the phone into or out of Airplane Mode. One or
@@ -1644,6 +1649,15 @@
      */
     public static final String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
 
+    /**
+     * Used as an int extra field in {@link android.content.Intent#ACTION_VOICE_COMMAND}
+     * intents to request which audio route the voice command should prefer.
+     * The value should be a route from {@link android.media.AudioManager}, for
+     * example ROUTE_BLUETOOTH_SCO. Providing this value is optional.
+     * {@hide pending API Council approval}
+     */
+    public static final String EXTRA_AUDIO_ROUTE = "android.intent.extra.AUDIO_ROUTE";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
@@ -1671,7 +1685,10 @@
     public static final int FLAG_DEBUG_LOG_RESOLUTION = 0x00000008;
 
     /**
-     * If set, the new activity is not kept in the history stack.
+     * If set, the new activity is not kept in the history stack.  As soon as
+     * the user navigates away from it, the activity is finished.  This may also
+     * be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory
+     * noHistory} attribute.
      */
     public static final int FLAG_ACTIVITY_NO_HISTORY = 0x40000000;
     /**
@@ -1794,9 +1811,33 @@
      */
     public static final int FLAG_ACTIVITY_RESET_TASK_IF_NEEDED = 0x00200000;
     /**
-     * If set, this activity is being launched from history (longpress home key).
+     * This flag is not normally set by application code, but set for you by
+     * the system if this activity is being launched from history
+     * (longpress home key).
      */
     public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 0x00100000;
+    /**
+     * If set, this marks a point in the task's activity stack that should
+     * be cleared when the task is reset.  That is, the next time the task
+     * is broad to the foreground with
+     * {@link #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED} (typically as a result of
+     * the user re-launching it from home), this activity and all on top of
+     * it will be finished so that the user does not return to them, but
+     * instead returns to whatever activity preceeded it.
+     * 
+     * <p>This is useful for cases where you have a logical break in your
+     * application.  For example, an e-mail application may have a command
+     * to view an attachment, which launches an image view activity to
+     * display it.  This activity should be part of the e-mail application's
+     * task, since it is a part of the task the user is involved in.  However,
+     * if the user leaves that task, and later selects the e-mail app from
+     * home, we may like them to return to the conversation they were
+     * viewing, not the picture attachment, since that is confusing.  By
+     * setting this flag when launching the image viewer, that viewer and
+     * any activities it starts will be removed the next time the user returns
+     * to mail.
+     */
+    public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 0x00080000;
 
     /**
      * If set, when sending a broadcast only registered receivers will be
@@ -3725,6 +3766,30 @@
     }
 
     /**
+     * Completely replace the extras in the Intent with the extras in the
+     * given Intent.
+     * 
+     * @param src The exact extras contained in this Intent are copied
+     * into the target intent, replacing any that were previously there.
+     */
+    public Intent replaceExtras(Intent src) {
+        mExtras = src.mExtras != null ? new Bundle(src.mExtras) : null;
+        return this;
+    }
+    
+    /**
+     * Completely replace the extras in the Intent with the given Bundle of
+     * extras.
+     * 
+     * @param extras The new set of extras in the Intent, or null to erase
+     * all extras.
+     */
+    public Intent replaceExtras(Bundle extras) {
+        mExtras = extras != null ? new Bundle(extras) : null;
+        return this;
+    }
+    
+    /**
      * Remove extended data from the intent.
      *
      * @see #putExtra
@@ -3762,14 +3827,17 @@
      * @see #FLAG_GRANT_WRITE_URI_PERMISSION
      * @see #FLAG_DEBUG_LOG_RESOLUTION
      * @see #FLAG_FROM_BACKGROUND
-     * @see #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
      * @see #FLAG_ACTIVITY_BROUGHT_TO_FRONT
+     * @see #FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
      * @see #FLAG_ACTIVITY_CLEAR_TOP
      * @see #FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
      * @see #FLAG_ACTIVITY_FORWARD_RESULT
+     * @see #FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
      * @see #FLAG_ACTIVITY_MULTIPLE_TASK
      * @see #FLAG_ACTIVITY_NEW_TASK
      * @see #FLAG_ACTIVITY_NO_HISTORY
+     * @see #FLAG_ACTIVITY_PREVIOUS_IS_TOP
+     * @see #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
      * @see #FLAG_ACTIVITY_SINGLE_TOP
      * @see #FLAG_RECEIVER_REGISTERED_ONLY
      */
@@ -4334,7 +4402,11 @@
                 XmlUtils.skipCurrentTag(parser);
 
             } else if (nodeName.equals("extra")) {
-                parseExtra(resources, intent, parser, attrs);
+                if (intent.mExtras == null) {
+                    intent.mExtras = new Bundle();
+                }
+                resources.parseBundleExtra("extra", attrs, intent.mExtras);
+                XmlUtils.skipCurrentTag(parser);
 
             } else {
                 XmlUtils.skipCurrentTag(parser);
@@ -4343,49 +4415,4 @@
 
         return intent;
     }
-
-    private static void parseExtra(Resources resources, Intent intent, XmlPullParser parser,
-            AttributeSet attrs) throws XmlPullParserException, IOException {
-        TypedArray sa = resources.obtainAttributes(attrs,
-                com.android.internal.R.styleable.IntentExtra);
-
-        String name = sa.getString(
-                com.android.internal.R.styleable.IntentExtra_name);
-        if (name == null) {
-            sa.recycle();
-            throw new RuntimeException(
-                    "<extra> requires an android:name attribute at "
-                    + parser.getPositionDescription());
-        }
-
-        TypedValue v = sa.peekValue(
-                com.android.internal.R.styleable.IntentExtra_value);
-        if (v != null) {
-            if (v.type == TypedValue.TYPE_STRING) {
-                CharSequence cs = v.coerceToString();
-                intent.putExtra(name, cs != null ? cs.toString() : null);
-            } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
-                intent.putExtra(name, v.data != 0);
-            } else if (v.type >= TypedValue.TYPE_FIRST_INT
-                    && v.type <= TypedValue.TYPE_LAST_INT) {
-                intent.putExtra(name, v.data);
-            } else if (v.type == TypedValue.TYPE_FLOAT) {
-                intent.putExtra(name, v.getFloat());
-            } else {
-                sa.recycle();
-                throw new RuntimeException(
-                        "<extra> only supports string, integer, float, color, and boolean at "
-                        + parser.getPositionDescription());
-            }
-        } else {
-            sa.recycle();
-            throw new RuntimeException(
-                    "<extra> requires an android:value or android:resource attribute at "
-                    + parser.getPositionDescription());
-        }
-
-        sa.recycle();
-
-        XmlUtils.skipCurrentTag(parser);
-    }
 }
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 2bf84e7..6bc3774 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -50,14 +50,14 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.pim.DateUtils;
-import android.pim.Time;
 import android.preference.Preference;
 import android.preference.PreferenceGroup;
 import android.provider.Sync;
 import android.provider.Settings;
 import android.provider.Sync.History;
 import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.text.format.Time;
 import android.util.Config;
 import android.util.EventLog;
 import android.util.Log;
@@ -1484,7 +1484,8 @@
                     // skip the sync if it isn't a force and the settings are off for this provider
                     final boolean force = syncOperation.extras.getBoolean(
                             ContentResolver.SYNC_EXTRAS_FORCE, false);
-                    if (!force && (!syncSettings.getListenForNetworkTickles()
+                    if (!force && (!syncSettings.getBackgroundData()
+                            || !syncSettings.getListenForNetworkTickles()
                             || !syncSettings.getSyncProviderAutomatically(
                             syncOperation.authority))) {
                         if (isLoggable) {
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index f577d2d..85d877a 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -120,12 +120,19 @@
      */
     public static final int FLAG_ALLOW_TASK_REPARENTING = 0x0040;
     /**
+     * Bit in {@link #flags} indicating that, when the user navigates away
+     * from an activity, it should be finished.
+     * Set from the
+     * {@link android.R.attr#noHistory} attribute.
+     */
+    public static final int FLAG_NO_HISTORY = 0x0080;
+    /**
      * Options that have been set in the activity declaration in the
      * manifest: {@link #FLAG_MULTIPROCESS},
      * {@link #FLAG_FINISH_ON_TASK_LAUNCH}, {@link #FLAG_CLEAR_TASK_ON_LAUNCH},
      * {@link #FLAG_ALWAYS_RETAIN_TASK_STATE},
      * {@link #FLAG_STATE_NOT_NEEDED}, {@link #FLAG_EXCLUDE_FROM_RECENTS},
-     * {@link #FLAG_ALLOW_TASK_REPARENTING}.
+     * {@link #FLAG_ALLOW_TASK_REPARENTING}, {@link #FLAG_NO_HISTORY}.
      */
     public int flags;
 
@@ -247,6 +254,16 @@
      */
     public int configChanges;
     
+    /**
+     * The desired soft input mode for this activity's main window.
+     * Set from the {@link android.R.attr#windowSoftInputMode} attribute
+     * in the activity's manifest.  May be any of the same values allowed
+     * for {@link android.view.WindowManager.LayoutParams#softInputMode
+     * WindowManager.LayoutParams.softInputMode}.  If 0 (unspecified),
+     * the mode from the theme will be used.
+     */
+    public int softInputMode;
+    
     public ActivityInfo() {
     }
 
@@ -260,6 +277,7 @@
         flags = orig.flags;
         screenOrientation = orig.screenOrientation;
         configChanges = orig.configChanges;
+        softInputMode = orig.softInputMode;
     }
     
     /**
@@ -280,9 +298,10 @@
                 + " targetActivity=" + targetActivity);
         pw.println(prefix + "launchMode=" + launchMode
                 + " flags=0x" + Integer.toHexString(flags)
-                + " theme=0x" + Integer.toHexString(theme)
-                + " orien=" + screenOrientation
-                + " configChanges=0x" + Integer.toHexString(configChanges));
+                + " theme=0x" + Integer.toHexString(theme));
+        pw.println(prefix + "screenOrientation=" + screenOrientation
+                + " configChanges=0x" + Integer.toHexString(configChanges)
+                + " softInputMode=0x" + Integer.toHexString(softInputMode));
         super.dumpBack(pw, prefix);
     }
     
@@ -306,6 +325,7 @@
         dest.writeInt(flags);
         dest.writeInt(screenOrientation);
         dest.writeInt(configChanges);
+        dest.writeInt(softInputMode);
     }
 
     public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -328,5 +348,6 @@
         flags = source.readInt();
         screenOrientation = source.readInt();
         configChanges = source.readInt();
+        softInputMode = source.readInt();
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 22d01dc..8d727ed 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -112,6 +112,13 @@
      * android:allowClearUserData} of the &lt;application&gt; tag.
      */
     public static final int FLAG_ALLOW_CLEAR_USER_DATA = 1<<6;
+    
+    
+    /**
+     * Value for {@link #flags}: default value for the corresponding ActivityInfo flag.
+     *  {@hide}
+     */
+    public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7;
 
     /**
      * Flags associated with the application.  Any combination of
@@ -195,7 +202,7 @@
                 sb = ab.packageName;
             }
             
-            return sCollator.compare(sa, sb);
+            return sCollator.compare(sa.toString(), sb.toString());
         }
 
         private final Collator   sCollator = Collator.getInstance();
diff --git a/core/java/android/content/pm/ConfigurationInfo.java b/core/java/android/content/pm/ConfigurationInfo.java
new file mode 100755
index 0000000..9115225
--- /dev/null
+++ b/core/java/android/content/pm/ConfigurationInfo.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.content.res.Configuration;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information you can retrieve about hardware configuration preferences
+ * declared by an application. This corresponds to information collected from the
+ * AndroidManifest.xml's &lt;uses-configuration&gt; tags.
+ */
+public class ConfigurationInfo implements Parcelable {    
+    /**
+     * The kind of touch screen attached to the device.
+     * One of: {@link android.content.res.Configuration#TOUCHSCREEN_NOTOUCH},
+     * {@link android.content.res.Configuration#TOUCHSCREEN_STYLUS}, 
+     * {@link android.content.res.Configuration#TOUCHSCREEN_FINGER}. 
+     */
+    public int reqTouchScreen;
+    
+    /**
+     * Application's input method preference.
+     * One of: {@link android.content.res.Configuration#KEYBOARD_UNDEFINED},
+     * {@link android.content.res.Configuration#KEYBOARD_NOKEYS},
+     * {@link android.content.res.Configuration#KEYBOARD_QWERTY},
+     * {@link android.content.res.Configuration#KEYBOARD_12KEY}
+     */
+    public int reqKeyboardType;
+    
+    /**
+     * A flag indicating whether any keyboard is available.
+     * one of: {@link android.content.res.Configuration#NAVIGATION_UNDEFINED},
+     * {@link android.content.res.Configuration#NAVIGATION_DPAD}, 
+     * {@link android.content.res.Configuration#NAVIGATION_TRACKBALL},
+     * {@link android.content.res.Configuration#NAVIGATION_WHEEL}
+     */
+    public int reqNavigation;
+    
+    /**
+     * Value for {@link #reqInputFeatures}: if set, indicates that the application
+     * requires a hard keyboard
+     */
+    public static final int INPUT_FEATURE_HARD_KEYBOARD = 0x00000001;
+    
+    /**
+     * Value for {@link #reqInputFeatures}: if set, indicates that the application
+     * requires a hard keyboard
+     */
+    public static final int INPUT_FEATURE_FIVE_WAY_NAV = 0x00000002;
+    
+    /**
+     * Flags associated with the application.  Any combination of
+     * {@link #INPUT_FEATURE_HARD_KEYBOARD},
+     * {@link #INPUT_FEATURE_FIVE_WAY_NAV}
+     */
+    public int reqInputFeatures = 0;
+
+    public ConfigurationInfo() {
+    }
+
+    public ConfigurationInfo(ConfigurationInfo orig) {
+        reqTouchScreen = orig.reqTouchScreen;
+        reqKeyboardType = orig.reqKeyboardType;
+        reqNavigation = orig.reqNavigation;
+        reqInputFeatures = orig.reqInputFeatures;
+    }
+
+    public String toString() {
+        return "ApplicationHardwarePreferences{"
+            + Integer.toHexString(System.identityHashCode(this))
+            + ", touchscreen = " + reqTouchScreen + "}"
+            + ", inputMethod = " + reqKeyboardType + "}"
+            + ", navigation = " + reqNavigation + "}"
+            + ", reqInputFeatures = " + reqInputFeatures + "}";
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int parcelableFlags) {
+        dest.writeInt(reqTouchScreen);
+        dest.writeInt(reqKeyboardType);
+        dest.writeInt(reqNavigation);
+        dest.writeInt(reqInputFeatures);
+    }
+
+    public static final Creator<ConfigurationInfo> CREATOR =
+        new Creator<ConfigurationInfo>() {
+        public ConfigurationInfo createFromParcel(Parcel source) {
+            return new ConfigurationInfo(source);
+        }
+        public ConfigurationInfo[] newArray(int size) {
+            return new ConfigurationInfo[size];
+        }
+    };
+
+    private ConfigurationInfo(Parcel source) {
+        reqTouchScreen = source.readInt();
+        reqKeyboardType = source.readInt();
+        reqNavigation = source.readInt();
+        reqInputFeatures = source.readInt();
+    }
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c79655d..fdb2a2f 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -76,6 +76,8 @@
     
     String getNameForUid(int uid);
     
+    int getUidForSharedUser(String sharedUserName);
+    
     ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags);
 
     List<ResolveInfo> queryIntentActivities(in Intent intent, 
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index e6745da..30ca002 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -73,6 +73,7 @@
         dest.writeString(publicSourceDir);
         dest.writeString(dataDir);
         dest.writeInt((handleProfiling == false) ? 0 : 1);
+        dest.writeInt((functionalTest == false) ? 0 : 1);
     }
 
     public static final Parcelable.Creator<InstrumentationInfo> CREATOR
@@ -92,5 +93,6 @@
         publicSourceDir = source.readString();
         dataDir = source.readString();
         handleProfiling = source.readInt() != 0;
+        functionalTest = source.readInt() != 0;
     }
 }
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 7d694c7..994afc8 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -103,6 +103,15 @@
      * in if the flag {@link PackageManager#GET_SIGNATURES} was set.
      */
     public Signature[] signatures;
+    
+    /**
+     * Application specified preferred configuration
+     * {@link android.R.styleable#AndroidManifestUsesConfiguration
+     * &lt;uses-configuration&gt;} tags included under &lt;manifest&gt;,
+     * or null if there were none. This is only filled in if the flag
+     * {@link PackageManager#GET_CONFIGURATIONS} was set.  
+     */
+    public ConfigurationInfo[] configPreferences;
 
     public PackageInfo() {
     }
@@ -136,6 +145,7 @@
         dest.writeTypedArray(permissions, parcelableFlags);
         dest.writeStringArray(requestedPermissions);
         dest.writeTypedArray(signatures, parcelableFlags);
+        dest.writeTypedArray(configPreferences, parcelableFlags);
     }
 
     public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -166,5 +176,6 @@
         permissions = source.createTypedArray(PermissionInfo.CREATOR);
         requestedPermissions = source.createStringArray();
         signatures = source.createTypedArray(Signature.CREATOR);
+        configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
     }
 }
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 406a3eb..46e7ca43 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -90,7 +90,10 @@
                 return label;
             }
         }
-        return name;
+        if(name != null) {
+            return name;
+        }
+        return packageName;
     }
     
     /**
@@ -179,7 +182,7 @@
             if (sa == null) sa = aa.name;
             CharSequence  sb = ab.loadLabel(mPM);
             if (sb == null) sb = ab.name;
-            return sCollator.compare(sa, sb);
+            return sCollator.compare(sa.toString(), sb.toString());
         }
 
         private final Collator   sCollator = Collator.getInstance();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index db00a9a..a544550 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -148,6 +148,21 @@
      * {@link PackageInfo#permissions}.
      */
     public static final int GET_PERMISSIONS               = 0x00001000;
+    
+    /**
+     * Flag parameter to retrieve all applications(even uninstalled ones) with data directories.
+     * This state could have resulted if applications have been deleted with flag 
+     * DONT_DELETE_DATA
+     * with a possibility of being replaced or reinstalled in future
+     */
+    public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+    
+    /**
+     * {@link PackageInfo} flag: return information about
+     * hardware preferences
+     * {@link PackageInfo#configPreferences}
+     */
+    public static final int GET_CONFIGURATIONS = 0x00004000;
 
     /**
      * Permission check result: this is returned by {@link #checkPermission}
@@ -427,16 +442,38 @@
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
      *                    desired package.
-     * @param flags Optional flags to control what information is returned.  If
-     *              0, none of the optional information is returned.
+
+     * @param flags Additional option flags. Use any combination of
+     * {@link #GET_ACTIVITIES},
+     * {@link #GET_GIDS},
+     * {@link #GET_CONFIGURATIONS},
+     * {@link #GET_INSTRUMENTATION},
+     * {@link #GET_PERMISSIONS},
+     * {@link #GET_PROVIDERS},
+     * {@link #GET_RECEIVERS},
+     * {@link #GET_SERVICES},
+     * {@link #GET_SIGNATURES},
+     * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
      *
-     * @return Returns a PackageInfo containing information about the package.
-     *
+     * @return Returns a PackageInfo object containing information about the package.
+     *         If flag GET_UNINSTALLED_PACKAGES is set and  if the package is not
+     *         found in the list of installed applications, the package information is
+     *         retrieved from the list of uninstalled applications(which includes 
+     *         installed applications as well as applications
+     *         with data directory ie applications which had been
+     *         deleted with DONT_DELTE_DATA flag set).
+     *         
      * @see #GET_ACTIVITIES
+     * @see #GET_GIDS
+     * @see #GET_CONFIGURATIONS
+     * @see #GET_INSTRUMENTATION
+     * @see #GET_PERMISSIONS
+     * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
-     * @see #GET_INSTRUMENTATION
      * @see #GET_SIGNATURES
+     * @see #GET_UNINSTALLED_PACKAGES
+     *                  
      */
     public abstract PackageInfo getPackageInfo(String packageName, int flags)
             throws NameNotFoundException;
@@ -530,10 +567,23 @@
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of an
      *                    application.
-     * @param flags Additional option flags.  Currently should always be 0.
+     * @param flags Additional option flags. Use any combination of 
+     * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
      *
-     * @return {@link ApplicationInfo} containing information about the
-     *         application.
+     * @return  {@link ApplicationInfo} Returns ApplicationInfo object containing 
+     *         information about the package.
+     *         If flag GET_UNINSTALLED_PACKAGES is set and  if the package is not
+     *         found in the list of installed applications, 
+     *         the application information is retrieved from the 
+     *         list of uninstalled applications(which includes 
+     *         installed applications as well as applications
+     *         with data directory ie applications which had been
+     *         deleted with DONT_DELTE_DATA flag set).
+     *
+     * @see #GET_META_DATA
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #GET_UNINSTALLED_PACKAGES
      */
     public abstract ApplicationInfo getApplicationInfo(String packageName,
             int flags) throws NameNotFoundException;
@@ -548,11 +598,15 @@
      * @param className The full name (i.e.
      *                  com.google.apps.contacts.ContactsList) of an Activity
      *                  class.
-     * @param flags Additional option flags.  Usually 0.
+     * @param flags Additional option flags. Use any combination of 
+     * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     * to modify the data (in ApplicationInfo) returned.
      *
      * @return {@link ActivityInfo} containing information about the activity.
      *
      * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
+     * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ActivityInfo getActivityInfo(ComponentName className,
             int flags) throws NameNotFoundException;
@@ -567,11 +621,15 @@
      * @param className The full name (i.e.
      *                  com.google.apps.contacts.CalendarAlarm) of a Receiver
      *                  class.
-     * @param flags Additional option flags.  Usually 0.
+     * @param flags Additional option flags.  Use any combination of 
+     * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     * to modify the data returned.
      *
      * @return {@link ActivityInfo} containing information about the receiver.
      *
      * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
+     * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ActivityInfo getReceiverInfo(ComponentName className,
             int flags) throws NameNotFoundException;
@@ -586,9 +644,14 @@
      * @param className The full name (i.e.
      *                  com.google.apps.media.BackgroundPlayback) of a Service
      *                  class.
-     * @param flags Additional option flags.  Currently should always be 0.
+     * @param flags Additional option flags.  Use any combination of 
+     * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     * to modify the data returned.
      *
      * @return ServiceInfo containing information about the service.
+     * 
+     * @see #GET_META_DATA
+     * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ServiceInfo getServiceInfo(ComponentName className,
             int flags) throws NameNotFoundException;
@@ -597,18 +660,36 @@
      * Return a List of all packages that are installed
      * on the device.
      *
-     * @param flags Optional flags to control what information is returned.  If
-     *              0, none of the optional information is returned.
+     * @param flags Additional option flags. Use any combination of
+     * {@link #GET_ACTIVITIES},
+     * {@link #GET_GIDS},
+     * {@link #GET_CONFIGURATIONS},
+     * {@link #GET_INSTRUMENTATION},
+     * {@link #GET_PERMISSIONS},
+     * {@link #GET_PROVIDERS},
+     * {@link #GET_RECEIVERS},
+     * {@link #GET_SERVICES},
+     * {@link #GET_SIGNATURES},
+     * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
      *
      * @return A List of PackageInfo objects, one for each package that is
      *         installed on the device.  In the unlikely case of there being no
-     *         installed packages, an empty list is returned.
+     *         installed packages, an empty list is returned. 
+     *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
+     *         applications including those deleted with DONT_DELETE_DATA
+     *         (partially installed apps with data directory) will be returned.
      *
      * @see #GET_ACTIVITIES
+     * @see #GET_GIDS
+     * @see #GET_CONFIGURATIONS
+     * @see #GET_INSTRUMENTATION
+     * @see #GET_PERMISSIONS
+     * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
-     * @see #GET_INSTRUMENTATION
      * @see #GET_SIGNATURES
+     * @see #GET_UNINSTALLED_PACKAGES
+     * 
      */
     public abstract List<PackageInfo> getInstalledPackages(int flags);
 
@@ -731,16 +812,42 @@
      * user id is not currently assigned.
      */
     public abstract String getNameForUid(int uid);
+    
+    /**
+     * Return the user id associated with a shared user name. Multiple
+     * applications can specify a shared user name in their manifest and thus
+     * end up using a common uid. This might be used for new applications
+     * that use an existing shared user name and need to know the uid of the
+     * shared user.
+     *
+     * @param sharedUserName The shared user name whose uid is to be retrieved.
+     * @return Returns the uid associated with the shared user, or  NameNotFoundException
+     * if the shared user name is not being used by any installed packages
+     * @hide
+     */
+    public abstract int getUidForSharedUser(String sharedUserName)
+            throws NameNotFoundException;
 
     /**
      * Return a List of all application packages that are installed on the
-     * device.
-     *
-     * @param flags Additional option flags.  Currently should always be 0.
+     * device. If flag GET_UNINSTALLED_PACKAGES has been set, a list of all
+     * applications including those deleted with DONT_DELETE_DATA(partially
+     * installed apps with data directory) will be returned.
+     * 
+     * @param flags Additional option flags. Use any combination of 
+     * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     * {link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
      *
      * @return A List of ApplicationInfo objects, one for each application that
      *         is installed on the device.  In the unlikely case of there being
-     *         no installed applications, an empty list is returned.
+     *         no installed applications, an empty list is returned. 
+     *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
+     *         applications including those deleted with DONT_DELETE_DATA
+     *         (partially installed apps with data directory) will be returned.
+     *         
+     * @see #GET_META_DATA
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #GET_UNINSTALLED_PACKAGES
      */
     public abstract List<ApplicationInfo> getInstalledApplications(int flags);
 
@@ -1139,17 +1246,30 @@
      * in a package archive file
      *
      * @param archiveFilePath The path to the archive file
-     * @param flags Optional flags to control what information is returned.  If
-     *              0, none of the optional information is returned.
+     * @param flags Additional option flags. Use any combination of
+     * {@link #GET_ACTIVITIES},
+     * {@link #GET_GIDS},
+     * {@link #GET_CONFIGURATIONS},
+     * {@link #GET_INSTRUMENTATION},
+     * {@link #GET_PERMISSIONS},
+     * {@link #GET_PROVIDERS},
+     * {@link #GET_RECEIVERS},
+     * {@link #GET_SERVICES},
+     * {@link #GET_SIGNATURES}, to modify the data returned.
      *
      * @return Returns the information about the package. Returns
      * null if the package could not be successfully parsed.
      *
      * @see #GET_ACTIVITIES
+     * @see #GET_GIDS
+     * @see #GET_CONFIGURATIONS
+     * @see #GET_INSTRUMENTATION
+     * @see #GET_PERMISSIONS
+     * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
-     * @see #GET_INSTRUMENTATION
      * @see #GET_SIGNATURES
+     * 
      */
     public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
         PackageParser packageParser = new PackageParser(archiveFilePath);
@@ -1314,16 +1434,28 @@
      * first package on the list is the most preferred, the last is the
      * least preferred.
      *
-     * @param flags Optional flags to control what information is returned.  If
-     *              0, none of the optional information is returned.
+     * @param flags Additional option flags. Use any combination of
+     * {@link #GET_ACTIVITIES},
+     * {@link #GET_GIDS},
+     * {@link #GET_CONFIGURATIONS},
+     * {@link #GET_INSTRUMENTATION},
+     * {@link #GET_PERMISSIONS},
+     * {@link #GET_PROVIDERS},
+     * {@link #GET_RECEIVERS},
+     * {@link #GET_SERVICES},
+     * {@link #GET_SIGNATURES}, to modify the data returned.
      *
      * @return Returns a list of PackageInfo objects describing each
      * preferred application, in order of preference.
      *
      * @see #GET_ACTIVITIES
+     * @see #GET_GIDS
+     * @see #GET_CONFIGURATIONS
+     * @see #GET_INSTRUMENTATION
+     * @see #GET_PERMISSIONS
+     * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
-     * @see #GET_INSTRUMENTATION
      * @see #GET_SIGNATURES
      */
     public abstract List<PackageInfo> getPreferredPackages(int flags);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5a90261..e08f1d1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.AssetManager;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
@@ -104,6 +105,15 @@
         if ((flags&PackageManager.GET_GIDS) != 0) {
             pi.gids = gids;
         }
+        if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) {
+            int N = p.configPreferences.size();
+            if (N > 0) {
+                pi.configPreferences = new ConfigurationInfo[N];
+                for (int i=0; i<N; i++) {
+                    pi.configPreferences[i] = p.configPreferences.get(i);
+                }
+            }
+        }
         if ((flags&PackageManager.GET_ACTIVITIES) != 0) {
             int N = p.activities.size();
             if (N > 0) {
@@ -245,18 +255,24 @@
 
         XmlResourceParser parser = null;
         AssetManager assmgr = null;
+        boolean assetError = true;
         try {
             assmgr = new AssetManager();
-            assmgr.addAssetPath(mArchiveSourcePath);
-            parser = assmgr.openXmlResourceParser("AndroidManifest.xml");
+            if(assmgr.addAssetPath(mArchiveSourcePath) != 0) {
+                parser = assmgr.openXmlResourceParser("AndroidManifest.xml");
+                assetError = false;
+            } else {
+                Log.w(TAG, "Failed adding asset path:"+mArchiveSourcePath);
+            }
         } catch (Exception e) {
-            if (assmgr != null) assmgr.close();
             Log.w(TAG, "Unable to read AndroidManifest.xml of "
                     + mArchiveSourcePath, e);
+        }
+        if(assetError) {
+            if (assmgr != null) assmgr.close();
             mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
             return null;
         }
-
         String[] errorText = new String[1];
         Package pkg = null;
         Exception errorException = null;
@@ -626,7 +642,35 @@
 
                 XmlUtils.skipCurrentTag(parser);
 
-            } else if (tagName.equals("uses-sdk")) {
+            } else if (tagName.equals("uses-configuration")) {
+                ConfigurationInfo cPref = new ConfigurationInfo();
+                sa = res.obtainAttributes(attrs,
+                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration);
+                cPref.reqTouchScreen = sa.getInt(
+                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
+                        Configuration.TOUCHSCREEN_UNDEFINED);
+                cPref.reqKeyboardType = sa.getInt(
+                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
+                        Configuration.KEYBOARD_UNDEFINED);
+                if (sa.getBoolean(
+                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
+                        false)) {
+                    cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
+                }
+                cPref.reqNavigation = sa.getInt(
+                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
+                        Configuration.NAVIGATION_UNDEFINED);
+                if (sa.getBoolean(
+                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
+                        false)) {
+                    cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
+                }
+                sa.recycle();
+                pkg.configPreferences.add(cPref);
+
+                XmlUtils.skipCurrentTag(parser);
+
+            }  else if (tagName.equals("uses-sdk")) {
                 if (mSdkVersion > 0) {
                     sa = res.obtainAttributes(attrs,
                             com.android.internal.R.styleable.AndroidManifestUsesSdk);
@@ -650,6 +694,10 @@
                 if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
                     return null;
                 }
+            } else if (tagName.equals("eat-comment")) {
+                // Just skip this tag
+                XmlUtils.skipCurrentTag(parser);
+                continue;
             } else if (RIGID_PARSER) {
                 outError[0] = "Bad element under <manifest>: "
                     + parser.getName();
@@ -1038,11 +1086,6 @@
         if (outError[0] != null) {
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
             return false;
-        } else if (ai.processName != null && !ai.processName.equals(ai.packageName)
-                && ai.className != null) {
-            Log.w(TAG, "In package " + ai.packageName
-                    + " <application> specifies both a name and a process; ignoring the process");
-            ai.processName = null;
         }
 
         final int innerDepth = parser.getDepth();
@@ -1258,6 +1301,12 @@
         }
 
         if (sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestActivity_noHistory,
+                false)) {
+            a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
+        }
+
+        if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState,
                 false)) {
             a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
@@ -1291,6 +1340,9 @@
             a.info.configChanges = sa.getInt(
                     com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
                     0);
+            a.info.softInputMode = sa.getInt(
+                    com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
+                    0);
         } else {
             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             a.info.configChanges = 0;
@@ -2002,6 +2054,12 @@
 
         // Additional data supplied by callers.
         public Object mExtras;
+        
+        /*
+         *  Applications hardware preferences
+         */
+        public final ArrayList<ConfigurationInfo> configPreferences =
+                new ArrayList<ConfigurationInfo>();
 
         public Package(String _name) {
             packageName = _name;
@@ -2031,7 +2089,7 @@
             metaData = clone.metaData;
         }
     }
-
+    
     public final static class Permission extends Component<IntentInfo> {
         public final PermissionInfo info;
         public boolean tree;
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index ee88c89..4b1e678 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -16,6 +16,10 @@
 
 package android.content.res;
 
+import com.google.android.collect.Lists;
+
+import com.android.internal.util.ArrayUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -30,8 +34,6 @@
 import java.lang.ref.WeakReference;
 import java.util.Arrays;
 
-import com.android.internal.util.ArrayUtils;
-
 /**
  *
  * Lets you map {@link android.view.View} state sets to colors.
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 78a90de..7e4b7ac 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -34,6 +34,12 @@
      */
     public Locale locale;
 
+    /**
+     * Locale should persist on setting
+     * @hide pending API council approval
+     */
+    public boolean userSetLocale;
+
     public static final int TOUCHSCREEN_UNDEFINED = 0;
     public static final int TOUCHSCREEN_NOTOUCH = 1;
     public static final int TOUCHSCREEN_STYLUS = 2;
@@ -60,14 +66,30 @@
     public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
     public static final int KEYBOARDHIDDEN_NO = 1;
     public static final int KEYBOARDHIDDEN_YES = 2;
+    /** Constant matching actual resource implementation. {@hide} */
+    public static final int KEYBOARDHIDDEN_SOFT = 3;
     
     /**
-     * A flag indicating whether the keyboard has been hidden.  This will
-     * be set on a device with a mechanism to hide the keyboard from the
-     * user, when that mechanism is closed.
+     * A flag indicating whether any keyboard is available.  Unlike
+     * {@link #hardKeyboardHidden}, this also takes into account a soft
+     * keyboard, so if the hard keyboard is hidden but there is soft
+     * keyboard available, it will be set to NO.  Value is one of:
+     * {@link #KEYBOARDHIDDEN_NO}, {@link #KEYBOARDHIDDEN_YES}.
      */
     public int keyboardHidden;
     
+    public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0;
+    public static final int HARDKEYBOARDHIDDEN_NO = 1;
+    public static final int HARDKEYBOARDHIDDEN_YES = 2;
+    
+    /**
+     * A flag indicating whether the hard keyboard has been hidden.  This will
+     * be set on a device with a mechanism to hide the keyboard from the
+     * user, when that mechanism is closed.  One of:
+     * {@link #HARDKEYBOARDHIDDEN_NO}, {@link #HARDKEYBOARDHIDDEN_YES}.
+     */
+    public int hardKeyboardHidden;
+    
     public static final int NAVIGATION_UNDEFINED = 0;
     public static final int NAVIGATION_NONAV = 1;
     public static final int NAVIGATION_DPAD = 2;
@@ -111,9 +133,11 @@
         if (o.locale != null) {
             locale = (Locale) o.locale.clone();
         }
+        userSetLocale = o.userSetLocale;
         touchscreen = o.touchscreen;
         keyboard = o.keyboard;
         keyboardHidden = o.keyboardHidden;
+        hardKeyboardHidden = o.hardKeyboardHidden;
         navigation = o.navigation;
         orientation = o.orientation;
     }
@@ -122,7 +146,7 @@
         return "{ scale=" + fontScale + " imsi=" + mcc + "/" + mnc
                 + " locale=" + locale
                 + " touch=" + touchscreen + " key=" + keyboard + "/"
-                + keyboardHidden
+                + keyboardHidden + "/" + hardKeyboardHidden
                 + " nav=" + navigation + " orien=" + orientation + " }";
     }
 
@@ -133,9 +157,11 @@
         fontScale = 1;
         mcc = mnc = 0;
         locale = Locale.getDefault();
+        userSetLocale = false;
         touchscreen = TOUCHSCREEN_UNDEFINED;
         keyboard = KEYBOARD_UNDEFINED;
         keyboardHidden = KEYBOARDHIDDEN_UNDEFINED;
+        hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
         navigation = NAVIGATION_UNDEFINED;
         orientation = ORIENTATION_UNDEFINED;
     }
@@ -173,6 +199,11 @@
             locale = delta.locale != null
                     ? (Locale) delta.locale.clone() : null;
         }
+        if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
+        {
+            userSetLocale = true;
+            changed |= ActivityInfo.CONFIG_LOCALE;
+        }
         if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
                 && touchscreen != delta.touchscreen) {
             changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
@@ -188,6 +219,11 @@
             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
             keyboardHidden = delta.keyboardHidden;
         }
+        if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
+                && hardKeyboardHidden != delta.hardKeyboardHidden) {
+            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
+            hardKeyboardHidden = delta.hardKeyboardHidden;
+        }
         if (delta.navigation != NAVIGATION_UNDEFINED
                 && navigation != delta.navigation) {
             changed |= ActivityInfo.CONFIG_NAVIGATION;
@@ -252,6 +288,10 @@
                 && keyboardHidden != delta.keyboardHidden) {
             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
         }
+        if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
+                && hardKeyboardHidden != delta.hardKeyboardHidden) {
+            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
+        }
         if (delta.navigation != NAVIGATION_UNDEFINED
                 && navigation != delta.navigation) {
             changed |= ActivityInfo.CONFIG_NAVIGATION;
@@ -298,9 +338,15 @@
             dest.writeString(locale.getCountry());
             dest.writeString(locale.getVariant());
         }
+        if(userSetLocale) {
+            dest.writeInt(1);
+        } else {
+            dest.writeInt(0);
+        }
         dest.writeInt(touchscreen);
         dest.writeInt(keyboard);
         dest.writeInt(keyboardHidden);
+        dest.writeInt(hardKeyboardHidden);
         dest.writeInt(navigation);
         dest.writeInt(orientation);
     }
@@ -327,9 +373,11 @@
             locale = new Locale(source.readString(), source.readString(),
                     source.readString());
         }
+        userSetLocale = (source.readInt()==1);
         touchscreen = source.readInt();
         keyboard = source.readInt();
         keyboardHidden = source.readInt();
+        hardKeyboardHidden = source.readInt();
         navigation = source.readInt();
         orientation = source.readInt();
     }
@@ -356,6 +404,8 @@
         if (n != 0) return n;
         n = this.keyboardHidden - that.keyboardHidden;
         if (n != 0) return n;
+        n = this.hardKeyboardHidden - that.hardKeyboardHidden;
+        if (n != 0) return n;
         n = this.navigation - that.navigation;
         if (n != 0) return n;
         n = this.orientation - that.orientation;
@@ -380,7 +430,7 @@
     public int hashCode() {
         return ((int)this.fontScale) + this.mcc + this.mnc
                 + this.locale.hashCode() + this.touchscreen
-                + this.keyboard + this.keyboardHidden + this.navigation
-                + this.orientation;
+                + this.keyboard + this.keyboardHidden + this.hardKeyboardHidden
+                + this.navigation + this.orientation;
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/res/PluralRules.java b/core/java/android/content/res/PluralRules.java
index 2d09ef0..2dce3c1 100644
--- a/core/java/android/content/res/PluralRules.java
+++ b/core/java/android/content/res/PluralRules.java
@@ -23,7 +23,7 @@
  * object has been integrated to android, we should switch to that.  For now, yuck-o.
  */
 
-abstract class PluralRule {
+abstract class PluralRules {
 
     static final int QUANTITY_OTHER = 0x0000;
     static final int QUANTITY_ZERO  = 0x0001;
@@ -37,7 +37,7 @@
     abstract int quantityForNumber(int n);
 
     final int attrForNumber(int n) {
-        return PluralRule.attrForQuantity(quantityForNumber(n));
+        return PluralRules.attrForQuantity(quantityForNumber(n));
     }
 
     static final int attrForQuantity(int quantity) {
@@ -69,7 +69,7 @@
         }
     }
 
-    static final PluralRule ruleForLocale(Locale locale) {
+    static final PluralRules ruleForLocale(Locale locale) {
         String lang = locale.getLanguage();
         if ("cs".equals(lang)) {
             if (cs == null) cs = new cs();
@@ -81,8 +81,8 @@
         }
     }
 
-    private static PluralRule cs;
-    private static class cs extends PluralRule {
+    private static PluralRules cs;
+    private static class cs extends PluralRules {
         int quantityForNumber(int n) {
             if (n == 1) {
                 return QUANTITY_ONE;
@@ -96,8 +96,8 @@
         }
     }
 
-    private static PluralRule en;
-    private static class en extends PluralRule {
+    private static PluralRules en;
+    private static class en extends PluralRules {
         int quantityForNumber(int n) {
             if (n == 1) {
                 return QUANTITY_ONE;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 1014eee..10eced6 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -17,9 +17,16 @@
 package android.content.res;
 
 
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Intent;
 import android.graphics.Movie;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
 import android.os.SystemProperties;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -27,6 +34,7 @@
 import android.util.SparseArray;
 import android.util.TypedValue;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
 
@@ -70,7 +78,7 @@
     /*package*/ final AssetManager mAssets;
     private final Configuration mConfiguration = new Configuration();
     /*package*/ final DisplayMetrics mMetrics = new DisplayMetrics();
-    PluralRule mPluralRule;
+    PluralRules mPluralRule;
     
     /**
      * This exception is thrown by the resource APIs when a requested resource
@@ -157,24 +165,24 @@
      *         possibly styled text information.
      */
     public CharSequence getQuantityText(int id, int quantity) throws NotFoundException {
-        PluralRule rule = getPluralRule();
+        PluralRules rule = getPluralRule();
         CharSequence res = mAssets.getResourceBagText(id, rule.attrForNumber(quantity));
         if (res != null) {
             return res;
         }
-        res = mAssets.getResourceBagText(id, PluralRule.ID_OTHER);
+        res = mAssets.getResourceBagText(id, PluralRules.ID_OTHER);
         if (res != null) {
             return res;
         }
         throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
                 + " quantity=" + quantity
-                + " item=" + PluralRule.stringForQuantity(rule.quantityForNumber(quantity)));
+                + " item=" + PluralRules.stringForQuantity(rule.quantityForNumber(quantity)));
     }
 
-    private PluralRule getPluralRule() {
+    private PluralRules getPluralRule() {
         synchronized (mSync) {
             if (mPluralRule == null) {
-                mPluralRule = PluralRule.ruleForLocale(mConfiguration.locale);
+                mPluralRule = PluralRules.ruleForLocale(mConfiguration.locale);
             }
             return mPluralRule;
         }
@@ -573,6 +581,33 @@
     }
 
     /**
+     * Return a boolean associated with a particular resource ID.  This can be
+     * used with any integral resource value, and will return true if it is
+     * non-zero.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     *
+     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
+     *
+     * @return Returns the boolean value contained in the resource.
+     */
+    public boolean getBoolean(int id) throws NotFoundException {
+        synchronized (mTmpValue) {
+            TypedValue value = mTmpValue;
+            getValue(id, value, true);
+            if (value.type >= TypedValue.TYPE_FIRST_INT
+                && value.type <= TypedValue.TYPE_LAST_INT) {
+                return value.data != 0;
+            }
+            throw new NotFoundException(
+                "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
+                + Integer.toHexString(value.type) + " is not valid");
+        }
+    }
+
+    /**
      * Return an integer associated with a particular resource ID.
      *
      * @param id The desired resource identifier, as generated by the aapt
@@ -1157,12 +1192,18 @@
                 width = mMetrics.heightPixels;
                 height = mMetrics.widthPixels;
             }
+            int keyboardHidden = mConfiguration.keyboardHidden;
+            if (keyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO
+                    && mConfiguration.hardKeyboardHidden
+                            == Configuration.HARDKEYBOARDHIDDEN_YES) {
+                keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
+            }
             mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
                     locale, mConfiguration.orientation,
                     mConfiguration.touchscreen,
                     (int)(mMetrics.density*160), mConfiguration.keyboard,
-                    mConfiguration.keyboardHidden,
-                    mConfiguration.navigation, width, height, sSdkVersion);
+                    keyboardHidden, mConfiguration.navigation, width, height,
+                    sSdkVersion);
             int N = mDrawableCache.size();
             if (DEBUG_CONFIG) {
                 Log.d(TAG, "Cleaning up drawables config changes: 0x"
@@ -1198,12 +1239,26 @@
         }
         synchronized (mSync) {
             if (mPluralRule != null) {
-                mPluralRule = PluralRule.ruleForLocale(config.locale);
+                mPluralRule = PluralRules.ruleForLocale(config.locale);
             }
         }
     }
 
     /**
+     * Update the system resources configuration if they have previously
+     * been initialized.
+     *
+     * @hide
+     */
+    public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics) {
+        if (mSystem != null) {
+            mSystem.updateConfiguration(config, metrics);
+            //Log.i(TAG, "Updated system resources " + mSystem
+            //        + ": " + mSystem.getConfiguration());
+        }
+    }
+
+    /**
      * Return the current display metrics that are in effect for this resource 
      * object.  The returned object should be treated as read-only.
      * 
@@ -1330,6 +1385,102 @@
     }
     
     /**
+     * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
+     * an XML file.  You call this when you are at the parent tag of the
+     * extra tags, and it return once all of the child tags have been parsed.
+     * This will call {@link #parseBundleExtra} for each extra tag encountered.
+     * 
+     * @param parser The parser from which to retrieve the extras.
+     * @param outBundle A Bundle in which to place all parsed extras.
+     * @throws XmlPullParserException
+     * @throws IOException
+     */
+    public void parseBundleExtras(XmlResourceParser parser, Bundle outBundle)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+               && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            
+            String nodeName = parser.getName();
+            if (nodeName.equals("extra")) {
+                parseBundleExtra("extra", parser, outBundle);
+                XmlUtils.skipCurrentTag(parser);
+
+            } else {
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }        
+    }
+    
+    /**
+     * Parse a name/value pair out of an XML tag holding that data.  The
+     * AttributeSet must be holding the data defined by
+     * {@link android.R.styleable#Extra}.  The following value types are supported:
+     * <ul>
+     * <li> {@link TypedValue#TYPE_STRING}:
+     * {@link Bundle#putCharSequence Bundle.putCharSequence()}
+     * <li> {@link TypedValue#TYPE_INT_BOOLEAN}:
+     * {@link Bundle#putCharSequence Bundle.putBoolean()}
+     * <li> {@link TypedValue#TYPE_FIRST_INT}-{@link TypedValue#TYPE_LAST_INT}:
+     * {@link Bundle#putCharSequence Bundle.putBoolean()}
+     * <li> {@link TypedValue#TYPE_FLOAT}:
+     * {@link Bundle#putCharSequence Bundle.putFloat()}
+     * </ul>
+     * 
+     * @param tagName The name of the tag these attributes come from; this is
+     * only used for reporting error messages.
+     * @param attrs The attributes from which to retrieve the name/value pair.
+     * @param outBundle The Bundle in which to place the parsed value.
+     * @throws XmlPullParserException If the attributes are not valid.
+     */
+    public void parseBundleExtra(String tagName, AttributeSet attrs,
+            Bundle outBundle) throws XmlPullParserException {
+        TypedArray sa = obtainAttributes(attrs,
+                com.android.internal.R.styleable.Extra);
+
+        String name = sa.getString(
+                com.android.internal.R.styleable.Extra_name);
+        if (name == null) {
+            sa.recycle();
+            throw new XmlPullParserException("<" + tagName
+                    + "> requires an android:name attribute at "
+                    + attrs.getPositionDescription());
+        }
+
+        TypedValue v = sa.peekValue(
+                com.android.internal.R.styleable.Extra_value);
+        if (v != null) {
+            if (v.type == TypedValue.TYPE_STRING) {
+                CharSequence cs = v.coerceToString();
+                outBundle.putCharSequence(name, cs);
+            } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
+                outBundle.putBoolean(name, v.data != 0);
+            } else if (v.type >= TypedValue.TYPE_FIRST_INT
+                    && v.type <= TypedValue.TYPE_LAST_INT) {
+                outBundle.putInt(name, v.data);
+            } else if (v.type == TypedValue.TYPE_FLOAT) {
+                outBundle.putFloat(name, v.getFloat());
+            } else {
+                sa.recycle();
+                throw new XmlPullParserException("<" + tagName
+                        + "> only supports string, integer, float, color, and boolean at "
+                        + attrs.getPositionDescription());
+            }
+        } else {
+            sa.recycle();
+            throw new XmlPullParserException("<" + tagName
+                    + "> requires an android:value or android:resource attribute at "
+                    + attrs.getPositionDescription());
+        }
+
+        sa.recycle();
+    }
+    
+    /**
      * Retrieve underlying AssetManager storage for these resources.
      */
     public final AssetManager getAssets() {
diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index da32cc8..3df7708 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -96,6 +96,7 @@
                     mStyleIDs.subId = nativeIndexOfString(mNative, "sub");
                     mStyleIDs.strikeId = nativeIndexOfString(mNative, "strike");
                     mStyleIDs.listItemId = nativeIndexOfString(mNative, "li");
+                    mStyleIDs.marqueeId = nativeIndexOfString(mNative, "marquee");
 
                     if (localLOGV) Log.v(TAG, "BoldId=" + mStyleIDs.boldId
                             + ", ItalicId=" + mStyleIDs.italicId
@@ -127,6 +128,7 @@
         private int supId;
         private int strikeId;
         private int listItemId;
+        private int marqueeId;
     }
 
     private CharSequence applyStyles(String str, int[] style, StyleIDs ids) {
@@ -179,6 +181,10 @@
                 buffer.setSpan(new BulletSpan(10),
                                style[i+1], style[i+2]+1,
                                Spannable.SPAN_PARAGRAPH);
+            } else if (type == ids.marqueeId) {
+                buffer.setSpan(TextUtils.TruncateAt.MARQUEE,
+                               style[i+1], style[i+2]+1,
+                               Spannable.SPAN_INCLUSIVE_INCLUSIVE);
             } else {
                 String tag = nativeGetString(mNative, type);
 
@@ -216,6 +222,15 @@
                                        style[i+1], style[i+2]+1,
                                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                     }
+                } else if (tag.startsWith("a;")) {
+                    String sub;
+
+                    sub = subtag(tag, ";href=");
+                    if (sub != null) {
+                        buffer.setSpan(new URLSpan(sub),
+                                       style[i+1], style[i+2]+1,
+                                       Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    }
                 }
             }
 
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index e81f7f8..76f0860 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -21,6 +21,10 @@
 import android.util.Config;
 import android.util.Log;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
 
 import java.lang.ref.WeakReference;
 import java.lang.UnsupportedOperationException;
@@ -457,9 +461,24 @@
             mContentObservable.unregisterObserver(observer);
         }
     }
-
+    
+    /**
+     * @hide pending API council approval
+     */
+    protected void notifyDataSetChange() {
+        mDataSetObservable.notifyChanged();
+    }
+    
+    /**
+     * @hide pending API council approval
+     */
+    protected DataSetObservable getDataSetObservable() {
+        return mDataSetObservable;
+        
+    }
     public void registerDataSetObserver(DataSetObserver observer) {
         mDataSetObservable.registerObserver(observer);
+        
     }
 
     public void unregisterDataSetObserver(DataSetObserver observer) {
diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java
index 1ec4312..4ac0aef 100644
--- a/core/java/android/database/AbstractWindowedCursor.java
+++ b/core/java/android/database/AbstractWindowedCursor.java
@@ -172,7 +172,7 @@
         super.checkPosition();
         
         if (mWindow == null) {
-            throw new StaleDataException("This cursor has changed, you must call requery()");
+            throw new StaleDataException("Access closed cursor");
         }
     }
 
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 72dc3a9..8e26730 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -409,8 +409,13 @@
      * change across a call to clear().
      */
     public void clear() {
-        mStartPos = 0;
-        native_clear();
+        acquireReference();
+        try {
+            mStartPos = 0;        
+            native_clear();
+        } finally {
+            releaseReference();
+        }
     }
 
     /** Clears out the native side of things */
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index ab0dc3f7..2ff7294 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -241,6 +241,21 @@
     }
     
     /**
+     * Concatenates two SQL WHERE clauses, handling empty or null values.
+     * @hide
+     */
+    public static String concatenateWhere(String a, String b) {
+        if (TextUtils.isEmpty(a)) {
+            return b;
+        }
+        if (TextUtils.isEmpty(b)) {
+            return a;
+        }
+            
+        return "(" + a + ") AND (" + b + ")";
+    }
+    
+    /**
      * return the collation key 
      * @param name
      * @return the collation key
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index ae2fc95..70b9b83 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -18,7 +18,12 @@
 
 import android.database.AbstractWindowedCursor;
 import android.database.CursorWindow;
+import android.database.DataSetObserver;
 import android.database.SQLException;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.Process;
 import android.text.TextUtils;
 import android.util.Config;
 import android.util.Log;
@@ -26,6 +31,7 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * A Cursor implementation that exposes results from a query on a
@@ -59,7 +65,131 @@
     /** Used to find out where a cursor was allocated in case it never got
      * released. */
     private StackTraceElement[] mStackTraceElements;
-
+    
+    /** 
+     *  mMaxRead is the max items that each cursor window reads 
+     *  default to a very high value
+     */
+    private int mMaxRead = Integer.MAX_VALUE;
+    private int mInitialRead = Integer.MAX_VALUE;
+    private int mCursorState = 0;
+    private ReentrantLock mLock = null;
+    private boolean mPendingData = false;
+    
+    /**
+     *  support for a cursor variant that doesn't always read all results
+     *  initialRead is the initial number of items that cursor window reads 
+     *  if query contains more than this number of items, a thread will be
+     *  created and handle the left over items so that caller can show 
+     *  results as soon as possible 
+     * @param initialRead initial number of items that cursor read
+     * @param maxRead leftover items read at maxRead items per time
+     * @hide
+     */
+    public void setLoadStyle(int initialRead, int maxRead) {
+        mMaxRead = maxRead;
+        mInitialRead = initialRead;
+        mLock = new ReentrantLock(true);
+    }
+    
+    private void queryThreadLock() {
+        if (mLock != null) {
+            mLock.lock();            
+        }
+    }
+    
+    private void queryThreadUnlock() {
+        if (mLock != null) {
+            mLock.unlock();            
+        }
+    }
+    
+    
+    /**
+     * @hide
+     */
+    final private class QueryThread implements Runnable {
+        private final int mThreadState;
+        QueryThread(int version) {
+            mThreadState = version;
+        }
+        private void sendMessage() {
+            if (mNotificationHandler != null) {
+                mNotificationHandler.sendEmptyMessage(1);
+                mPendingData = false;
+            } else {
+                mPendingData = true;
+            }
+            
+        }
+        public void run() {
+             // use cached mWindow, to avoid get null mWindow
+            CursorWindow cw = mWindow;
+            Process.setThreadPriority(Process.myTid(), Process.THREAD_PRIORITY_BACKGROUND);
+            // the cursor's state doesn't change
+            while (true) {
+                mLock.lock();
+                if (mCursorState != mThreadState) {
+                    mLock.unlock();
+                    break;
+                }
+                try {
+                    int count = mQuery.fillWindow(cw, mMaxRead, mCount);
+                    // return -1 means not finished
+                    if (count != 0) {
+                        if (count == NO_COUNT){
+                            mCount += mMaxRead;
+                            sendMessage();
+                        } else {                                
+                            mCount = count;
+                            sendMessage();
+                            break;
+                        }
+                    } else {
+                        break;
+                    }
+                } catch (Exception e) {
+                    // end the tread when the cursor is close
+                    break;
+                } finally {
+                    mLock.unlock();
+                }
+            }
+        }        
+    }
+    
+    /**
+     * @hide
+     */   
+    protected class MainThreadNotificationHandler extends Handler {
+        public void handleMessage(Message msg) {
+            notifyDataSetChange();
+        }
+    }
+    
+    /**
+     * @hide
+     */
+    protected MainThreadNotificationHandler mNotificationHandler;    
+    
+    public void registerDataSetObserver(DataSetObserver observer) {
+        super.registerDataSetObserver(observer);
+        if ((Integer.MAX_VALUE != mMaxRead || Integer.MAX_VALUE != mInitialRead) && 
+                mNotificationHandler == null) {
+            queryThreadLock();
+            try {
+                mNotificationHandler = new MainThreadNotificationHandler();
+                if (mPendingData) {
+                    notifyDataSetChange();
+                    mPendingData = false;
+                }
+            } finally {
+                queryThreadUnlock();
+            }
+        }
+        
+    }
+    
     /**
      * Execute a query and provide access to its result set through a Cursor
      * interface. For a query such as: {@code SELECT name, birth, phone FROM
@@ -146,11 +276,22 @@
             // If there isn't a window set already it will only be accessed locally
             mWindow = new CursorWindow(true /* the window is local only */);
         } else {
-            mWindow.clear();
+            mCursorState++;
+                queryThreadLock();
+                try {
+                    mWindow.clear();
+                } finally {
+                    queryThreadUnlock();
+                }
         }
-
-        // mWindow must be cleared
-        mCount = mQuery.fillWindow(mWindow, startPos);
+        mWindow.setStartPosition(startPos);
+        mCount = mQuery.fillWindow(mWindow, mInitialRead, 0);
+        // return -1 means not finished
+        if (mCount == NO_COUNT){
+            mCount = startPos + mInitialRead;
+            Thread t = new Thread(new QueryThread(mCursorState), "query thread");
+            t.start();
+        } 
     }
 
     @Override
@@ -344,6 +485,7 @@
 
     private void deactivateCommon() {
         if (Config.LOGV) Log.v(TAG, "<<< Releasing cursor " + this);
+        mCursorState = 0;
         if (mWindow != null) {
             mWindow.close();
             mWindow = null;
@@ -368,6 +510,9 @@
 
     @Override
     public boolean requery() {
+        if (isClosed()) {
+            return false;
+        }
         long timeStart = 0;
         if (Config.LOGV) {
             timeStart = System.currentTimeMillis();
@@ -385,8 +530,13 @@
             // This one will recreate the temp table, and get its count
             mDriver.cursorRequeried(this);
             mCount = NO_COUNT;
-            // Requery the program that runs over the temp table
-            mQuery.requery();
+            mCursorState++;
+            queryThreadLock();
+            try {
+                mQuery.requery();
+            } finally {
+                queryThreadUnlock();
+            }
         } finally {
             mDatabase.unlock();
         }
@@ -405,9 +555,15 @@
     }
 
     @Override
-    public void setWindow(CursorWindow window) {
+    public void setWindow(CursorWindow window) {        
         if (mWindow != null) {
-            mWindow.close();
+            mCursorState++;
+            queryThreadLock();
+            try {
+                mWindow.close();
+            } finally {
+                queryThreadUnlock();
+            }
             mCount = NO_COUNT;
         }
         mWindow = window;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index e497190..fa062c8 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -54,6 +54,69 @@
     private final static String TAG = "Database";
 
     /**
+     * Algorithms used in ON CONFLICT clause
+     * http://www.sqlite.org/lang_conflict.html
+     * @hide
+     */
+    public enum ConflictAlgorithm {
+        /**
+         *  When a constraint violation occurs, an immediate ROLLBACK occurs, 
+         * thus ending the current transaction, and the command aborts with a 
+         * return code of SQLITE_CONSTRAINT. If no transaction is active 
+         * (other than the implied transaction that is created on every command)
+         *  then this algorithm works the same as ABORT.
+         */
+        ROLLBACK("ROLLBACK"),
+        
+        /**
+         * When a constraint violation occurs,no ROLLBACK is executed 
+         * so changes from prior commands within the same transaction 
+         * are preserved. This is the default behavior.
+         */
+        ABORT("ABORT"),
+        
+        /**
+         * When a constraint violation occurs, the command aborts with a return 
+         * code SQLITE_CONSTRAINT. But any changes to the database that 
+         * the command made prior to encountering the constraint violation 
+         * are preserved and are not backed out.
+         */
+        FAIL("FAIL"),
+        
+        /**
+         * When a constraint violation occurs, the one row that contains 
+         * the constraint violation is not inserted or changed. 
+         * But the command continues executing normally. Other rows before and 
+         * after the row that contained the constraint violation continue to be 
+         * inserted or updated normally. No error is returned.
+         */
+        IGNORE("IGNORE"),
+        
+        /**
+         * When a UNIQUE constraint violation occurs, the pre-existing rows that
+         * are causing the constraint violation are removed prior to inserting 
+         * or updating the current row. Thus the insert or update always occurs.
+         * The command continues executing normally. No error is returned. 
+         * If a NOT NULL constraint violation occurs, the NULL value is replaced
+         * by the default value for that column. If the column has no default 
+         * value, then the ABORT algorithm is used. If a CHECK constraint 
+         * violation occurs then the IGNORE algorithm is used. When this conflict 
+         * resolution strategy deletes rows in order to satisfy a constraint, 
+         * it does not invoke delete triggers on those rows.
+         *  This behavior might change in a future release.
+         */
+        REPLACE("REPLACE");
+        
+        private final String mValue;
+        ConflictAlgorithm(String value) {
+            mValue = value;
+        }
+        public String value() {
+            return mValue;
+        }
+    }
+    
+    /**
      * Maximum Length Of A LIKE Or GLOB Pattern
      * The pattern matching algorithm used in the default LIKE and GLOB implementation
      * of SQLite can exhibit O(N^2) performance (where N is the number of characters in
@@ -437,8 +500,26 @@
      * successful so far. Do not call setTransactionSuccessful before calling this. When this
      * returns a new transaction will have been created but not marked as successful.
      * @return true if the transaction was yielded
+     * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
+     *   will not be yielded. Use yieldIfContendedSafely instead.
      */
     public boolean yieldIfContended() {
+        return yieldIfContendedHelper(false /* do not check yielding */);
+    }
+
+    /**
+     * Temporarily end the transaction to let other threads run. The transaction is assumed to be
+     * successful so far. Do not call setTransactionSuccessful before calling this. When this
+     * returns a new transaction will have been created but not marked as successful. This assumes
+     * that there are no nested transactions (beginTransaction has only been called once) and will
+     * through an exception if that is not the case.
+     * @return true if the transaction was yielded
+     */
+    public boolean yieldIfContendedSafely() {
+        return yieldIfContendedHelper(true /* check yielding */);
+    }
+
+    private boolean yieldIfContendedHelper(boolean checkFullyYielded) {
         if (mLock.getQueueLength() == 0) {
             // Reset the lock acquire time since we know that the thread was willing to yield
             // the lock at this time.
@@ -448,6 +529,12 @@
         }
         setTransactionSuccessful();
         endTransaction();
+        if (checkFullyYielded) {
+            if (this.isDbLockedByCurrentThread()) {
+                throw new IllegalStateException(
+                        "Db locked more than once. yielfIfContended cannot yield");
+            }
+        }
         beginTransaction();
         return true;
     }
@@ -1031,6 +1118,28 @@
     }
 
     /**
+     * Runs the provided SQL and returns a cursor over the result set.
+     * The cursor will read an initial set of rows and the return to the caller. 
+     * It will continue to read in batches and send data changed notifications 
+     * when the later batches are ready.
+     * @param sql the SQL query. The SQL string must not be ; terminated
+     * @param selectionArgs You may include ?s in where clause in the query,
+     *     which will be replaced by the values from selectionArgs. The
+     *     values will be bound as Strings.
+     * @param initialRead set the initial count of items to read from the cursor
+     * @param maxRead set the count of items to read on each iteration after the first
+     * @return A {@link Cursor} object, which is positioned before the first entry
+     * @hide pending API council approval
+     */
+    public Cursor rawQuery(String sql, String[] selectionArgs, 
+            int initialRead, int maxRead) {
+        SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
+                null, sql, selectionArgs, null);
+        c.setLoadStyle(initialRead, maxRead);
+        return c;
+    }
+    
+    /**
      * Convenience method for inserting a row into the database.
      *
      * @param table the table to insert the row into
@@ -1044,7 +1153,7 @@
      */
     public long insert(String table, String nullColumnHack, ContentValues values) {
         try {
-            return insertOrReplace(table, nullColumnHack, values, false);
+            return insertWithOnConflict(table, nullColumnHack, values, null);
         } catch (SQLException e) {
             Log.e(TAG, "Error inserting " + values, e);
             return -1;
@@ -1066,7 +1175,7 @@
      */
     public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
             throws SQLException {
-        return insertOrReplace(table, nullColumnHack, values, false) ;
+        return insertWithOnConflict(table, nullColumnHack, values, null);
     }
 
     /**
@@ -1082,7 +1191,8 @@
      */
     public long replace(String table, String nullColumnHack, ContentValues initialValues) {
         try {
-            return insertOrReplace(table, nullColumnHack, initialValues, true);
+            return insertWithOnConflict(table, nullColumnHack, initialValues, 
+                    ConflictAlgorithm.REPLACE);
         } catch (SQLException e) {
             Log.e(TAG, "Error inserting " + initialValues, e);
             return -1;
@@ -1103,22 +1213,38 @@
      */
     public long replaceOrThrow(String table, String nullColumnHack,
             ContentValues initialValues) throws SQLException {
-        return insertOrReplace(table, nullColumnHack, initialValues, true);
+        return insertWithOnConflict(table, nullColumnHack, initialValues, 
+                ConflictAlgorithm.REPLACE);
     }
 
-    private long insertOrReplace(String table, String nullColumnHack,
-            ContentValues initialValues, boolean allowReplace) {
+    /**
+     * General method for inserting a row into the database.
+     *
+     * @param table the table to insert the row into
+     * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
+     *            so if initialValues is empty this column will explicitly be
+     *            assigned a NULL value
+     * @param initialValues this map contains the initial column values for the
+     *            row. The keys should be the column names and the values the
+     *            column values
+     * @param algorithm  {@link ConflictAlgorithm} for insert conflict resolver
+     * @return the row ID of the newly inserted row, or -1 if an error occurred
+     * @hide
+     */
+    public long insertWithOnConflict(String table, String nullColumnHack,
+            ContentValues initialValues, ConflictAlgorithm algorithm) {
         if (!isOpen()) {
             throw new IllegalStateException("database not open");
         }
 
         // Measurements show most sql lengths <= 152
         StringBuilder sql = new StringBuilder(152);
-        sql.append("INSERT ");
-        if (allowReplace) {
-            sql.append("OR REPLACE ");
+        sql.append("INSERT");
+        if (algorithm != null) {
+            sql.append(" OR ");
+            sql.append(algorithm.value());
         }
-        sql.append("INTO ");
+        sql.append(" INTO ");
         sql.append(table);
         // Measurements show most values lengths < 40
         StringBuilder values = new StringBuilder(40);
@@ -1241,6 +1367,23 @@
      * @return the number of rows affected
      */
     public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
+        return updateWithOnConflict(table, values, whereClause, whereArgs, null);
+    }
+    
+    /**
+     * Convenience method for updating rows in the database.
+     *
+     * @param table the table to update in
+     * @param values a map from column names to new column values. null is a
+     *            valid value that will be translated to NULL.
+     * @param whereClause the optional WHERE clause to apply when updating.
+     *            Passing null will update all rows.
+     * @param algorithm  {@link ConflictAlgorithm} for update conflict resolver
+     * @return the number of rows affected
+     * @hide
+     */
+    public int updateWithOnConflict(String table, ContentValues values, 
+            String whereClause, String[] whereArgs, ConflictAlgorithm algorithm) {
         if (!isOpen()) {
             throw new IllegalStateException("database not open");
         }
@@ -1251,6 +1394,11 @@
 
         StringBuilder sql = new StringBuilder(120);
         sql.append("UPDATE ");
+        if (algorithm != null) {
+            sql.append(" OR ");
+            sql.append(algorithm.value());
+        }
+        
         sql.append(table);
         sql.append(" SET ");
 
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index f6872ac..35bf645 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -26,8 +26,6 @@
  * optionally {@link #onOpen}, and this class takes care of opening the database
  * if it exists, creating it if it does not, and upgrading it as necessary.
  * Transactions are used to make sure the database is always in a sensible state.
- *
- * @see com.google.provider.NotePad.NotePadProvider
  */
 public abstract class SQLiteOpenHelper {
     private static final String TAG = SQLiteOpenHelper.class.getSimpleName();
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index e0341a2..f89c87d 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -239,7 +239,9 @@
                     Log.d(TAG, "      " + ste);
                 }
             }
-            onAllReferencesReleased();
+            // when in finalize() it is already removed from weakhashmap
+            // so it is safe to not removed itself from db
+            onAllReferencesReleasedFromContainer();
         }
     }
 
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index 40855b6..22c53ab 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -40,9 +40,8 @@
      * Create a persistent query object.
      * 
      * @param db The database that this query object is associated with
-     * @param query The SQL string for this query. It must include "INDEX -1
-     *            OFFSET ?" at the end
-     * @param offsetIndex The 1-based index to the OFFSET parameter
+     * @param query The SQL string for this query. 
+     * @param offsetIndex The 1-based index to the OFFSET parameter, 
      */
     /* package */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs) {
         super(db, query);
@@ -59,24 +58,28 @@
      * @param startPos The position to start reading rows from
      * @return number of total rows in the query
      */
-    /* package */ int fillWindow(CursorWindow window, int startPos) {
-        if (startPos < 0) {
-            throw new IllegalArgumentException("startPos should > 0");
-        }
-        window.setStartPosition(startPos);
+    /* package */ int fillWindow(CursorWindow window,  
+            int maxRead, int lastPos) {
         mDatabase.lock();
         try {
             acquireReference();
-            window.acquireReference();
-            return native_fill_window(window, startPos, mOffsetIndex);
-        } catch (IllegalStateException e){
-            // simply ignore it
-            return 0;
-        } catch (SQLiteDatabaseCorruptException e) {
-            mDatabase.onCorruption();
-            throw e;
+            try {
+                window.acquireReference();
+                // if the start pos is not equal to 0, then most likely window is 
+                // too small for the data set, loading by another thread
+                // is not safe in this situation. the native code will ignore maxRead
+                return native_fill_window(window, window.getStartPosition(), mOffsetIndex, 
+                        maxRead, lastPos);
+            } catch (IllegalStateException e){
+                // simply ignore it
+                return 0;
+            } catch (SQLiteDatabaseCorruptException e) {
+                mDatabase.onCorruption();
+                throw e;
+            } finally {
+                window.releaseReference();                
+            }
         } finally {
-            window.releaseReference();
             releaseReference();
             mDatabase.unlock();
         }
@@ -113,7 +116,13 @@
             releaseReference();
         }
     }
-
+    
+    /** {@hide pending API Council approval} */
+    @Override
+    public String toString() {
+        return "SQLiteQuery: " + mQuery;
+    }
+    
     @Override
     public void close() {
         super.close();
@@ -124,11 +133,6 @@
      * Called by SQLiteCursor when it is requeried.
      */
     /* package */ void requery() {
-        boolean oldMClosed = mClosed;
-        if (mClosed) {
-            mClosed = false;
-            compile(mQuery, false);
-        }
         if (mBindArgs != null) {
             int len = mBindArgs.length;
             try {
@@ -136,8 +140,7 @@
                     super.bindString(i + 1, mBindArgs[i]);
                 }
             } catch (SQLiteMisuseException e) {
-                StringBuilder errMsg = new StringBuilder
-                    ("old mClosed " + oldMClosed + " mQuery " + mQuery);
+                StringBuilder errMsg = new StringBuilder("mQuery " + mQuery);
                 for (int i = 0; i < len; i++) {
                     errMsg.append(" ");
                     errMsg.append(mBindArgs[i]);
@@ -174,7 +177,8 @@
         if (!mClosed) super.bindString(index, value);
     }
 
-    private final native int native_fill_window(CursorWindow window, int startPos, int offsetParam);
+    private final native int native_fill_window(CursorWindow window, 
+            int startPos, int offsetParam, int maxRead, int lastPos);
 
     private final native int native_column_count();
 
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 8330750..dc75748 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -18,6 +18,7 @@
 
 import java.lang.ref.WeakReference;
 import java.util.HashMap;
+import java.io.IOException;
 
 import android.util.Log;
 import android.view.Surface;
@@ -98,13 +99,28 @@
     }
 
     /**
+     * Reconnect to the camera after passing it to MediaRecorder. To save
+     * setup/teardown time, a client of Camara can pass an initialized Camera
+     * object to a MediaRecorder to use for video recording. Once the 
+     * MediaRecorder is done with the Camera, this method can be used to
+     * re-establish a connection with the camera hardware.
+     *
+     * @throws IOException if the method fails.
+     *
+     * FIXME: Unhide after approval
+     * @hide
+     */
+    public native final void reconnect() throws IOException;
+    
+    /**
      * Sets the SurfaceHolder to be used for a picture preview. If the surface
      * changed since the last call, the screen will blank. Nothing happens
      * if the same surface is re-set.
      * 
      * @param holder the SurfaceHolder upon which to place the picture preview
+     * @throws IOException if the method fails.
      */
-    public final void setPreviewDisplay(SurfaceHolder holder) {
+    public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {
         setPreviewDisplay(holder.getSurface());
     }
 
@@ -263,10 +279,19 @@
     };
 
     /**
-     * Registers a callback to be invoked when a picture is taken.
+     * Triggers an asynchronous image capture. The camera service
+     * will initiate a series of callbacks to the application as the
+     * image capture progresses. The shutter callback occurs after
+     * the image is captured. This can be used to trigger a sound
+     * to let the user know that image has been captured. The raw
+     * callback occurs when the raw image data is available. The jpeg
+     * callback occurs when the compressed image is available. If the
+     * application does not need a particular callback, a null can be
+     * passed instead of a callback method.
      * 
-     * @param raw  the callback to run for raw images, may be null
-     * @param jpeg the callback to run for jpeg images, may be null
+     * @param shutter   callback after the image is captured, may be null
+     * @param raw       callback with raw image data, may be null
+     * @param jpeg      callback with jpeg image data, may be null
      */
     public final void takePicture(ShutterCallback shutter, PictureCallback raw,
             PictureCallback jpeg) {
diff --git a/core/java/android/hardware/ISensorService.aidl b/core/java/android/hardware/ISensorService.aidl
index b6ac3ab..8aad9b4 100644
--- a/core/java/android/hardware/ISensorService.aidl
+++ b/core/java/android/hardware/ISensorService.aidl
@@ -26,5 +26,4 @@
 {
     ParcelFileDescriptor getDataChanel();
     boolean enableSensor(IBinder listener, int sensor, int enable);
-    oneway void reportAccuracy(int sensor, int value);
 }
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
new file mode 100644
index 0000000..0ce2f7b
--- /dev/null
+++ b/core/java/android/hardware/Sensor.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.hardware;
+
+/** 
+ * Class representing a sensor. Use {@link SensorManager#getSensorList}
+ * to get the list of available Sensors.
+ */
+public class Sensor {
+
+    /** 
+     * A constant describing an accelerometer sensor type.
+     * See {@link android.hardware.SensorEvent SensorEvent}
+     * for more details.
+     */
+    public static final int TYPE_ACCELEROMETER  = 1;
+
+    /** 
+     * A constant describing a magnetic field sensor type.
+     * See {@link android.hardware.SensorEvent SensorEvent}
+     * for more details.
+     */
+    public static final int TYPE_MAGNETIC_FIELD = 2;
+    
+    /** 
+     * A constant describing an orientation sensor type.
+     * See {@link android.hardware.SensorEvent SensorEvent}
+     * for more details.
+     */
+    public static final int TYPE_ORIENTATION    = 3;
+
+    /** A constant describing a gyroscope sensor type */
+    public static final int TYPE_GYROSCOPE      = 4;
+    /** A constant describing a light sensor type */
+    public static final int TYPE_LIGHT          = 5;
+    /** A constant describing a pressure sensor type */
+    public static final int TYPE_PRESSURE       = 6;
+    /** A constant describing a temperature sensor type */
+    public static final int TYPE_TEMPERATURE    = 7;
+    /** A constant describing a proximity sensor type */
+    public static final int TYPE_PROXIMITY      = 8;
+
+    
+    /** 
+     * A constant describing all sensor types.
+     */
+    public static final int TYPE_ALL             = -1;
+
+    /* Some of these fields are set only by the native bindings in 
+     * SensorManager.
+     */
+    private String  mName;
+    private String  mVendor;
+    private int     mVersion;
+    private int     mHandle;
+    private int     mType;
+    private float   mMaxRange;
+    private float   mResolution;
+    private float   mPower;
+    private int     mLegacyType;
+    
+    
+    Sensor() {
+    }
+
+    /**
+     * @return name string of the sensor.
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * @return vendor string of this sensor.
+     */
+    public String getVendor() {
+        return mVendor;
+    }
+    
+    /**
+     * @return generic type of this sensor.
+     */
+    public int getType() {
+        return mType;
+    }
+    
+    /**
+     * @return version of the sensor's module.
+     */
+    public int getVersion() {
+        return mVersion;
+    }
+    
+    /**
+     * @return maximum range of the sensor in the sensor's unit.
+     */
+    public float getMaximumRange() {
+        return mMaxRange;
+    }
+    
+    /**
+     * @return resolution of the sensor in the sensor's unit.
+     */
+    public float getResolution() {
+        return mResolution;
+    }
+    
+    /**
+     * @return the power in mA used by this sensor while in use
+     */
+    public float getPower() {
+        return mPower;
+    }
+    
+    int getHandle() {
+        return mHandle;
+    }
+    
+    void setRange(float max, float res) {
+        mMaxRange = max;
+        mResolution = res;
+    }
+    
+    void setLegacyType(int legacyType) {
+        mLegacyType = legacyType;
+    }
+
+    int getLegacyType() {
+        return mLegacyType;
+    }
+}
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
new file mode 100644
index 0000000..cf939c5
--- /dev/null
+++ b/core/java/android/hardware/SensorEvent.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+/**
+ * This class represents a sensor event and holds informations such as the
+ * sensor type (eg: accelerometer, orientation, etc...), the time-stamp, 
+ * accuracy and of course the sensor's {@link SensorEvent#values data}.
+ *
+ * <p><u>Definition of the coordinate system used by the SensorEvent API.</u><p>
+ * 
+ * <pre>
+ * The coordinate space is defined relative to the screen of the phone 
+ * in its default orientation. The axes are not swapped when the device's
+ * screen orientation changes.
+ * 
+ * The OpenGL ES coordinate system is used. The origin is in the
+ * lower-left corner  with respect to the screen, with the X axis horizontal
+ * and pointing  right, the Y axis vertical and pointing up and the Z axis
+ * pointing outside the front face of the screen. In this system, coordinates
+ * behind the screen have negative Z values.
+ * 
+ * <b>Note:</b> This coordinate system is different from the one used in the
+ * Android 2D APIs where the origin is in the top-left corner. 
+ *
+ *   x<0         x>0
+ *                ^
+ *                |
+ *    +-----------+-->  y>0
+ *    |           |
+ *    |           |
+ *    |           |
+ *    |           |   / z<0
+ *    |           |  /
+ *    |           | /
+ *    O-----------+/
+ *    |[]  [ ]  []/
+ *    +----------/+     y<0
+ *              /
+ *             /
+ *           |/ z>0 (toward the sky)
+ *
+ *    O: Origin (x=0,y=0,z=0)
+ * </pre>
+ */
+
+public class SensorEvent {
+    /**
+     * The length and contents of the values array vary depending on which
+     * sensor type is being monitored (see also {@link SensorEvent} for a 
+     * definition of the coordinate system used):
+     * 
+     * <p>{@link android.hardware.Sensor#TYPE_ORIENTATION Sensor.TYPE_ORIENTATION}:<p>
+     *  All values are angles in degrees.
+     * 
+     * <p>values[0]: Azimuth, angle between the magnetic north direction and
+     * the Y axis, around the Z axis (0 to 359). 
+     * 0=North, 90=East, 180=South, 270=West
+     * 
+     * <p>values[1]: Pitch, rotation around X axis (-180 to 180), 
+     * with positive values when the z-axis moves <b>toward</b> the y-axis.
+     *
+     * <p>values[2]: Roll, rotation around Y axis (-90 to 90), with 
+     * positive values  when the x-axis moves <b>away</b> from the z-axis.
+     * 
+     * <p><b>Note:</b> This definition is different from <b>yaw, pitch and 
+     * roll</b> used in aviation where the X axis is along the long side of
+     * the plane (tail to nose).
+     * 
+     * <p><b>Note:</b> It is preferable to use 
+     * {@link android.hardware.SensorManager#getRotationMatrix 
+     *      getRotationMatrix()} in conjunction with
+     * {@link android.hardware.SensorManager#remapCoordinateSystem 
+     *      remapCoordinateSystem()} and
+     * {@link android.hardware.SensorManager#getOrientation getOrientation()}
+     * to compute these values; while it may be more expensive, it is usually 
+     * more accurate.
+     *
+     * <p>{@link android.hardware.Sensor#TYPE_ACCELEROMETER Sensor.TYPE_ACCELEROMETER}:<p>
+     *  All values are in SI units (m/s^2) and measure the acceleration applied
+     *  to the phone minus the force of gravity.
+     *  
+     *  <p>values[0]: Acceleration minus Gx on the x-axis 
+     *  <p>values[1]: Acceleration minus Gy on the y-axis 
+     *  <p>values[2]: Acceleration minus Gz on the z-axis
+     *  
+     *  <p><u>Examples</u>:
+     *    <li>When the device lies flat on a table and is pushed on its left 
+     *    side toward the right, the x acceleration value is positive.</li>
+     *    
+     *    <li>When the device lies flat on a table, the acceleration value is 
+     *    +9.81, which correspond to the acceleration of the device (0 m/s^2) 
+     *    minus the force of gravity (-9.81 m/s^2).</li>
+     *    
+     *    <li>When the device lies flat on a table and is pushed toward the sky
+     *    with an acceleration of A m/s^2, the acceleration value is equal to 
+     *    A+9.81 which correspond to the acceleration of the 
+     *    device (+A m/s^2) minus the force of gravity (-9.81 m/s^2).</li>
+     * 
+     * 
+     * <p>{@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD Sensor.TYPE_MAGNETIC_FIELD}:<p>
+     *  All values are in micro-Tesla (uT) and measure the ambient magnetic
+     *  field in the X, Y and Z axis.
+     *  
+     */    
+    public final float[] values;
+
+    /**
+     * The sensor that generated this event.
+     * See {@link android.hardware.SensorManager SensorManager}
+     * for details.
+     */
+    public Sensor sensor;
+    
+    /**
+     * The accuracy of this event.
+     * See {@link android.hardware.SensorManager SensorManager}
+     * for details.
+     */
+    public int accuracy;
+    
+    
+    /**
+     * The time in nanosecond at which the event happened
+     */
+    public long timestamp;
+
+    
+    SensorEvent(int size) {
+        values = new float[size];
+    }
+}
diff --git a/core/java/android/hardware/SensorEventListener.java b/core/java/android/hardware/SensorEventListener.java
new file mode 100644
index 0000000..716d0d4
--- /dev/null
+++ b/core/java/android/hardware/SensorEventListener.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+/**
+ * Used for receiving notifications from the SensorManager when
+ * sensor values have changed.
+ */
+public interface SensorEventListener {
+
+    /**
+     * Called when sensor values have changed.
+     * <p>See {@link android.hardware.SensorManager SensorManager}
+     * for details on possible sensor types.
+     * <p>See also {@link android.hardware.SensorEvent SensorEvent}.
+     * 
+     * <p><b>NOTE:</b> The application doesn't own the
+     * {@link android.hardware.SensorEvent event}
+     * object passed as a parameter and therefore cannot hold on o it.
+     * The object may be part of an internal pool and may be reused by
+     * the framework.
+     *
+     * @param event the {@link android.hardware.SensorEvent SensorEvent}. 
+     */
+    public void onSensorChanged(SensorEvent event);
+
+    /**
+     * Called when the accuracy of a sensor has changed.
+     * <p>See {@link android.hardware.SensorManager SensorManager}
+     * for details.
+     *
+     * @param accuracy The new accuracy of this sensor
+     */
+    public void onAccuracyChanged(Sensor sensor, int accuracy);    
+}
diff --git a/core/java/android/hardware/SensorListener.java b/core/java/android/hardware/SensorListener.java
index d676a5e..cfa184b 100644
--- a/core/java/android/hardware/SensorListener.java
+++ b/core/java/android/hardware/SensorListener.java
@@ -19,18 +19,74 @@
 /**
  * Used for receiving notifications from the SensorManager when
  * sensor values have changed.
+ * 
+ * This interface is deprecated, use 
+ * {@link android.hardware.SensorEventListener SensorEventListener} instead.
+ * 
  */
+@Deprecated
 public interface SensorListener {
 
     /**
-     * Called when sensor values have changed.
+     * <p>Called when sensor values have changed.
      * The length and contents of the values array vary
      * depending on which sensor is being monitored.
      * See {@link android.hardware.SensorManager SensorManager}
-     * for details on possible sensor types and values.
+     * for details on possible sensor types.
      *
+     * <p><u>Definition of the coordinate system used below.</u><p>
+     * <p>The X axis refers to the screen's horizontal axis
+     * (the small edge in portrait mode, the long edge in landscape mode) and
+     * points to the right. 
+     * <p>The Y axis refers to the screen's vertical axis and points towards
+     * the top of the screen (the origin is in the lower-left corner).
+     * <p>The Z axis points toward the sky when the device is lying on its back
+     * on a table.
+     * <p> <b>IMPORTANT NOTE:</b> The axis <b><u>are swapped</u></b> when the
+     * device's screen orientation changes. To access the unswapped values,
+     * use indices 3, 4 and 5 in values[].
+     * 
+     * <p>{@link android.hardware.SensorManager#SENSOR_ORIENTATION SENSOR_ORIENTATION},
+     * {@link android.hardware.SensorManager#SENSOR_ORIENTATION_RAW SENSOR_ORIENTATION_RAW}:<p>
+     *  All values are angles in degrees.
+     * 
+     * <p>values[0]: Azimuth, rotation around the Z axis (0<=azimuth<360).
+     * 0 = North, 90 = East, 180 = South, 270 = West
+     * 
+     * <p>values[1]: Pitch, rotation around X axis (-180<=pitch<=180), with positive
+     * values when the z-axis moves toward the y-axis.
+     *
+     * <p>values[2]: Roll, rotation around Y axis (-90<=roll<=90), with positive values 
+     * when the z-axis moves toward the x-axis.
+     *
+     * <p>Note that this definition of yaw, pitch and roll is different from the
+     * traditional definition used in aviation where the X axis is along the long
+     * side of the plane (tail to nose).
+     *
+     * <p>{@link android.hardware.SensorManager#SENSOR_ACCELEROMETER SENSOR_ACCELEROMETER}:<p>
+     *  All values are in SI units (m/s^2) and measure contact forces.
+     *  
+     *  <p>values[0]: force applied by the device on the x-axis 
+     *  <p>values[1]: force applied by the device on the y-axis 
+     *  <p>values[2]: force applied by the device on the z-axis
+     *  
+     *  <p><u>Examples</u>:
+     *    <li>When the device is pushed on its left side toward the right, the
+     *    x acceleration value is negative (the device applies a reaction force
+     *    to the push toward the left)</li>
+     *    
+     *    <li>When the device lies flat on a table, the acceleration value is 
+     *    {@link android.hardware.SensorManager#STANDARD_GRAVITY -STANDARD_GRAVITY},
+     *    which correspond to the force the device applies on the table in reaction
+     *    to gravity.</li>
+     *
+     * <p>{@link android.hardware.SensorManager#SENSOR_MAGNETIC_FIELD SENSOR_MAGNETIC_FIELD}:<p>
+     *  All values are in micro-Tesla (uT) and measure the ambient magnetic
+     *  field in the X, Y and -Z axis.
+     *  <p><b><u>Note:</u></b> the magnetic field's Z axis is inverted.
+     *  
      * @param sensor The ID of the sensor being monitored
-     * @param values The new values for the sensor
+     * @param values The new values for the sensor.
      */
     public void onSensorChanged(int sensor, float[] values);
 
@@ -40,7 +96,7 @@
      * for details.
      *
      * @param sensor The ID of the sensor being monitored
-     * @param accuracy The new accuracy of this sensor
+     * @param accuracy The new accuracy of this sensor.
      */
     public void onAccuracyChanged(int sensor, int accuracy);    
 }
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 9b88fff..f02094e 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -26,6 +26,7 @@
 import android.os.Message;
 import android.os.ServiceManager;
 import android.util.Log;
+import android.util.SparseArray;
 import android.view.IRotationWatcher;
 import android.view.IWindowManager;
 import android.view.Surface;
@@ -33,7 +34,9 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
 
 /**
  * Class that lets you access the device's sensors. Get an instance of this
@@ -43,126 +46,119 @@
 public class SensorManager extends IRotationWatcher.Stub
 {
     private static final String TAG = "SensorManager";
+    private static final float[] mTempMatrix = new float[16];
 
-    /** NOTE: sensor IDs must be a power of 2 */
+    /* NOTE: sensor IDs must be a power of 2 */
 
-    /** A constant describing an orientation sensor.
-     * Sensor values are yaw, pitch and roll
-     *
-     * Yaw is the compass heading in degrees, range [0, 360[
-     * 0 = North, 90 = East, 180 = South, 270 = West
-     *
-     * Pitch indicates the tilt of the top of the device,
-     * with range -90 to 90.
-     * Positive values indicate that the bottom of the device is tilted up
-     * and negative values indicate the top of the device is tilted up.
-     *
-     * Roll indicates the side to side tilt of the device,
-     * with range -90 to 90.
-     * Positive values indicate that the left side of the device is tilted up
-     * and negative values indicate the right side of the device is tilted up.
+    /**
+     * A constant describing an orientation sensor.
+     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
+    @Deprecated
     public static final int SENSOR_ORIENTATION = 1 << 0;
 
-    /** A constant describing an accelerometer.
-     * Sensor values are acceleration in the X, Y and Z axis,
-     * where the X axis has positive direction toward the right side of the device,
-     * the Y axis has positive direction toward the top of the device
-     * and the Z axis has positive direction toward the front of the device.
-     *
-     * The direction of the force of gravity is indicated by acceleration values in the
-     * X, Y and Z axes.  The typical case where the device is flat relative to the surface
-     * of the Earth appears as -STANDARD_GRAVITY in the Z axis
-     * and X and Z values close to zero.
-     *
-     * Acceleration values are given in SI units (m/s^2)
-     *
+    /**
+     * A constant describing an accelerometer.
+     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
+    @Deprecated
     public static final int SENSOR_ACCELEROMETER = 1 << 1;
 
-    /** A constant describing a temperature sensor
-     * Only the first value is defined for this sensor and it
-     * contains the ambient temperature in degree C.
+    /**
+     * A constant describing a temperature sensor
+     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
+    @Deprecated
     public static final int SENSOR_TEMPERATURE = 1 << 2;
 
-    /** A constant describing a magnetic sensor
-     * Sensor values are the magnetic vector in the X, Y and Z axis,
-     * where the X axis has positive direction toward the right side of the device,
-     * the Y axis has positive direction toward the top of the device
-     * and the Z axis has positive direction toward the front of the device.
-     * 
-     * Magnetic values are given in micro-Tesla (uT)
-     * 
+    /**
+     * A constant describing a magnetic sensor
+     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
+    @Deprecated
     public static final int SENSOR_MAGNETIC_FIELD = 1 << 3;
 
-    /** A constant describing an ambient light sensor
-     * Only the first value is defined for this sensor and it contains
-     * the ambient light measure in lux.
-     * 
+    /**
+     * A constant describing an ambient light sensor
+     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
+    @Deprecated
     public static final int SENSOR_LIGHT = 1 << 4;
 
-    /** A constant describing a proximity sensor
-     * Only the first value is defined for this sensor and it contains
-     * the distance between the sensor and the object in meters (m)
+    /**
+     * A constant describing a proximity sensor
+     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
+    @Deprecated
     public static final int SENSOR_PROXIMITY = 1 << 5;
 
-    /** A constant describing a Tricorder
-     * When this sensor is available and enabled, the device can be
-     * used as a fully functional Tricorder. All values are returned in 
-     * SI units.
+    /**
+     * A constant describing a Tricorder
+     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
+    @Deprecated
     public static final int SENSOR_TRICORDER = 1 << 6;
 
-    /** A constant describing an orientation sensor.
-     * Sensor values are yaw, pitch and roll
-     *
-     * Yaw is the compass heading in degrees, 0 <= range < 360
-     * 0 = North, 90 = East, 180 = South, 270 = West
-     *
-     * This is similar to SENSOR_ORIENTATION except the data is not 
-     * smoothed or filtered in any way.
+    /**
+     * A constant describing an orientation sensor.
+     * See {@link android.hardware.SensorListener SensorListener} for more details.
+     * @deprecated use {@link android.hardware.Sensor Sensor} instead.
      */
+    @Deprecated
     public static final int SENSOR_ORIENTATION_RAW = 1 << 7;
 
     /** A constant that includes all sensors */
+    @Deprecated
     public static final int SENSOR_ALL = 0x7F;
 
     /** Smallest sensor ID */
+    @Deprecated
     public static final int SENSOR_MIN = SENSOR_ORIENTATION;
 
     /** Largest sensor ID */
+    @Deprecated
     public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1);
 
 
-    /** Index of the X value in the array returned by 
+    /** Index of the X value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged} */
+    @Deprecated
     public static final int DATA_X = 0;
-    /** Index of the Y value in the array returned by 
+    /** Index of the Y value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged} */
+    @Deprecated
     public static final int DATA_Y = 1;
-    /** Index of the Z value in the array returned by 
+    /** Index of the Z value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged} */
+    @Deprecated
     public static final int DATA_Z = 2;
-    
-    /** Offset to the raw values in the array returned by 
+
+    /** Offset to the untransformed values in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged} */
+    @Deprecated
     public static final int RAW_DATA_INDEX = 3;
 
-    /** Index of the raw X value in the array returned by 
+    /** Index of the untransformed X value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged} */
+    @Deprecated
     public static final int RAW_DATA_X = 3;
-    /** Index of the raw X value in the array returned by 
+    /** Index of the untransformed Y value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged} */
+    @Deprecated
     public static final int RAW_DATA_Y = 4;
-    /** Index of the raw X value in the array returned by 
+    /** Index of the untransformed Z value in the array returned by
      * {@link android.hardware.SensorListener#onSensorChanged} */
+    @Deprecated
     public static final int RAW_DATA_Z = 5;
-    
-    
+
+
     /** Standard gravity (g) on Earth. This value is equivalent to 1G */
     public static final float STANDARD_GRAVITY = 9.80665f;
 
@@ -177,7 +173,7 @@
     public static final float GRAVITY_JUPITER         = 23.12f;
     public static final float GRAVITY_SATURN          = 8.96f;
     public static final float GRAVITY_URANUS          = 8.69f;
-    public static final float GRAVITY_NEPTUN          = 11.0f;
+    public static final float GRAVITY_NEPTUNE         = 11.0f;
     public static final float GRAVITY_PLUTO           = 0.6f;
     public static final float GRAVITY_DEATH_STAR_I    = 0.000000353036145f;
     public static final float GRAVITY_THE_ISLAND      = 4.815162342f;
@@ -208,52 +204,84 @@
     /** rate suitable for the user interface  */
     public static final int SENSOR_DELAY_UI = 2;
     /** rate (default) suitable for screen orientation changes */
-    public static final int SENSOR_DELAY_NORMAL = 3; 
+    public static final int SENSOR_DELAY_NORMAL = 3;
 
-    
+
     /** The values returned by this sensor cannot be trusted, calibration
      * is needed or the environment doesn't allow readings */
     public static final int SENSOR_STATUS_UNRELIABLE = 0;
-    
+
     /** This sensor is reporting data with low accuracy, calibration with the
      * environment is needed */
     public static final int SENSOR_STATUS_ACCURACY_LOW = 1;
 
-    /** This sensor is reporting data with an average level of accuracy, 
+    /** This sensor is reporting data with an average level of accuracy,
      * calibration with the environment may improve the readings */
     public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2;
-    
+
     /** This sensor is reporting data with maximum accuracy */
     public static final int SENSOR_STATUS_ACCURACY_HIGH = 3;
 
-    
+    /** see {@link #remapCoordinateSystem} */
+    public static final int AXIS_X = 1;
+    /** see {@link #remapCoordinateSystem} */
+    public static final int AXIS_Y = 2;
+    /** see {@link #remapCoordinateSystem} */
+    public static final int AXIS_Z = 3;
+    /** see {@link #remapCoordinateSystem} */
+    public static final int AXIS_MINUS_X = AXIS_X | 0x80;
+    /** see {@link #remapCoordinateSystem} */
+    public static final int AXIS_MINUS_Y = AXIS_Y | 0x80;
+    /** see {@link #remapCoordinateSystem} */
+    public static final int AXIS_MINUS_Z = AXIS_Z | 0x80;
+
+    /*-----------------------------------------------------------------------*/
+
+    private ISensorService mSensorService;
+    Looper mMainLooper;
+    @SuppressWarnings("deprecation")
+    private HashMap<SensorListener, LegacyListener> mLegacyListenersMap =
+        new HashMap<SensorListener, LegacyListener>();
+
+    /*-----------------------------------------------------------------------*/
 
     private static final int SENSOR_DISABLE = -1;
-    private static final int SENSOR_ORDER_MASK = 0x1F;
-    private static final int SENSOR_STATUS_SHIFT = 28;
-    private ISensorService mSensorService;
-    private Looper mLooper;
-
+    private static boolean sSensorModuleInitialized = false;
+    private static ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
+    private static SparseArray<List<Sensor>> sSensorListByType = new SparseArray<List<Sensor>>();
     private static IWindowManager sWindowManager;
-    private static int sRotation = 0;
-
-    /* The thread and the sensor list are global to the process 
+    private static int sRotation = Surface.ROTATION_0;
+    /* The thread and the sensor list are global to the process
      * but the actual thread is spawned on demand */
-    static final private SensorThread sSensorThread = new SensorThread();
-    static final private ArrayList<ListenerDelegate> sListeners = 
+    private static SensorThread sSensorThread;
+
+    // Used within this module from outside SensorManager, don't make private
+    static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
+    static final ArrayList<ListenerDelegate> sListeners =
         new ArrayList<ListenerDelegate>();
 
+    /*-----------------------------------------------------------------------*/
 
     static private class SensorThread {
 
-        private Thread mThread;
+        Thread mThread;
+
+        SensorThread() {
+            // this gets to the sensor module. We can have only one per process.
+            sensors_data_init();
+        }
+
+        @Override
+        protected void finalize() {
+            sensors_data_uninit();
+        }
 
         // must be called with sListeners lock
         void startLocked(ISensorService service) {
             try {
                 if (mThread == null) {
                     ParcelFileDescriptor fd = service.getDataChanel();
-                    mThread = new Thread(new SensorThreadRunnable(fd, service), 
+                    mThread = new Thread(new SensorThreadRunnable(fd),
                             SensorThread.class.getName());
                     mThread.start();
                 }
@@ -263,162 +291,165 @@
         }
 
         private class SensorThreadRunnable implements Runnable {
-            private ISensorService mSensorService;
             private ParcelFileDescriptor mSensorDataFd;
-            private final byte mAccuracies[] = new byte[32];
-            SensorThreadRunnable(ParcelFileDescriptor fd, ISensorService service) {
+            SensorThreadRunnable(ParcelFileDescriptor fd) {
                 mSensorDataFd = fd;
-                mSensorService = service;
-                Arrays.fill(mAccuracies, (byte)-1);
             }
             public void run() {
-                int sensors_of_interest;
-                float[] values = new float[6];
+                //Log.d(TAG, "entering main sensor thread");
+                final float[] values = new float[3];
+                final int[] status = new int[1];
+                final long timestamp[] = new long[1];
                 Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
 
-                synchronized (sListeners) {
-                    _sensors_data_open(mSensorDataFd.getFileDescriptor());
-                    try {
-                        mSensorDataFd.close();
-                    } catch (IOException e) {
-                        // *shrug*
-                        Log.e(TAG, "IOException: ", e);
-                    }
-                    mSensorDataFd = null;
-                    //mSensorDataFd.
-                    // the first time, compute the sensors we need. this is not
-                    // a big deal if it changes by the time we call
-                    // _sensors_data_poll, it'll get recomputed for the next
-                    // round.
-                    sensors_of_interest = 0;
-                    final int size = sListeners.size();
-                    for (int i=0 ; i<size ; i++) {
-                        sensors_of_interest |= sListeners.get(i).mSensors;
-                        if ((sensors_of_interest & SENSOR_ALL) == SENSOR_ALL)
-                            break;
-                    }
+                if (mSensorDataFd == null) {
+                    Log.e(TAG, "mSensorDataFd == NULL, exiting");
+                    return;
                 }
+                // this thread is guaranteed to be unique
+                sensors_data_open(mSensorDataFd.getFileDescriptor());
+                try {
+                    mSensorDataFd.close();
+                } catch (IOException e) {
+                    // *shrug*
+                    Log.e(TAG, "IOException: ", e);
+                }
+                mSensorDataFd = null;
+
 
                 while (true) {
                     // wait for an event
-                    final int sensor_result = _sensors_data_poll(values, sensors_of_interest);
-                    final int sensor_order = sensor_result & SENSOR_ORDER_MASK;
-                    final int sensor = 1 << sensor_result;
-                    int accuracy = sensor_result>>>SENSOR_STATUS_SHIFT;
+                    final int sensor = sensors_data_poll(values, status, timestamp);
 
-                    if ((sensors_of_interest & sensor)!=0) {
-                        // show the notification only if someone is listening for
-                        // this sensor
-                        if (accuracy != mAccuracies[sensor_order]) {
-                            try {
-                                mSensorService.reportAccuracy(sensor, accuracy);
-                                mAccuracies[sensor_order] = (byte)accuracy;
-                            } catch (RemoteException e) {
-                                Log.e(TAG, "RemoteException in reportAccuracy: ", e);
-                            }
-                        } else {
-                            accuracy = -1;
-                        }
+                    if (sensor == -1) {
+                        // we lost the connection to the event stream. this happens
+                        // when the last listener is removed.
+                        Log.d(TAG, "_sensors_data_poll() failed, we bail out.");
+                        break;
                     }
-                    
+
+                    int accuracy = status[0];
                     synchronized (sListeners) {
                         if (sListeners.isEmpty()) {
                             // we have no more listeners, terminate the thread
-                            _sensors_data_close();
+                            sensors_data_close();
                             mThread = null;
                             break;
                         }
-                        // convert for the current screen orientation
-                        mapSensorDataToWindow(sensor, values, SensorManager.getRotation());
-                        // report the sensor event to all listeners that
-                        // care about it.
-                        sensors_of_interest = 0;
-                        final int size = sListeners.size();
-                        for (int i=0 ; i<size ; i++) {
-                            ListenerDelegate listener = sListeners.get(i);
-                            sensors_of_interest |= listener.mSensors;
-                            if (listener.hasSensor(sensor)) {
-                                // this is asynchronous (okay to call
-                                // with sListeners lock held.
-                                listener.onSensorChanged(sensor, values, accuracy);
+                        final Sensor sensorObject = sHandleToSensor.get(sensor);
+                        if (sensorObject != null) {
+                            // report the sensor event to all listeners that
+                            // care about it.
+                            final int size = sListeners.size();
+                            for (int i=0 ; i<size ; i++) {
+                                ListenerDelegate listener = sListeners.get(i);
+                                if (listener.hasSensor(sensorObject)) {
+                                    // this is asynchronous (okay to call
+                                    // with sListeners lock held).
+                                    listener.onSensorChangedLocked(sensorObject,
+                                            values, timestamp, accuracy);
+                                }
                             }
                         }
                     }
                 }
+                //Log.d(TAG, "exiting main sensor thread");
             }
         }
     }
 
+    /*-----------------------------------------------------------------------*/
+
     private class ListenerDelegate extends Binder {
+        final SensorEventListener mSensorEventListener;
+        private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>();
+        private final Handler mHandler;
+        private SensorEvent mValuesPool;
+        public int mSensors;
 
-        private SensorListener mListener;
-        private int mSensors;
-        private float[] mValuesPool;
-
-        ListenerDelegate(SensorListener listener, int sensors) {
-            mListener = listener;
-            mSensors = sensors;
-            mValuesPool = new float[6];
+        ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) {
+            mSensorEventListener = listener;
+            Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
+            // currently we create one Handler instance per listener, but we could
+            // have one per looper (we'd need to pass the ListenerDelegate
+            // instance to handleMessage and keep track of them separately).
+            mHandler = new Handler(looper) {
+                @Override
+                public void handleMessage(Message msg) {
+                    SensorEvent t = (SensorEvent)msg.obj;
+                    if (t.accuracy >= 0) {
+                        mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy);
+                    }
+                    mSensorEventListener.onSensorChanged(t);
+                    returnToPool(t);
+                }
+            };
+            addSensor(sensor);
         }
 
-        int addSensors(int sensors) {
-            mSensors |= sensors;
-            return mSensors;
-        }
-        int removeSensors(int sensors) {
-            mSensors &= ~sensors;
-            return mSensors;
-        }
-        boolean hasSensor(int sensor) {
-            return ((mSensors & sensor) != 0);
+        protected SensorEvent createSensorEvent() {
+            // maximal size for all legacy events is 3
+            return new SensorEvent(3);
         }
 
-        void onSensorChanged(int sensor, float[] values, int accuracy) {
-            float[] v;
+        protected SensorEvent getFromPool() {
+            SensorEvent t = null;
             synchronized (this) {
                 // remove the array from the pool
-                v = mValuesPool;
+                t = mValuesPool;
                 mValuesPool = null;
             }
-
-            if (v != null) {
-                v[0] = values[0];
-                v[1] = values[1];
-                v[2] = values[2];
-                v[3] = values[3];
-                v[4] = values[4];
-                v[5] = values[5];
-            } else {
-                // the pool was empty, we need to dup the array
-                v = values.clone();
+            if (t == null) {
+                // the pool was empty, we need a new one
+                t = createSensorEvent();
             }
-
-            Message msg = Message.obtain();
-            msg.what = sensor;
-            msg.obj = v;
-            msg.arg1 = accuracy;
-            mHandler.sendMessage(msg);
+            return t;
         }
 
-        private final Handler mHandler = new Handler(mLooper) {
-            @Override public void handleMessage(Message msg) {
-                if (msg.arg1 >= 0) {
-                    try {
-                        mListener.onAccuracyChanged(msg.what, msg.arg1);
-                    } catch (AbstractMethodError e) {
-                        // old app that doesn't implement this method
-                        // just ignore it.
-                    }
-                }
-                mListener.onSensorChanged(msg.what, (float[])msg.obj);
-                synchronized (this) {
-                    // put back the array into the pool
-                    if (mValuesPool == null) {
-                        mValuesPool = (float[])msg.obj;
-                    }
+        protected void returnToPool(SensorEvent t) {
+            synchronized (this) {
+                // put back the array into the pool
+                if (mValuesPool == null) {
+                    mValuesPool = t;
                 }
             }
-        };
+        }
+
+        Object getListener() {
+            return mSensorEventListener;
+        }
+
+        int addSensor(Sensor sensor) {
+            mSensors |= 1<<sensor.getHandle();
+            mSensorList.add(sensor);
+            return mSensors;
+        }
+        int removeSensor(Sensor sensor) {
+            mSensors &= ~(1<<sensor.getHandle());
+            mSensorList.remove(sensor);
+            return mSensors;
+        }
+        boolean hasSensor(Sensor sensor) {
+            return ((mSensors & (1<<sensor.getHandle())) != 0);
+        }
+        List<Sensor> getSensors() {
+            return mSensorList;
+        }
+
+        void onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy) {
+            SensorEvent t = getFromPool();
+            final float[] v = t.values;
+            v[0] = values[0];
+            v[1] = values[1];
+            v[2] = values[2];
+            t.timestamp = timestamp[0];
+            t.accuracy = accuracy;
+            t.sensor = sensor;
+            Message msg = Message.obtain();
+            msg.what = 0;
+            msg.obj = t;
+            mHandler.sendMessage(msg);
+        }
     }
 
     /**
@@ -427,41 +458,157 @@
     public SensorManager(Looper mainLooper) {
         mSensorService = ISensorService.Stub.asInterface(
                 ServiceManager.getService(Context.SENSOR_SERVICE));
-        
-        sWindowManager = IWindowManager.Stub.asInterface(
-                ServiceManager.getService("window"));
+        mMainLooper = mainLooper;
 
-        if (sWindowManager != null) {
-            // if it's null we're running in the system process
-            // which won't get the rotated values
-            try {
-                sWindowManager.watchRotation(this);
-            } catch (RemoteException e) {
+
+        synchronized(sListeners) {
+            if (!sSensorModuleInitialized) {
+                sSensorModuleInitialized = true;
+
+                nativeClassInit();
+
+                sWindowManager = IWindowManager.Stub.asInterface(
+                        ServiceManager.getService("window"));
+                if (sWindowManager != null) {
+                    // if it's null we're running in the system process
+                    // which won't get the rotated values
+                    try {
+                        sRotation = sWindowManager.watchRotation(this);
+                    } catch (RemoteException e) {
+                    }
+                }
+
+                // initialize the sensor list
+                sensors_module_init();
+                final ArrayList<Sensor> fullList = sFullSensorsList;
+                int i = 0;
+                do {
+                    Sensor sensor = new Sensor();
+                    i = sensors_module_get_next_sensor(sensor, i);
+
+                    if (i>=0) {
+                        Log.d(TAG, "found sensor: " + sensor.getName() +
+                                ", handle=" + sensor.getHandle());
+                        sensor.setLegacyType(getLegacySensorType(sensor.getType()));
+                        fullList.add(sensor);
+                        sHandleToSensor.append(sensor.getHandle(), sensor);
+                    }
+                } while (i>0);
+
+                sSensorThread = new SensorThread();
             }
         }
-
-        mLooper = mainLooper;
     }
 
-    /** @return available sensors */
+    private int getLegacySensorType(int type) {
+        switch (type) {
+            case Sensor.TYPE_ACCELEROMETER:
+                return SENSOR_ACCELEROMETER;
+            case Sensor.TYPE_MAGNETIC_FIELD:
+                return SENSOR_MAGNETIC_FIELD;
+            case Sensor.TYPE_ORIENTATION:
+                return SENSOR_ORIENTATION_RAW;
+            case Sensor.TYPE_TEMPERATURE:
+                return SENSOR_TEMPERATURE;
+        }
+        return 0;
+    }
+
+    /** @return available sensors.
+     * @deprecated This method is deprecated, use
+     * {@link SensorManager#getSensorList(int)} instead
+     */
+    @Deprecated
     public int getSensors() {
-        return _sensors_data_get_sensors();
+        int result = 0;
+        final ArrayList<Sensor> fullList = sFullSensorsList;
+        for (Sensor i : fullList) {
+            switch (i.getType()) {
+                case Sensor.TYPE_ACCELEROMETER:
+                    result |= SensorManager.SENSOR_ACCELEROMETER;
+                    break;
+                case Sensor.TYPE_MAGNETIC_FIELD:
+                    result |= SensorManager.SENSOR_MAGNETIC_FIELD;
+                    break;
+                case Sensor.TYPE_ORIENTATION:
+                    result |= SensorManager.SENSOR_ORIENTATION |
+                                    SensorManager.SENSOR_ORIENTATION_RAW;
+                    break;
+            }
+        }
+        return result;
     }
 
     /**
+     * Use this method to get the list of available sensors of a certain
+     * type. Make multiple calls to get sensors of different types or use
+     * {@link android.hardware.Sensor#TYPE_ALL Sensor.TYPE_ALL} to get all
+     * the sensors.
+     *
+     * @param type of sensors requested
+     * @return a list of sensors matching the asked type.
+     */
+    public List<Sensor> getSensorList(int type) {
+        // cache the returned lists the first time
+        List<Sensor> list;
+        final ArrayList<Sensor> fullList = sFullSensorsList;
+        synchronized(fullList) {
+            list = sSensorListByType.get(type);
+            if (list == null) {
+                if (type == Sensor.TYPE_ALL) {
+                    list = fullList;
+                } else {
+                    list = new ArrayList<Sensor>();
+                    for (Sensor i : fullList) {
+                        if (i.getType() == type)
+                            list.add(i);
+                    }
+                }
+                list = Collections.unmodifiableList(list);
+                sSensorListByType.append(type, list);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Use this method to get the default sensor for a given type. Note that
+     * the returned sensor could be a composite sensor, and its data could be
+     * averaged or filtered. If you need to access the raw sensors use
+     * {@link SensorManager#getSensorList(int) getSensorList}.
+     *
+     *
+     * @param type of sensors requested
+     * @return the default sensors matching the asked type.
+     */
+    public Sensor getDefaultSensor(int type) {
+        // TODO: need to be smarter, for now, just return the 1st sensor
+        List<Sensor> l = getSensorList(type);
+        return l.isEmpty() ? null : l.get(0);
+    }
+
+
+    /**
      * Registers a listener for given sensors.
+     * @deprecated This method is deprecated, use
+     * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}
+     * instead.
      *
      * @param listener sensor listener object
      * @param sensors a bit masks of the sensors to register to
      *
      * @return true if the sensor is supported and successfully enabled
      */
+    @Deprecated
     public boolean registerListener(SensorListener listener, int sensors) {
         return registerListener(listener, sensors, SENSOR_DELAY_NORMAL);
     }
 
     /**
-     * Registers a listener for given sensors.
+     * Registers a SensorListener for given sensors.
+     * @deprecated This method is deprecated, use
+     * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}
+     * instead.
      *
      * @param listener sensor listener object
      * @param sensors a bit masks of the sensors to register to
@@ -471,9 +618,189 @@
      *
      * @return true if the sensor is supported and successfully enabled
      */
+    @Deprecated
     public boolean registerListener(SensorListener listener, int sensors, int rate) {
-        boolean result;
+        boolean result = false;
+        result = registerLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
+                listener, sensors, rate) || result;
+        result = registerLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
+                listener, sensors, rate) || result;
+        result = registerLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
+                listener, sensors, rate) || result;
+        result = registerLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
+                listener, sensors, rate) || result;
+        result = registerLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
+                listener, sensors, rate) || result;
+        return result;
+    }
 
+    @SuppressWarnings("deprecation")
+    private boolean registerLegacyListener(int legacyType, int type,
+            SensorListener listener, int sensors, int rate)
+    {
+        boolean result = false;
+        // Are we activating this legacy sensor?
+        if ((sensors & legacyType) != 0) {
+            // if so, find a suitable Sensor
+            Sensor sensor = getDefaultSensor(type);
+            if (sensor != null) {
+                // If we don't already have one, create a LegacyListener
+                // to wrap this listener and process the events as
+                // they are expected by legacy apps.
+                LegacyListener legacyListener = null;
+                synchronized (mLegacyListenersMap) {
+                    legacyListener = mLegacyListenersMap.get(listener);
+                    if (legacyListener == null) {
+                        // we didn't find a LegacyListener for this client,
+                        // create one, and put it in our list.
+                        legacyListener = new LegacyListener(listener);
+                        mLegacyListenersMap.put(listener, legacyListener);
+                    }
+                }
+                // register this legacy sensor with this legacy listener
+                legacyListener.registerSensor(legacyType);
+                // and finally, register the legacy listener with the new apis
+                result = registerListener(legacyListener, sensor, rate);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Unregisters a listener for the sensors with which it is registered.
+     * @deprecated This method is deprecated, use
+     * {@link SensorManager#unregisterListener(SensorEventListener, Sensor)}
+     * instead.
+     *
+     * @param listener a SensorListener object
+     * @param sensors a bit masks of the sensors to unregister from
+     */
+    @Deprecated
+    public void unregisterListener(SensorListener listener, int sensors) {
+        unregisterLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
+                listener, sensors);
+        unregisterLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
+                listener, sensors);
+        unregisterLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
+                listener, sensors);
+        unregisterLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
+                listener, sensors);
+        unregisterLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
+                listener, sensors);
+    }
+
+    @SuppressWarnings("deprecation")
+    private void unregisterLegacyListener(int legacyType, int type,
+            SensorListener listener, int sensors)
+    {
+        // do we know about this listener?
+        LegacyListener legacyListener = null;
+        synchronized (mLegacyListenersMap) {
+            legacyListener = mLegacyListenersMap.get(listener);
+        }
+        if (legacyListener != null) {
+            // Are we deactivating this legacy sensor?
+            if ((sensors & legacyType) != 0) {
+                // if so, find the corresponding Sensor
+                Sensor sensor = getDefaultSensor(type);
+                if (sensor != null) {
+                    // unregister this legacy sensor and if we don't
+                    // need the corresponding Sensor, unregister it too
+                    if (legacyListener.unregisterSensor(legacyType)) {
+                        // corresponding sensor not needed, unregister
+                        unregisterListener(legacyListener, sensor);
+                        // finally check if we still need the legacyListener
+                        // in our mapping, if not, get rid of it too.
+                        synchronized(sListeners) {
+                            boolean found = false;
+                            for (ListenerDelegate i : sListeners) {
+                                if (i.getListener() == legacyListener) {
+                                    found = true;
+                                    break;
+                                }
+                            }
+                            if (!found) {
+                                synchronized (mLegacyListenersMap) {
+                                    mLegacyListenersMap.remove(listener);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Unregisters a listener for all sensors.
+     * @deprecated This method is deprecated, use
+     * {@link SensorManager#unregisterListener(SensorEventListener)}
+     * instead.
+     *
+     * @param listener a SensorListener object
+     */
+    @Deprecated
+    public void unregisterListener(SensorListener listener) {
+        unregisterListener(listener, SENSOR_ALL);
+    }
+
+    /**
+     * Unregisters a listener for the sensors with which it is registered.
+     *
+     * @param listener a SensorEventListener object
+     * @param sensor the sensor to unregister from
+     *
+     */
+    public void unregisterListener(SensorEventListener listener, Sensor sensor) {
+        unregisterListener((Object)listener, sensor);
+    }
+
+    /**
+     * Unregisters a listener for all sensors.
+     *
+     * @param listener a SensorListener object
+     *
+     */
+    public void unregisterListener(SensorEventListener listener) {
+        unregisterListener((Object)listener);
+    }
+
+
+    /**
+     * Registers a {@link android.hardware.SensorEventListener SensorEventListener}
+     * for the given sensor.
+     *
+     * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object.
+     * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
+     * @param rate The rate {@link android.hardware.SensorEvent sensor events} are delivered at.
+     * This is only a hint to the system. Events may be received faster or
+     * slower than the specified rate. Usually events are received faster.
+     *
+     * @return true if the sensor is supported and successfully enabled.
+     *
+     */
+    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) {
+        return registerListener(listener, sensor, rate, null);
+    }
+
+    /**
+     * Registers a {@link android.hardware.SensorEventListener SensorEventListener}
+     * for the given sensor.
+     *
+     * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object.
+     * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
+     * @param rate The rate {@link android.hardware.SensorEvent sensor events} are delivered at.
+     * This is only a hint to the system. Events may be received faster or
+     * slower than the specified rate. Usually events are received faster.
+     * @param handler The {@link android.os.Handler Handler} the
+     * {@link android.hardware.SensorEvent sensor events} will be delivered to.
+     *
+     * @return true if the sensor is supported and successfully enabled.
+     *
+     */
+    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate,
+            Handler handler) {
+        boolean result;
         int delay = -1;
         switch (rate) {
             case SENSOR_DELAY_FASTEST:
@@ -496,15 +823,15 @@
             synchronized (sListeners) {
                 ListenerDelegate l = null;
                 for (ListenerDelegate i : sListeners) {
-                    if (i.mListener == listener) {
+                    if (i.getListener() == listener) {
                         l = i;
                         break;
                     }
                 }
 
                 if (l == null) {
-                    l = new ListenerDelegate(listener, sensors);
-                    result = mSensorService.enableSensor(l, sensors, delay);
+                    l = new ListenerDelegate(listener, sensor, handler);
+                    result = mSensorService.enableSensor(l, sensor.getHandle(), delay);
                     if (result) {
                         sListeners.add(l);
                         sListeners.notify();
@@ -513,9 +840,9 @@
                         sSensorThread.startLocked(mSensorService);
                     }
                 } else {
-                    result = mSensorService.enableSensor(l, sensors, delay);
+                    result = mSensorService.enableSensor(l, sensor.getHandle(), delay);
                     if (result) {
-                        l.addSensors(sensors);
+                        l.addSensor(sensor);
                     }
                 }
             }
@@ -526,25 +853,42 @@
         return result;
     }
 
-    /**
-     * Unregisters a listener for the sensors with which it is registered.
-     *
-     * @param listener a SensorListener object
-     * @param sensors a bit masks of the sensors to unregister from
-     */
-    public void unregisterListener(SensorListener listener, int sensors) {
+    private void unregisterListener(Object listener, Sensor sensor) {
         try {
             synchronized (sListeners) {
                 final int size = sListeners.size();
                 for (int i=0 ; i<size ; i++) {
                     ListenerDelegate l = sListeners.get(i);
-                    if (l.mListener == listener) {
+                    if (l.getListener() == listener) {
                         // disable these sensors
-                        mSensorService.enableSensor(l, sensors, SENSOR_DISABLE);
+                        int handle = sensor.getHandle();
+                        mSensorService.enableSensor(l, handle, SENSOR_DISABLE);
                         // if we have no more sensors enabled on this listener,
                         // take it off the list.
-                        if (l.removeSensors(sensors) == 0)
+                        if (l.removeSensor(sensor) == 0) {
                             sListeners.remove(i);
+                        }
+                        break;
+                    }
+                }
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in unregisterListener: ", e);
+        }
+    }
+
+    private void unregisterListener(Object listener) {
+        try {
+            synchronized (sListeners) {
+                final int size = sListeners.size();
+                for (int i=0 ; i<size ; i++) {
+                    ListenerDelegate l = sListeners.get(i);
+                    if (l.getListener() == listener) {
+                        // disable all sensors for this listener
+                        for (Sensor sensor : l.getSensors()) {
+                            mSensorService.enableSensor(l, sensor.getHandle(), SENSOR_DISABLE);
+                        }
+                        sListeners.remove(i);
                         break;
                     }
                 }
@@ -555,65 +899,541 @@
     }
 
     /**
-     * Unregisters a listener for all sensors.
+     * Computes the inclination matrix <b>I</b> as well as the rotation
+     * matrix <b>R</b> transforming a vector from the
+     * device coordinate system to the world's coordinate system which is
+     * defined as a direct orthonormal basis, where:
+     * 
+     * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to
+     * the ground at the device's current location and roughly points East).</li>
+     * <li>Y is tangential to the ground at the device's current location and
+     * points towards the magnetic North Pole.</li>
+     * <li>Z points towards the sky and is perpendicular to the ground.</li>
+     * <p>
+     * <hr>
+     * <p>By definition:
+     * <p>[0 0 g] = <b>R</b> * <b>gravity</b> (g = magnitude of gravity)
+     * <p>[0 m 0] = <b>I</b> * <b>R</b> * <b>geomagnetic</b>
+     * (m = magnitude of geomagnetic field)
+     * <p><b>R</b> is the identity matrix when the device is aligned with the
+     * world's coordinate system, that is, when the device's X axis points
+     * toward East, the Y axis points to the North Pole and the device is facing
+     * the sky.
      *
-     * @param listener a SensorListener object
+     * <p><b>I</b> is a rotation matrix transforming the geomagnetic
+     * vector into the same coordinate space as gravity (the world's coordinate
+     * space). <b>I</b> is a simple rotation around the X axis.
+     * The inclination angle in radians can be computed with
+     * {@link #getInclination}.
+     * <hr>
+     * 
+     * <p> Each matrix is returned either as a 3x3 or 4x4 row-major matrix
+     * depending on the length of the passed array:
+     * <p><u>If the array length is 16:</u>
+     * <pre>
+     *   /  M[ 0]   M[ 1]   M[ 2]   M[ 3]  \
+     *   |  M[ 4]   M[ 5]   M[ 6]   M[ 7]  |
+     *   |  M[ 8]   M[ 9]   M[10]   M[11]  |
+     *   \  M[12]   M[13]   M[14]   M[15]  /
+     *</pre>
+     * This matrix is ready to be used by OpenGL ES's 
+     * {@link javax.microedition.khronos.opengles.GL10#glLoadMatrixf(float[], int) 
+     * glLoadMatrixf(float[], int)}. 
+     * <p>Note that because OpenGL matrices are column-major matrices you must
+     * transpose the matrix before using it. However, since the matrix is a 
+     * rotation matrix, its transpose is also its inverse, conveniently, it is
+     * often the inverse of the rotation that is needed for rendering; it can
+     * therefore be used with OpenGL ES directly.
+     * <p>
+     * Also note that the returned matrices always have this form:
+     * <pre>
+     *   /  M[ 0]   M[ 1]   M[ 2]   0  \
+     *   |  M[ 4]   M[ 5]   M[ 6]   0  |
+     *   |  M[ 8]   M[ 9]   M[10]   0  |
+     *   \      0       0       0   1  /
+     *</pre>
+     * <p><u>If the array length is 9:</u>
+     * <pre>
+     *   /  M[ 0]   M[ 1]   M[ 2]  \
+     *   |  M[ 3]   M[ 4]   M[ 5]  |
+     *   \  M[ 6]   M[ 7]   M[ 8]  /
+     *</pre>
+     *
+     * <hr>
+     * <p>The inverse of each matrix can be computed easily by taking its
+     * transpose.
+     *
+     * <p>The matrices returned by this function are meaningful only when the
+     * device is not free-falling and it is not close to the magnetic north.
+     * If the device is accelerating, or placed into a strong magnetic field,
+     * the returned matrices may be inaccurate.
+     *
+     * @param R is an array of 9 floats holding the rotation matrix <b>R</b>
+     * when this function returns. R can be null.<p>
+     * @param I is an array of 9 floats holding the rotation matrix <b>I</b>
+     * when this function returns. I can be null.<p>
+     * @param gravity is an array of 3 floats containing the gravity vector
+     * expressed in the device's coordinate. You can simply use the
+     * {@link android.hardware.SensorEvent#values values}
+     * returned by a {@link android.hardware.SensorEvent SensorEvent} of a
+     * {@link android.hardware.Sensor Sensor} of type
+     * {@link android.hardware.Sensor#TYPE_ACCELEROMETER TYPE_ACCELEROMETER}.<p>
+     * @param geomagnetic is an array of 3 floats containing the geomagnetic
+     * vector expressed in the device's coordinate. You can simply use the
+     * {@link android.hardware.SensorEvent#values values}
+     * returned by a {@link android.hardware.SensorEvent SensorEvent} of a
+     * {@link android.hardware.Sensor Sensor} of type
+     * {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD TYPE_MAGNETIC_FIELD}.
+     * @return
+     *   true on success<p>
+     *   false on failure (for instance, if the device is in free fall).
+     *   On failure the output matrices are not modified.
      */
-    public void unregisterListener(SensorListener listener) {
-        unregisterListener(listener, SENSOR_ALL);
+
+    public static boolean getRotationMatrix(float[] R, float[] I,
+            float[] gravity, float[] geomagnetic) {
+        // TODO: move this to native code for efficiency
+        float Ax = gravity[0];
+        float Ay = gravity[1];
+        float Az = gravity[2];
+        final float Ex = geomagnetic[0];
+        final float Ey = geomagnetic[1];
+        final float Ez = geomagnetic[2];
+        float Hx = Ey*Az - Ez*Ay;
+        float Hy = Ez*Ax - Ex*Az;
+        float Hz = Ex*Ay - Ey*Ax;
+        final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
+        if (normH < 0.1f) {
+            // device is close to free fall (or in space?), or close to
+            // magnetic north pole. Typical values are  > 100.
+            return false;
+        }
+        final float invH = 1.0f / normH;
+        Hx *= invH;
+        Hy *= invH;
+        Hz *= invH;
+        final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az);
+        Ax *= invA;
+        Ay *= invA;
+        Az *= invA;
+        final float Mx = Ay*Hz - Az*Hy;
+        final float My = Az*Hx - Ax*Hz;
+        final float Mz = Ax*Hy - Ay*Hx;
+        if (R != null) {
+            if (R.length == 9) {
+                R[0] = Hx;     R[1] = Hy;     R[2] = Hz;
+                R[3] = Mx;     R[4] = My;     R[5] = Mz;
+                R[6] = Ax;     R[7] = Ay;     R[8] = Az;
+            } else if (R.length == 16) {
+                R[0]  = Hx;    R[1]  = Hy;    R[2]  = Hz;   R[3]  = 0;
+                R[4]  = Mx;    R[5]  = My;    R[6]  = Mz;   R[7]  = 0;
+                R[8]  = Ax;    R[9]  = Ay;    R[10] = Az;   R[11] = 0;
+                R[12] = 0;     R[13] = 0;     R[14] = 0;    R[15] = 1;
+            }
+        }
+        if (I != null) {
+            // compute the inclination matrix by projecting the geomagnetic
+            // vector onto the Z (gravity) and X (horizontal component
+            // of geomagnetic vector) axes.
+            final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez);
+            final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE;
+            final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE;
+            if (I.length == 9) {
+                I[0] = 1;     I[1] = 0;     I[2] = 0;
+                I[3] = 0;     I[4] = c;     I[5] = s;
+                I[6] = 0;     I[7] =-s;     I[8] = c;
+            } else if (I.length == 16) {
+                I[0] = 1;     I[1] = 0;     I[2] = 0;
+                I[4] = 0;     I[5] = c;     I[6] = s;
+                I[8] = 0;     I[9] =-s;     I[10]= c;
+                I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0;
+                I[15] = 1;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Computes the geomagnetic inclination angle in radians from the
+     * inclination matrix <b>I</b> returned by {@link #getRotationMatrix}.
+     * @param I inclination matrix see {@link #getRotationMatrix}.
+     * @return The geomagnetic inclination angle in radians.
+     */
+    public static float getInclination(float[] I) {
+        if (I.length == 9) {
+            return (float)Math.atan2(I[5], I[4]);
+        } else {
+            return (float)Math.atan2(I[6], I[5]);            
+        }
+    }
+
+    /**
+     * Rotates the supplied rotation matrix so it is expressed in a
+     * different coordinate system. This is typically used when an application
+     * needs to compute the three orientation angles of the device (see
+     * {@link #getOrientation}) in a different coordinate system.
+     * 
+     * <p>When the rotation matrix is used for drawing (for instance with 
+     * OpenGL ES), it usually <b>doesn't need</b> to be transformed by this 
+     * function, unless the screen is physically rotated, such as when used
+     * in landscape mode. 
+     *
+     * <p><u>Examples:</u><p>
+     *
+     * <li>Using the camera (Y axis along the camera's axis) for an augmented 
+     * reality application where the rotation angles are needed :</li><p>
+     *
+     * <code>remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);</code><p>
+     *
+     * <li>Using the device as a mechanical compass in landscape mode:</li><p>
+     *
+     * <code>remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR);</code><p>
+     *
+     * Beware of the above example. This call is needed only if the device is
+     * physically used in landscape mode to calculate the rotation angles (see 
+     * {@link #getOrientation}).
+     * If the rotation matrix is also used for rendering, it may not need to 
+     * be transformed, for instance if your {@link android.app.Activity
+     * Activity} is running in landscape mode.
+     *
+     * <p>Since the resulting coordinate system is orthonormal, only two axes
+     * need to be specified.
+     *
+     * @param inR the rotation matrix to be transformed. Usually it is the
+     * matrix returned by {@link #getRotationMatrix}.
+     * @param X defines on which world axis and direction the X axis of the
+     *        device is mapped.
+     * @param Y defines on which world axis and direction the Y axis of the
+     *        device is mapped.
+     * @param outR the transformed rotation matrix. inR and outR can be the same
+     *        array, but it is not recommended for performance reason.
+     * @return true on success. false if the input parameters are incorrect, for
+     * instance if X and Y define the same axis. Or if inR and outR don't have 
+     * the same length.
+     */
+
+    public static boolean remapCoordinateSystem(float[] inR, int X, int Y,
+            float[] outR)
+    {
+        if (inR == outR) {
+            final float[] temp = mTempMatrix;
+            synchronized(temp) {
+                // we don't expect to have a lot of contention
+                if (remapCoordinateSystemImpl(inR, X, Y, temp)) {
+                    final int size = outR.length;
+                    for (int i=0 ; i<size ; i++)
+                        outR[i] = temp[i];
+                    return true;
+                }
+            }
+        }
+        return remapCoordinateSystemImpl(inR, X, Y, outR);
+    }
+
+    private static boolean remapCoordinateSystemImpl(float[] inR, int X, int Y,
+            float[] outR)
+    {
+        /*
+         * X and Y define a rotation matrix 'r':
+         *
+         *  (X==1)?((X&0x80)?-1:1):0    (X==2)?((X&0x80)?-1:1):0    (X==3)?((X&0x80)?-1:1):0
+         *  (Y==1)?((Y&0x80)?-1:1):0    (Y==2)?((Y&0x80)?-1:1):0    (Y==3)?((X&0x80)?-1:1):0
+         *                              r[0] ^ r[1]
+         *
+         * where the 3rd line is the vector product of the first 2 lines
+         *
+         */
+
+        final int length = outR.length;
+        if (inR.length != length)
+            return false;   // invalid parameter
+        if ((X & 0x7C)!=0 || (Y & 0x7C)!=0)
+            return false;   // invalid parameter
+        if (((X & 0x3)==0) || ((Y & 0x3)==0))
+            return false;   // no axis specified
+        if ((X & 0x3) == (Y & 0x3))
+            return false;   // same axis specified
+
+        // Z is "the other" axis, its sign is either +/- sign(X)*sign(Y)
+        // this can be calculated by exclusive-or'ing X and Y; except for
+        // the sign inversion (+/-) which is calculated below.
+        int Z = X ^ Y;
+
+        // extract the axis (remove the sign), offset in the range 0 to 2.
+        final int x = (X & 0x3)-1;
+        final int y = (Y & 0x3)-1;
+        final int z = (Z & 0x3)-1;
+
+        // compute the sign of Z (whether it needs to be inverted)
+        final int axis_y = (z+1)%3;
+        final int axis_z = (z+2)%3;
+        if (((x^axis_y)|(y^axis_z)) != 0)
+            Z ^= 0x80;
+
+        final boolean sx = (X>=0x80);
+        final boolean sy = (Y>=0x80);
+        final boolean sz = (Z>=0x80);
+
+        // Perform R * r, in avoiding actual muls and adds.
+        final int rowLength = ((length==16)?4:3);
+        for (int j=0 ; j<3 ; j++) {
+            final int offset = j*rowLength;
+            for (int i=0 ; i<3 ; i++) {
+                if (x==i)   outR[offset+i] = sx ? -inR[offset+0] : inR[offset+0];
+                if (y==i)   outR[offset+i] = sy ? -inR[offset+1] : inR[offset+1];
+                if (z==i)   outR[offset+i] = sz ? -inR[offset+2] : inR[offset+2];
+            }
+        }
+        if (length == 16) {
+            outR[3] = outR[7] = outR[11] = outR[12] = outR[13] = outR[14] = 0;
+            outR[15] = 1;
+        }
+        return true;
+    }
+
+    /**
+     * Computes the device's orientation based on the rotation matrix.
+     * <p> When it returns, the array values is filled with the result:
+     * <li>values[0]: <i>azimuth</i>, rotation around the Z axis.</li>
+     * <li>values[1]: <i>pitch</i>, rotation around the X axis.</li>
+     * <li>values[2]: <i>roll</i>, rotation around the Y axis.</li>
+     * <p>
+     *
+     * @param R rotation matrix see {@link #getRotationMatrix}.
+     * @param values an array of 3 floats to hold the result.
+     * @return The array values passed as argument.
+     */
+    public static float[] getOrientation(float[] R, float values[]) {
+        /*
+         * 4x4 (length=16) case:
+         *   /  R[ 0]   R[ 1]   R[ 2]   0  \
+         *   |  R[ 4]   R[ 5]   R[ 6]   0  |
+         *   |  R[ 8]   R[ 9]   R[10]   0  |
+         *   \      0       0       0   1  /
+         *   
+         * 3x3 (length=9) case:
+         *   /  R[ 0]   R[ 1]   R[ 2]  \
+         *   |  R[ 3]   R[ 4]   R[ 5]  |
+         *   \  R[ 6]   R[ 7]   R[ 8]  /
+         * 
+         */
+        if (R.length == 9) {
+            values[0] = (float)Math.atan2(R[1], R[4]);
+            values[1] = (float)Math.asin(-R[7]);
+            values[2] = (float)Math.atan2(-R[6], R[8]);
+        } else {
+            values[0] = (float)Math.atan2(R[1], R[5]);
+            values[1] = (float)Math.asin(-R[9]);
+            values[2] = (float)Math.atan2(-R[8], R[10]);
+        }
+        return values;
     }
 
 
     /**
-     * Helper function to convert the specified sensor's data to the windows's 
-     * coordinate space from the device's coordinate space.
-     */ 
-    
-    private static void mapSensorDataToWindow(int sensor, float[] values, int orientation) {
-        final float x = values[DATA_X];
-        final float y = values[DATA_Y];
-        final float z = values[DATA_Z];
-        // copy the raw raw values...
-        values[RAW_DATA_X] = x;
-        values[RAW_DATA_Y] = y;
-        values[RAW_DATA_Z] = z;
-        // TODO: add support for 180 and 270 orientations
-        if (orientation == Surface.ROTATION_90) {
-            switch (sensor) {
-                case SENSOR_ACCELEROMETER:
-                case SENSOR_MAGNETIC_FIELD:
-                    values[DATA_X] =-y;
-                    values[DATA_Y] = x;
-                    values[DATA_Z] = z; 
-                    break;
-                case SENSOR_ORIENTATION:
-                case SENSOR_ORIENTATION_RAW:
-                    values[DATA_X] = x + ((x < 270) ? 90 : -270);
-                    values[DATA_Y] = z;
-                    values[DATA_Z] = y; 
-                    break;
-            }
-        }
-    }
-
-
-    private static native int _sensors_data_open(FileDescriptor fd);
-    private static native int _sensors_data_close();
-    // returns the sensor's status in the top 4 bits of "res".
-    private static native int _sensors_data_poll(float[] values, int sensors);
-    private static native int _sensors_data_get_sensors();
-
-    /** {@hide} */
+     * {@hide}
+     */
     public void onRotationChanged(int rotation) {
         synchronized(sListeners) {
             sRotation  = rotation;
         }
     }
-    
-    private static int getRotation() {
+
+    static int getRotation() {
         synchronized(sListeners) {
             return sRotation;
         }
     }
-}
 
+    private class LegacyListener implements SensorEventListener {
+        private float mValues[] = new float[6];
+        @SuppressWarnings("deprecation")
+        private SensorListener mTarget;
+        private int mSensors;
+        private final LmsFilter mYawfilter = new LmsFilter();
+
+        @SuppressWarnings("deprecation")
+        LegacyListener(SensorListener target) {
+            mTarget = target;
+            mSensors = 0;
+        }
+
+        void registerSensor(int legacyType) {
+            mSensors |= legacyType;
+        }
+
+        boolean unregisterSensor(int legacyType) {
+            mSensors &= ~legacyType;
+            int mask = SENSOR_ORIENTATION|SENSOR_ORIENTATION_RAW;
+            if (((legacyType&mask)!=0) && ((mSensors&mask)!=0)) {
+                return false;
+            }
+            return true;
+        }
+
+        @SuppressWarnings("deprecation")
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+            try {
+                mTarget.onAccuracyChanged(sensor.getLegacyType(), accuracy);
+            } catch (AbstractMethodError e) {
+                // old app that doesn't implement this method
+                // just ignore it.
+            }
+        }
+
+        @SuppressWarnings("deprecation")
+        public void onSensorChanged(SensorEvent event) {
+            final float v[] = mValues;
+            v[0] = event.values[0];
+            v[1] = event.values[1];
+            v[2] = event.values[2];
+            int legacyType = event.sensor.getLegacyType();
+            mapSensorDataToWindow(legacyType, v, SensorManager.getRotation());
+            if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
+                if ((mSensors & SENSOR_ORIENTATION_RAW)!=0) {
+                    mTarget.onSensorChanged(SENSOR_ORIENTATION_RAW, v);
+                }
+                if ((mSensors & SENSOR_ORIENTATION)!=0) {
+                    v[0] = mYawfilter.filter(event.timestamp, v[0]);
+                    mTarget.onSensorChanged(SENSOR_ORIENTATION, v);
+                }
+            } else {
+                mTarget.onSensorChanged(legacyType, v);
+            }
+        }
+
+        /*
+         * Helper function to convert the specified sensor's data to the windows's
+         * coordinate space from the device's coordinate space.
+         *
+         * output: 3,4,5: values in the old API format
+         *         0,1,2: transformed values in the old API format
+         *
+         */
+        private void mapSensorDataToWindow(int sensor,
+                float[] values, int orientation) {
+            float x = values[0];
+            float y = values[1];
+            float z = values[2];
+
+            switch (sensor) {
+                case SensorManager.SENSOR_ORIENTATION:
+                case SensorManager.SENSOR_ORIENTATION_RAW:
+                    z = -z;
+                    break;
+                case SensorManager.SENSOR_ACCELEROMETER:
+                    x = -x;
+                    y = -y;
+                    z = -z;
+                    break;
+                case SensorManager.SENSOR_MAGNETIC_FIELD:
+                    x = -x;
+                    y = -y;
+                    break;
+            }
+            values[0] = x;
+            values[1] = y;
+            values[2] = z;
+            values[3] = x;
+            values[4] = y;
+            values[5] = z;
+            // TODO: add support for 180 and 270 orientations
+            if (orientation == Surface.ROTATION_90) {
+                switch (sensor) {
+                    case SENSOR_ACCELEROMETER:
+                    case SENSOR_MAGNETIC_FIELD:
+                        values[0] =-y;
+                        values[1] = x;
+                        values[2] = z;
+                        break;
+                    case SENSOR_ORIENTATION:
+                    case SENSOR_ORIENTATION_RAW:
+                        values[0] = x + ((x < 270) ? 90 : -270);
+                        values[1] = z;
+                        values[2] = y;
+                        break;
+                }
+            }
+        }
+    }
+
+    class LmsFilter {
+        private static final int SENSORS_RATE_MS = 20;
+        private static final int COUNT = 12;
+        private static final float PREDICTION_RATIO = 1.0f/3.0f;
+        private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO;
+        private float mV[] = new float[COUNT*2];
+        private float mT[] = new float[COUNT*2];
+        private int mIndex;
+
+        public LmsFilter() {
+            mIndex = COUNT;
+        }
+
+        public float filter(long time, float in) {
+            float v = in;
+            final float ns = 1.0f / 1000000000.0f;
+            final float t = time*ns;
+            float v1 = mV[mIndex];
+            if ((v-v1) > 180) {
+                v -= 360;
+            } else if ((v1-v) > 180) {
+                v += 360;
+            }
+            /* Manage the circular buffer, we write the data twice spaced
+             * by COUNT values, so that we don't have to copy the array
+             * when it's full
+             */
+            mIndex++;
+            if (mIndex >= COUNT*2)
+                mIndex = COUNT;
+            mV[mIndex] = v;
+            mT[mIndex] = t;
+            mV[mIndex-COUNT] = v;
+            mT[mIndex-COUNT] = t;
+
+            float A, B, C, D, E;
+            float a, b;
+            int i;
+
+            A = B = C = D = E = 0;
+            for (i=0 ; i<COUNT-1 ; i++) {
+                final int j = mIndex - 1 - i;
+                final float Z = mV[j];
+                final float T = 0.5f*(mT[j] + mT[j+1]) - t;
+                float dT = mT[j] - mT[j+1];
+                dT *= dT;
+                A += Z*dT;
+                B += T*(T*dT);
+                C +=   (T*dT);
+                D += Z*(T*dT);
+                E += dT;
+            }
+            b = (A*B + C*D) / (E*B + C*C);
+            a = (E*b - A) / C;
+            float f = b + PREDICTION_TIME*a;
+
+            // Normalize
+            f *= (1.0f / 360.0f);
+            if (((f>=0)?f:-f) >= 0.5f)
+                f = f - (float)Math.ceil(f + 0.5f) + 1.0f;
+            if (f < 0)
+                f += 1.0f;
+            f *= 360.0f;
+            return f;
+        }
+    }
+
+
+    private static native void nativeClassInit();
+
+    private static native int sensors_module_init();
+    private static native int sensors_module_get_next_sensor(Sensor sensor, int next);
+
+    // Used within this module from outside SensorManager, don't make private
+    static native int sensors_data_init();
+    static native int sensors_data_uninit();
+    static native int sensors_data_open(FileDescriptor fd);
+    static native int sensors_data_close();
+    static native int sensors_data_poll(float[] values, int[] status, long[] timestamp);
+}
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
new file mode 100644
index 0000000..7d02f65
--- /dev/null
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.inputmethodservice;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.inputmethod.InputMethod;
+import android.view.inputmethod.InputMethodSession;
+
+/**
+ * AbstractInputMethodService provides a abstract base class for input methods.
+ * Normal input method implementations will not derive from this directly,
+ * instead building on top of {@link InputMethodService} or another more
+ * complete base class.  Be sure to read {@link InputMethod} for more
+ * information on the basics of writing input methods.
+ * 
+ * <p>This class combines a Service (representing the input method component
+ * to the system with the InputMethod interface that input methods must
+ * implement.  This base class takes care of reporting your InputMethod from
+ * the service when clients bind to it, but provides no standard implementation
+ * of the InputMethod interface itself.  Derived classes must implement that
+ * interface.
+ */
+public abstract class AbstractInputMethodService extends Service
+        implements KeyEvent.Callback {
+    private InputMethod mInputMethod;
+    
+    /**
+     * Base class for derived classes to implement their {@link InputMethod}
+     * interface.  This takes care of basic maintenance of the input method,
+     * but most behavior must be implemented in a derived class.
+     */
+    public abstract class AbstractInputMethodImpl implements InputMethod {
+        /**
+         * Instantiate a new client session for the input method, by calling
+         * back to {@link AbstractInputMethodService#onCreateInputMethodSessionInterface()
+         * AbstractInputMethodService.onCreateInputMethodSessionInterface()}.
+         */
+        public void createSession(SessionCallback callback) {
+            callback.sessionCreated(onCreateInputMethodSessionInterface());
+        }
+        
+        /**
+         * Take care of enabling or disabling an existing session by calling its
+         * {@link AbstractInputMethodSessionImpl#revokeSelf()
+         * AbstractInputMethodSessionImpl.setEnabled()} method.
+         */
+        public void setSessionEnabled(InputMethodSession session, boolean enabled) {
+            ((AbstractInputMethodSessionImpl)session).setEnabled(enabled);
+        }
+        
+        /**
+         * Take care of killing an existing session by calling its
+         * {@link AbstractInputMethodSessionImpl#revokeSelf()
+         * AbstractInputMethodSessionImpl.revokeSelf()} method.
+         */
+        public void revokeSession(InputMethodSession session) {
+            ((AbstractInputMethodSessionImpl)session).revokeSelf();
+        }
+    }
+    
+    /**
+     * Base class for derived classes to implement their {@link InputMethodSession}
+     * interface.  This takes care of basic maintenance of the session,
+     * but most behavior must be implemented in a derived class.
+     */
+    public abstract class AbstractInputMethodSessionImpl implements InputMethodSession {
+        boolean mEnabled = true;
+        boolean mRevoked;
+        
+        /**
+         * Check whether this session has been enabled by the system.  If not
+         * enabled, you should not execute any calls on to it.
+         */
+        public boolean isEnabled() {
+            return mEnabled;
+        }
+        
+        /**
+         * Check whether this session has been revoked by the system.  Revoked
+         * session is also always disabled, so there is generally no need to
+         * explicitly check for this.
+         */
+        public boolean isRevoked() {
+            return mRevoked;
+        }
+        
+        /**
+         * Change the enabled state of the session.  This only works if the
+         * session has not been revoked.
+         */
+        public void setEnabled(boolean enabled) {
+            if (!mRevoked) {
+                mEnabled = enabled;
+            }
+        }
+        
+        /**
+         * Revoke the session from the client.  This disabled the session, and
+         * prevents it from ever being enabled again.
+         */
+        public void revokeSelf() {
+            mRevoked = true;
+            mEnabled = false;
+        }
+        
+        /**
+         * Take care of dispatching incoming key events to the appropriate
+         * callbacks on the service, and tell the client when this is done.
+         */
+        public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) {
+            boolean handled = event.dispatch(AbstractInputMethodService.this);
+            if (callback != null) {
+                callback.finishedEvent(seq, handled);
+            }
+        }
+
+        /**
+         * Take care of dispatching incoming trackball events to the appropriate
+         * callbacks on the service, and tell the client when this is done.
+         */
+        public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback) {
+            boolean handled = onTrackballEvent(event);
+            if (callback != null) {
+                callback.finishedEvent(seq, handled);
+            }
+        }
+    }
+    
+    /**
+     * Called by the framework during initialization, when the InputMethod
+     * interface for this service needs to be created.
+     */
+    public abstract AbstractInputMethodImpl onCreateInputMethodInterface();
+    
+    /**
+     * Called by the framework when a new InputMethodSession interface is
+     * needed for a new client of the input method.
+     */
+    public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
+    
+    @Override
+    final public IBinder onBind(Intent intent) {
+        if (mInputMethod == null) {
+            mInputMethod = onCreateInputMethodInterface();
+        }
+        return new IInputMethodWrapper(this, mInputMethod);
+    }
+    
+    public boolean onTrackballEvent(MotionEvent event) {
+        return false;
+    }
+}
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
new file mode 100644
index 0000000..e59f38b
--- /dev/null
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -0,0 +1,23 @@
+package android.inputmethodservice;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.EditText;
+
+/***
+ * Specialization of {@link EditText} for showing and interacting with the
+ * extracted text in a full-screen input method.
+ */
+public class ExtractEditText extends EditText {
+    public ExtractEditText(Context context) {
+        super(context, null);
+    }
+
+    public ExtractEditText(Context context, AttributeSet attrs) {
+        super(context, attrs, com.android.internal.R.attr.editTextStyle);
+    }
+
+    public ExtractEditText(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+}
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
new file mode 100644
index 0000000..40c03cd
--- /dev/null
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -0,0 +1,151 @@
+package android.inputmethodservice;
+
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.view.IInputMethodCallback;
+import com.android.internal.view.IInputMethodSession;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.InputMethodSession;
+import android.view.inputmethod.EditorInfo;
+
+class IInputMethodSessionWrapper extends IInputMethodSession.Stub
+        implements HandlerCaller.Callback {
+    private static final String TAG = "InputMethodWrapper";
+    private static final boolean DEBUG = false;
+    
+    private static final int DO_FINISH_INPUT = 60;
+    private static final int DO_DISPLAY_COMPLETIONS = 65;
+    private static final int DO_UPDATE_EXTRACTED_TEXT = 67;
+    private static final int DO_DISPATCH_KEY_EVENT = 70;
+    private static final int DO_DISPATCH_TRACKBALL_EVENT = 80;
+    private static final int DO_UPDATE_SELECTION = 90;
+    private static final int DO_UPDATE_CURSOR = 95;
+    private static final int DO_APP_PRIVATE_COMMAND = 100;
+   
+    final HandlerCaller mCaller;
+    final InputMethodSession mInputMethodSession;
+    
+    // NOTE: we should have a cache of these.
+    static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback {
+        final IInputMethodCallback mCb;
+        InputMethodEventCallbackWrapper(IInputMethodCallback cb) {
+            mCb = cb;
+        }
+        public void finishedEvent(int seq, boolean handled) {
+            try {
+                mCb.finishedEvent(seq, handled);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+    
+    public IInputMethodSessionWrapper(Context context,
+            InputMethodSession inputMethodSession) {
+        mCaller = new HandlerCaller(context, this);
+        mInputMethodSession = inputMethodSession;
+    }
+
+    public InputMethodSession getInternalInputMethodSession() {
+        return mInputMethodSession;
+    }
+
+    public void executeMessage(Message msg) {
+        switch (msg.what) {
+            case DO_FINISH_INPUT:
+                mInputMethodSession.finishInput();
+                return;
+            case DO_DISPLAY_COMPLETIONS:
+                mInputMethodSession.displayCompletions((CompletionInfo[])msg.obj);
+                return;
+            case DO_UPDATE_EXTRACTED_TEXT:
+                mInputMethodSession.updateExtractedText(msg.arg1,
+                        (ExtractedText)msg.obj);
+                return;
+            case DO_DISPATCH_KEY_EVENT: {
+                HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
+                mInputMethodSession.dispatchKeyEvent(msg.arg1,
+                        (KeyEvent)args.arg1,
+                        new InputMethodEventCallbackWrapper(
+                                (IInputMethodCallback)args.arg2));
+                mCaller.recycleArgs(args);
+                return;
+            }
+            case DO_DISPATCH_TRACKBALL_EVENT: {
+                HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
+                mInputMethodSession.dispatchTrackballEvent(msg.arg1,
+                        (MotionEvent)args.arg1,
+                        new InputMethodEventCallbackWrapper(
+                                (IInputMethodCallback)args.arg2));
+                mCaller.recycleArgs(args);
+                return;
+            }
+            case DO_UPDATE_SELECTION: {
+                HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
+                mInputMethodSession.updateSelection(args.argi1, args.argi2,
+                        args.argi3, args.argi4);
+                mCaller.recycleArgs(args);
+                return;
+            }
+            case DO_UPDATE_CURSOR: {
+                mInputMethodSession.updateCursor((Rect)msg.obj);
+                return;
+            }
+            case DO_APP_PRIVATE_COMMAND: {
+                HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
+                mInputMethodSession.appPrivateCommand((String)args.arg1,
+                        (Bundle)args.arg2);
+                mCaller.recycleArgs(args);
+                return;
+            }
+        }
+        Log.w(TAG, "Unhandled message code: " + msg.what);
+    }
+    
+    public void finishInput() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_INPUT));
+    }
+
+    public void displayCompletions(CompletionInfo[] completions) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(
+                DO_DISPLAY_COMPLETIONS, completions));
+    }
+    
+    public void updateExtractedText(int token, ExtractedText text) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageIO(
+                DO_UPDATE_EXTRACTED_TEXT, token, text));
+    }
+    
+    public void dispatchKeyEvent(int seq, KeyEvent event, IInputMethodCallback callback) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_KEY_EVENT, seq,
+                event, callback));
+    }
+
+    public void dispatchTrackballEvent(int seq, MotionEvent event, IInputMethodCallback callback) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_TRACKBALL_EVENT, seq,
+                event, callback));
+    }
+
+    public void updateSelection(int oldSelStart, int oldSelEnd,
+            int newSelStart, int newSelEnd) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageIIII(DO_UPDATE_SELECTION,
+                oldSelStart, oldSelEnd, newSelStart, newSelEnd));
+    }
+    
+    public void updateCursor(Rect newCursor) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_UPDATE_CURSOR,
+                newCursor));
+    }
+    
+    public void appPrivateCommand(String action, Bundle data) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data));
+    }
+}
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
new file mode 100644
index 0000000..4108bdd
--- /dev/null
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -0,0 +1,172 @@
+package android.inputmethodservice;
+
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethod;
+import com.android.internal.view.IInputMethodCallback;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.InputConnectionWrapper;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethod;
+import android.view.inputmethod.InputMethodSession;
+
+/**
+ * Implements the internal IInputMethod interface to convert incoming calls
+ * on to it back to calls on the public InputMethod interface, scheduling
+ * them on the main thread of the process.
+ */
+class IInputMethodWrapper extends IInputMethod.Stub
+        implements HandlerCaller.Callback {
+    private static final String TAG = "InputMethodWrapper";
+    private static final boolean DEBUG = false;
+    
+    private static final int DO_ATTACH_TOKEN = 10;
+    private static final int DO_SET_INPUT_CONTEXT = 20;
+    private static final int DO_UNSET_INPUT_CONTEXT = 30;
+    private static final int DO_START_INPUT = 32;
+    private static final int DO_RESTART_INPUT = 34;
+    private static final int DO_CREATE_SESSION = 40;
+    private static final int DO_SET_SESSION_ENABLED = 45;
+    private static final int DO_REVOKE_SESSION = 50;
+    private static final int DO_SHOW_SOFT_INPUT = 60;
+    private static final int DO_HIDE_SOFT_INPUT = 70;
+   
+    final HandlerCaller mCaller;
+    final InputMethod mInputMethod;
+    
+    // NOTE: we should have a cache of these.
+    static class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {
+        final Context mContext;
+        final IInputMethodCallback mCb;
+        InputMethodSessionCallbackWrapper(Context context, IInputMethodCallback cb) {
+            mContext = context;
+            mCb = cb;
+        }
+        public void sessionCreated(InputMethodSession session) {
+            try {
+                if (session != null) {
+                    IInputMethodSessionWrapper wrap =
+                            new IInputMethodSessionWrapper(mContext, session);
+                    mCb.sessionCreated(wrap);
+                } else {
+                    mCb.sessionCreated(null);
+                }
+            } catch (RemoteException e) {
+            }
+        }
+    }
+    
+    public IInputMethodWrapper(Context context, InputMethod inputMethod) {
+        mCaller = new HandlerCaller(context, this);
+        mInputMethod = inputMethod;
+    }
+
+    public InputMethod getInternalInputMethod() {
+        return mInputMethod;
+    }
+
+    public void executeMessage(Message msg) {
+        switch (msg.what) {
+            case DO_ATTACH_TOKEN: {
+                mInputMethod.attachToken((IBinder)msg.obj);
+                return;
+            }
+            case DO_SET_INPUT_CONTEXT: {
+                mInputMethod.bindInput((InputBinding)msg.obj);
+                return;
+            }
+            case DO_UNSET_INPUT_CONTEXT:
+                mInputMethod.unbindInput();
+                return;
+            case DO_START_INPUT:
+                mInputMethod.startInput((EditorInfo)msg.obj);
+                return;
+            case DO_RESTART_INPUT:
+                mInputMethod.restartInput((EditorInfo)msg.obj);
+                return;
+            case DO_CREATE_SESSION: {
+                mInputMethod.createSession(new InputMethodSessionCallbackWrapper(
+                        mCaller.mContext, (IInputMethodCallback)msg.obj));
+                return;
+            }
+            case DO_SET_SESSION_ENABLED:
+                mInputMethod.setSessionEnabled((InputMethodSession)msg.obj,
+                        msg.arg1 != 0);
+                return;
+            case DO_REVOKE_SESSION:
+                mInputMethod.revokeSession((InputMethodSession)msg.obj);
+                return;
+            case DO_SHOW_SOFT_INPUT:
+                mInputMethod.showSoftInput();
+                return;
+            case DO_HIDE_SOFT_INPUT:
+                mInputMethod.hideSoftInput();
+                return;
+        }
+        Log.w(TAG, "Unhandled message code: " + msg.what);
+    }
+    
+    public void attachToken(IBinder token) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_ATTACH_TOKEN, token));
+    }
+    
+    public void bindInput(InputBinding binding) {
+        InputConnection ic = new InputConnectionWrapper(
+                IInputContext.Stub.asInterface(binding.getConnectionToken()));
+        InputBinding nu = new InputBinding(ic, binding);
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_INPUT_CONTEXT, nu));
+    }
+
+    public void unbindInput() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_UNSET_INPUT_CONTEXT));
+    }
+
+    public void startInput(EditorInfo attribute) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_START_INPUT, attribute));
+    }
+
+    public void restartInput(EditorInfo attribute) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RESTART_INPUT, attribute));
+    }
+
+    public void createSession(IInputMethodCallback callback) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CREATE_SESSION, callback));
+    }
+
+    public void setSessionEnabled(IInputMethodSession session, boolean enabled) {
+        try {
+            InputMethodSession ls = ((IInputMethodSessionWrapper)
+                    session).getInternalInputMethodSession();
+            mCaller.executeOrSendMessage(mCaller.obtainMessageIO(
+                    DO_SET_SESSION_ENABLED, enabled ? 1 : 0, ls));
+        } catch (ClassCastException e) {
+            Log.w(TAG, "Incoming session not of correct type: " + session, e);
+        }
+    }
+    
+    public void revokeSession(IInputMethodSession session) {
+        try {
+            InputMethodSession ls = ((IInputMethodSessionWrapper)
+                    session).getInternalInputMethodSession();
+            mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_REVOKE_SESSION, ls));
+        } catch (ClassCastException e) {
+            Log.w(TAG, "Incoming session not of correct type: " + session, e);
+        }
+    }
+    
+    public void showSoftInput() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_SHOW_SOFT_INPUT));
+    }
+    
+    public void hideSoftInput() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_HIDE_SOFT_INPUT));
+    }
+}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
new file mode 100644
index 0000000..9ebf127
--- /dev/null
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.inputmethodservice;
+
+import static android.view.ViewGroup.LayoutParams.FILL_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethod;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.EditorInfo;
+import android.widget.FrameLayout;
+
+/**
+ * InputMethodService provides a standard implementation of an InputMethod,
+ * which final implementations can derive from and customize.  See the
+ * base class {@link AbstractInputMethodService} and the {@link InputMethod}
+ * interface for more information on the basics of writing input methods.
+ */
+public class InputMethodService extends AbstractInputMethodService {
+    static final String TAG = "InputMethodService";
+    static final boolean DEBUG = false;
+    
+    LayoutInflater mInflater;
+    View mRootView;
+    SoftInputWindow mWindow;
+    boolean mWindowCreated;
+    boolean mWindowAdded;
+    boolean mWindowVisible;
+    FrameLayout mExtractFrame;
+    FrameLayout mCandidatesFrame;
+    FrameLayout mInputFrame;
+    
+    IBinder mToken;
+    
+    InputBinding mInputBinding;
+    InputConnection mInputConnection;
+    boolean mInputStarted;
+    EditorInfo mInputInfo;
+    
+    boolean mShowInputRequested;
+    boolean mShowCandidatesRequested;
+    
+    boolean mFullscreenApplied;
+    boolean mIsFullscreen;
+    View mExtractView;
+    ExtractEditText mExtractEditText;
+    ExtractedText mExtractedText;
+    int mExtractedToken;
+    
+    View mInputView;
+    boolean mIsInputViewShown;
+    
+    int mStatusIcon;
+
+    final Insets mTmpInsets = new Insets();
+    final int[] mTmpLocation = new int[2];
+    
+    final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
+            new ViewTreeObserver.OnComputeInternalInsetsListener() {
+        public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+            if (isFullscreenMode()) {
+                // In fullscreen mode, we just say the window isn't covering
+                // any content so we don't impact whatever is behind.
+                View decor = getWindow().getWindow().getDecorView();
+                info.contentInsets.top = info.visibleInsets.top
+                        = decor.getHeight();
+                info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+            } else {
+                onComputeInsets(mTmpInsets);
+                info.contentInsets.top = mTmpInsets.contentTopInsets;
+                info.visibleInsets.top = mTmpInsets.visibleTopInsets;
+                info.setTouchableInsets(mTmpInsets.touchableInsets);
+            }
+        }
+    };
+
+    /**
+     * Concrete implementation of
+     * {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides
+     * all of the standard behavior for an input method.
+     */
+    public class InputMethodImpl extends AbstractInputMethodImpl {
+        /**
+         * Take care of attaching the given window token provided by the system.
+         */
+        public void attachToken(IBinder token) {
+            if (mToken == null) {
+                mToken = token;
+                mWindow.setToken(token);
+            }
+        }
+        
+        /**
+         * Handle a new input binding, calling
+         * {@link InputMethodService#onBindInput InputMethodService.onBindInput()}
+         * when done.
+         */
+        public void bindInput(InputBinding binding) {
+            mInputBinding = binding;
+            mInputConnection = binding.getConnection();
+            onBindInput();
+        }
+
+        /**
+         * Clear the current input binding.
+         */
+        public void unbindInput() {
+            mInputStarted = false;
+            mInputBinding = null;
+            mInputConnection = null;
+        }
+
+        public void startInput(EditorInfo attribute) {
+            doStartInput(attribute, false);
+        }
+
+        public void restartInput(EditorInfo attribute) {
+            doStartInput(attribute, false);
+        }
+
+        /**
+         * Handle a request by the system to hide the soft input area.
+         */
+        public void hideSoftInput() {
+            if (DEBUG) Log.v(TAG, "hideSoftInput()");
+            mShowInputRequested = false;
+            hideWindow();
+        }
+
+        /**
+         * Handle a request by the system to show the soft input area.
+         */
+        public void showSoftInput() {
+            if (DEBUG) Log.v(TAG, "showSoftInput()");
+            showWindow(true);
+        }
+    }
+    
+    /**
+     * Concrete implementation of
+     * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides
+     * all of the standard behavior for an input method session.
+     */
+    public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
+        public void finishInput() {
+            if (!isEnabled()) {
+                return;
+            }
+            onFinishInput();
+            mInputStarted = false;
+        }
+
+        /**
+         * Call {@link InputMethodService#onDisplayCompletions
+         * InputMethodService.onDisplayCompletions()}.
+         */
+        public void displayCompletions(CompletionInfo[] completions) {
+            if (!isEnabled()) {
+                return;
+            }
+            onDisplayCompletions(completions);
+        }
+        
+        /**
+         * Call {@link InputMethodService#onUpdateExtractedText
+         * InputMethodService.onUpdateExtractedText()}.
+         */
+        public void updateExtractedText(int token, ExtractedText text) {
+            if (!isEnabled()) {
+                return;
+            }
+            onUpdateExtractedText(token, text);
+        }
+        
+        /**
+         * Call {@link InputMethodService#onUpdateSelection
+         * InputMethodService.onUpdateSelection()}.
+         */
+        public void updateSelection(int oldSelStart, int oldSelEnd,
+                int newSelStart, int newSelEnd) {
+            if (!isEnabled()) {
+                return;
+            }
+            InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
+                    newSelStart, newSelEnd);
+        }
+        
+        /**
+         * Call {@link InputMethodService#onUpdateCursor
+         * InputMethodService.onUpdateCursor()}.
+         */
+        public void updateCursor(Rect newCursor) {
+            if (!isEnabled()) {
+                return;
+            }
+            InputMethodService.this.onUpdateCursor(newCursor);
+        }
+        
+        /**
+         * Call {@link InputMethodService#onAppPrivateCommand
+         * InputMethodService.onAppPrivateCommand()}.
+         */
+        public void appPrivateCommand(String action, Bundle data) {
+            if (!isEnabled()) {
+                return;
+            }
+            InputMethodService.this.onAppPrivateCommand(action, data);
+        }
+    }
+    
+    /**
+     * Information about where interesting parts of the input method UI appear.
+     */
+    public static final class Insets {
+        /**
+         * This is the top part of the UI that is the main content.  It is
+         * used to determine the basic space needed, to resize/pan the
+         * application behind.  It is assumed that this inset does not
+         * change very much, since any change will cause a full resize/pan
+         * of the application behind.  This value is relative to the top edge
+         * of the input method window.
+         */
+        int contentTopInsets;
+        
+        /**
+         * This is the top part of the UI that is visibly covering the
+         * application behind it.  This provides finer-grained control over
+         * visibility, allowing you to change it relatively frequently (such
+         * as hiding or showing candidates) without disrupting the underlying
+         * UI too much.  For example, this will never resize the application
+         * UI, will only pan if needed to make the current focus visible, and
+         * will not aggressively move the pan position when this changes unless
+         * needed to make the focus visible.  This value is relative to the top edge
+         * of the input method window.
+         */
+        int visibleTopInsets;
+        
+        /**
+         * Option for {@link #touchableInsets}: the entire window frame
+         * can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_FRAME
+                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
+        
+        /**
+         * Option for {@link #touchableInsets}: the area inside of
+         * the content insets can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_CONTENT
+                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
+        
+        /**
+         * Option for {@link #touchableInsets}: the area inside of
+         * the visible insets can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_VISIBLE
+                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
+        
+        /**
+         * Determine which area of the window is touchable by the user.  May
+         * be one of: {@link #TOUCHABLE_INSETS_FRAME},
+         * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_VISIBLE}. 
+         */
+        public int touchableInsets;
+    }
+    
+    @Override public void onCreate() {
+        super.onCreate();
+        mInflater = (LayoutInflater)getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        mWindow = new SoftInputWindow(this);
+        initViews();
+    }
+    
+    void initViews() {
+        mWindowVisible = false;
+        mWindowCreated = false;
+        mShowInputRequested = false;
+        mShowCandidatesRequested = false;
+        
+        mRootView = mInflater.inflate(
+                com.android.internal.R.layout.input_method, null);
+        mWindow.setContentView(mRootView);
+        mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
+        
+        mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea);
+        mExtractView = null;
+        mExtractEditText = null;
+        mFullscreenApplied = false;
+        
+        mCandidatesFrame = (FrameLayout)mRootView.findViewById(android.R.id.candidatesArea);
+        mInputFrame = (FrameLayout)mRootView.findViewById(android.R.id.inputArea);
+        mInputView = null;
+        mIsInputViewShown = false;
+        
+        mExtractFrame.setVisibility(View.GONE);
+        mCandidatesFrame.setVisibility(View.GONE);
+        mInputFrame.setVisibility(View.GONE);
+    }
+    
+    @Override public void onDestroy() {
+        super.onDestroy();
+        mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
+                mInsetsComputer);
+        if (mWindowAdded) {
+            mWindow.dismiss();
+        }
+    }
+    
+    /**
+     * Implement to return our standard {@link InputMethodImpl}.  Subclasses
+     * can override to provide their own customized version.
+     */
+    public AbstractInputMethodImpl onCreateInputMethodInterface() {
+        return new InputMethodImpl();
+    }
+    
+    /**
+     * Implement to return our standard {@link InputMethodSessionImpl}.  Subclasses
+     * can override to provide their own customized version.
+     */
+    public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() {
+        return new InputMethodSessionImpl();
+    }
+    
+    public LayoutInflater getLayoutInflater() {
+        return mInflater;
+    }
+    
+    public Dialog getWindow() {
+        return mWindow;
+    }
+    
+    /**
+     * Return the currently active InputBinding for the input method, or
+     * null if there is none.
+     */
+    public InputBinding getCurrentInputBinding() {
+        return mInputBinding;
+    }
+    
+    /**
+     * Retrieve the currently active InputConnection that is bound to
+     * the input method, or null if there is none.
+     */
+    public InputConnection getCurrentInputConnection() {
+        return mInputConnection;
+    }
+    
+    public boolean getCurrentInputStarted() {
+        return mInputStarted;
+    }
+    
+    public EditorInfo getCurrentInputInfo() {
+        return mInputInfo;
+    }
+    
+    /**
+     * Re-evaluate whether the input method should be running in fullscreen
+     * mode, and update its UI if this has changed since the last time it
+     * was evaluated.  This will call {@link #onEvaluateFullscreenMode()} to
+     * determine whether it should currently run in fullscreen mode.  You
+     * can use {@link #isFullscreenMode()} to determine if the input method
+     * is currently running in fullscreen mode.
+     */
+    public void updateFullscreenMode() {
+        boolean isFullscreen = onEvaluateFullscreenMode();
+        if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
+            mIsFullscreen = isFullscreen;
+            mFullscreenApplied = true;
+            mWindow.getWindow().setBackgroundDrawable(
+                    onCreateBackgroundDrawable());
+            mExtractFrame.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
+            if (isFullscreen) {
+                if (mExtractView == null) {
+                    View v = onCreateExtractTextView();
+                    if (v != null) {
+                        setExtractView(v);
+                    }
+                }
+                startExtractingText();
+                mWindow.getWindow().setLayout(FILL_PARENT, FILL_PARENT);
+            } else {
+                mWindow.getWindow().setLayout(WRAP_CONTENT, WRAP_CONTENT);
+            }
+        }
+    }
+    
+    /**
+     * Return whether the input method is <em>currently</em> running in
+     * fullscreen mode.  This is the mode that was last determined and
+     * applied by {@link #updateFullscreenMode()}.
+     */
+    public boolean isFullscreenMode() {
+        return mIsFullscreen;
+    }
+    
+    /**
+     * Override this to control when the input method should run in
+     * fullscreen mode.  The default implementation runs in fullsceen only
+     * when the screen is in landscape mode and the input view is being
+     * shown ({@link #onEvaluateInputViewShown} returns true).  If you change what
+     * this returns, you will need to call {@link #updateFullscreenMode()}
+     * yourself whenever the returned value may have changed to have it
+     * re-evaluated and applied.
+     */
+    public boolean onEvaluateFullscreenMode() {
+        Configuration config = getResources().getConfiguration();
+        return config.orientation == Configuration.ORIENTATION_LANDSCAPE
+                && onEvaluateInputViewShown();
+    }
+    
+    /**
+     * Compute the interesting insets into your UI.  The default implementation
+     * uses the top of the candidates frame for the visible insets, and the
+     * top of the input frame for the content insets.  The default touchable
+     * insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}.
+     * 
+     * <p>Note that this method is not called when in fullscreen mode, since
+     * in that case the application is left as-is behind the input method and
+     * not impacted by anything in its UI.
+     * 
+     * @param outInsets Fill in with the current UI insets.
+     */
+    public void onComputeInsets(Insets outInsets) {
+        int[] loc = mTmpLocation;
+        if (mInputFrame.getVisibility() == View.VISIBLE) {
+            mInputFrame.getLocationInWindow(loc);
+            outInsets.contentTopInsets = loc[1];
+        }
+        if (mCandidatesFrame.getVisibility() == View.VISIBLE) {
+            mCandidatesFrame.getLocationInWindow(loc);
+            outInsets.visibleTopInsets = loc[1];
+        } else {
+            outInsets.visibleTopInsets = loc[1];
+        }
+        outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
+    }
+    
+    /**
+     * Re-evaluate whether the soft input area should currently be shown, and
+     * update its UI if this has changed since the last time it
+     * was evaluated.  This will call {@link #onEvaluateInputViewShown()} to
+     * determine whether the input view should currently be shown.  You
+     * can use {@link #isInputViewShown()} to determine if the input view
+     * is currently shown.
+     */
+    public void updateInputViewShown() {
+        boolean isShown = onEvaluateInputViewShown();
+        if (mIsInputViewShown != isShown && mWindowVisible) {
+            mIsInputViewShown = isShown;
+            mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
+            if (mInputView == null) {
+                View v = onCreateInputView();
+                if (v != null) {
+                    setInputView(v);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Return whether the soft input view is <em>currently</em> shown to the
+     * user.  This is the state that was last determined and
+     * applied by {@link #updateInputViewShown()}.
+     */
+    public boolean isInputViewShown() {
+        return mIsInputViewShown;
+    }
+    
+    /**
+     * Override this to control when the soft input area should be shown to
+     * the user.  The default implementation only shows the input view when
+     * there is no hard keyboard or the keyboard is hidden.  If you change what
+     * this returns, you will need to call {@link #updateInputViewShown()}
+     * yourself whenever the returned value may have changed to have it
+     * re-evalauted and applied.
+     */
+    public boolean onEvaluateInputViewShown() {
+        Configuration config = getResources().getConfiguration();
+        return config.keyboard == Configuration.KEYBOARD_NOKEYS
+                || config.hardKeyboardHidden == Configuration.KEYBOARDHIDDEN_YES;
+    }
+    
+    /**
+     * Controls the visibility of the candidates display area.  By default
+     * it is hidden.
+     */
+    public void setCandidatesViewShown(boolean shown) {
+        if (mShowCandidatesRequested != shown) {
+            mCandidatesFrame.setVisibility(shown ? View.VISIBLE : View.INVISIBLE);
+            if (!mShowInputRequested) {
+                // If we are being asked to show the candidates view while the app
+                // has not asked for the input view to be shown, then we need
+                // to update whether the window is shown.
+                if (shown) {
+                    showWindow(false);
+                } else {
+                    hideWindow();
+                }
+            }
+            mShowCandidatesRequested = shown;
+        }
+    }
+    
+    public void setStatusIcon(int iconResId) {
+        mStatusIcon = iconResId;
+        if (mInputConnection != null && mWindowVisible) {
+            mInputConnection.showStatusIcon(getPackageName(), iconResId);
+        }
+    }
+    
+    /**
+     * Force switch to a new input method, as identified by <var>id</var>.  This
+     * input method will be destroyed, and the requested one started on the
+     * current input field.
+     * 
+     * @param id Unique identifier of the new input method ot start.
+     */
+    public void switchInputMethod(String id) {
+        ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE))
+                .setInputMethod(mToken, id);
+    }
+    
+    public void setExtractView(View view) {
+        mExtractFrame.removeAllViews();
+        mExtractFrame.addView(view, new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        mExtractView = view;
+        if (view != null) {
+            mExtractEditText = (ExtractEditText)view.findViewById(
+                    com.android.internal.R.id.inputExtractEditText);
+            startExtractingText();
+        } else {
+            mExtractEditText = null;
+        }
+    }
+    
+    /**
+     * Replaces the current candidates view with a new one.  You only need to
+     * call this when dynamically changing the view; normally, you should
+     * implement {@link #onCreateCandidatesView()} and create your view when
+     * first needed by the input method.
+     */
+    public void setCandidatesView(View view) {
+        mCandidatesFrame.removeAllViews();
+        mCandidatesFrame.addView(view, new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+    }
+    
+    /**
+     * Replaces the current input view with a new one.  You only need to
+     * call this when dynamically changing the view; normally, you should
+     * implement {@link #onCreateInputView()} and create your view when
+     * first needed by the input method.
+     */
+    public void setInputView(View view) {
+        mInputFrame.removeAllViews();
+        mInputFrame.addView(view, new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        mInputView = view;
+    }
+    
+    /**
+     * Called by the framework to create a Drawable for the background of
+     * the input method window.  May return null for no background.  The default
+     * implementation returns a non-null standard background only when in
+     * fullscreen mode.
+     */
+    public Drawable onCreateBackgroundDrawable() {
+        if (isFullscreenMode()) {
+            return getResources().getDrawable(
+                    com.android.internal.R.drawable.input_method_fullscreen_background);
+        }
+        return null;
+    }
+    
+    /**
+     * Called by the framework to create the layout for showing extacted text.
+     * Only called when in fullscreen mode.  The returned view hierarchy must
+     * have an {@link ExtractEditText} whose ID is 
+     * {@link android.R.id#inputExtractEditText}.
+     */
+    public View onCreateExtractTextView() {
+        return mInflater.inflate(
+                com.android.internal.R.layout.input_method_extract_view, null);
+    }
+    
+    /**
+     * Create and return the view hierarchy used to show candidates.  This will
+     * be called once, when the candidates are first displayed.  You can return
+     * null to have no candidates view; the default implementation returns null.
+     * 
+     * <p>To control when the candidates view is displayed, use
+     * {@link #setCandidatesViewShown(boolean)}.
+     * To change the candidates view after the first one is created by this
+     * function, use {@link #setCandidatesView(View)}.
+     */
+    public View onCreateCandidatesView() {
+        return null;
+    }
+    
+    /**
+     * Create and return the view hierarchy used for the input area (such as
+     * a soft keyboard).  This will be called once, when the input area is
+     * first displayed.  You can return null to have no input area; the default
+     * implementation returns null.
+     * 
+     * <p>To control when the input view is displayed, implement
+     * {@link #onEvaluateInputViewShown()}.
+     * To change the input view after the first one is created by this
+     * function, use {@link #setInputView(View)}.
+     */
+    public View onCreateInputView() {
+        return null;
+    }
+    
+    /**
+     * Called when an input session is starting or restarting.
+     * 
+     * @param info Description of the type of text being edited.
+     * @param restarting Set to true if we are restarting input on the
+     * same text field as before.
+     */
+    public void onStartInputView(EditorInfo info, boolean restarting) {
+    }
+    
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        
+        boolean visible = mWindowVisible;
+        boolean showingInput = mShowInputRequested;
+        boolean showingCandidates = mShowCandidatesRequested;
+        initViews();
+        if (visible) {
+            if (showingCandidates) {
+                setCandidatesViewShown(true);
+            }
+            showWindow(showingInput);
+        }
+    }
+
+    public void showWindow(boolean showInput) {
+        if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
+                + " mShowInputRequested=" + mShowInputRequested
+                + " mWindowAdded=" + mWindowAdded
+                + " mWindowCreated=" + mWindowCreated
+                + " mWindowVisible=" + mWindowVisible
+                + " mInputStarted=" + mInputStarted);
+        boolean doShowInput = false;
+        boolean wasVisible = mWindowVisible;
+        mWindowVisible = true;
+        if (!mShowInputRequested) {
+            doShowInput = true;
+            mShowInputRequested = true;
+        } else {
+            showInput = true;
+        }
+        
+        if (doShowInput) {
+            if (DEBUG) Log.v(TAG, "showWindow: updating UI");
+            updateFullscreenMode();
+            updateInputViewShown();
+        }
+        
+        if (!mWindowAdded || !mWindowCreated) {
+            mWindowAdded = true;
+            mWindowCreated = true;
+            View v = onCreateCandidatesView();
+            if (DEBUG) Log.v(TAG, "showWindow: candidates=" + v);
+            if (v != null) {
+                setCandidatesView(v);
+            }
+        }
+        if (doShowInput) {
+            if (mInputStarted) {
+                if (DEBUG) Log.v(TAG, "showWindow: starting input view");
+                onStartInputView(mInputInfo, false);
+            }
+            startExtractingText();
+        }
+        
+        if (!wasVisible) {
+            if (DEBUG) Log.v(TAG, "showWindow: showing!");
+            mWindow.show();
+            if (mInputConnection != null) {
+                mInputConnection.showStatusIcon(getPackageName(), mStatusIcon);
+            }
+        }
+    }
+    
+    public void hideWindow() {
+        if (mWindowVisible) {
+            mWindow.hide();
+            mWindowVisible = false;
+            if (mInputConnection != null) {
+                mInputConnection.hideStatusIcon();
+            }
+        }
+    }
+    
+    public void onBindInput() {
+    }
+    
+    public void onStartInput(EditorInfo attribute, boolean restarting) {
+    }
+    
+    void doStartInput(EditorInfo attribute, boolean restarting) {
+        mInputStarted = true;
+        mInputInfo = attribute;
+        onStartInput(attribute, restarting);
+        if (mWindowVisible) {
+            if (mWindowCreated) {
+                onStartInputView(mInputInfo, restarting);
+            }
+            startExtractingText();
+        }
+    }
+    
+    public void onFinishInput() {
+    }
+    
+    /**
+     * Called when the application has reported auto-completion candidates that
+     * it would like to have the input method displayed.  Typically these are
+     * only used when an input method is running in full-screen mode, since
+     * otherwise the user can see and interact with the pop-up window of
+     * completions shown by the application.
+     * 
+     * <p>The default implementation here does nothing.
+     */
+    public void onDisplayCompletions(CompletionInfo[] completions) {
+    }
+    
+    /**
+     * Called when the application has reported new extracted text to be shown
+     * due to changes in its current text state.  The default implementation
+     * here places the new text in the extract edit text, when the input
+     * method is running in fullscreen mode.
+     */
+    public void onUpdateExtractedText(int token, ExtractedText text) {
+        if (mExtractedToken != token) {
+            return;
+        }
+        if (mExtractEditText != null && text != null) {
+            mExtractedText = text;
+            mExtractEditText.setExtractedText(text);
+        }
+    }
+    
+    /**
+     * Called when the application has reported a new selection region of
+     * the text.  This is called whether or not the input method has requested
+     * extracted text updates, although if so it will not receive this call
+     * if the extracted text has changed as well.
+     * 
+     * <p>The default implementation takes care of updating the cursor in
+     * the extract text, if it is being shown.
+     */
+    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
+            int newSelStart, int newSelEnd) {
+        if (mExtractEditText != null && mExtractedText != null) {
+            final int off = mExtractedText.startOffset;
+            mExtractEditText.setSelection(newSelStart-off, newSelEnd-off);
+        }
+    }
+
+    /**
+     * Called when the application has reported a new location of its text
+     * cursor.  This is only called if explicitly requested by the input method.
+     * The default implementation does nothing.
+     */
+    public void onUpdateCursor(Rect newCursor) {
+    }
+
+    /**
+     * Close this input method's soft input area, removing it from the display.
+     * The input method will continue running, but the user can no longer use
+     * it to generate input by touching the screen.
+     */
+    public void dismissSoftInput() {
+        ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE))
+                .hideSoftInputFromInputMethod(mToken);
+    }
+    
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (mWindowVisible && event.getKeyCode() == KeyEvent.KEYCODE_BACK
+                && event.getRepeatCount() == 0) {
+            dismissSoftInput();
+            return true;
+        }
+        return false;
+    }
+
+    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+        return false;
+    }
+
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    public boolean onTrackballEvent(MotionEvent event) {
+        return false;
+    }
+
+    public void onAppPrivateCommand(String action, Bundle data) {
+    }
+    
+    void startExtractingText() {
+        if (mExtractEditText != null && getCurrentInputStarted()
+                && isFullscreenMode()) {
+            mExtractedToken++;
+            ExtractedTextRequest req = new ExtractedTextRequest();
+            req.token = mExtractedToken;
+            req.hintMaxLines = 10;
+            req.hintMaxChars = 10000;
+            mExtractedText = mInputConnection.getExtractedText(req,
+                    InputConnection.EXTRACTED_TEXT_MONITOR);
+            if (mExtractedText != null) {
+                mExtractEditText.setExtractedText(mExtractedText);
+            }
+            mExtractEditText.setInputType(getCurrentInputInfo().inputType);
+            mExtractEditText.setHint(mInputInfo.hintText);
+        }
+    }
+}
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
new file mode 100755
index 0000000..75a2911
--- /dev/null
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -0,0 +1,756 @@
+/*
+ * Copyright (C) 2008-2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.inputmethodservice;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.TypedValue;
+import android.util.Xml;
+import android.view.Display;
+import android.view.WindowManager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+
+/**
+ * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
+ * consists of rows of keys.
+ * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p>
+ * <pre>
+ * &lt;Keyboard
+ *         android:keyWidth="%10p"
+ *         android:keyHeight="50px"
+ *         android:horizontalGap="2px"
+ *         android:verticalGap="2px" &gt;
+ *     &lt;Row android:keyWidth="32px" &gt;
+ *         &lt;Key android:keyLabel="A" /&gt;
+ *         ...
+ *     &lt;/Row&gt;
+ *     ...
+ * &lt;/Keyboard&gt;
+ * </pre>
+ * @attr ref android.R.styleable#Keyboard_keyWidth
+ * @attr ref android.R.styleable#Keyboard_keyHeight
+ * @attr ref android.R.styleable#Keyboard_horizontalGap
+ * @attr ref android.R.styleable#Keyboard_verticalGap
+ */
+public class Keyboard {
+
+    static final String TAG = "Keyboard";
+    
+    // Keyboard XML Tags
+    private static final String TAG_KEYBOARD = "Keyboard";
+    private static final String TAG_ROW = "Row";
+    private static final String TAG_KEY = "Key";
+
+    public static final int EDGE_LEFT = 0x01;
+    public static final int EDGE_RIGHT = 0x02;
+    public static final int EDGE_TOP = 0x04;
+    public static final int EDGE_BOTTOM = 0x08;
+
+    public static final int KEYCODE_SHIFT = -1;
+    public static final int KEYCODE_MODE_CHANGE = -2;
+    public static final int KEYCODE_CANCEL = -3;
+    public static final int KEYCODE_DONE = -4;
+    public static final int KEYCODE_DELETE = -5;
+    public static final int KEYCODE_ALT = -6;
+    
+    /** Keyboard label **/
+    private CharSequence mLabel;
+
+    /** Horizontal gap default for all rows */
+    private int mDefaultHorizontalGap;
+    
+    /** Default key width */
+    private int mDefaultWidth;
+
+    /** Default key height */
+    private int mDefaultHeight;
+
+    /** Default gap between rows */
+    private int mDefaultVerticalGap;
+
+    /** Is the keyboard in the shifted state */
+    private boolean mShifted;
+    
+    /** Key instance for the shift key, if present */
+    private Key mShiftKey;
+    
+    /** Key index for the shift key, if present */
+    private int mShiftKeyIndex = -1;
+    
+    /** Current key width, while loading the keyboard */
+    private int mKeyWidth;
+    
+    /** Current key height, while loading the keyboard */
+    private int mKeyHeight;
+    
+    /** Total height of the keyboard, including the padding and keys */
+    private int mTotalHeight;
+    
+    /** 
+     * Total width of the keyboard, including left side gaps and keys, but not any gaps on the
+     * right side.
+     */
+    private int mTotalWidth;
+    
+    /** List of keys in this keyboard */
+    private List<Key> mKeys;
+    
+    /** List of modifier keys such as Shift & Alt, if any */
+    private List<Key> mModifierKeys;
+    
+    /** Width of the screen available to fit the keyboard */
+    private int mDisplayWidth;
+
+    /** Height of the screen */
+    private int mDisplayHeight;
+
+    /** Keyboard mode, or zero, if none.  */
+    private int mKeyboardMode;
+    
+    /**
+     * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. 
+     * Some of the key size defaults can be overridden per row from what the {@link Keyboard}
+     * defines. 
+     * @attr ref android.R.styleable#Keyboard_keyWidth
+     * @attr ref android.R.styleable#Keyboard_keyHeight
+     * @attr ref android.R.styleable#Keyboard_horizontalGap
+     * @attr ref android.R.styleable#Keyboard_verticalGap
+     * @attr ref android.R.styleable#Keyboard_Row_rowEdgeFlags
+     * @attr ref android.R.styleable#Keyboard_Row_keyboardMode
+     */
+    public static class Row {
+        /** Default width of a key in this row. */
+        public int defaultWidth;
+        /** Default height of a key in this row. */
+        public int defaultHeight;
+        /** Default horizontal gap between keys in this row. */
+        public int defaultHorizontalGap;
+        /** Vertical gap following this row. */
+        public int verticalGap;
+        /**
+         * Edge flags for this row of keys. Possible values that can be assigned are
+         * {@link Keyboard#EDGE_TOP EDGE_TOP} and {@link Keyboard#EDGE_BOTTOM EDGE_BOTTOM}  
+         */
+        public int rowEdgeFlags;
+        
+        /** The keyboard mode for this row */
+        public int mode;
+        
+        private Keyboard parent;
+
+        public Row(Keyboard parent) {
+            this.parent = parent;
+        }
+        
+        public Row(Resources res, Keyboard parent, XmlResourceParser parser) {
+            this.parent = parent;
+            TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), 
+                    com.android.internal.R.styleable.Keyboard);
+            defaultWidth = getDimensionOrFraction(a, 
+                    com.android.internal.R.styleable.Keyboard_keyWidth, 
+                    parent.mDisplayWidth, parent.mDefaultWidth);
+            defaultHeight = getDimensionOrFraction(a, 
+                    com.android.internal.R.styleable.Keyboard_keyHeight, 
+                    parent.mDisplayWidth, parent.mDefaultHeight);
+            defaultHorizontalGap = getDimensionOrFraction(a, 
+                    com.android.internal.R.styleable.Keyboard_horizontalGap, 
+                    parent.mDisplayWidth, parent.mDefaultHorizontalGap);
+            verticalGap = getDimensionOrFraction(a, 
+                    com.android.internal.R.styleable.Keyboard_verticalGap, 
+                    parent.mDisplayWidth, parent.mDefaultVerticalGap);
+            a.recycle();
+            a = res.obtainAttributes(Xml.asAttributeSet(parser),
+                    com.android.internal.R.styleable.Keyboard_Row);
+            rowEdgeFlags = a.getInt(com.android.internal.R.styleable.Keyboard_Row_rowEdgeFlags, 0);
+            mode = a.getResourceId(com.android.internal.R.styleable.Keyboard_Row_keyboardMode,
+                    0);
+        }
+    }
+
+    /**
+     * Class for describing the position and characteristics of a single key in the keyboard.
+     * 
+     * @attr ref android.R.styleable#Keyboard_keyWidth
+     * @attr ref android.R.styleable#Keyboard_keyHeight
+     * @attr ref android.R.styleable#Keyboard_horizontalGap
+     * @attr ref android.R.styleable#Keyboard_Key_codes
+     * @attr ref android.R.styleable#Keyboard_Key_keyIcon
+     * @attr ref android.R.styleable#Keyboard_Key_keyLabel
+     * @attr ref android.R.styleable#Keyboard_Key_iconPreview
+     * @attr ref android.R.styleable#Keyboard_Key_isSticky
+     * @attr ref android.R.styleable#Keyboard_Key_isRepeatable
+     * @attr ref android.R.styleable#Keyboard_Key_isModifier
+     * @attr ref android.R.styleable#Keyboard_Key_popupKeyboard
+     * @attr ref android.R.styleable#Keyboard_Key_popupCharacters
+     * @attr ref android.R.styleable#Keyboard_Key_keyOutputText
+     * @attr ref android.R.styleable#Keyboard_Key_keyEdgeFlags
+     */
+    public static class Key {
+        /** 
+         * All the key codes (unicode or custom code) that this key could generate, zero'th 
+         * being the most important.
+         */
+        public int[] codes;
+        
+        /** Label to display */
+        public CharSequence label;
+        
+        /** Icon to display instead of a label. Icon takes precedence over a label */
+        public Drawable icon;
+        /** Preview version of the icon, for the preview popup */
+        public Drawable iconPreview;
+        /** Width of the key, not including the gap */
+        public int width;
+        /** Height of the key, not including the gap */
+        public int height;
+        /** The horizontal gap before this key */
+        public int gap;
+        /** Whether this key is sticky, i.e., a toggle key */
+        public boolean sticky;
+        /** X coordinate of the key in the keyboard layout */
+        public int x;
+        /** Y coordinate of the key in the keyboard layout */
+        public int y;
+        /** The current pressed state of this key */
+        public boolean pressed;
+        /** If this is a sticky key, is it on? */
+        public boolean on;
+        /** Text to output when pressed. This can be multiple characters, like ".com" */
+        public CharSequence text;
+        /** Popup characters */
+        public CharSequence popupCharacters;
+        
+        /** 
+         * Flags that specify the anchoring to edges of the keyboard for detecting touch events
+         * that are just out of the boundary of the key. This is a bit mask of 
+         * {@link Keyboard#EDGE_LEFT}, {@link Keyboard#EDGE_RIGHT}, {@link Keyboard#EDGE_TOP} and
+         * {@link Keyboard#EDGE_BOTTOM}.
+         */
+        public int edgeFlags;
+        /** Whether this is a modifier key, such as Shift or Alt */
+        public boolean modifier;
+        /** The keyboard that this key belongs to */
+        private Keyboard keyboard;
+        /** 
+         * If this key pops up a mini keyboard, this is the resource id for the XML layout for that
+         * keyboard.
+         */
+        public int popupResId;
+        /** Whether this key repeats itself when held down */
+        public boolean repeatable;
+
+        
+        private final static int[] KEY_STATE_NORMAL_ON = { 
+            android.R.attr.state_checkable, 
+            android.R.attr.state_checked
+        };
+        
+        private final static int[] KEY_STATE_PRESSED_ON = { 
+            android.R.attr.state_pressed, 
+            android.R.attr.state_checkable, 
+            android.R.attr.state_checked 
+        };
+        
+        private final static int[] KEY_STATE_NORMAL_OFF = { 
+            android.R.attr.state_checkable 
+        };
+        
+        private final static int[] KEY_STATE_PRESSED_OFF = { 
+            android.R.attr.state_pressed, 
+            android.R.attr.state_checkable 
+        };
+        
+        private final static int[] KEY_STATE_NORMAL = {
+        };
+        
+        private final static int[] KEY_STATE_PRESSED = {
+            android.R.attr.state_pressed
+        };
+
+        /** Create an empty key with no attributes. */
+        public Key(Row parent) {
+            keyboard = parent.parent;
+        }
+        
+        /** Create a key with the given top-left coordinate and extract its attributes from
+         * the XML parser.
+         * @param res resources associated with the caller's context
+         * @param parent the row that this key belongs to. The row must already be attached to
+         * a {@link Keyboard}.
+         * @param x the x coordinate of the top-left
+         * @param y the y coordinate of the top-left
+         * @param parser the XML parser containing the attributes for this key
+         */
+        public Key(Resources res, Row parent, int x, int y, XmlResourceParser parser) {
+            this(parent);
+
+            this.x = x;
+            this.y = y;
+            
+            TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), 
+                    com.android.internal.R.styleable.Keyboard);
+
+            width = getDimensionOrFraction(a, 
+                    com.android.internal.R.styleable.Keyboard_keyWidth,
+                    keyboard.mDisplayWidth, parent.defaultWidth);
+            height = getDimensionOrFraction(a, 
+                    com.android.internal.R.styleable.Keyboard_keyHeight,
+                    keyboard.mDisplayHeight, parent.defaultHeight);
+            gap = getDimensionOrFraction(a, 
+                    com.android.internal.R.styleable.Keyboard_horizontalGap,
+                    keyboard.mDisplayWidth, parent.defaultHorizontalGap);
+            a.recycle();
+            a = res.obtainAttributes(Xml.asAttributeSet(parser),
+                    com.android.internal.R.styleable.Keyboard_Key);
+            this.x += gap;
+            TypedValue codesValue = new TypedValue();
+            a.getValue(com.android.internal.R.styleable.Keyboard_Key_codes, 
+                    codesValue);
+            if (codesValue.type == TypedValue.TYPE_INT_DEC 
+                    || codesValue.type == TypedValue.TYPE_INT_HEX) {
+                codes = new int[] { codesValue.data };
+            } else if (codesValue.type == TypedValue.TYPE_STRING) {
+                codes = parseCSV(codesValue.string.toString());
+            }
+            
+            iconPreview = a.getDrawable(com.android.internal.R.styleable.Keyboard_Key_iconPreview);
+            if (iconPreview != null) {
+                iconPreview.setBounds(0, 0, iconPreview.getIntrinsicWidth(), 
+                        iconPreview.getIntrinsicHeight());
+            }
+            popupCharacters = a.getText(
+                    com.android.internal.R.styleable.Keyboard_Key_popupCharacters);
+            popupResId = a.getResourceId(
+                    com.android.internal.R.styleable.Keyboard_Key_popupKeyboard, 0);
+            repeatable = a.getBoolean(
+                    com.android.internal.R.styleable.Keyboard_Key_isRepeatable, false);
+            modifier = a.getBoolean(
+                    com.android.internal.R.styleable.Keyboard_Key_isModifier, false);
+            sticky = a.getBoolean(
+                    com.android.internal.R.styleable.Keyboard_Key_isSticky, false);
+            edgeFlags = a.getInt(com.android.internal.R.styleable.Keyboard_Key_keyEdgeFlags, 0);
+            edgeFlags |= parent.rowEdgeFlags;
+
+            icon = a.getDrawable(
+                    com.android.internal.R.styleable.Keyboard_Key_keyIcon);
+            if (icon != null) {
+                icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
+            }
+            label = a.getText(com.android.internal.R.styleable.Keyboard_Key_keyLabel);
+            text = a.getText(com.android.internal.R.styleable.Keyboard_Key_keyOutputText);
+            
+            if (codes == null && !TextUtils.isEmpty(label)) {
+                codes = new int[] { label.charAt(0) };
+            }
+            a.recycle();
+        }
+        
+        /**
+         * Informs the key that it has been pressed, in case it needs to change its appearance or
+         * state.
+         * @see #onReleased(boolean)
+         */
+        public void onPressed() {
+            pressed = !pressed;
+        }
+        
+        /**
+         * Changes the pressed state of the key. If it is a sticky key, it will also change the
+         * toggled state of the key if the finger was release inside.
+         * @param inside whether the finger was released inside the key
+         * @see #onPressed()
+         */
+        public void onReleased(boolean inside) {
+            pressed = !pressed;
+            if (sticky) {
+                on = !on;
+            }
+        }
+
+        int[] parseCSV(String value) {
+            int count = 0;
+            int lastIndex = 0;
+            if (value.length() > 0) {
+                count++;
+                while ((lastIndex = value.indexOf(",", lastIndex + 1)) > 0) {
+                    count++;
+                }
+            }
+            int[] values = new int[count];
+            count = 0;
+            StringTokenizer st = new StringTokenizer(value, ",");
+            while (st.hasMoreTokens()) {
+                try {
+                    values[count++] = Integer.parseInt(st.nextToken());
+                } catch (NumberFormatException nfe) {
+                    Log.e(TAG, "Error parsing keycodes " + value);
+                }
+            }
+            return values;
+        }
+
+        /**
+         * Detects if a point falls inside this key.
+         * @param x the x-coordinate of the point 
+         * @param y the y-coordinate of the point
+         * @return whether or not the point falls inside the key. If the key is attached to an edge,
+         * it will assume that all points between the key and the edge are considered to be inside
+         * the key.
+         */
+        public boolean isInside(int x, int y) {
+            boolean leftEdge = (edgeFlags & EDGE_LEFT) > 0;
+            boolean rightEdge = (edgeFlags & EDGE_RIGHT) > 0;
+            boolean topEdge = (edgeFlags & EDGE_TOP) > 0;
+            boolean bottomEdge = (edgeFlags & EDGE_BOTTOM) > 0;
+            if ((x >= this.x || (leftEdge && x <= this.x + this.width)) 
+                    && (x < this.x + this.width || (rightEdge && x >= this.x)) 
+                    && (y >= this.y || (topEdge && y <= this.y + this.height))
+                    && (y < this.y + this.height || (bottomEdge && y >= this.y))) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        
+        /**
+         * Returns the square of the distance between the center of the key and the given point.
+         * @param x the x-coordinate of the point
+         * @param y the y-coordinate of the point
+         * @return the square of the distance of the point from the center of the key
+         */
+        public int squaredDistanceFrom(int x, int y) {
+            float xDist = Math.abs((this.x + this.x + width) / 2f - x);
+            float yDist = Math.abs((this.y + this.y + height) / 2f - y);
+            return (int) (xDist * xDist + yDist * yDist);
+        }
+        
+        /**
+         * Returns the drawable state for the key, based on the current state and type of the key.
+         * @return the drawable state of the key.
+         * @see android.graphics.drawable.StateListDrawable#setState(int[])
+         */
+        public int[] getCurrentDrawableState() {
+            int[] states = KEY_STATE_NORMAL;
+
+            if (on) {
+                if (pressed) {
+                    states = KEY_STATE_PRESSED_ON;
+                } else {
+                    states = KEY_STATE_NORMAL_ON;
+                }
+            } else {
+                if (sticky) {
+                    if (pressed) {
+                        states = KEY_STATE_PRESSED_OFF;
+                    } else {
+                        states = KEY_STATE_NORMAL_OFF;
+                    }
+                } else {
+                    if (pressed) {
+                        states = KEY_STATE_PRESSED;
+                    }
+                }
+            }
+            return states;
+        }
+    }
+
+    /**
+     * Creates a keyboard from the given xml key layout file.
+     * @param context the application or service context
+     * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
+     */
+    public Keyboard(Context context, int xmlLayoutResId) {
+        this(context, xmlLayoutResId, 0);
+    }
+    
+    /**
+     * Creates a keyboard from the given xml key layout file. Weeds out rows
+     * that have a keyboard mode defined but don't match the specified mode. 
+     * @param context the application or service context
+     * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
+     * @param modeId keyboard mode identifier
+     */
+    public Keyboard(Context context, int xmlLayoutResId, int modeId) {
+        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        final Display display = wm.getDefaultDisplay();
+        mDisplayWidth = display.getWidth();
+        mDisplayHeight = display.getHeight();
+        mDefaultHorizontalGap = 0;
+        mDefaultWidth = mDisplayWidth / 10;
+        mDefaultVerticalGap = 0;
+        mDefaultHeight = mDefaultWidth;
+        mKeys = new ArrayList<Key>();
+        mModifierKeys = new ArrayList<Key>();
+        mKeyboardMode = modeId;
+        loadKeyboard(context, context.getResources().getXml(xmlLayoutResId));
+    }
+
+    /**
+     * <p>Creates a blank keyboard from the given resource file and populates it with the specified
+     * characters in left-to-right, top-to-bottom fashion, using the specified number of columns.
+     * </p>
+     * <p>If the specified number of columns is -1, then the keyboard will fit as many keys as
+     * possible in each row.</p>
+     * @param context the application or service context
+     * @param layoutTemplateResId the layout template file, containing no keys.
+     * @param characters the list of characters to display on the keyboard. One key will be created
+     * for each character.
+     * @param columns the number of columns of keys to display. If this number is greater than the 
+     * number of keys that can fit in a row, it will be ignored. If this number is -1, the 
+     * keyboard will fit as many keys as possible in each row.
+     */
+    public Keyboard(Context context, int layoutTemplateResId, 
+            CharSequence characters, int columns, int horizontalPadding) {
+        this(context, layoutTemplateResId);
+        int x = 0;
+        int y = 0;
+        int column = 0;
+        mTotalWidth = 0;
+        
+        Row row = new Row(this);
+        row.defaultHeight = mDefaultHeight;
+        row.defaultWidth = mDefaultWidth;
+        row.defaultHorizontalGap = mDefaultHorizontalGap;
+        row.verticalGap = mDefaultVerticalGap;
+        row.rowEdgeFlags = EDGE_TOP | EDGE_BOTTOM;
+        
+        final int maxColumns = columns == -1 ? Integer.MAX_VALUE : columns;
+        for (int i = 0; i < characters.length(); i++) {
+            char c = characters.charAt(i);
+            if (column >= maxColumns 
+                    || x + mDefaultWidth + horizontalPadding > mDisplayWidth) {
+                x = 0;
+                y += mDefaultVerticalGap + mDefaultHeight;
+                column = 0;
+            }
+            final Key key = new Key(row);
+            key.x = x;
+            key.y = y;
+            key.width = mDefaultWidth;
+            key.height = mDefaultHeight;
+            key.gap = mDefaultHorizontalGap;
+            key.label = String.valueOf(c);
+            key.codes = new int[] { c };
+            column++;
+            x += key.width + key.gap;
+            mKeys.add(key);
+            if (x > mTotalWidth) {
+                mTotalWidth = x;
+            }
+        }
+        mTotalHeight = y + mDefaultHeight; 
+    }
+    
+    public List<Key> getKeys() {
+        return mKeys;
+    }
+    
+    public List<Key> getModifierKeys() {
+        return mModifierKeys;
+    }
+    
+    protected int getHorizontalGap() {
+        return mDefaultHorizontalGap;
+    }
+    
+    protected void setHorizontalGap(int gap) {
+        mDefaultHorizontalGap = gap;
+    }
+
+    protected int getVerticalGap() {
+        return mDefaultVerticalGap;
+    }
+
+    protected void setVerticalGap(int gap) {
+        mDefaultVerticalGap = gap;
+    }
+
+    protected int getKeyHeight() {
+        return mDefaultHeight;
+    }
+
+    protected void setKeyHeight(int height) {
+        mDefaultHeight = height;
+    }
+
+    protected int getKeyWidth() {
+        return mDefaultWidth;
+    }
+    
+    protected void setKeyWidth(int width) {
+        mDefaultWidth = width;
+    }
+
+    /**
+     * Returns the total height of the keyboard
+     * @return the total height of the keyboard
+     */
+    public int getHeight() {
+        return mTotalHeight;
+    }
+    
+    public int getMinWidth() {
+        return mTotalWidth;
+    }
+
+    public boolean setShifted(boolean shiftState) {
+        if (mShiftKey != null) {
+            mShiftKey.on = shiftState;
+        }
+        if (mShifted != shiftState) {
+            mShifted = shiftState;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isShifted() {
+        return mShifted;
+    }
+
+    public int getShiftKeyIndex() {
+        return mShiftKeyIndex;
+    }
+
+    protected Row createRowFromXml(Resources res, XmlResourceParser parser) {
+        return new Row(res, this, parser);
+    }
+    
+    protected Key createKeyFromXml(Resources res, Row parent, int x, int y, 
+            XmlResourceParser parser) {
+        return new Key(res, parent, x, y, parser);
+    }
+
+    private void loadKeyboard(Context context, XmlResourceParser parser) {
+        boolean inKey = false;
+        boolean inRow = false;
+        boolean leftMostKey = false;
+        int row = 0;
+        int x = 0;
+        int y = 0;
+        Key key = null;
+        Row currentRow = null;
+        Resources res = context.getResources();
+        boolean skipRow = false;
+        
+        try {
+            int event;
+            while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
+                if (event == XmlResourceParser.START_TAG) {
+                    String tag = parser.getName();
+                    if (TAG_ROW.equals(tag)) {
+                        inRow = true;
+                        x = 0;
+                        currentRow = createRowFromXml(res, parser);
+                        skipRow = currentRow.mode != 0 && currentRow.mode != mKeyboardMode;
+                        if (skipRow) {
+                            skipToEndOfRow(parser);
+                            inRow = false;
+                        }
+                   } else if (TAG_KEY.equals(tag)) {
+                        inKey = true;
+                        key = createKeyFromXml(res, currentRow, x, y, parser);
+                        mKeys.add(key);
+                        if (key.codes[0] == KEYCODE_SHIFT) {
+                            mShiftKey = key;
+                            mShiftKeyIndex = mKeys.size()-1;
+                            mModifierKeys.add(key);
+                        } else if (key.codes[0] == KEYCODE_ALT) {
+                            mModifierKeys.add(key);
+                        }
+                    } else if (TAG_KEYBOARD.equals(tag)) {
+                        parseKeyboardAttributes(res, parser);
+                    }
+                } else if (event == XmlResourceParser.END_TAG) {
+                    if (inKey) {
+                        inKey = false;
+                        x += key.gap + key.width;
+                        if (x > mTotalWidth) {
+                            mTotalWidth = x;
+                        }
+                    } else if (inRow) {
+                        inRow = false;
+                        y += currentRow.verticalGap;
+                        y += currentRow.defaultHeight;
+                        row++;
+                    } else {
+                        // TODO: error or extend?
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Parse error:" + e);
+            e.printStackTrace();
+        }
+        mTotalHeight = y - mDefaultVerticalGap;
+    }
+
+    private void skipToEndOfRow(XmlResourceParser parser) 
+            throws XmlPullParserException, IOException {
+        int event;
+        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
+            if (event == XmlResourceParser.END_TAG 
+                    && parser.getName().equals(TAG_ROW)) {
+                break;
+            }
+        }
+    }
+    
+    private void parseKeyboardAttributes(Resources res, XmlResourceParser parser) {
+        TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), 
+                com.android.internal.R.styleable.Keyboard);
+
+        mDefaultWidth = getDimensionOrFraction(a,
+                com.android.internal.R.styleable.Keyboard_keyWidth,
+                mDisplayWidth, mDisplayWidth / 10);
+        mDefaultHeight = getDimensionOrFraction(a,
+                com.android.internal.R.styleable.Keyboard_keyHeight,
+                mDisplayHeight, 50);
+        mDefaultHorizontalGap = getDimensionOrFraction(a,
+                com.android.internal.R.styleable.Keyboard_horizontalGap,
+                mDisplayWidth, 0);
+        mDefaultVerticalGap = getDimensionOrFraction(a,
+                com.android.internal.R.styleable.Keyboard_verticalGap,
+                mDisplayHeight, 0);
+        a.recycle();
+    }
+    
+    static int getDimensionOrFraction(TypedArray a, int index, int base, int defValue) {
+        TypedValue value = a.peekValue(index);
+        if (value == null) return defValue;
+        if (value.type == TypedValue.TYPE_DIMENSION) {
+            return a.getDimensionPixelOffset(index, defValue);
+        } else if (value.type == TypedValue.TYPE_FRACTION) {
+            return (int) a.getFraction(index, base, base, defValue);
+        }
+        return defValue;
+    }
+}
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
new file mode 100755
index 0000000..56473da
--- /dev/null
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -0,0 +1,1049 @@
+/*
+ * Copyright (C) 2008-2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.inputmethodservice;
+
+import com.android.internal.R;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Paint.Align;
+import android.graphics.drawable.Drawable;
+import android.inputmethodservice.Keyboard.Key;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Vibrator;
+import android.preference.PreferenceManager;
+import android.util.AttributeSet;
+import android.view.GestureDetector;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.Button;
+import android.widget.PopupWindow;
+import android.widget.TextView;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A view that renders a virtual {@link Keyboard}. It handles rendering of keys and
+ * detecting key presses and touch movements.
+ * 
+ * @attr ref android.R.styleable#KeyboardView_keyBackground
+ * @attr ref android.R.styleable#KeyboardView_keyPreviewLayout
+ * @attr ref android.R.styleable#KeyboardView_keyPreviewOffset
+ * @attr ref android.R.styleable#KeyboardView_labelTextSize
+ * @attr ref android.R.styleable#KeyboardView_keyTextSize
+ * @attr ref android.R.styleable#KeyboardView_keyTextColor
+ * @attr ref android.R.styleable#KeyboardView_verticalCorrection
+ * @attr ref android.R.styleable#KeyboardView_popupLayout
+ */
+public class KeyboardView extends View implements View.OnClickListener {
+
+    /**
+     * Listener for virtual keyboard events.
+     */
+    public interface OnKeyboardActionListener {
+        /**
+         * Send a key press to the listener.
+         * @param primaryCode this is the key that was pressed
+         * @param keyCodes the codes for all the possible alternative keys
+         * with the primary code being the first. If the primary key code is
+         * a single character such as an alphabet or number or symbol, the alternatives
+         * will include other characters that may be on the same key or adjacent keys.
+         * These codes are useful to correct for accidental presses of a key adjacent to
+         * the intended key.
+         */
+        void onKey(int primaryCode, int[] keyCodes);
+
+        /**
+         * Called when the user quickly moves the finger from right to left.
+         */
+        void swipeLeft();
+        
+        /**
+         * Called when the user quickly moves the finger from left to right.
+         */
+        void swipeRight();
+        
+        /**
+         * Called when the user quickly moves the finger from up to down.
+         */
+        void swipeDown();
+        
+        /**
+         * Called when the user quickly moves the finger from down to up.
+         */
+        void swipeUp();
+    }
+
+    private static final boolean DEBUG = false;
+    private static final int NOT_A_KEY = -1;
+    private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE };
+    private static final int[] LONG_PRESSABLE_STATE_SET = { R.attr.state_long_pressable };   
+    
+    private Keyboard mKeyboard;
+    private int mCurrentKeyIndex = NOT_A_KEY;
+    private int mLabelTextSize;
+    private int mKeyTextSize;
+    private int mKeyTextColor;
+    
+    private TextView mPreviewText;
+    private PopupWindow mPreviewPopup;
+    private int mPreviewTextSizeLarge;
+    private int mPreviewOffset;
+    private int mPreviewHeight;
+    private int[] mOffsetInWindow;
+
+    private PopupWindow mPopupKeyboard;
+    private View mMiniKeyboardContainer;
+    private KeyboardView mMiniKeyboard;
+    private boolean mMiniKeyboardOnScreen;
+    private View mPopupParent;
+    private int mMiniKeyboardOffsetX;
+    private int mMiniKeyboardOffsetY;
+    private Map<Key,View> mMiniKeyboardCache;
+    private int[] mWindowOffset;
+
+    /** Listener for {@link OnKeyboardActionListener}. */
+    private OnKeyboardActionListener mKeyboardActionListener;
+    
+    private static final int MSG_REMOVE_PREVIEW = 1;
+    private static final int MSG_REPEAT = 2;
+    
+    private int mVerticalCorrection;
+    private int mProximityThreshold;
+
+    private boolean mPreviewCentered = false;
+    private boolean mShowPreview = true;
+    private boolean mShowTouchPoints = false;
+    private int mPopupPreviewX;
+    private int mPopupPreviewY;
+
+    private int mLastX;
+    private int mLastY;
+    private int mStartX;
+    private int mStartY;
+
+    private boolean mVibrateOn;
+    private boolean mSoundOn;
+    private boolean mProximityCorrectOn;
+    
+    private Paint mPaint;
+    private Rect mPadding;
+    
+    private long mDownTime;
+    private long mLastMoveTime;
+    private int mLastKey;
+    private int mLastCodeX;
+    private int mLastCodeY;
+    private int mCurrentKey = NOT_A_KEY;
+    private long mLastKeyTime;
+    private long mCurrentKeyTime;
+    private int[] mKeyIndices = new int[12];
+    private GestureDetector mGestureDetector;
+    private int mPopupX;
+    private int mPopupY;
+    private int mRepeatKeyIndex = NOT_A_KEY;
+    private int mPopupLayout;
+    private boolean mAbortKey;
+    
+    private Drawable mKeyBackground;
+    
+    private static final String PREF_VIBRATE_ON = "vibrate_on";
+    private static final String PREF_SOUND_ON = "sound_on";
+    private static final String PREF_PROXIMITY_CORRECTION = "hit_correction";
+
+    private static final int REPEAT_INTERVAL = 50; // ~20 keys per second
+    private static final int REPEAT_START_DELAY = 400;
+
+    private Vibrator mVibrator;
+    private long[] mVibratePattern = new long[] {1, 20};
+
+    private static int MAX_NEARBY_KEYS = 12;
+    private int[] mDistances = new int[MAX_NEARBY_KEYS];
+
+    // For multi-tap
+    private int mLastSentIndex;
+    private int mTapCount;
+    private long mLastTapTime;
+    private boolean mInMultiTap;
+    private static final int MULTITAP_INTERVAL = 800; // milliseconds
+    private StringBuilder mPreviewLabel = new StringBuilder(1);
+
+    Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_REMOVE_PREVIEW:
+                    mPreviewText.setVisibility(INVISIBLE);
+                    break;
+                case MSG_REPEAT:
+                    if (repeatKey()) {
+                        Message repeat = Message.obtain(this, MSG_REPEAT);
+                        sendMessageDelayed(repeat, REPEAT_INTERVAL);                        
+                    }
+                    break;
+            }
+            
+        }
+    };
+
+    public KeyboardView(Context context, AttributeSet attrs) {
+        this(context, attrs, com.android.internal.R.attr.keyboardViewStyle);
+    }
+
+    public KeyboardView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a =
+            context.obtainStyledAttributes(
+                attrs, android.R.styleable.KeyboardView, defStyle, 0);
+
+        LayoutInflater inflate =
+                (LayoutInflater) context
+                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        int previewLayout = 0;
+        int keyTextSize = 0;
+
+        int n = a.getIndexCount();
+        
+        for (int i = 0; i < n; i++) {
+            int attr = a.getIndex(i);
+
+            switch (attr) {
+            case com.android.internal.R.styleable.KeyboardView_keyBackground:
+                mKeyBackground = a.getDrawable(attr);
+                break;
+            case com.android.internal.R.styleable.KeyboardView_verticalCorrection:
+                mVerticalCorrection = a.getDimensionPixelOffset(attr, 0);
+                break;
+            case com.android.internal.R.styleable.KeyboardView_keyPreviewLayout:
+                previewLayout = a.getResourceId(attr, 0);
+                break;
+            case com.android.internal.R.styleable.KeyboardView_keyPreviewOffset:
+                mPreviewOffset = a.getDimensionPixelOffset(attr, 0);
+                break;
+            case com.android.internal.R.styleable.KeyboardView_keyPreviewHeight:
+                mPreviewHeight = a.getDimensionPixelSize(attr, 80);
+                break;
+            case com.android.internal.R.styleable.KeyboardView_keyTextSize:
+                mKeyTextSize = a.getDimensionPixelSize(attr, 18);
+                break;
+            case com.android.internal.R.styleable.KeyboardView_keyTextColor:
+                mKeyTextColor = a.getColor(attr, 0xFF000000);
+                break;
+            case com.android.internal.R.styleable.KeyboardView_labelTextSize:
+                mLabelTextSize = a.getDimensionPixelSize(attr, 14);
+                break;
+            case com.android.internal.R.styleable.KeyboardView_popupLayout:
+                mPopupLayout = a.getResourceId(attr, 0);
+                break;
+            }
+        }
+        
+        // Get the settings preferences
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+        mVibrateOn = sp.getBoolean(PREF_VIBRATE_ON, mVibrateOn);
+        mSoundOn = sp.getBoolean(PREF_SOUND_ON, mSoundOn);
+        mProximityCorrectOn = sp.getBoolean(PREF_PROXIMITY_CORRECTION, true);
+        
+        mPreviewPopup = new PopupWindow(context);
+        if (previewLayout != 0) {
+            mPreviewText = (TextView) inflate.inflate(previewLayout, null);
+            mPreviewTextSizeLarge = (int) mPreviewText.getTextSize();
+            mPreviewPopup.setContentView(mPreviewText);
+            mPreviewPopup.setBackgroundDrawable(null);
+        } else {
+            mShowPreview = false;
+        }
+        
+        mPreviewPopup.setTouchable(false);
+        
+        mPopupKeyboard = new PopupWindow(context);
+        mPopupKeyboard.setBackgroundDrawable(null);
+        //mPopupKeyboard.setClippingEnabled(false);
+        
+        mPopupParent = this;
+        //mPredicting = true;
+        
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setTextSize(keyTextSize);
+        mPaint.setTextAlign(Align.CENTER);
+
+        mPadding = new Rect(0, 0, 0, 0);
+        mMiniKeyboardCache = new HashMap<Key,View>();
+        mKeyBackground.getPadding(mPadding);
+        
+        resetMultiTap();
+        initGestureDetector();
+    }
+    
+    private void initGestureDetector() {
+        mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
+            @Override
+            public boolean onFling(MotionEvent me1, MotionEvent me2, 
+                    float velocityX, float velocityY) {
+                if (velocityX > 400 && Math.abs(velocityY) < 400) {
+                    swipeRight();
+                    return true;
+                } else if (velocityX < -400 && Math.abs(velocityY) < 400) {
+                    swipeLeft();
+                    return true;
+                } else if (velocityY < -400 && Math.abs(velocityX) < 400) {
+                    swipeUp();
+                    return true;
+                } else if (velocityY > 400 && Math.abs(velocityX) < 400) {
+                    swipeDown();
+                    return true;
+                }
+                return false;
+            }
+            
+            @Override
+            public void onLongPress(MotionEvent me) {
+                openPopupIfRequired(me);
+            }
+        });
+    }
+
+    public void setOnKeyboardActionListener(OnKeyboardActionListener listener) {
+        mKeyboardActionListener = listener;
+    }
+
+    /**
+     * Returns the {@link OnKeyboardActionListener} object.
+     * @return the listener attached to this keyboard
+     */
+    protected OnKeyboardActionListener getOnKeyboardActionListener() {
+        return mKeyboardActionListener;
+    }
+
+    /**
+     * Attaches a keyboard to this view. The keyboard can be switched at any time and the
+     * view will re-layout itself to accommodate the keyboard.
+     * @see Keyboard
+     * @see #getKeyboard()
+     * @param keyboard the keyboard to display in this view
+     */
+    public void setKeyboard(Keyboard keyboard) {
+        mKeyboard = keyboard;
+        requestLayout();
+        invalidate();
+        computeProximityThreshold(keyboard);
+    }
+
+    /**
+     * Returns the current keyboard being displayed by this view.
+     * @return the currently attached keyboard
+     * @see #setKeyboard(Keyboard)
+     */
+    public Keyboard getKeyboard() {
+        return mKeyboard;
+    }
+    
+    /**
+     * Sets the state of the shift key of the keyboard, if any.
+     * @param shifted whether or not to enable the state of the shift key
+     * @return true if the shift key state changed, false if there was no change
+     * @see KeyboardView#isShifted()
+     */
+    public boolean setShifted(boolean shifted) {
+        if (mKeyboard != null) {
+            if (mKeyboard.setShifted(shifted)) {
+                // The whole keyboard probably needs to be redrawn
+                invalidate();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the state of the shift key of the keyboard, if any.
+     * @return true if the shift is in a pressed state, false otherwise. If there is
+     * no shift key on the keyboard or there is no keyboard attached, it returns false.
+     * @see KeyboardView#setShifted(boolean)
+     */
+    public boolean isShifted() {
+        if (mKeyboard != null) {
+            return mKeyboard.isShifted();
+        }
+        return false;
+    }
+
+    /**
+     * Enables or disables the key feedback popup. This is a popup that shows a magnified
+     * version of the depressed key. By default the preview is enabled. 
+     * @param previewEnabled whether or not to enable the key feedback popup
+     * @see #isPreviewEnabled()
+     */
+    public void setPreviewEnabled(boolean previewEnabled) {
+        mShowPreview = previewEnabled;
+    }
+
+    /**
+     * Returns the enabled state of the key feedback popup.
+     * @return whether or not the key feedback popup is enabled
+     * @see #setPreviewEnabled(boolean)
+     */
+    public boolean isPreviewEnabled() {
+        return mShowPreview;
+    }
+    
+    public void setVerticalCorrection(int verticalOffset) {
+        
+    }
+    public void setPopupParent(View v) {
+        mPopupParent = v;
+    }
+    
+    public void setPopupOffset(int x, int y) {
+        mMiniKeyboardOffsetX = x;
+        mMiniKeyboardOffsetY = y;
+        if (mPreviewPopup.isShowing()) {
+            mPreviewPopup.dismiss();
+        }
+    }
+    
+    /** 
+     * Popup keyboard close button clicked.
+     * @hide 
+     */
+    public void onClick(View v) {
+        dismissPopupKeyboard();
+    }
+
+    private CharSequence adjustCase(CharSequence label) {
+        if (mKeyboard.isShifted() && label != null && label.length() == 1
+                && Character.isLowerCase(label.charAt(0))) {
+            label = label.toString().toUpperCase();
+        }
+        return label;
+    }
+
+    @Override
+    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // Round up a little
+        if (mKeyboard == null) {
+            setMeasuredDimension(mPaddingLeft + mPaddingRight, mPaddingTop + mPaddingBottom);
+        } else {
+            int width = mKeyboard.getMinWidth() + mPaddingLeft + mPaddingRight;
+            if (MeasureSpec.getSize(widthMeasureSpec) < width + 10) {
+                width = MeasureSpec.getSize(widthMeasureSpec);
+            }
+            setMeasuredDimension(width, mKeyboard.getHeight() + mPaddingTop + mPaddingBottom);
+        }
+    }
+
+    /**
+     * Compute the average distance between adjacent keys (horizontally and vertically)
+     * and square it to get the proximity threshold. We use a square here and in computing
+     * the touch distance from a key's center to avoid taking a square root.
+     * @param keyboard
+     */
+    private void computeProximityThreshold(Keyboard keyboard) {
+        if (keyboard == null) return;
+        List<Key> keys = keyboard.getKeys();
+        if (keys == null) return;
+        int length = keys.size();
+        int dimensionSum = 0;
+        for (int i = 0; i < length; i++) {
+            Key key = keys.get(i);
+            dimensionSum += key.width + key.gap + key.height; 
+        }
+        if (dimensionSum < 0 || length == 0) return;
+        mProximityThreshold = dimensionSum / (length * 2);
+        mProximityThreshold *= mProximityThreshold; // Square it
+    }
+    
+    @Override
+    public void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        if (mKeyboard == null) return;
+        
+        final Paint paint = mPaint;
+        //final int descent = (int) paint.descent();
+        final Drawable keyBackground = mKeyBackground;
+        final Rect padding = mPadding;
+        final int kbdPaddingLeft = mPaddingLeft;
+        final int kbdPaddingTop = mPaddingTop;
+        List<Key> keys = mKeyboard.getKeys();
+        //canvas.translate(0, mKeyboardPaddingTop);
+        paint.setAlpha(255);
+        paint.setColor(mKeyTextColor);
+
+        final int keyCount = keys.size();
+        for (int i = 0; i < keyCount; i++) {
+            final Key key = keys.get(i);
+            int[] drawableState = key.getCurrentDrawableState();
+            keyBackground.setState(drawableState);
+            
+            // Switch the character to uppercase if shift is pressed
+            String label = key.label == null? null : adjustCase(key.label).toString();
+            
+            final Rect bounds = keyBackground.getBounds();
+            if (key.width != bounds.right || 
+                    key.height != bounds.bottom) {
+                keyBackground.setBounds(0, 0, key.width, key.height);
+            }
+            canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop);
+            keyBackground.draw(canvas);
+            
+            if (label != null) {
+                // For characters, use large font. For labels like "Done", use small font.
+                if (label.length() > 1 && key.codes.length < 2) {
+                    paint.setTextSize(mLabelTextSize);
+                    paint.setFakeBoldText(true);
+                } else {
+                    paint.setTextSize(mKeyTextSize);
+                    paint.setFakeBoldText(false);
+                }
+                // Draw a drop shadow for the text
+                paint.setShadowLayer(3f, 0, 0, 0xCC000000);
+                // Draw the text
+                canvas.drawText(label,
+                    (key.width - padding.left - padding.right) / 2
+                            + padding.left,
+                    (key.height - padding.top - padding.bottom) / 2
+                            + (paint.getTextSize() - paint.descent()) / 2 + padding.top,
+                    paint);
+                // Turn off drop shadow
+                paint.setShadowLayer(0, 0, 0, 0);
+            } else if (key.icon != null) {
+                final int drawableX = (key.width - padding.left - padding.right 
+                                - key.icon.getIntrinsicWidth()) / 2 + padding.left;
+                final int drawableY = (key.height - padding.top - padding.bottom 
+                        - key.icon.getIntrinsicHeight()) / 2 + padding.top;
+                canvas.translate(drawableX, drawableY);
+                key.icon.setBounds(0, 0, 
+                        key.icon.getIntrinsicWidth(), key.icon.getIntrinsicHeight());
+                key.icon.draw(canvas);
+                canvas.translate(-drawableX, -drawableY);
+            }
+            canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop);
+        }
+        
+        // Overlay a dark rectangle to dim the keyboard
+        if (mMiniKeyboardOnScreen) {
+            paint.setColor(0xA0000000);
+            canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
+        }
+
+        if (DEBUG && mShowTouchPoints) {
+            paint.setAlpha(128);
+            paint.setColor(0xFFFF0000);
+            canvas.drawCircle(mStartX, mStartY, 3, paint);
+            canvas.drawLine(mStartX, mStartY, mLastX, mLastY, paint);
+            paint.setColor(0xFF0000FF);
+            canvas.drawCircle(mLastX, mLastY, 3, paint);
+            paint.setColor(0xFF00FF00);
+            canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint);
+        }
+    }
+
+    private void playKeyClick() {
+        if (mSoundOn) {
+            playSoundEffect(0);
+        }
+    }
+
+    private void vibrate() {
+        if (!mVibrateOn) {
+            return;
+        }
+        if (mVibrator == null) {
+            mVibrator = new Vibrator();
+        }
+        mVibrator.vibrate(mVibratePattern, -1);
+    }
+
+    private int getKeyIndices(int x, int y, int[] allKeys) {
+        final List<Key> keys = mKeyboard.getKeys();
+        final boolean shifted = mKeyboard.isShifted();
+        int primaryIndex = NOT_A_KEY;
+        int closestKey = NOT_A_KEY;
+        int closestKeyDist = mProximityThreshold + 1;
+        java.util.Arrays.fill(mDistances, Integer.MAX_VALUE);
+        final int keyCount = keys.size();
+        for (int i = 0; i < keyCount; i++) {
+            final Key key = keys.get(i);
+            int dist = 0;
+            boolean isInside = key.isInside(x,y);
+            if (((mProximityCorrectOn 
+                    && (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold) 
+                    || isInside)
+                    && key.codes[0] > 32) {
+                // Find insertion point
+                final int nCodes = key.codes.length;
+                if (dist < closestKeyDist) {
+                    closestKeyDist = dist;
+                    closestKey = i;
+                }
+                
+                if (allKeys == null) continue;
+                
+                for (int j = 0; j < mDistances.length; j++) {
+                    if (mDistances[j] > dist) {
+                        // Make space for nCodes codes
+                        System.arraycopy(mDistances, j, mDistances, j + nCodes,
+                                mDistances.length - j - nCodes);
+                        System.arraycopy(allKeys, j, allKeys, j + nCodes,
+                                allKeys.length - j - nCodes);
+                        for (int c = 0; c < nCodes; c++) {
+                            allKeys[j + c] = key.codes[c];
+                            if (shifted) {
+                                //allKeys[j + c] = Character.toUpperCase(key.codes[c]);
+                            }
+                            mDistances[j + c] = dist;
+                        }
+                        break;
+                    }
+                }
+            }
+            
+            if (isInside) {
+                primaryIndex = i;
+            }
+        }
+        if (primaryIndex == NOT_A_KEY) {
+            primaryIndex = closestKey;
+        }
+        return primaryIndex;
+    }
+
+    private void detectAndSendKey(int x, int y, long eventTime) {
+        int index = mCurrentKey;
+        if (index != NOT_A_KEY) {
+            vibrate();
+            final Key key = mKeyboard.getKeys().get(index);
+            if (key.text != null) {
+                for (int i = 0; i < key.text.length(); i++) {
+                    mKeyboardActionListener.onKey(key.text.charAt(i), key.codes);
+                }
+            } else {
+                int code = key.codes[0];
+                //TextEntryState.keyPressedAt(key, x, y);
+                int[] codes = new int[MAX_NEARBY_KEYS];
+                Arrays.fill(codes, NOT_A_KEY);
+                getKeyIndices(x, y, codes);
+                // Multi-tap
+                if (mInMultiTap) {
+                    if (mTapCount != -1) {
+                        mKeyboardActionListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE);
+                    } else {
+                        mTapCount = 0;
+                    }
+                    code = key.codes[mTapCount];
+                }
+                mKeyboardActionListener.onKey(code, codes);
+            }
+            mLastSentIndex = index;
+            mLastTapTime = eventTime;
+        }
+    }
+
+    /**
+     * Handle multi-tap keys by producing the key label for the current multi-tap state.
+     */
+    private CharSequence getPreviewText(Key key) {
+        if (mInMultiTap) {
+            // Multi-tap
+            mPreviewLabel.setLength(0);
+            mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]);
+            return adjustCase(mPreviewLabel);
+        } else {
+            return adjustCase(key.label);
+        }
+    }
+
+    private void showPreview(int keyIndex) {
+        int oldKeyIndex = mCurrentKeyIndex;
+        final PopupWindow previewPopup = mPreviewPopup;
+        
+        mCurrentKeyIndex = keyIndex;
+        // Release the old key and press the new key
+        final List<Key> keys = mKeyboard.getKeys();
+        if (oldKeyIndex != mCurrentKeyIndex) {
+            if (oldKeyIndex != NOT_A_KEY && keys.size() > oldKeyIndex) {
+                keys.get(oldKeyIndex).onReleased(mCurrentKeyIndex == NOT_A_KEY);
+                invalidateKey(oldKeyIndex);
+            }
+            if (mCurrentKeyIndex != NOT_A_KEY && keys.size() > mCurrentKeyIndex) {
+                keys.get(mCurrentKeyIndex).onPressed();
+                invalidateKey(mCurrentKeyIndex);
+            }
+        }
+        // If key changed and preview is on ...
+        if (oldKeyIndex != mCurrentKeyIndex && mShowPreview) {
+            if (previewPopup.isShowing()) {
+                if (keyIndex == NOT_A_KEY) {
+                    mHandler.sendMessageDelayed(mHandler
+                            .obtainMessage(MSG_REMOVE_PREVIEW), 60);
+                }
+            }
+            if (keyIndex != NOT_A_KEY) {
+                Key key = keys.get(keyIndex);
+                if (key.icon != null) {
+                    mPreviewText.setCompoundDrawables(null, null, null, 
+                            key.iconPreview != null ? key.iconPreview : key.icon);
+                    mPreviewText.setText(null);
+                } else {
+                    mPreviewText.setCompoundDrawables(null, null, null, null);
+                    mPreviewText.setText(getPreviewText(key));
+                    if (key.label.length() > 1 && key.codes.length < 2) {
+                        mPreviewText.setTextSize(mLabelTextSize);
+                    } else {
+                        mPreviewText.setTextSize(mPreviewTextSizeLarge);
+                    }
+                }
+                mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
+                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+                int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width 
+                        + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight());
+                final int popupHeight = mPreviewHeight;
+                LayoutParams lp = mPreviewText.getLayoutParams();
+                if (lp != null) {
+                    lp.width = popupWidth;
+                    lp.height = popupHeight;
+                }
+                previewPopup.setWidth(popupWidth);
+                previewPopup.setHeight(popupHeight);
+                if (!mPreviewCentered) {
+                    mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + mPaddingLeft;
+                    mPopupPreviewY = key.y - popupHeight + mPreviewOffset;
+                } else {
+                    // TODO: Fix this if centering is brought back
+                    mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2;
+                    mPopupPreviewY = - mPreviewText.getMeasuredHeight();
+                }
+                mHandler.removeMessages(MSG_REMOVE_PREVIEW);
+                if (mOffsetInWindow == null) {
+                    mOffsetInWindow = new int[2];
+                    getLocationInWindow(mOffsetInWindow);
+                    mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero
+                    mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero
+                }
+                // Set the preview background state
+                mPreviewText.getBackground().setState(
+                        key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET);
+                if (previewPopup.isShowing()) {
+                    previewPopup.update(mPopupPreviewX + mOffsetInWindow[0], 
+                            mPopupPreviewY + mOffsetInWindow[1], 
+                            popupWidth, popupHeight);
+                } else {
+                    previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY, 
+                            mPopupPreviewX + mOffsetInWindow[0], 
+                            mPopupPreviewY + mOffsetInWindow[1]);
+                }
+                mPreviewText.setVisibility(VISIBLE);
+            }
+        }
+    }
+
+    private void invalidateKey(int keyIndex) {
+        if (keyIndex < 0 || keyIndex >= mKeyboard.getKeys().size()) {
+            return;
+        }
+        final Key key = mKeyboard.getKeys().get(keyIndex);
+        invalidate(key.x + mPaddingLeft, key.y + mPaddingTop, 
+                key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop);
+    }
+
+    private boolean openPopupIfRequired(MotionEvent me) {
+        // Check if we have a popup layout specified first.
+        if (mPopupLayout == 0) {
+            return false;
+        }
+        if (mCurrentKey < 0 || mCurrentKey >= mKeyboard.getKeys().size()) {
+            return false;
+        }
+
+        Key popupKey = mKeyboard.getKeys().get(mCurrentKey);        
+        boolean result = onLongPress(popupKey);
+        if (result) {
+            mAbortKey = true;
+            showPreview(NOT_A_KEY);
+        }
+        return result;
+    }
+
+    /**
+     * Called when a key is long pressed. By default this will open any popup keyboard associated
+     * with this key through the attributes popupLayout and popupCharacters.
+     * @param popupKey the key that was long pressed
+     * @return true if the long press is handled, false otherwise. Subclasses should call the
+     * method on the base class if the subclass doesn't wish to handle the call.
+     */
+    protected boolean onLongPress(Key popupKey) {
+        int popupKeyboardId = popupKey.popupResId;
+
+        if (popupKeyboardId != 0) {
+            mMiniKeyboardContainer = mMiniKeyboardCache.get(popupKey);
+            if (mMiniKeyboardContainer == null) {
+                LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
+                        Context.LAYOUT_INFLATER_SERVICE);
+                mMiniKeyboardContainer = inflater.inflate(mPopupLayout, null);
+                mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById(
+                        com.android.internal.R.id.keyboardView);
+                View closeButton = mMiniKeyboardContainer.findViewById(
+                        com.android.internal.R.id.button_close);
+                if (closeButton != null) closeButton.setOnClickListener(this);
+                mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() {
+                    public void onKey(int primaryCode, int[] keyCodes) {
+                        mKeyboardActionListener.onKey(primaryCode, keyCodes);
+                        dismissPopupKeyboard();
+                    }
+                    
+                    public void swipeLeft() { }
+                    public void swipeRight() { }
+                    public void swipeUp() { }
+                    public void swipeDown() { }
+                });
+                //mInputView.setSuggest(mSuggest);
+                Keyboard keyboard;
+                if (popupKey.popupCharacters != null) {
+                    keyboard = new Keyboard(getContext(), popupKeyboardId, 
+                            popupKey.popupCharacters, -1, getPaddingLeft() + getPaddingRight());
+                } else {
+                    keyboard = new Keyboard(getContext(), popupKeyboardId);
+                }
+                mMiniKeyboard.setKeyboard(keyboard);
+                mMiniKeyboard.setPopupParent(this);
+                mMiniKeyboardContainer.measure(
+                        MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), 
+                        MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
+                
+                mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer);
+            } else {
+                mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById(
+                        com.android.internal.R.id.keyboardView);
+            }
+            if (mWindowOffset == null) {
+                mWindowOffset = new int[2];
+                getLocationInWindow(mWindowOffset);
+            }
+            mPopupX = popupKey.x + mPaddingLeft;
+            mPopupY = popupKey.y + mPaddingTop;
+            mPopupX = mPopupX + popupKey.width - mMiniKeyboardContainer.getMeasuredWidth();
+            mPopupY = mPopupY - mMiniKeyboardContainer.getMeasuredHeight();
+            final int x = mPopupX + mMiniKeyboardContainer.getPaddingRight() + mWindowOffset[0];
+            final int y = mPopupY + mMiniKeyboardContainer.getPaddingBottom() + mWindowOffset[1];
+            mMiniKeyboard.setPopupOffset(x < 0 ? 0 : x, y);
+            mMiniKeyboard.setShifted(isShifted());
+            mPopupKeyboard.setContentView(mMiniKeyboardContainer);
+            mPopupKeyboard.setWidth(mMiniKeyboardContainer.getMeasuredWidth());
+            mPopupKeyboard.setHeight(mMiniKeyboardContainer.getMeasuredHeight());
+            mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y);
+            mMiniKeyboardOnScreen = true;
+            //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me));
+            invalidate();
+            return true;
+        }
+        return false;
+    }
+    
+    @Override
+    public boolean onTouchEvent(MotionEvent me) {
+        int touchX = (int) me.getX() - mPaddingLeft;
+        int touchY = (int) me.getY() + mVerticalCorrection - mPaddingTop;
+        int action = me.getAction();
+        long eventTime = me.getEventTime();
+        int keyIndex = getKeyIndices(touchX, touchY, null);
+        
+        if (mGestureDetector.onTouchEvent(me)) {
+            showPreview(NOT_A_KEY);
+            mHandler.removeMessages(MSG_REPEAT);
+            return true;
+        }
+        
+        // Needs to be called after the gesture detector gets a turn, as it may have
+        // displayed the mini keyboard
+        if (mMiniKeyboardOnScreen) {
+            return true;
+        }
+
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                mAbortKey = false;
+                mStartX = touchX;
+                mStartY = touchY;
+                mLastCodeX = touchX;
+                mLastCodeY = touchY;
+                mLastKeyTime = 0;
+                mCurrentKeyTime = 0;
+                mLastKey = NOT_A_KEY;
+                mCurrentKey = keyIndex;
+                mDownTime = me.getEventTime();
+                mLastMoveTime = mDownTime;
+                checkMultiTap(eventTime, keyIndex);
+                if (mCurrentKey >= 0 && mKeyboard.getKeys().get(mCurrentKey).repeatable) {
+                    mRepeatKeyIndex = mCurrentKey;
+                    repeatKey();
+                    Message msg = mHandler.obtainMessage(MSG_REPEAT);
+                    mHandler.sendMessageDelayed(msg, REPEAT_START_DELAY);
+                }
+                showPreview(keyIndex);
+                playKeyClick();
+                vibrate();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                if (keyIndex != NOT_A_KEY) {
+                    if (mCurrentKey == NOT_A_KEY) {
+                        mCurrentKey = keyIndex;
+                        mCurrentKeyTime = eventTime - mDownTime;
+                    } else {
+                        if (keyIndex == mCurrentKey) {
+                            mCurrentKeyTime += eventTime - mLastMoveTime;
+                        } else {
+                            resetMultiTap();
+                            mLastKey = mCurrentKey;
+                            mLastCodeX = mLastX;
+                            mLastCodeY = mLastY;
+                            mLastKeyTime =
+                                    mCurrentKeyTime + eventTime - mLastMoveTime;
+                            mCurrentKey = keyIndex;
+                            mCurrentKeyTime = 0;
+                        }
+                    }
+                    if (keyIndex != mRepeatKeyIndex) {
+                        mHandler.removeMessages(MSG_REPEAT);
+                        mRepeatKeyIndex = NOT_A_KEY;
+                    }
+                }
+                showPreview(keyIndex);
+                break;
+
+            case MotionEvent.ACTION_UP:
+                mHandler.removeMessages(MSG_REPEAT);
+                if (keyIndex == mCurrentKey) {
+                    mCurrentKeyTime += eventTime - mLastMoveTime;
+                } else {
+                    resetMultiTap();
+                    mLastKey = mCurrentKey;
+                    mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime;
+                    mCurrentKey = keyIndex;
+                    mCurrentKeyTime = 0;
+                }
+                if (mCurrentKeyTime < mLastKeyTime && mLastKey != NOT_A_KEY) {
+                    mCurrentKey = mLastKey;
+                    touchX = mLastCodeX;
+                    touchY = mLastCodeY;
+                }
+                showPreview(NOT_A_KEY);
+                Arrays.fill(mKeyIndices, NOT_A_KEY);
+                invalidateKey(keyIndex);
+                // If we're not on a repeating key (which sends on a DOWN event)
+                if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) {
+                    detectAndSendKey(touchX, touchY, eventTime);
+                }
+                mRepeatKeyIndex = NOT_A_KEY;
+                break;
+        }
+        mLastX = touchX;
+        mLastY = touchY;
+        return true;
+    }
+
+    private boolean repeatKey() {
+        Key key = mKeyboard.getKeys().get(mRepeatKeyIndex);
+        detectAndSendKey(key.x, key.y, mLastTapTime);
+        return true;
+    }
+    
+    protected void swipeRight() {
+        mKeyboardActionListener.swipeRight();
+    }
+    
+    protected void swipeLeft() {
+        mKeyboardActionListener.swipeLeft();
+    }
+
+    protected void swipeUp() {
+        mKeyboardActionListener.swipeUp();
+    }
+
+    protected void swipeDown() {
+        mKeyboardActionListener.swipeDown();
+    }
+
+    public void closing() {
+        if (mPreviewPopup.isShowing()) {
+            mPreviewPopup.dismiss();
+        }
+        dismissPopupKeyboard();
+    }
+    
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        closing();
+    }
+
+    private void dismissPopupKeyboard() {
+        if (mPopupKeyboard.isShowing()) {
+            mPopupKeyboard.dismiss();
+            mMiniKeyboardOnScreen = false;
+            invalidate();
+        }
+    }
+    
+    public boolean handleBack() {
+        if (mPopupKeyboard.isShowing()) {
+            dismissPopupKeyboard();
+            return true;
+        }
+        return false;
+    }
+
+    private void resetMultiTap() {
+        mLastSentIndex = NOT_A_KEY;
+        mTapCount = 0;
+        mLastTapTime = -1;
+        mInMultiTap = false;
+    }
+    
+    private void checkMultiTap(long eventTime, int keyIndex) {
+        if (keyIndex == NOT_A_KEY) return;
+        Key key = mKeyboard.getKeys().get(keyIndex);
+        if (key.codes.length > 1) {
+            mInMultiTap = true;
+            if (eventTime < mLastTapTime + MULTITAP_INTERVAL
+                    && keyIndex == mLastSentIndex) {
+                mTapCount = (mTapCount + 1) % key.codes.length;
+                return;
+            } else {
+                mTapCount = -1;
+                return;
+            }
+        }
+        if (eventTime > mLastTapTime + MULTITAP_INTERVAL || keyIndex != mLastSentIndex) {
+            resetMultiTap();
+        }
+    }
+}
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
new file mode 100644
index 0000000..9ff1665
--- /dev/null
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.inputmethodservice;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.IBinder;
+import android.view.Gravity;
+import android.view.WindowManager;
+
+/**
+ * A SoftInputWindow is a Dialog that is intended to be used for a top-level input
+ * method window.  It will be displayed along the edge of the screen, moving
+ * the application user interface away from it so that the focused item is
+ * always visible.
+ */
+class SoftInputWindow extends Dialog {
+
+    /**
+     * Create a DockWindow that uses the default style.
+     * 
+     * @param context The Context the DockWindow is to run it. In particular, it
+     *        uses the window manager and theme in this context to present its
+     *        UI.
+     */
+    public SoftInputWindow(Context context) {
+        super(context, com.android.internal.R.style.Theme_InputMethod);
+        initDockWindow();
+    }
+
+    public void setToken(IBinder token) {
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+        lp.token = token;
+        getWindow().setAttributes(lp);
+    }
+    
+    /**
+     * Create a DockWindow that uses a custom style.
+     * 
+     * @param context The Context in which the DockWindow should run. In
+     *        particular, it uses the window manager and theme from this context
+     *        to present its UI.
+     * @param theme A style resource describing the theme to use for the window.
+     *        See <a href="{@docRoot}reference/available-resources.html#stylesandthemes">Style
+     *        and Theme Resources</a> for more information about defining and
+     *        using styles. This theme is applied on top of the current theme in
+     *        <var>context</var>. If 0, the default dialog theme will be used.
+     */
+    public SoftInputWindow(Context context, int theme) {
+        super(context, theme);
+        initDockWindow();
+    }
+
+    /**
+     * Get the size of the DockWindow.
+     * 
+     * @return If the DockWindow sticks to the top or bottom of the screen, the
+     *         return value is the height of the DockWindow, and its width is
+     *         equal to the width of the screen; If the DockWindow sticks to the
+     *         left or right of the screen, the return value is the width of the
+     *         DockWindow, and its height is equal to the height of the screen.
+     */
+    public int getSize() {
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+
+        if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
+            return lp.height;
+        } else {
+            return lp.width;
+        }
+    }
+
+    /**
+     * Set the size of the DockWindow.
+     * 
+     * @param size If the DockWindow sticks to the top or bottom of the screen,
+     *        <var>size</var> is the height of the DockWindow, and its width is
+     *        equal to the width of the screen; If the DockWindow sticks to the
+     *        left or right of the screen, <var>size</var> is the width of the
+     *        DockWindow, and its height is equal to the height of the screen.
+     */
+    public void setSize(int size) {
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+
+        if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
+            lp.width = -1;
+            lp.height = size;
+        } else {
+            lp.width = size;
+            lp.height = -1;
+        }
+        getWindow().setAttributes(lp);
+    }
+
+    /**
+     * Set which boundary of the screen the DockWindow sticks to.
+     * 
+     * @param gravity The boundary of the screen to stick. See {#link
+     *        android.view.Gravity.LEFT}, {#link android.view.Gravity.TOP},
+     *        {#link android.view.Gravity.BOTTOM}, {#link
+     *        android.view.Gravity.RIGHT}.
+     */
+    public void setGravity(int gravity) {
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+
+        boolean oldIsVertical = (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM);
+
+        lp.gravity = gravity;
+
+        boolean newIsVertical = (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM);
+
+        if (oldIsVertical != newIsVertical) {
+            int tmp = lp.width;
+            lp.width = lp.height;
+            lp.height = tmp;
+            getWindow().setAttributes(lp);
+        }
+    }
+
+    private void initDockWindow() {
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+
+        lp.type = WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+        lp.setTitle("InputMethod");
+
+        lp.gravity = Gravity.BOTTOM;
+        lp.width = -1;
+
+        getWindow().setAttributes(lp);
+        getWindow().setFlags(
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
+                WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+    }
+}
diff --git a/core/java/android/inputmethodservice/package.html b/core/java/android/inputmethodservice/package.html
new file mode 100644
index 0000000..164349b
--- /dev/null
+++ b/core/java/android/inputmethodservice/package.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+Base classes for writing input methods.  These APIs are not for use by
+normal applications, they are a framework specifically for writing input
+method components.  Implementations will typically derive from
+{@link android.inputmethodservice.InputMethodService}.
+</body>
+</html>
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index ae74e6f..1d939e1 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -30,7 +30,6 @@
 import android.net.NetworkInfo.DetailedState;
 import android.telephony.TelephonyManager;
 import android.util.Log;
-import android.util.Config;
 import android.text.TextUtils;
 
 import java.util.List;
@@ -71,7 +70,9 @@
      * @param target a message handler for getting callbacks about state changes
      */
     public MobileDataStateTracker(Context context, Handler target) {
-        super(context, target, ConnectivityManager.TYPE_MOBILE);
+        super(context, target, ConnectivityManager.TYPE_MOBILE,
+              TelephonyManager.getDefault().getNetworkType(), "MOBILE",
+              TelephonyManager.getDefault().getNetworkTypeName());
         mPhoneService = null;
         mDnsServers = new ArrayList<String>();
     }
@@ -80,9 +81,10 @@
      * Begin monitoring mobile data connectivity.
      */
     public void startMonitoring() {
-
-        IntentFilter filter = new IntentFilter(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
+        IntentFilter filter =
+                new IntentFilter(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
         filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
+        filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
 
         Intent intent = mContext.registerReceiver(new MobileDataStateReceiver(), filter);
         if (intent != null)
@@ -146,6 +148,9 @@
                     reason == null ? "" : "(" + reason + ")");
                 setDetailedState(DetailedState.FAILED, reason, apnName);
             }
+            TelephonyManager tm = TelephonyManager.getDefault();
+            setRoamingStatus(tm.isNetworkRoaming());
+            setSubtype(tm.getNetworkType(), tm.getNetworkTypeName());
         }
     }
 
@@ -223,6 +228,15 @@
     }
 
     /**
+     * {@inheritDoc}
+     * The mobile data network subtype indicates what generation network technology is in effect,
+     * e.g., GPRS, EDGE, UMTS, etc.
+     */
+    public int getNetworkSubtype() {
+        return TelephonyManager.getDefault().getNetworkType();
+    }
+
+    /**
      * Return the system properties name associated with the tcp buffer sizes
      * for this network.
      */
@@ -358,8 +372,8 @@
     }
 
     /**
-     * Tells the phone sub-system that the caller is finished is
-     * finished using the named feature. The only supported feature at
+     * Tells the phone sub-system that the caller is finished
+     * using the named feature. The only supported feature at
      * this time is {@code Phone.FEATURE_ENABLE_MMS}, which allows an application
      * to specify that it wants to send and/or receive MMS data.
      * @param feature the name of the feature that is no longer needed
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index f776abf..8c82212 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -99,24 +99,38 @@
     }
     
     private int mNetworkType;
+    private int mSubtype;
+    private String mTypeName;
+    private String mSubtypeName;
     private State mState;
     private DetailedState mDetailedState;
     private String mReason;
     private String mExtraInfo;
     private boolean mIsFailover;
+    private boolean mIsRoaming;
     /**
      * Indicates whether network connectivity is possible:
      */
     private boolean mIsAvailable;
 
-    public NetworkInfo(int type) {
+    /**
+     * TODO This is going away as soon as API council review happens.
+     * @param type network type
+     */
+    public NetworkInfo(int type) {}
+
+    NetworkInfo(int type, int subtype, String typeName, String subtypeName) {
         if (!ConnectivityManager.isNetworkTypeValid(type)) {
             throw new IllegalArgumentException("Invalid network type: " + type);
         }
-        this.mNetworkType = type;
+        mNetworkType = type;
+        mSubtype = subtype;
+        mTypeName = typeName;
+        mSubtypeName = subtypeName;
         setDetailedState(DetailedState.IDLE, null, null);
         mState = State.UNKNOWN;
         mIsAvailable = true;
+        mIsRoaming = false;
     }
 
     /**
@@ -129,6 +143,41 @@
     }
 
     /**
+     * Return a network-type-specific integer describing the subtype
+     * of the network.
+     * @return the network subtype
+     *
+     * @hide pending API council review
+     */
+    public int getSubtype() {
+        return mSubtype;
+    }
+
+    void setSubtype(int subtype, String subtypeName) {
+        mSubtype = subtype;
+        mSubtypeName = subtypeName;
+    }
+
+    /**
+     * Return a human-readable name describe the type of the network,
+     * for example "WIFI" or "MOBILE".
+     * @return the name of the network type
+     */
+    public String getTypeName() {
+        return mTypeName;
+    }
+
+    /**
+     * Return a human-readable name describing the subtype of the network.
+     * @return the name of the network subtype
+     * 
+     * @hide pending API council review
+     */
+    public String getSubtypeName() {
+        return mSubtypeName;
+    }
+
+    /**
      * Indicates whether network connectivity exists or is in the process
      * of being established. This is good for applications that need to
      * do anything related to the network other than read or write data.
@@ -170,7 +219,7 @@
      * Sets if the network is available, ie, if the connectivity is possible.
      * @param isAvailable the new availability value.
      *
-     * {@hide}
+     * @hide
      */
     public void setIsAvailable(boolean isAvailable) {
         mIsAvailable = isAvailable;
@@ -187,12 +236,33 @@
         return mIsFailover;
     }
 
-    /** {@hide} */
+    /**
+     * Set the failover boolean.
+     * @param isFailover {@code true} to mark the current connection attempt
+     * as a failover.
+     * @hide
+     */
     public void setFailover(boolean isFailover) {
         mIsFailover = isFailover;
     }
 
     /**
+     * Indicates whether the device is currently roaming on this network.
+     * When {@code true}, it suggests that use of data on this network
+     * may incur extra costs.
+     * @return {@code true} if roaming is in effect, {@code false} otherwise.
+     *
+     * @hide pending API council
+     */
+    public boolean isRoaming() {
+        return mIsRoaming;
+    }
+
+    void setRoaming(boolean isRoaming) {
+        mIsRoaming = isRoaming;
+    }
+
+    /**
      * Reports the current coarse-grained state of the network.
      * @return the coarse-grained state
      */
@@ -215,8 +285,6 @@
      * if one was supplied. May be {@code null}.
      * @param extraInfo an optional {@code String} providing addditional network state
      * information passed up from the lower networking layers.
-     *
-     * {@hide}
      */
     void setDetailedState(DetailedState detailedState, String reason, String extraInfo) {
         this.mDetailedState = detailedState;
@@ -247,52 +315,59 @@
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder("NetworkInfo: ");
-        builder.append("type: ").append(getTypeName()).append(", state: ").append(mState).
-                append("/").append(mDetailedState).
+        builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()).
+                append("], state: ").append(mState).append("/").append(mDetailedState).
                 append(", reason: ").append(mReason == null ? "(unspecified)" : mReason).
                 append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo).
+                append(", roaming: ").append(mIsRoaming).
                 append(", failover: ").append(mIsFailover).
                 append(", isAvailable: ").append(mIsAvailable);
         return builder.toString();
     }
 
-    public String getTypeName() {
-        switch (mNetworkType) {
-            case ConnectivityManager.TYPE_WIFI:
-                return "WIFI";
-            case ConnectivityManager.TYPE_MOBILE:
-                return "MOBILE";
-            default:
-                return "<invalid>";
-        }
-    }
-
-    /** Implement the Parcelable interface {@hide} */
+    /**
+     * Implement the Parcelable interface
+     * @hide
+     */
     public int describeContents() {
         return 0;
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mNetworkType);
+        dest.writeInt(mSubtype);
+        dest.writeString(mTypeName);
+        dest.writeString(mSubtypeName);
         dest.writeString(mState.name());
         dest.writeString(mDetailedState.name());
         dest.writeInt(mIsFailover ? 1 : 0);
         dest.writeInt(mIsAvailable ? 1 : 0);
+        dest.writeInt(mIsRoaming ? 1 : 0);
         dest.writeString(mReason);
         dest.writeString(mExtraInfo);
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
     public static final Creator<NetworkInfo> CREATOR =
         new Creator<NetworkInfo>() {
             public NetworkInfo createFromParcel(Parcel in) {
                 int netType = in.readInt();
-                NetworkInfo netInfo = new NetworkInfo(netType);
+                int subtype = in.readInt();
+                String typeName = in.readString();
+                String subtypeName = in.readString();
+                NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName);
                 netInfo.mState = State.valueOf(in.readString());
                 netInfo.mDetailedState = DetailedState.valueOf(in.readString());
                 netInfo.mIsFailover = in.readInt() != 0;
                 netInfo.mIsAvailable = in.readInt() != 0;
+                netInfo.mIsRoaming = in.readInt() != 0;
                 netInfo.mReason = in.readString();
                 netInfo.mExtraInfo = in.readString();
                 return netInfo;
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index 4e1efa6d..37087ac 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -22,7 +22,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemProperties;
-import android.os.PowerManager;
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.Config;
@@ -41,6 +40,7 @@
     protected NetworkInfo mNetworkInfo;
     protected Context mContext;
     protected Handler mTarget;
+    private boolean mTeardownRequested;
 
     private static boolean DBG = Config.LOGV; 
     private static final String TAG = "NetworkStateTracker";
@@ -54,12 +54,20 @@
      */
     public static final int EVENT_NOTIFICATION_CHANGED = 3;
     public static final int EVENT_CONFIGURATION_CHANGED = 4;
+    public static final int EVENT_ROAMING_CHANGED = 5;
+    public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6;
 
-    public NetworkStateTracker(Context context, Handler target, int networkType) {
+    public NetworkStateTracker(Context context,
+            Handler target,
+            int networkType,
+            int subType,
+            String typeName,
+            String subtypeName) {
         super();
         mContext = context;
         mTarget = target;
-        this.mNetworkInfo = new NetworkInfo(networkType);
+        mTeardownRequested = false;
+        this.mNetworkInfo = new NetworkInfo(networkType, subType, typeName, subtypeName);
     }
 
     public NetworkInfo getNetworkInfo() {
@@ -222,6 +230,14 @@
         mNetworkInfo.setDetailedState(state, null, null);
     }
 
+    public void setTeardownRequested(boolean isRequested) {
+        mTeardownRequested = isRequested;
+    }
+
+    public boolean isTeardownRequested() {
+        return mTeardownRequested;
+    }
+    
     /**
      * Send a  notification that the results of a scan for network access
      * points has completed, and results are available.
@@ -231,6 +247,32 @@
         msg.sendToTarget();
     }
 
+    /**
+     * Record the roaming status of the device, and if it is a change from the previous
+     * status, send a notification to any listeners.
+     * @param isRoaming {@code true} if the device is now roaming, {@code false}
+     * if it is no longer roaming.
+     */
+    protected void setRoamingStatus(boolean isRoaming) {
+        if (isRoaming != mNetworkInfo.isRoaming()) {
+            mNetworkInfo.setRoaming(isRoaming);
+            Message msg = mTarget.obtainMessage(EVENT_ROAMING_CHANGED, mNetworkInfo);
+            msg.sendToTarget();
+        }
+    }
+
+    protected void setSubtype(int subtype, String subtypeName) {
+        if (mNetworkInfo.isConnected()) {
+            int oldSubtype = mNetworkInfo.getSubtype();
+            if (subtype != oldSubtype) {
+                mNetworkInfo.setSubtype(subtype, subtypeName);
+                Message msg = mTarget.obtainMessage(
+                        EVENT_NETWORK_SUBTYPE_CHANGED, oldSubtype, 0, mNetworkInfo);
+                msg.sendToTarget();
+            }
+        }
+    }
+
     public abstract void startMonitoring();
 
     /**
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 129248a..1153648 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -67,6 +67,14 @@
     public native static boolean stopDhcp(String interfaceName);
 
     /**
+     * Release the current DHCP lease.
+     * @param interfaceName the name of the interface for which the lease should
+     * be released
+     * @return {@code true} for success, {@code false} for failure
+     */
+    public native static boolean releaseDhcpLease(String interfaceName);
+
+    /**
      * Return the last DHCP-related error message that was recorded.
      * <p/>NOTE: This string is not localized, but currently it is only
      * used in logging.
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index 86e1d5b..9f07c0a 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -43,9 +43,9 @@
     static final public String getHost(Context ctx) {
         ContentResolver contentResolver = ctx.getContentResolver();
         Assert.assertNotNull(contentResolver);
-        String host = Settings.System.getString(
+        String host = Settings.Secure.getString(
                 contentResolver,
-                Settings.System.HTTP_PROXY);
+                Settings.Secure.HTTP_PROXY);
         if (host != null) {
             int i = host.indexOf(':');
             if (i == -1) {
@@ -67,9 +67,9 @@
     static final public int getPort(Context ctx) {
         ContentResolver contentResolver = ctx.getContentResolver();
         Assert.assertNotNull(contentResolver);
-        String host = Settings.System.getString(
+        String host = Settings.Secure.getString(
                 contentResolver,
-                Settings.System.HTTP_PROXY);
+                Settings.Secure.HTTP_PROXY);
         if (host != null) {
             int i = host.indexOf(':');
             if (i == -1) {
diff --git a/core/java/android/net/http/Connection.java b/core/java/android/net/http/Connection.java
index 2c82582..563634f 100644
--- a/core/java/android/net/http/Connection.java
+++ b/core/java/android/net/http/Connection.java
@@ -375,6 +375,11 @@
             if (HttpLog.LOGV) HttpLog.v("Failed to open connection");
             error = EventHandler.ERROR_LOOKUP;
             exception = e;
+        } catch (IllegalArgumentException e) {
+            if (HttpLog.LOGV) HttpLog.v("Illegal argument exception");
+            error = EventHandler.ERROR_CONNECT;
+            req.mFailCount = RETRY_REQUEST_LIMIT;
+            exception = e;
         } catch (SSLConnectionClosedByUserException e) {
             // hack: if we have an SSL connection failure,
             // we don't want to reconnect
diff --git a/core/java/android/net/http/Headers.java b/core/java/android/net/http/Headers.java
index 5d85ba4..b0923d1 100644
--- a/core/java/android/net/http/Headers.java
+++ b/core/java/android/net/http/Headers.java
@@ -30,7 +30,7 @@
 
 /**
  * Manages received headers
- * 
+ *
  * {@hide}
  */
 public final class Headers {
@@ -42,16 +42,16 @@
      */
     public final static int CONN_CLOSE = 1;
     /**
-     * indicate HTTP 1.1 connection keep alive 
+     * indicate HTTP 1.1 connection keep alive
      */
     public final static int CONN_KEEP_ALIVE = 2;
-    
+
     // initial values.
     public final static int NO_CONN_TYPE = 0;
     public final static long NO_TRANSFER_ENCODING = 0;
     public final static long NO_CONTENT_LENGTH = -1;
 
-    // header string
+    // header strings
     public final static String TRANSFER_ENCODING = "transfer-encoding";
     public final static String CONTENT_LEN = "content-length";
     public final static String CONTENT_TYPE = "content-type";
@@ -93,25 +93,61 @@
     private final static int HASH_PRAGMA = -980228804;
     private final static int HASH_REFRESH = 1085444827;
 
+    // keep any headers that require direct access in a presized
+    // string array
+    private final static int IDX_TRANSFER_ENCODING = 0;
+    private final static int IDX_CONTENT_LEN = 1;
+    private final static int IDX_CONTENT_TYPE = 2;
+    private final static int IDX_CONTENT_ENCODING = 3;
+    private final static int IDX_CONN_DIRECTIVE = 4;
+    private final static int IDX_LOCATION = 5;
+    private final static int IDX_PROXY_CONNECTION = 6;
+    private final static int IDX_WWW_AUTHENTICATE = 7;
+    private final static int IDX_PROXY_AUTHENTICATE = 8;
+    private final static int IDX_CONTENT_DISPOSITION = 9;
+    private final static int IDX_ACCEPT_RANGES = 10;
+    private final static int IDX_EXPIRES = 11;
+    private final static int IDX_CACHE_CONTROL = 12;
+    private final static int IDX_LAST_MODIFIED = 13;
+    private final static int IDX_ETAG = 14;
+    private final static int IDX_SET_COOKIE = 15;
+    private final static int IDX_PRAGMA = 16;
+    private final static int IDX_REFRESH = 17;
+
+    private final static int HEADER_COUNT = 18;
+
+    /* parsed values */
     private long transferEncoding;
     private long contentLength; // Content length of the incoming data
     private int connectionType;
-
-    private String contentType;
-    private String contentEncoding;
-    private String location;
-    private String wwwAuthenticate;
-    private String proxyAuthenticate;
-    private String contentDisposition;
-    private String acceptRanges;
-    private String expires;
-    private String cacheControl;
-    private String lastModified;
-    private String etag;
-    private String pragma;
-    private String refresh;
     private ArrayList<String> cookies = new ArrayList<String>(2);
 
+    private String[] mHeaders = new String[HEADER_COUNT];
+    private final static String[] sHeaderNames = {
+        TRANSFER_ENCODING,
+        CONTENT_LEN,
+        CONTENT_TYPE,
+        CONTENT_ENCODING,
+        CONN_DIRECTIVE,
+        LOCATION,
+        PROXY_CONNECTION,
+        WWW_AUTHENTICATE,
+        PROXY_AUTHENTICATE,
+        CONTENT_DISPOSITION,
+        ACCEPT_RANGES,
+        EXPIRES,
+        CACHE_CONTROL,
+        LAST_MODIFIED,
+        ETAG,
+        SET_COOKIE,
+        PRAGMA,
+        REFRESH
+    };
+
+    // Catch-all for headers not explicitly handled
+    private ArrayList<String> mExtraHeaderNames = new ArrayList<String>(4);
+    private ArrayList<String> mExtraHeaderValues = new ArrayList<String>(4);
+
     public Headers() {
         transferEncoding = NO_TRANSFER_ENCODING;
         contentLength = NO_CONTENT_LENGTH;
@@ -129,23 +165,22 @@
         }
         pos++;
 
+        String val = buffer.substringTrimmed(pos, buffer.length());
         if (HttpLog.LOGV) {
-            String val = buffer.substringTrimmed(pos, buffer.length());
             HttpLog.v("hdr " + buffer.length() + " " + buffer);
         }
 
         switch (name.hashCode()) {
         case HASH_TRANSFER_ENCODING:
             if (name.equals(TRANSFER_ENCODING)) {
-                // headers.transferEncoding =
+                mHeaders[IDX_TRANSFER_ENCODING] = val;
                 HeaderElement[] encodings = BasicHeaderValueParser.DEFAULT
-                        .parseElements(buffer, new ParserCursor(pos, 
+                        .parseElements(buffer, new ParserCursor(pos,
                                 buffer.length()));
                 // The chunked encoding must be the last one applied RFC2616,
                 // 14.41
                 int len = encodings.length;
-                if (HTTP.IDENTITY_CODING.equalsIgnoreCase(buffer
-                        .substringTrimmed(pos, buffer.length()))) {
+                if (HTTP.IDENTITY_CODING.equalsIgnoreCase(val)) {
                     transferEncoding = ContentLengthStrategy.IDENTITY;
                 } else if ((len > 0)
                         && (HTTP.CHUNK_CODING
@@ -158,9 +193,9 @@
             break;
         case HASH_CONTENT_LEN:
             if (name.equals(CONTENT_LEN)) {
+                mHeaders[IDX_CONTENT_LEN] = val;
                 try {
-                    contentLength = Long.parseLong(buffer.substringTrimmed(pos,
-                            buffer.length()));
+                    contentLength = Long.parseLong(val);
                 } catch (NumberFormatException e) {
                     if (Config.LOGV) {
                         Log.v(LOGTAG, "Headers.headers(): error parsing"
@@ -171,88 +206,90 @@
             break;
         case HASH_CONTENT_TYPE:
             if (name.equals(CONTENT_TYPE)) {
-                contentType = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_CONTENT_TYPE] = val;
             }
             break;
         case HASH_CONTENT_ENCODING:
             if (name.equals(CONTENT_ENCODING)) {
-                contentEncoding = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_CONTENT_ENCODING] = val;
             }
             break;
         case HASH_CONN_DIRECTIVE:
             if (name.equals(CONN_DIRECTIVE)) {
+                mHeaders[IDX_CONN_DIRECTIVE] = val;
                 setConnectionType(buffer, pos);
             }
             break;
         case HASH_LOCATION:
             if (name.equals(LOCATION)) {
-                location = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_LOCATION] = val;
             }
             break;
         case HASH_PROXY_CONNECTION:
             if (name.equals(PROXY_CONNECTION)) {
+                mHeaders[IDX_PROXY_CONNECTION] = val;
                 setConnectionType(buffer, pos);
             }
             break;
         case HASH_WWW_AUTHENTICATE:
             if (name.equals(WWW_AUTHENTICATE)) {
-                wwwAuthenticate = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_WWW_AUTHENTICATE] = val;
             }
             break;
         case HASH_PROXY_AUTHENTICATE:
             if (name.equals(PROXY_AUTHENTICATE)) {
-                proxyAuthenticate = buffer.substringTrimmed(pos, buffer
-                        .length());
+                mHeaders[IDX_PROXY_AUTHENTICATE] = val;
             }
             break;
         case HASH_CONTENT_DISPOSITION:
             if (name.equals(CONTENT_DISPOSITION)) {
-                contentDisposition = buffer.substringTrimmed(pos, buffer
-                        .length());
+                mHeaders[IDX_CONTENT_DISPOSITION] = val;
             }
             break;
         case HASH_ACCEPT_RANGES:
             if (name.equals(ACCEPT_RANGES)) {
-                acceptRanges = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_ACCEPT_RANGES] = val;
             }
             break;
         case HASH_EXPIRES:
             if (name.equals(EXPIRES)) {
-                expires = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_EXPIRES] = val;
             }
             break;
         case HASH_CACHE_CONTROL:
             if (name.equals(CACHE_CONTROL)) {
-                cacheControl = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_CACHE_CONTROL] = val;
             }
             break;
         case HASH_LAST_MODIFIED:
             if (name.equals(LAST_MODIFIED)) {
-                lastModified = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_LAST_MODIFIED] = val;
             }
             break;
         case HASH_ETAG:
             if (name.equals(ETAG)) {
-                etag = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_ETAG] = val;
             }
             break;
         case HASH_SET_COOKIE:
             if (name.equals(SET_COOKIE)) {
-                cookies.add(buffer.substringTrimmed(pos, buffer.length()));
+                mHeaders[IDX_SET_COOKIE] = val;
+                cookies.add(val);
             }
             break;
         case HASH_PRAGMA:
             if (name.equals(PRAGMA)) {
-                pragma = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_PRAGMA] = val;
             }
             break;
         case HASH_REFRESH:
             if (name.equals(REFRESH)) {
-                refresh = buffer.substringTrimmed(pos, buffer.length());
+                mHeaders[IDX_REFRESH] = val;
             }
             break;
         default:
-            // ignore
+            mExtraHeaderNames.add(name);
+            mExtraHeaderValues.add(val);
         }
     }
 
@@ -268,6 +305,136 @@
         return connectionType;
     }
 
+    public String getContentType() {
+        return mHeaders[IDX_CONTENT_TYPE];
+    }
+
+    public String getContentEncoding() {
+        return mHeaders[IDX_CONTENT_ENCODING];
+    }
+
+    public String getLocation() {
+        return mHeaders[IDX_LOCATION];
+    }
+
+    public String getWwwAuthenticate() {
+        return mHeaders[IDX_WWW_AUTHENTICATE];
+    }
+
+    public String getProxyAuthenticate() {
+        return mHeaders[IDX_PROXY_AUTHENTICATE];
+    }
+
+    public String getContentDisposition() {
+        return mHeaders[IDX_CONTENT_DISPOSITION];
+    }
+
+    public String getAcceptRanges() {
+        return mHeaders[IDX_ACCEPT_RANGES];
+    }
+
+    public String getExpires() {
+        return mHeaders[IDX_EXPIRES];
+    }
+
+    public String getCacheControl() {
+        return mHeaders[IDX_CACHE_CONTROL];
+    }
+
+    public String getLastModified() {
+        return mHeaders[IDX_LAST_MODIFIED];
+    }
+
+    public String getEtag() {
+        return mHeaders[IDX_ETAG];
+    }
+
+    public ArrayList<String> getSetCookie() {
+        return this.cookies;
+    }
+
+    public String getPragma() {
+        return mHeaders[IDX_PRAGMA];
+    }
+
+    public String getRefresh() {
+        return mHeaders[IDX_REFRESH];
+    }
+
+    public void setContentLength(long value) {
+        this.contentLength = value;
+    }
+
+    public void setContentType(String value) {
+        mHeaders[IDX_CONTENT_TYPE] = value;
+    }
+
+    public void setContentEncoding(String value) {
+        mHeaders[IDX_CONTENT_ENCODING] = value;
+    }
+
+    public void setLocation(String value) {
+        mHeaders[IDX_LOCATION] = value;
+    }
+
+    public void setWwwAuthenticate(String value) {
+        mHeaders[IDX_WWW_AUTHENTICATE] = value;
+    }
+
+    public void setProxyAuthenticate(String value) {
+        mHeaders[IDX_PROXY_AUTHENTICATE] = value;
+    }
+
+    public void setContentDisposition(String value) {
+        mHeaders[IDX_CONTENT_DISPOSITION] = value;
+    }
+
+    public void setAcceptRanges(String value) {
+        mHeaders[IDX_ACCEPT_RANGES] = value;
+    }
+
+    public void setExpires(String value) {
+        mHeaders[IDX_EXPIRES] = value;
+    }
+
+    public void setCacheControl(String value) {
+        mHeaders[IDX_CACHE_CONTROL] = value;
+    }
+
+    public void setLastModified(String value) {
+        mHeaders[IDX_LAST_MODIFIED] = value;
+    }
+
+    public void setEtag(String value) {
+        mHeaders[IDX_ETAG] = value;
+    }
+
+    public interface HeaderCallback {
+        public void header(String name, String value);
+    }
+
+    /**
+     * Reports all non-null headers to the callback
+     */
+    public void getHeaders(HeaderCallback hcb) {
+        for (int i = 0; i < HEADER_COUNT; i++) {
+            String h = mHeaders[i];
+            if (h != null) {
+                hcb.header(sHeaderNames[i], h);
+            }
+        }
+        int extraLen = mExtraHeaderNames.size();
+        for (int i = 0; i < extraLen; i++) {
+            if (Config.LOGV) {
+                HttpLog.v("Headers.getHeaders() extra: " + i + " " +
+                          mExtraHeaderNames.get(i) + " " + mExtraHeaderValues.get(i));
+            }
+            hcb.header(mExtraHeaderNames.get(i),
+                       mExtraHeaderValues.get(i));
+        }
+
+    }
+
     private void setConnectionType(CharArrayBuffer buffer, int pos) {
         if (CharArrayBuffers.containsIgnoreCaseTrimmed(
                 buffer, pos, HTTP.CONN_CLOSE)) {
@@ -277,108 +444,4 @@
             connectionType = CONN_KEEP_ALIVE;
         }
     }
-
-    public String getContentType() {
-        return this.contentType;
-    }
-
-    public String getContentEncoding() {
-        return this.contentEncoding;
-    }
-
-    public String getLocation() {
-        return this.location;
-    }
-
-    public String getWwwAuthenticate() {
-        return this.wwwAuthenticate;
-    }
-
-    public String getProxyAuthenticate() {
-        return this.proxyAuthenticate;
-    }
-
-    public String getContentDisposition() {
-        return this.contentDisposition;
-    }
-
-    public String getAcceptRanges() {
-        return this.acceptRanges;
-    }
-
-    public String getExpires() {
-        return this.expires;
-    }
-
-    public String getCacheControl() {
-        return this.cacheControl;
-    }
-
-    public String getLastModified() {
-        return this.lastModified;
-    }
-
-    public String getEtag() {
-        return this.etag;
-    }
-
-    public ArrayList<String> getSetCookie() {
-        return this.cookies;
-    }
-    
-    public String getPragma() {
-        return this.pragma;
-    }
-    
-    public String getRefresh() {
-        return this.refresh;
-    }
-
-    public void setContentLength(long value) {
-        this.contentLength = value;
-    }
-
-    public void setContentType(String value) {
-        this.contentType = value;
-    }
-
-    public void setContentEncoding(String value) {
-        this.contentEncoding = value;
-    }
-
-    public void setLocation(String value) {
-        this.location = value;
-    }
-
-    public void setWwwAuthenticate(String value) {
-        this.wwwAuthenticate = value;
-    }
-
-    public void setProxyAuthenticate(String value) {
-        this.proxyAuthenticate = value;
-    }
-
-    public void setContentDisposition(String value) {
-        this.contentDisposition = value;
-    }
-
-    public void setAcceptRanges(String value) {
-        this.acceptRanges = value;
-    }
-
-    public void setExpires(String value) {
-        this.expires = value;
-    }
-
-    public void setCacheControl(String value) {
-        this.cacheControl = value;
-    }
-
-    public void setLastModified(String value) {
-        this.lastModified = value;
-    }
-
-    public void setEtag(String value) {
-        this.etag = value;
-    }
 }
diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java
index bcbecf0..df4fff0 100644
--- a/core/java/android/net/http/Request.java
+++ b/core/java/android/net/http/Request.java
@@ -16,6 +16,7 @@
 
 package android.net.http;
 
+import java.io.EOFException;
 import java.io.InputStream;
 import java.io.IOException;
 import java.util.Iterator;
@@ -279,6 +280,11 @@
                         count = 0;
                     }
                 }
+            } catch (EOFException e) {
+                /* InflaterInputStream throws an EOFException when the
+                   server truncates gzipped content.  Handle this case
+                   as we do truncated non-gzipped content: no error */
+                if (HttpLog.LOGV) HttpLog.v( "readResponse() handling " + e);
             } catch(IOException e) {
                 // don't throw if we have a non-OK status code
                 if (statusCode == HttpStatus.SC_OK) {
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
index 5d81250..65e6117 100644
--- a/core/java/android/net/http/RequestHandle.java
+++ b/core/java/android/net/http/RequestHandle.java
@@ -113,7 +113,7 @@
      * @param statusCode HTTP status code returned from original request
      * @param cacheHeaders Cache header for redirect URL
      * @return true if setup succeeds, false otherwise (redirect loop
-     * count exceeded)
+     * count exceeded, body provider unable to rewind on 307 redirect)
      */
     public boolean setupRedirect(String redirectTo, int statusCode,
             Map<String, String> cacheHeaders) {
@@ -164,8 +164,22 @@
             }
             mMethod = "GET";
         }
-        mHeaders.remove("Content-Type");
-        mBodyProvider = null;
+        /* Only repost content on a 307.  If 307, reset the body
+           provider so we can replay the body */
+        if (statusCode == 307) {
+            try {
+                if (mBodyProvider != null) mBodyProvider.reset();
+            } catch (java.io.IOException ex) {
+                if (HttpLog.LOGV) {
+                    HttpLog.v("setupAuthResponse() failed to reset body provider");
+                }
+                return false;
+            }
+
+        } else {
+            mHeaders.remove("Content-Type");
+            mBodyProvider = null;
+        }
 
         // Update the cache headers for this URL
         mHeaders.putAll(cacheHeaders);
diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java
index d592995..66d5722 100644
--- a/core/java/android/net/http/RequestQueue.java
+++ b/core/java/android/net/http/RequestQueue.java
@@ -596,7 +596,7 @@
     }
 
     protected synchronized void queueRequest(Request request, boolean head) {
-        HttpHost host = request.mHost;
+        HttpHost host = request.mProxyHost == null ? request.mHost : request.mProxyHost;
         LinkedList<Request> reqList;
         if (mPending.containsKey(host)) {
             reqList = mPending.get(host);
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
new file mode 100644
index 0000000..ee4e897
--- /dev/null
+++ b/core/java/android/os/AsyncTask.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * <p>AsyncTask enables proper and easy use of the UI thread. This class allows to
+ * perform background operations and publish results on the UI thread without
+ * having to manipulate threads and/or handlers.</p>
+ *
+ * <p>An asynchronous task is defined by a computation that runs on a background thread and
+ * whose result is published on the UI thread. An asynchronous task is defined by 3 generic
+ * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
+ * and 4 steps, called <code>begin</code>, <code>doInBackground</code>,
+ * <code>processProgress<code> and <code>end</code>.</p>
+ *
+ * <h2>Usage</h2>
+ * <p>AsyncTask must be subclassed to be used. The subclass will override at least
+ * one method ({@link #doInBackground}), and most often will override a
+ * second one ({@link #onPostExecute}.)</p>
+ *
+ * <p>Here is an example of subclassing:</p>
+ * <pre class="prettyprint">
+ * private class DownloadFilesTask extends AsyncTask&lt;URL, Integer, Long&gt; {
+ *     protected Long doInBackground(URL... urls) {
+ *         int count = urls.length;
+ *         long totalSize = 0;
+ *         for (int i = 0; i < count; i++) {
+ *             totalSize += Downloader.downloadFile(urls[i]);
+ *             publishProgress((int) ((i / (float) count) * 100));
+ *         }
+ *         return totalSize;
+ *     }
+ *
+ *     protected void onProgressUpdate(Integer... progress) {
+ *         setProgressPercent(progress[0]);
+ *     }
+ *
+ *     protected void onPostExecute(Long result) {
+ *         showDialog("Downloaded " + result + " bytes");
+ *     }
+ * }
+ * </pre>
+ *
+ * <p>Once created, a task is executed very simply:</p>
+ * <pre class="prettyprint">
+ * new DownloadFilesTask().execute(url1, url2, url3);
+ * </pre>
+ *
+ * <h2>AsyncTask's generic types</h2>
+ * <p>The three types used by an asynchronous task are the following:</p>
+ * <ol>
+ *     <li><code>Params</code>, the type of the parameters sent to the task upon
+ *     execution.</li>
+ *     <li><code>Progress</code>, the type of the progress units published during
+ *     the background computation.</li>
+ *     <li><code>Result</code>, the type of the result of the background
+ *     computation.</li>
+ * </ol>
+ * <p>Not all types are always used by am asynchronous task. To mark a type as unused,
+ * simply use the type {@link Void}:</p>
+ * <pre>
+ * private class MyTask extends AsyncTask<Void, Void, Void) { ... }
+ * </pre>
+ *
+ * <h2>The 4 steps</h2>
+ * <p>When an asynchronous task is executed, the task goes through 4 steps:</p>
+ * <ol>
+ *     <li>{@link #onPreExecute()}, invoked on the UI thread immediately after the task
+ *     is executed. This step is normally used to setup the task, for instance by
+ *     showing a progress bar in the user interface.</li>
+ *     <li>{@link #doInBackground}, invoked on the background thread
+ *     immediately after {@link #onPreExecute()} finishes executing. This step is used
+ *     to perform background computation that can take a long time. The parameters
+ *     of the asynchronous task are passed to this step. The result of the computation must
+ *     be returned by this step and will be passed back to the last step. This step
+ *     can also use {@link #publishProgress} to publish one or more units
+ *     of progress. These values are published on the UI thread, in the
+ *     {@link #onProgressUpdate} step.</li>
+ *     <li>{@link #onProgressUpdate}, invoked on the UI thread after a
+ *     call to {@link #publishProgress}. The timing of the execution is
+ *     undefined. This method is used to display any form of progress in the user
+ *     interface while the background computation is still executing. For instance,
+ *     it can be used to animate a progress bar or show logs in a text field.</li>
+ *     <li>{@link #onPostExecute}, invoked on the UI thread after the background
+ *     computation finishes. The result of the background computation is passed to
+ *     this step as a parameter.</li>
+ * </ol>
+ *
+ * <h2>Threading rules</h2>
+ * <p>There are a few threading rules that must be followed for this class to
+ * work properly:</p>
+ * <ul>
+ *     <li>The task instance must be created on the UI thread.</li>
+ *     <li>{@link #execute} must be invoked on the UI thread.</li>
+ *     <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
+ *     {@link #doInBackground}, {@link #onProgressUpdate} manually.</li>
+ *     <li>The task can be executed only once (an exception will be thrown if
+ *     a second execution is attempted.)</li>
+ * </ul>
+ */
+public abstract class AsyncTask<Params, Progress, Result> {
+    private static final String LOG_TAG = "AsyncTask";
+
+    private static final int CORE_POOL_SIZE = 1;
+    private static final int MAXIMUM_POOL_SIZE = 10;
+    private static final int KEEP_ALIVE = 10;
+
+    private static final BlockingQueue<Runnable> sWorkQueue =
+            new LinkedBlockingQueue<Runnable>(MAXIMUM_POOL_SIZE);
+
+    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
+        private final AtomicInteger mCount = new AtomicInteger(1);
+
+        public Thread newThread(Runnable r) {
+            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
+        }
+    };
+
+    private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
+            MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
+
+    private static final int MESSAGE_POST_RESULT = 0x1;
+    private static final int MESSAGE_POST_PROGRESS = 0x2;
+    private static final int MESSAGE_POST_CANCEL = 0x3;
+
+    private static final InternalHandler sHandler = new InternalHandler();
+
+    private final WorkerRunnable<Params, Result> mWorker;
+    private final FutureTask<Result> mFuture;
+
+    private volatile Status mStatus = Status.PENDING;
+
+    /**
+     * Indicates the current status of the task. Each status will be set only once
+     * during the lifetime of a task.
+     */
+    public enum Status {
+        /**
+         * Indicates that the task has not been executed yet.
+         */
+        PENDING,
+        /**
+         * Indicates that the task is running.
+         */
+        RUNNING,
+        /**
+         * Indicates that {@link AsyncTask#onPostExecute} has finished.
+         */
+        FINISHED,
+    }
+
+    /**
+     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
+     */
+    public AsyncTask() {
+        mWorker = new WorkerRunnable<Params, Result>() {
+            public Result call() throws Exception {
+                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                return doInBackground(mParams);
+            }
+        };
+
+        mFuture = new FutureTask<Result>(mWorker) {
+            @Override
+            protected void done() {
+                Message message;
+                Result result = null;
+
+                try {
+                    result = get();
+                } catch (InterruptedException e) {
+                    android.util.Log.w(LOG_TAG, e);
+                } catch (ExecutionException e) {
+                    throw new RuntimeException("An error occured while executing doInBackground()",
+                            e.getCause());
+                } catch (CancellationException e) {
+                    message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
+                            new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
+                    message.sendToTarget();
+                    return;
+                } catch (Throwable t) {
+                    throw new RuntimeException("An error occured while executing "
+                            + "doInBackground()", t);
+                }
+
+                message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
+                        new AsyncTaskResult<Result>(AsyncTask.this, result));
+                message.sendToTarget();
+            }
+        };
+    }
+
+    /**
+     * Returns the current status of this task.
+     *
+     * @return The current status.
+     */
+    public final Status getStatus() {
+        return mStatus;
+    }
+
+    /**
+     * Override this method to perform a computation on a background thread. The
+     * specified parameters are the parameters passed to {@link #execute}
+     * by the caller of this task.
+     *
+     * This method can call {@link #publishProgress} to publish updates
+     * on the UI thread.
+     *
+     * @param params The parameters of the task.
+     *
+     * @return A result, defined by the subclass of this task.
+     *
+     * @see #onPreExecute()
+     * @see #onPostExecute
+     * @see #publishProgress
+     */
+    protected abstract Result doInBackground(Params... params);
+
+    /**
+     * Runs on the UI thread before {@link #doInBackground}.
+     *
+     * @see #onPostExecute
+     * @see #doInBackground
+     */
+    protected void onPreExecute() {
+    }
+
+    /**
+     * Runs on the UI thread after {@link #doInBackground}. The
+     * specified result is the value returned by {@link #doInBackground}
+     * or null if the task was cancelled or an exception occured.
+     *
+     * @param result The result of the operation computed by {@link #doInBackground}.
+     *
+     * @see #onPreExecute
+     * @see #doInBackground
+     */
+    @SuppressWarnings({"UnusedDeclaration"})
+    protected void onPostExecute(Result result) {
+    }
+
+    /**
+     * Runs on the UI thread after {@link #publishProgress} is invoked.
+     * The specified values are the values passed to {@link #publishProgress}.
+     *
+     * @param values The values indicating progress.
+     *
+     * @see #publishProgress
+     * @see #doInBackground
+     */
+    @SuppressWarnings({"UnusedDeclaration"})
+    protected void onProgressUpdate(Progress... values) {
+    }
+
+    /**
+     * Runs on the UI thread after {@link #cancel(boolean)} is invoked.
+     *
+     * @see #cancel(boolean)
+     * @see #isCancelled()
+     */
+    protected void onCancelled() {
+    }
+
+    /**
+     * Returns <tt>true</tt> if this task was cancelled before it completed
+     * normally.
+     *
+     * @return <tt>true</tt> if task was cancelled before it completed
+     *
+     * @see #cancel(boolean)
+     */
+    public final boolean isCancelled() {
+        return mFuture.isCancelled();
+    }
+
+    /**
+     * Attempts to cancel execution of this task.  This attempt will
+     * fail if the task has already completed, already been cancelled,
+     * or could not be cancelled for some other reason. If successful,
+     * and this task has not started when <tt>cancel</tt> is called,
+     * this task should never run.  If the task has already started,
+     * then the <tt>mayInterruptIfRunning</tt> parameter determines
+     * whether the thread executing this task should be interrupted in
+     * an attempt to stop the task.
+     *
+     * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
+     *        task should be interrupted; otherwise, in-progress tasks are allowed
+     *        to complete.
+     *
+     * @return <tt>false</tt> if the task could not be cancelled,
+     *         typically because it has already completed normally;
+     *         <tt>true</tt> otherwise
+     *
+     * @see #isCancelled()
+     * @see #onCancelled()
+     */
+    public final boolean cancel(boolean mayInterruptIfRunning) {
+        return mFuture.cancel(mayInterruptIfRunning);
+    }
+
+    /**
+     * Waits if necessary for the computation to complete, and then
+     * retrieves its result.
+     *
+     * @return The computed result.
+     *
+     * @throws CancellationException If the computation was cancelled.
+     * @throws ExecutionException If the computation threw an exception.
+     * @throws InterruptedException If the current thread was interrupted
+     *         while waiting.
+     */
+    public final Result get() throws InterruptedException, ExecutionException {
+        return mFuture.get();
+    }
+
+    /**
+     * Waits if necessary for at most the given time for the computation
+     * to complete, and then retrieves its result.
+     *
+     * @param timeout Time to wait before cancelling the operation.
+     * @param unit The time unit for the timeout.
+     *
+     * @return The computed result.
+     *
+     * @throws CancellationException If the computation was cancelled.
+     * @throws ExecutionException If the computation threw an exception.
+     * @throws InterruptedException If the current thread was interrupted
+     *         while waiting.
+     * @throws TimeoutException If the wait timed out.
+     */
+    public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
+            ExecutionException, TimeoutException {
+        return mFuture.get(timeout, unit);
+    }
+
+    /**
+     * Executes the task with the specified parameters. The task returns
+     * itself (this) so that the caller can keep a reference to it.
+     *
+     * This method must be invoked on the UI thread.
+     *
+     * @param params The parameters of the task.
+     *
+     * @return This instance of AsyncTask.
+     *
+     * @throws IllegalStateException If {@link #getStatus()} returns either
+     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
+     */
+    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
+        if (mStatus != Status.PENDING) {
+            switch (mStatus) {
+                case RUNNING:
+                    throw new IllegalStateException("Cannot execute task:"
+                            + " the task is already running.");
+                case FINISHED:
+                    throw new IllegalStateException("Cannot execute task:"
+                            + " the task has already been executed "
+                            + "(a task can be executed only once)");
+            }
+        }
+
+        mStatus = Status.RUNNING;
+
+        onPreExecute();
+
+        mWorker.mParams = params;
+        sExecutor.execute(mFuture);
+
+        return this;
+    }
+
+    /**
+     * This method can be invoked from {@link #doInBackground} to
+     * publish updates on the UI thread while the background computation is
+     * still running. Each call to this method will trigger the execution of
+     * {@link #onProgressUpdate} on the UI thread.
+     *
+     * @param values The progress values to update the UI with.
+     *
+     * @see #onProgressUpdate
+     * @see #doInBackground
+     */
+    protected final void publishProgress(Progress... values) {
+        sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
+                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
+    }
+
+    private void finish(Result result) {
+        onPostExecute(result);
+        mStatus = Status.FINISHED;
+    }
+
+    private static class InternalHandler extends Handler {
+        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
+        @Override
+        public void handleMessage(Message msg) {
+            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
+            switch (msg.what) {
+                case MESSAGE_POST_RESULT:
+                    // There is only one result
+                    result.mTask.finish(result.mData[0]);
+                    break;
+                case MESSAGE_POST_PROGRESS:
+                    result.mTask.onProgressUpdate(result.mData);
+                    break;
+                case MESSAGE_POST_CANCEL:
+                    result.mTask.onCancelled();
+                    break;
+            }
+        }
+    }
+
+    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
+        Params[] mParams;
+    }
+
+    @SuppressWarnings({"RawUseOfParameterizedType"})
+    private static class AsyncTaskResult<Data> {
+        final AsyncTask mTask;
+        final Data[] mData;
+
+        AsyncTaskResult(AsyncTask task, Data... data) {
+            mTask = task;
+            mData = data;
+        }
+    }
+}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index bf47555..8f1a756 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -37,8 +37,10 @@
     public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5;
     public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
 
-    // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent
+    // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent.
+    // These must be powers of 2.
+    /** Power source is an AC charger. */
     public static final int BATTERY_PLUGGED_AC = 1;
+    /** Power source is a USB port. */
     public static final int BATTERY_PLUGGED_USB = 2;
-
 }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
new file mode 100644
index 0000000..e065063
--- /dev/null
+++ b/core/java/android/os/BatteryStats.java
@@ -0,0 +1,518 @@
+package android.os;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Formatter;
+import java.util.Map;
+
+import android.util.SparseArray;
+
+/**
+ * A class providing access to battery usage statistics, including information on
+ * wakelocks, processes, packages, and services.  All times are represented in microseconds
+ * except where indicated otherwise.
+ */
+public abstract class BatteryStats {
+
+    /**
+     * A constant indicating a partial wake lock.
+     */
+    public static final int WAKE_TYPE_PARTIAL = 0;
+
+    /**
+     * A constant indicating a full wake lock.
+     */
+    public static final int WAKE_TYPE_FULL = 1;
+
+    /**
+     * A constant indicating a window wake lock.
+     */
+    public static final int WAKE_TYPE_WINDOW = 2;
+
+    /**
+     * Include all of the data in the stats, including previously saved data.
+     */
+    public static final int STATS_TOTAL = 0;
+
+    /**
+     * Include only the last run in the stats.
+     */
+    public static final int STATS_LAST = 1;
+
+    /**
+     * Include only the current run in the stats.
+     */
+    public static final int STATS_CURRENT = 2;
+
+    /**
+     * Include only the run since the last time the device was unplugged in the stats.
+     */
+    public static final int STATS_UNPLUGGED = 3;
+
+    private final StringBuilder mFormatBuilder = new StringBuilder(8);
+    private final Formatter mFormatter = new Formatter(mFormatBuilder);
+
+    /**
+     * State for keeping track of timing information.
+     */
+    public static abstract class Timer {
+
+        /**
+         * Returns the count associated with this Timer for the
+         * selected type of statistics.
+         *
+         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+         */
+        public abstract int getCount(int which);
+
+        /**
+         * Returns the total time in microseconds associated with this Timer for the
+         * selected type of statistics.
+         *
+         * @param now system uptime time in microseconds
+         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+         * @return a time in microseconds
+         */
+        public abstract long getTotalTime(long now, int which);
+    }
+
+    /**
+     * The statistics associated with a particular uid.
+     */
+    public static abstract class Uid {
+
+        /**
+         * Returns a mapping containing wakelock statistics.
+         *
+         * @return a Map from Strings to Uid.Wakelock objects.
+         */
+        public abstract Map<String, ? extends Wakelock> getWakelockStats();
+
+        /**
+         * The statistics associated with a particular wake lock.
+         */
+        public static abstract class Wakelock {
+            public abstract Timer getWakeTime(int type);
+        }
+
+        /**
+         * Returns a mapping containing sensor statistics.
+         *
+         * @return a Map from Integer sensor ids to Uid.Sensor objects.
+         */
+        public abstract Map<Integer, ? extends Sensor> getSensorStats();
+
+        /**
+         * Returns a mapping containing process statistics.
+         *
+         * @return a Map from Strings to Uid.Proc objects.
+         */
+        public abstract Map<String, ? extends Proc> getProcessStats();
+
+        /**
+         * Returns a mapping containing package statistics.
+         *
+         * @return a Map from Strings to Uid.Pkg objects.
+         */
+        public abstract Map<String, ? extends Pkg> getPackageStats();
+
+        public static abstract class Sensor {
+            public abstract Timer getSensorTime();
+        }
+
+        /**
+         * The statistics associated with a particular process.
+         */
+        public static abstract class Proc {
+
+            /**
+             * Returns the total time (in 1/100 sec) spent executing in user code.
+             *
+             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             */
+            public abstract long getUserTime(int which);
+
+            /**
+             * Returns the total time (in 1/100 sec) spent executing in system code.
+             *
+             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             */
+            public abstract long getSystemTime(int which);
+
+            /**
+             * Returns the number of times the process has been started.
+             *
+             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             */
+            public abstract int getStarts(int which);
+        }
+
+        /**
+         * The statistics associated with a particular package.
+         */
+        public static abstract class Pkg {
+
+            /**
+             * Returns the number of times this package has done something that could wake up the
+             * device from sleep.
+             *
+             * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+             */
+            public abstract int getWakeups(int which);
+
+            /**
+             * Returns a mapping containing service statistics.
+             */
+            public abstract Map<String, ? extends Serv> getServiceStats();
+
+            /**
+             * The statistics associated with a particular service.
+             */
+            public abstract class Serv {
+
+                /**
+                 * Returns the amount of time spent started.
+                 *
+                 * @param now elapsed realtime in microseconds.
+                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+                 * @return
+                 */
+                public abstract long getStartTime(long now, int which);
+
+                /**
+                 * Returns the total number of times startService() has been called.
+                 *
+                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+                 */
+                public abstract int getStarts(int which);
+
+                /**
+                 * Returns the total number times the service has been launched.
+                 *
+                 * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+                 */
+                public abstract int getLaunches(int which);
+            }
+        }
+    }
+
+    /**
+     * Returns the number of times the device has been started.
+     */
+    public abstract int getStartCount();
+
+    /**
+     * Returns a SparseArray containing the statistics for each uid.
+     */
+    public abstract SparseArray<? extends Uid> getUidStats();
+
+    /**
+     * Returns the current battery uptime in microseconds.
+     *
+     * @param curTime the amount of elapsed realtime in microseconds.
+     */
+    public abstract long getBatteryUptime(long curTime);
+
+    /**
+     * Returns the current battery realtime in microseconds.
+     *
+     * @param curTime the amount of elapsed realtime in microseconds.
+     */
+    public abstract long getBatteryRealtime(long curTime);
+
+    /**
+     * Returns the total, last, or current battery uptime in microseconds.
+     *
+     * @param curTime the elapsed realtime in microseconds.
+     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     */
+    public abstract long computeBatteryUptime(long curTime, int which);
+
+    /**
+     * Returns the total, last, or current battery realtime in microseconds.
+     *
+     * @param curTime the current elapsed realtime in microseconds.
+     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     */
+    public abstract long computeBatteryRealtime(long curTime, int which);
+
+    /**
+     * Returns the total, last, or current uptime in micropeconds.
+     *
+     * @param curTime the current elapsed realtime in microseconds.
+     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     */
+    public abstract long computeUptime(long curTime, int which);
+
+    /**
+     * Returns the total, last, or current realtime in microseconds.
+     * *
+     * @param curTime the current elapsed realtime in microseconds.
+     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     */
+    public abstract long computeRealtime(long curTime, int which);
+
+    private final static void formatTime(StringBuilder out, long seconds) {
+        long days = seconds / (60 * 60 * 24);
+        if (days != 0) {
+            out.append(days);
+            out.append("d ");
+        }
+        long used = days * 60 * 60 * 24;
+
+        long hours = (seconds - used) / (60 * 60);
+        if (hours != 0 || used != 0) {
+            out.append(hours);
+            out.append("h ");
+        }
+        used += hours * 60 * 60;
+
+        long mins = (seconds-used) / 60;
+        if (mins != 0 || used != 0) {
+            out.append(mins);
+            out.append("m ");
+        }
+        used += mins * 60;
+
+        if (seconds != 0 || used != 0) {
+            out.append(seconds-used);
+            out.append("s ");
+        }
+    }
+
+    private final static String formatTime(long time) {
+        long sec = time / 100;
+        StringBuilder sb = new StringBuilder();
+        formatTime(sb, sec);
+        sb.append((time - (sec * 100)) * 10);
+        sb.append("ms ");
+        return sb.toString();
+    }
+
+    private final static String formatTimeMs(long time) {
+        long sec = time / 1000;
+        StringBuilder sb = new StringBuilder();
+        formatTime(sb, sec);
+        sb.append(time - (sec * 1000));
+        sb.append("ms ");
+        return sb.toString();
+    }
+
+    private final String formatRatioLocked(long num, long den) {
+        float perc = ((float)num) / ((float)den) * 100;
+        mFormatBuilder.setLength(0);
+        mFormatter.format("%.1f%%", perc);
+        return mFormatBuilder.toString();
+    }
+
+    /**
+     *
+     * @param sb a StringBuilder object.
+     * @param timer a Timer object contining the wakelock times.
+     * @param now the current time in microseconds.
+     * @param name the name of the wakelock.
+     * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     * @param linePrefix a String to be prepended to each line of output.
+     * @return the line prefix
+     */
+    private final String printWakeLock(StringBuilder sb, Timer timer, long now,
+        String name, int which, String linePrefix) {
+        if (timer != null) {
+            // Convert from microseconds to milliseconds with rounding
+            long totalTimeMillis = (timer.getTotalTime(now, which) + 500) / 1000;
+            int count = timer.getCount(which);
+            if (totalTimeMillis != 0) {
+                sb.append(linePrefix);
+                sb.append(formatTimeMs(totalTimeMillis));
+                sb.append(name);
+                sb.append(' ');
+                sb.append('(');
+                sb.append(count);
+                sb.append(" times)");
+                return ", ";
+            }
+        }
+        return linePrefix;
+    }
+
+    @SuppressWarnings("unused")
+    private final void dumpLocked(FileDescriptor fd, PrintWriter pw, String prefix, int which) {
+        long uSecTime = SystemClock.elapsedRealtime() * 1000;
+        final long uSecNow = getBatteryUptime(uSecTime);
+
+        StringBuilder sb = new StringBuilder(128);
+        if (which == STATS_TOTAL) {
+            pw.println(prefix + "Current and Historic Battery Usage Statistics:");
+            pw.println(prefix + "  System starts: " + getStartCount());
+        } else if (which == STATS_LAST) {
+            pw.println(prefix + "Last Battery Usage Statistics:");
+        } else {
+            pw.println(prefix + "Current Battery Usage Statistics:");
+        }
+        long batteryUptime = computeBatteryUptime(uSecNow, which);
+        long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which);
+        long elapsedRealtime = computeRealtime(uSecTime, which);
+        pw.println(prefix
+                + "  On battery: " + formatTimeMs(batteryUptime) + "("
+                + formatRatioLocked(batteryUptime, batteryRealtime)
+                + ") uptime, "
+                + formatTimeMs(batteryRealtime) + "("
+                + formatRatioLocked(batteryRealtime, elapsedRealtime)
+                + ") realtime");
+        pw.println(prefix
+                + "  Total: "
+                + formatTimeMs(computeUptime(SystemClock.uptimeMillis() * 1000, which))
+                + "uptime, "
+                + formatTimeMs(elapsedRealtime)
+                + "realtime");
+
+        pw.println(" ");
+
+        SparseArray<? extends Uid> uidStats = getUidStats();
+        final int NU = uidStats.size();
+        for (int iu=0; iu<NU; iu++) {
+            final int uid = uidStats.keyAt(iu);
+            Uid u = uidStats.valueAt(iu);
+            pw.println(prefix + "  #" + uid + ":");
+            boolean uidActivity = false;
+
+            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
+            if (wakelocks.size() > 0) {
+                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
+                    : wakelocks.entrySet()) {
+                    Uid.Wakelock wl = ent.getValue();
+                    String linePrefix = ": ";
+                    sb.setLength(0);
+                    sb.append(prefix);
+                    sb.append("    Wake lock ");
+                    sb.append(ent.getKey());
+                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow,
+                            "full", which, linePrefix);
+                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow,
+                            "partial", which, linePrefix);
+                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow,
+                            "window", which, linePrefix);
+                    if (linePrefix.equals(": ")) {
+                        sb.append(": (nothing executed)");
+                    }
+                    pw.println(sb.toString());
+                    uidActivity = true;
+                }
+            }
+
+            Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+            if (sensors.size() > 0) {
+                for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
+                    : sensors.entrySet()) {
+                    Uid.Sensor se = ent.getValue();
+                    int sensorNumber = ent.getKey();
+                    sb.setLength(0);
+                    sb.append(prefix);
+                    sb.append("    Sensor ");
+                    sb.append(sensorNumber);
+
+                    Timer timer = se.getSensorTime();
+                    if (timer != null) {
+                        // Convert from microseconds to milliseconds with rounding
+                        long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000;
+                        int count = timer.getCount(which);
+                        if (totalTime != 0) {
+                            sb.append(": ");
+                            sb.append(formatTimeMs(totalTime));
+                            sb.append(' ');
+                            sb.append('(');
+                            sb.append(count);
+                            sb.append(" times)");
+                        }
+                    } else {
+                        sb.append(": (none used)");
+                    }
+
+                    pw.println(sb.toString());
+                    uidActivity = true;
+                }
+            }
+
+            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
+            if (processStats.size() > 0) {
+                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
+                    : processStats.entrySet()) {
+                    Uid.Proc ps = ent.getValue();
+                    long userTime;
+                    long systemTime;
+                    int starts;
+
+                    userTime = ps.getUserTime(which);
+                    systemTime = ps.getSystemTime(which);
+                    starts = ps.getStarts(which);
+
+                    if (userTime != 0 || systemTime != 0 || starts != 0) {
+                        pw.println(prefix + "    Proc " + ent.getKey() + ":");
+                        pw.println(prefix + "      CPU: " + formatTime(userTime) + "user + "
+                                + formatTime(systemTime) + "kernel");
+                        pw.println(prefix + "      " + starts + " process starts");
+                        uidActivity = true;
+                    }
+                }
+            }
+
+            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
+            if (packageStats.size() > 0) {
+                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
+                    : packageStats.entrySet()) {
+                    pw.println(prefix + "    Apk " + ent.getKey() + ":");
+                    boolean apkActivity = false;
+                    Uid.Pkg ps = ent.getValue();
+                    int wakeups = ps.getWakeups(which);
+                    if (wakeups != 0) {
+                        pw.println(prefix + "      " + wakeups + " wakeup alarms");
+                        apkActivity = true;
+                    }
+                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+                    if (serviceStats.size() > 0) {
+                        for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
+                                : serviceStats.entrySet()) {
+                            BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
+                            long startTime = ss.getStartTime(uSecNow, which);
+                            int starts = ss.getStarts(which);
+                            int launches = ss.getLaunches(which);
+                            if (startTime != 0 || starts != 0 || launches != 0) {
+                                pw.println(prefix + "      Service " + sent.getKey() + ":");
+                                pw.println(prefix + "        Time spent started: "
+                                        + formatTimeMs(startTime));
+                                pw.println(prefix + "        Starts: " + starts
+                                        + ", launches: " + launches);
+                                apkActivity = true;
+                            }
+                        }
+                    }
+                    if (!apkActivity) {
+                        pw.println(prefix + "      (nothing executed)");
+                    }
+                    uidActivity = true;
+                }
+            }
+            if (!uidActivity) {
+                pw.println(prefix + "    (nothing executed)");
+            }
+        }
+    }
+
+    /**
+     * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
+     *
+     * @param fd a FileDescriptor, currently unused.
+     * @param pw a PrintWriter to receive the dump output.
+     * @param args an array of Strings, currently unused.
+     */
+    @SuppressWarnings("unused")
+    public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
+        synchronized (this) {
+            dumpLocked(fd, pw, "", STATS_TOTAL);
+            pw.println("");
+            dumpLocked(fd, pw, "", STATS_LAST);
+            pw.println("");
+            dumpLocked(fd, pw, "", STATS_CURRENT);
+        }
+    }
+}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index b9b2773..c3bb967 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -117,6 +117,10 @@
      * waitForDebugger() call if you want to start tracing immediately.
      */
     public static void waitForDebugger() {
+        if (!VMDebug.isDebuggingEnabled()) {
+            //System.out.println("debugging not enabled, not waiting");
+            return;
+        }
         if (isDebuggerConnected())
             return;
 
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index b6f38d9..2a32e54 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -54,7 +54,7 @@
  * <p>When a
  * process is created for your application, its main thread is dedicated to
  * running a message queue that takes care of managing the top-level
- * application objects (activities, intent receivers, etc) and any windows
+ * application objects (activities, broadcast receivers, etc) and any windows
  * they create.  You can create your own threads, and communicate back with
  * the main application thread through a Handler.  This is done by calling
  * the same <em>post</em> or <em>sendMessage</em> methods as before, but from
@@ -71,20 +71,31 @@
     private static final String TAG = "Handler";
 
     /**
+     * Callback interface you can use when instantiating a Handler to avoid
+     * having to implement your own subclass of Handler.
+     */
+    public interface Callback {
+        public boolean handleMessage(Message msg);
+    }
+    
+    /**
      * Subclasses must implement this to receive messages.
      */
-    public void handleMessage(Message msg)
-    {
+    public void handleMessage(Message msg) {
     }
     
     /**
      * Handle system messages here.
      */
-    public void dispatchMessage(Message msg)
-    {
+    public void dispatchMessage(Message msg) {
         if (msg.callback != null) {
             handleCallback(msg);
         } else {
+            if (mCallback != null) {
+                if (mCallback.handleMessage(msg)) {
+                    return;
+                }
+            }
             handleMessage(msg);
         }
     }
@@ -95,8 +106,7 @@
      *
      * If there isn't one, this handler won't be able to receive messages.
      */
-    public Handler()
-    {
+    public Handler() {
         if (FIND_POTENTIAL_LEAKS) {
             final Class<? extends Handler> klass = getClass();
             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
@@ -112,15 +122,50 @@
                 "Can't create handler inside thread that has not called Looper.prepare()");
         }
         mQueue = mLooper.mQueue;
+        mCallback = null;
+    }
+
+    /**
+     * Constructor associates this handler with the queue for the
+     * current thread and takes a callback interface in which you can handle
+     * messages.
+     */
+    public Handler(Callback callback) {
+        if (FIND_POTENTIAL_LEAKS) {
+            final Class<? extends Handler> klass = getClass();
+            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
+                    (klass.getModifiers() & Modifier.STATIC) == 0) {
+                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
+                    klass.getCanonicalName());
+            }
+        }
+
+        mLooper = Looper.myLooper();
+        if (mLooper == null) {
+            throw new RuntimeException(
+                "Can't create handler inside thread that has not called Looper.prepare()");
+        }
+        mQueue = mLooper.mQueue;
+        mCallback = callback;
     }
 
     /**
      * Use the provided queue instead of the default one.
      */
-    public Handler(Looper looper)
-    {
+    public Handler(Looper looper) {
         mLooper = looper;
         mQueue = looper.mQueue;
+        mCallback = null;
+    }
+
+    /**
+     * Use the provided queue instead of the default one and take a callback
+     * interface in which to handle messages.
+     */
+    public Handler(Looper looper, Callback callback) {
+        mLooper = looper;
+        mQueue = looper.mQueue;
+        mCallback = callback;
     }
 
     /**
@@ -544,5 +589,6 @@
 
     final MessageQueue mQueue;
     final Looper mLooper;
+    final Callback mCallback;
     IMessenger mMessenger;
 }
diff --git a/core/java/android/os/ICheckinService.aidl b/core/java/android/os/ICheckinService.aidl
index aa43852..70ad28e 100644
--- a/core/java/android/os/ICheckinService.aidl
+++ b/core/java/android/os/ICheckinService.aidl
@@ -39,5 +39,6 @@
      * Determine if the device is under parental control. Return null if
      * we are unable to check the parental control status.
      */
-    void getParentalControlState(IParentalControlCallback p);
+    void getParentalControlState(IParentalControlCallback p,
+                                 String requestingApp);
 }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 9d05917..abc1e2f 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -26,6 +26,6 @@
     void userActivity(long when, boolean noChangeLights);
     void userActivityWithForce(long when, boolean noChangeLights, boolean force);
     void setPokeLock(int pokey, IBinder lock, String tag);
-    void setStayOnSetting(boolean val);
+    void setStayOnSetting(int val);
     long getScreenOnTime();
 }
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 80b68e2..9581893 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -130,7 +130,8 @@
     }
 
     /**
-     * Return the Looper object associated with the current thread.
+     * Return the Looper object associated with the current thread.  Returns
+     * null if the calling thread is not associated with a Looper.
      */
     public static final Looper myLooper() {
         return (Looper)sThreadLocal.get();
@@ -151,7 +152,8 @@
     
     /**
      * Return the {@link MessageQueue} object associated with the current
-     * thread.
+     * thread.  This must be called from a thread running a Looper, or a
+     * NullPointerException will be thrown.
      */
     public static final MessageQueue myQueue() {
         return myLooper().mQueue;
@@ -171,6 +173,16 @@
         mQueue.enqueueMessage(msg, 0);
     }
 
+    /**
+     * Return the Thread associated with this Looper.
+     * 
+     * @since CURRENT
+     * {@hide pending API Council approval}
+     */
+    public Thread getThread() {
+        return mThread;
+    }
+    
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + this);
         pw.println(prefix + "mRun=" + mRun);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 2be7768..cd86fbe 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -19,6 +19,7 @@
 import android.net.LocalSocketAddress;
 import android.net.LocalSocket;
 import android.util.Log;
+import dalvik.system.Zygote;
 
 import java.io.BufferedWriter;
 import java.io.DataInputStream;
@@ -221,13 +222,13 @@
     public static final int start(final String processClass,
                                   final String niceName,
                                   int uid, int gid, int[] gids,
-                                  boolean enableDebugger,
+                                  int debugFlags,
                                   String[] zygoteArgs)
     {
         if (supportsProcesses()) {
             try {
                 return startViaZygote(processClass, niceName, uid, gid, gids,
-                        enableDebugger, zygoteArgs);
+                        debugFlags, zygoteArgs);
             } catch (ZygoteStartFailedEx ex) {
                 Log.e(LOG_TAG,
                         "Starting VM process through Zygote failed");
@@ -259,9 +260,9 @@
      * {@hide}
      */
     public static final int start(String processClass, int uid, int gid,
-            int[] gids, boolean enableDebugger, String[] zygoteArgs) {
+            int[] gids, int debugFlags, String[] zygoteArgs) {
         return start(processClass, "", uid, gid, gids, 
-                enableDebugger, zygoteArgs);
+                debugFlags, zygoteArgs);
     }
 
     private static void invokeStaticMain(String className) {
@@ -452,7 +453,7 @@
                                   final String niceName,
                                   final int uid, final int gid,
                                   final int[] gids,
-                                  boolean enableDebugger,
+                                  int debugFlags,
                                   String[] extraArgs)
                                   throws ZygoteStartFailedEx {
         int pid;
@@ -465,9 +466,15 @@
             argsForZygote.add("--runtime-init");
             argsForZygote.add("--setuid=" + uid);
             argsForZygote.add("--setgid=" + gid);
-            if (enableDebugger) {
+            if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
                 argsForZygote.add("--enable-debugger");
             }
+            if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
+                argsForZygote.add("--enable-checkjni");
+            }
+            if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
+                argsForZygote.add("--enable-assert");
+            }
 
             //TODO optionally enable debuger
             //argsForZygote.add("--enable-debugger");
@@ -529,7 +536,12 @@
     public static final native int myTid();
 
     /**
-     * Returns the UID assigned to a partlicular user name, or -1 if there is
+     * Returns the identifier of this process's user.
+     */
+    public static final native int myUid();
+
+    /**
+     * Returns the UID assigned to a particular user name, or -1 if there is
      * none.  If the given string consists of only numbers, it is converted
      * directly to a uid.
      */
diff --git a/core/java/android/pim/EventRecurrence.java b/core/java/android/pim/EventRecurrence.java
index ad671f68..edf69ee 100644
--- a/core/java/android/pim/EventRecurrence.java
+++ b/core/java/android/pim/EventRecurrence.java
@@ -18,6 +18,7 @@
 
 import android.content.res.Resources;
 import android.text.TextUtils;
+import android.text.format.Time;
 
 import java.util.Calendar;
 
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index c02ff52..c6615da 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -21,6 +21,7 @@
 import android.os.Bundle;
 import android.provider.Calendar;
 import android.text.TextUtils;
+import android.text.format.Time;
 import android.util.Config;
 import android.util.Log;
 
@@ -145,7 +146,7 @@
         long[] dates = new long[n];
         for (int i = 0; i<n; ++i) {
             // The timezone is updated to UTC if the time string specified 'Z'.
-            time.parse2445(rawDates[i]);
+            time.parse(rawDates[i]);
             dates[i] = time.toMillis(false /* use isDst */);
             time.timezone = tz;
         }
@@ -173,7 +174,7 @@
         // NOTE: the timezone may be null, if this is a floating time.
         String tzid = tzidParam == null ? null : tzidParam.value;
         Time start = new Time(tzidParam == null ? Time.TIMEZONE_UTC : tzid);
-        boolean inUtc = start.parse2445(dtstart);
+        boolean inUtc = start.parse(dtstart);
         boolean allDay = start.allDay;
 
         if (inUtc) {
@@ -350,7 +351,7 @@
                 ? start.timezone : endTzidParameter.value;
 
         Time end = new Time(endTzid);
-        end.parse2445(dtendProperty.getValue());
+        end.parse(dtendProperty.getValue());
         long durationMillis = end.toMillis(false /* use isDst */) 
                 - start.toMillis(false /* use isDst */);
         long durationSeconds = (durationMillis / 1000);
diff --git a/core/java/android/preference/CheckBoxPreference.java b/core/java/android/preference/CheckBoxPreference.java
index 4bebf87..1e9b7ae 100644
--- a/core/java/android/preference/CheckBoxPreference.java
+++ b/core/java/android/preference/CheckBoxPreference.java
@@ -27,7 +27,7 @@
 import android.widget.TextView;
 
 /**
- * The {@link CheckBoxPreference} is a preference that provides checkbox widget
+ * A {@link Preference} that provides checkbox widget
  * functionality.
  * <p>
  * This preference will store a boolean into the SharedPreferences.
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index 3eb65e2..666efae 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -34,7 +34,7 @@
 import android.widget.TextView;
 
 /**
- * The {@link DialogPreference} class is a base class for preferences that are
+ * A base class for {@link Preference} objects that are
  * dialog-based. These preferences will, when clicked, open a dialog showing the
  * actual preference controls.
  * 
@@ -356,7 +356,7 @@
         getPreferenceManager().unregisterOnActivityDestroyListener(this);
         
         mDialog = null;
-        onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON1);
+        onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE);
     }
 
     /**
@@ -370,6 +370,15 @@
     }
 
     /**
+     * Gets the dialog that is shown by this preference.
+     * 
+     * @return The dialog, or null if a dialog is not being shown.
+     */
+    public Dialog getDialog() {
+        return mDialog;
+    }
+
+    /**
      * {@inheritDoc}
      */
     public void onActivityDestroy() {
diff --git a/core/java/android/preference/EditTextPreference.java b/core/java/android/preference/EditTextPreference.java
index be56003..a12704f 100644
--- a/core/java/android/preference/EditTextPreference.java
+++ b/core/java/android/preference/EditTextPreference.java
@@ -31,7 +31,7 @@
 import android.widget.LinearLayout;
 
 /**
- * The {@link EditTextPreference} class is a preference that allows for string
+ * A {@link Preference} that allows for string
  * input.
  * <p>
  * It is a subclass of {@link DialogPreference} and shows the {@link EditText}
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index 6c98ded..f842d75 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -26,7 +26,7 @@
 import android.util.AttributeSet;
 
 /**
- * The {@link ListPreference} is a preference that displays a list of entries as
+ * A {@link Preference} that displays a list of entries as
  * a dialog.
  * <p>
  * This preference will store a string into the SharedPreferences. This string will be the value
@@ -192,8 +192,22 @@
                 new DialogInterface.OnClickListener() {
                     public void onClick(DialogInterface dialog, int which) {
                         mClickedDialogEntryIndex = which;
+
+                        /*
+                         * Clicking on an item simulates the positive button
+                         * click, and dismisses the dialog.
+                         */
+                        ListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
+                        dialog.dismiss();
                     }
         });
+        
+        /*
+         * The typical interaction for list-based dialogs is to have
+         * click-on-an-item dismiss the dialog instead of the user having to
+         * press 'Ok'.
+         */
+        builder.setPositiveButton(null, null);
     }
 
     @Override
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 1db7525..3820f28 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -37,13 +37,13 @@
 import android.widget.TextView;
 
 /**
- * The {@link Preference} class represents the basic preference UI building
- * block that is displayed by a {@link PreferenceActivity} in the form of a
+ * Represents the basic Preference UI building
+ * block displayed by a {@link PreferenceActivity} in the form of a
  * {@link ListView}. This class provides the {@link View} to be displayed in
  * the activity and associates with a {@link SharedPreferences} to
  * store/retrieve the preference data.
  * <p>
- * When specifying a preference hierarchy in XML, each tag name can point to a
+ * When specifying a preference hierarchy in XML, each element can point to a
  * subclass of {@link Preference}, similar to the view hierarchy and layouts.
  * <p>
  * This class contains a {@code key} that will be used as the key into the
@@ -109,46 +109,46 @@
     private boolean mBaseMethodCalled;
     
     /**
-     * Interface definition for a callback to be invoked when this
-     * {@link Preference Preference's} value has been changed by the user and is
+     * Interface definition for a callback to be invoked when the value of this
+     * {@link Preference} has been changed by the user and is
      * about to be set and/or persisted.  This gives the client a chance
      * to prevent setting and/or persisting the value.
      */
     public interface OnPreferenceChangeListener {
         /**
-         * Called when this preference has been changed by the user. This is
-         * called before the preference's state is about to be updated and
+         * Called when a Preference has been changed by the user. This is
+         * called before the state of the Preference is about to be updated and
          * before the state is persisted.
          * 
-         * @param preference This preference.
-         * @param newValue The new value of the preference.
-         * @return Whether or not to update this preference's state with the new value.
+         * @param preference The changed Preference.
+         * @param newValue The new value of the Preference.
+         * @return True to update the state of the Preference with the new value.
          */
         boolean onPreferenceChange(Preference preference, Object newValue);
     }
 
     /**
-     * Interface definition for a callback to be invoked when a preference is
+     * Interface definition for a callback to be invoked when a {@link Preference} is
      * clicked.
      */
     public interface OnPreferenceClickListener {
         /**
-         * Called when a preference has been clicked.
+         * Called when a Preference has been clicked.
          *
-         * @param preference The preference that was clicked.
-         * @return Whether the click was handled.
+         * @param preference The Preference that was clicked.
+         * @return True if the click was handled.
          */
         boolean onPreferenceClick(Preference preference);
     }
 
     /**
      * Interface definition for a callback to be invoked when this
-     * {@link Preference} is changed or if this is a group, there is an
+     * {@link Preference} is changed or, if this is a group, there is an
      * addition/removal of {@link Preference}(s). This is used internally.
      */
     interface OnPreferenceChangeInternalListener {
         /**
-         * Called when this preference has changed.
+         * Called when this Preference has changed.
          * 
          * @param preference This preference.
          */
@@ -157,18 +157,18 @@
         /**
          * Called when this group has added/removed {@link Preference}(s).
          * 
-         * @param preference This preference.
+         * @param preference This Preference.
          */
         void onPreferenceHierarchyChange(Preference preference);
     }
 
     /**
      * Perform inflation from XML and apply a class-specific base style. This
-     * constructor of {@link Preference} allows subclasses to use their own base
-     * style when they are inflating. For example, a {@link CheckBoxPreference}'s
-     * constructor would call this version of the super class constructor and
-     * supply {@code android.R.attr.checkBoxPreferenceStyle} for <var>defStyle</var>;
-     * this allows the theme's checkbox preference style to modify all of the base
+     * constructor of Preference allows subclasses to use their own base
+     * style when they are inflating. For example, a {@link CheckBoxPreference}
+     * constructor calls this version of the super class constructor and
+     * supplies {@code android.R.attr.checkBoxPreferenceStyle} for <var>defStyle</var>.
+     * This allows the theme's checkbox preference style to modify all of the base
      * preference attributes as well as the {@link CheckBoxPreference} class's
      * attributes.
      * 
@@ -254,8 +254,8 @@
     }
     
     /**
-     * Constructor that is called when inflating a preference from XML. This is
-     * called when a preference is being constructed from an XML file, supplying
+     * Constructor that is called when inflating a Preference from XML. This is
+     * called when a Preference is being constructed from an XML file, supplying
      * attributes that were specified in the XML file. This version uses a
      * default style of 0, so the only attribute values applied are those in the
      * Context's Theme and the given AttributeSet.
@@ -274,15 +274,15 @@
     /**
      * Constructor to create a Preference.
      * 
-     * @param context The context to store preference values.
+     * @param context The Context in which to store Preference values.
      */
     public Preference(Context context) {
         this(context, null);
     }
 
     /**
-     * Called when {@link Preference} is being inflated and the default value
-     * attribute needs to be read. Since different preference types have
+     * Called when a Preference is being inflated and the default value
+     * attribute needs to be read. Since different Preference types have
      * different value types, the subclass should get and return the default
      * value which will be its value type.
      * <p>
@@ -299,16 +299,16 @@
     
     /**
      * Sets an {@link Intent} to be used for
-     * {@link Context#startActivity(Intent)} when the preference is clicked.
+     * {@link Context#startActivity(Intent)} when this Preference is clicked.
      * 
-     * @param intent The intent associated with the preference.
+     * @param intent The intent associated with this Preference.
      */
     public void setIntent(Intent intent) {
         mIntent = intent;
     }
     
     /**
-     * Return the {@link Intent} associated with this preference.
+     * Return the {@link Intent} associated with this Preference.
      * 
      * @return The {@link Intent} last set via {@link #setIntent(Intent)} or XML. 
      */
@@ -318,12 +318,12 @@
 
     /**
      * Sets the layout resource that is inflated as the {@link View} to be shown
-     * for this preference. In most cases, the default layout is sufficient for
-     * custom preferences and only the widget layout needs to be changed.
+     * for this Preference. In most cases, the default layout is sufficient for
+     * custom Preference objects and only the widget layout needs to be changed.
      * <p>
      * This layout should contain a {@link ViewGroup} with ID
      * {@link android.R.id#widget_frame} to be the parent of the specific widget
-     * for this preference. It should similarly contain
+     * for this Preference. It should similarly contain
      * {@link android.R.id#title} and {@link android.R.id#summary}.
      * 
      * @param layoutResId The layout resource ID to be inflated and returned as
@@ -340,7 +340,7 @@
     }
     
     /**
-     * Gets the layout resource that will be shown as the {@link View} for this preference.
+     * Gets the layout resource that will be shown as the {@link View} for this Preference.
      * 
      * @return The layout resource ID.
      */
@@ -349,8 +349,8 @@
     }
     
     /**
-     * Sets The layout for the controllable widget portion of a preference. This
-     * is inflated into the main layout. For example, a checkbox preference
+     * Sets The layout for the controllable widget portion of this Preference. This
+     * is inflated into the main layout. For example, a {@link CheckBoxPreference}
      * would specify a custom layout (consisting of just the CheckBox) here,
      * instead of creating its own main layout.
      * 
@@ -363,7 +363,7 @@
     }
 
     /**
-     * Gets the layout resource for the controllable widget portion of a preference.
+     * Gets the layout resource for the controllable widget portion of this Preference.
      * 
      * @return The layout resource ID.
      */
@@ -374,11 +374,11 @@
     /**
      * Gets the View that will be shown in the {@link PreferenceActivity}.
      * 
-     * @param convertView The old view to reuse, if possible. Note: You should
-     *            check that this view is non-null and of an appropriate type
-     *            before using. If it is not possible to convert this view to
-     *            display the correct data, this method can create a new view.
-     * @param parent The parent that this view will eventually be attached to.
+     * @param convertView The old View to reuse, if possible. Note: You should
+     *            check that this View is non-null and of an appropriate type
+     *            before using. If it is not possible to convert this View to
+     *            display the correct data, this method can create a new View.
+     * @param parent The parent that this View will eventually be attached to.
      * @return Returns the same Preference object, for chaining multiple calls
      *         into a single statement.
      * @see #onCreateView(ViewGroup)
@@ -393,16 +393,16 @@
     }
     
     /**
-     * Creates the View to be shown for this preference in the
+     * Creates the View to be shown for this Preference in the
      * {@link PreferenceActivity}. The default behavior is to inflate the main
-     * layout of this preference (see {@link #setLayoutResource(int)}. If
+     * layout of this Preference (see {@link #setLayoutResource(int)}. If
      * changing this behavior, please specify a {@link ViewGroup} with ID
      * {@link android.R.id#widget_frame}.
      * <p>
      * Make sure to call through to the superclass's implementation.
      * 
-     * @param parent The parent that this view will eventually be attached to.
-     * @return The View that displays this preference.
+     * @param parent The parent that this View will eventually be attached to.
+     * @return The View that displays this Preference.
      * @see #onBindView(View)
      */
     protected View onCreateView(ViewGroup parent) {
@@ -420,14 +420,14 @@
     }
     
     /**
-     * Binds the created View to the data for the preference.
+     * Binds the created View to the data for this Preference.
      * <p>
      * This is a good place to grab references to custom Views in the layout and
      * set properties on them.
      * <p>
      * Make sure to call through to the superclass's implementation.
      * 
-     * @param view The View that shows this preference.
+     * @param view The View that shows this Preference.
      * @see #onCreateView(ViewGroup)
      */
     protected void onBindView(View view) {
@@ -453,7 +453,7 @@
         }
         
         if (mShouldDisableView) {
-            setEnabledStateOnViews(view, mEnabled);
+            setEnabledStateOnViews(view, isEnabled());
         }
     }
     
@@ -472,13 +472,13 @@
     }
     
     /**
-     * Sets the order of this {@link Preference} with respect to other
-     * {@link Preference} on the same level. If this is not specified, the
+     * Sets the order of this Preference with respect to other
+     * Preference objects on the same level. If this is not specified, the
      * default behavior is to sort alphabetically. The
      * {@link PreferenceGroup#setOrderingAsAdded(boolean)} can be used to order
-     * preferences based on the order they appear in the XML.
+     * Preference objects based on the order they appear in the XML.
      * 
-     * @param order The order for this preference. A lower value will be shown
+     * @param order The order for this Preference. A lower value will be shown
      *            first. Use {@link #DEFAULT_ORDER} to sort alphabetically or
      *            allow ordering from XML.
      * @see PreferenceGroup#setOrderingAsAdded(boolean)
@@ -494,9 +494,10 @@
     }
     
     /**
-     * Gets the order of this {@link Preference}.
+     * Gets the order of this Preference with respect to other Preference objects
+     * on the same level.
      * 
-     * @return The order of this {@link Preference}.
+     * @return The order of this Preference.
      * @see #setOrder(int)
      */
     public int getOrder() {
@@ -504,11 +505,12 @@
     }
 
     /**
-     * Sets the title for the preference. This title will be placed into the ID
+     * Sets the title for this Preference with a CharSequence. 
+     * This title will be placed into the ID
      * {@link android.R.id#title} within the View created by
      * {@link #onCreateView(ViewGroup)}.
      * 
-     * @param title The title of the preference.
+     * @param title The title for this Preference.
      */
     public void setTitle(CharSequence title) {
         if (title == null && mTitle != null || title != null && !title.equals(mTitle)) {
@@ -518,6 +520,8 @@
     }
     
     /**
+     * Sets the title for this Preference with a resource ID. 
+     * 
      * @see #setTitle(CharSequence)
      * @param titleResId The title as a resource ID.
      */
@@ -526,7 +530,7 @@
     }
     
     /**
-     * Returns the title of the preference.
+     * Returns the title of this Preference.
      * 
      * @return The title.
      * @see #setTitle(CharSequence)
@@ -536,7 +540,7 @@
     }
 
     /**
-     * Returns the summary of the preference.
+     * Returns the summary of this Preference.
      * 
      * @return The summary.
      * @see #setSummary(CharSequence)
@@ -546,11 +550,9 @@
     }
 
     /**
-     * Sets the summary for the preference. This summary will be placed into the
-     * ID {@link android.R.id#summary} within the View created by
-     * {@link #onCreateView(ViewGroup)}.
+     * Sets the summary for this Preference with a CharSequence. 
      * 
-     * @param summary The summary of the preference.
+     * @param summary The summary for the preference.
      */
     public void setSummary(CharSequence summary) {
         if (summary == null && mSummary != null || summary != null && !summary.equals(mSummary)) {
@@ -560,6 +562,8 @@
     }
 
     /**
+     * Sets the summary for this Preference with a resource ID. 
+     * 
      * @see #setSummary(CharSequence)
      * @param summaryResId The summary as a resource.
      */
@@ -568,10 +572,10 @@
     }
     
     /**
-     * Sets whether this preference is enabled. If disabled, the preference will
+     * Sets whether this Preference is enabled. If disabled, it will
      * not handle clicks.
      * 
-     * @param enabled Whether the preference is enabled.
+     * @param enabled Set true to enable it.
      */
     public void setEnabled(boolean enabled) {
         if (mEnabled != enabled) {
@@ -585,18 +589,18 @@
     }
     
     /**
-     * Whether this {@link Preference} should be enabled in the list.
+     * Checks whether this Preference should be enabled in the list.
      * 
-     * @return Whether this preference is enabled.
+     * @return True if this Preference is enabled, false otherwise.
      */
     public boolean isEnabled() {
         return mEnabled;
     }
 
     /**
-     * Sets whether this preference is selectable.
+     * Sets whether this Preference is selectable.
      * 
-     * @param selectable Whether the preference is selectable.
+     * @param selectable Set true to make it selectable.
      */
     public void setSelectable(boolean selectable) {
         if (mSelectable != selectable) {
@@ -606,23 +610,23 @@
     }
     
     /**
-     * Whether this {@link Preference} should be selectable in the list.
+     * Checks whether this Preference should be selectable in the list.
      * 
-     * @return Whether this preference is selectable.
+     * @return True if it is selectable, false otherwise.
      */
     public boolean isSelectable() {
         return mSelectable;
     }
 
     /**
-     * Sets whether this {@link Preference} should disable its view when it gets
+     * Sets whether this Preference should disable its view when it gets
      * disabled.
      * <p>
      * For example, set this and {@link #setEnabled(boolean)} to false for
      * preferences that are only displaying information and 1) should not be
      * clickable 2) should not have the view set to the disabled state.
      * 
-     * @param shouldDisableView Whether this preference should disable its view
+     * @param shouldDisableView Set true if this preference should disable its view
      *            when the preference is disabled.
      */
     public void setShouldDisableView(boolean shouldDisableView) {
@@ -631,18 +635,19 @@
     }
     
     /**
+     * Checks whether this Preference should disable its view when it's action is disabled.
      * @see #setShouldDisableView(boolean)
-     * @return Whether this preference should disable its view when it is disabled. 
+     * @return True if it should disable the view. 
      */
     public boolean getShouldDisableView() {
         return mShouldDisableView;
     }
 
     /**
-     * Returns a unique ID for this preference.  This ID should be unique across all
-     * preferences in a hierarchy.
+     * Returns a unique ID for this Preference.  This ID should be unique across all
+     * Preference objects in a hierarchy.
      * 
-     * @return A unique ID for this preference.
+     * @return A unique ID for this Preference.
      */
     long getId() {
         return mId;
@@ -658,7 +663,7 @@
     }
     
     /**
-     * Sets the key for the preference which is used as a key to the
+     * Sets the key for this Preference, which is used as a key to the
      * {@link SharedPreferences}. This should be unique for the package.
      * 
      * @param key The key for the preference.
@@ -673,7 +678,7 @@
     }
     
     /**
-     * Gets the key for the preference, which is also the key used for storing
+     * Gets the key for this Preference, which is also the key used for storing
      * values into SharedPreferences.
      * 
      * @return The key.
@@ -686,6 +691,8 @@
      * Checks whether the key is present, and if it isn't throws an
      * exception. This should be called by subclasses that store preferences in
      * the {@link SharedPreferences}.
+     * 
+     * @throws IllegalStateException If there is no key assigned.
      */
     void requireKey() {
         if (mKey == null) {
@@ -696,43 +703,43 @@
     }
     
     /**
-     * Returns whether this {@link Preference} has a valid key.
+     * Checks whether this Preference has a valid key.
      * 
-     * @return Whether the key exists and is not a blank string.
+     * @return True if the key exists and is not a blank string, false otherwise.
      */
     public boolean hasKey() {
         return !TextUtils.isEmpty(mKey);
     }
     
     /**
-     * Returns whether this {@link Preference} is persistent. If it is persistent, it stores its value(s) into
+     * Checks whether this Preference is persistent. If it is, it stores its value(s) into
      * the persistent {@link SharedPreferences} storage.
      * 
-     * @return Whether this is persistent.
+     * @return True if it is persistent.
      */
     public boolean isPersistent() {
         return mPersistent;
     }
     
     /**
-     * Convenience method of whether at the given time this method is called,
-     * the {@link Preference} should store/restore its value(s) into the
-     * {@link SharedPreferences}. This, at minimum, checks whether the
-     * {@link Preference} is persistent and it currently has a key. Before you
+     * Checks whether, at the given time this method is called,
+     * this Preference should store/restore its value(s) into the
+     * {@link SharedPreferences}. This, at minimum, checks whether this
+     * Preference is persistent and it currently has a key. Before you
      * save/restore from the {@link SharedPreferences}, check this first.
      * 
-     * @return Whether to persist the value.
+     * @return True if it should persist the value.
      */
     protected boolean shouldPersist() {
         return mPreferenceManager != null && isPersistent() && hasKey();
     }
     
     /**
-     * Sets whether this {@link Preference} is persistent. If it is persistent,
+     * Sets whether this Preference is persistent. When persistent,
      * it stores its value(s) into the persistent {@link SharedPreferences}
      * storage.
      * 
-     * @param persistent Whether it should store its value(s) into the {@link SharedPreferences}.
+     * @param persistent Set true if it should store its value(s) into the {@link SharedPreferences}.
      */
     public void setPersistent(boolean persistent) {
         mPersistent = persistent;
@@ -742,8 +749,8 @@
      * Call this method after the user changes the preference, but before the
      * internal state is set. This allows the client to ignore the user value.
      * 
-     * @param newValue The new value of the preference.
-     * @return Whether or not the user value should be set as the preference
+     * @param newValue The new value of this Preference.
+     * @return True if the user value should be set as the preference
      *         value (and persisted).
      */
     protected boolean callChangeListener(Object newValue) {
@@ -751,7 +758,7 @@
     }
     
     /**
-     * Sets the callback to be invoked when this preference is changed by the
+     * Sets the callback to be invoked when this Preference is changed by the
      * user (but before the internal state has been updated).
      * 
      * @param onPreferenceChangeListener The callback to be invoked.
@@ -761,7 +768,7 @@
     }
 
     /**
-     * Gets the callback to be invoked when this preference is changed by the
+     * Returns the callback to be invoked when this Preference is changed by the
      * user (but before the internal state has been updated).
      * 
      * @return The callback to be invoked.
@@ -771,7 +778,7 @@
     }
 
     /**
-     * Sets the callback to be invoked when this preference is clicked.
+     * Sets the callback to be invoked when this Preference is clicked.
      * 
      * @param onPreferenceClickListener The callback to be invoked.
      */
@@ -780,7 +787,7 @@
     }
 
     /**
-     * Gets the callback to be invoked when this preference is clicked.
+     * Returns the callback to be invoked when this Preference is clicked.
      * 
      * @return The callback to be invoked.
      */
@@ -791,9 +798,9 @@
     /**
      * Called when a click should be performed.
      * 
-     * @param preferenceScreen Optional {@link PreferenceScreen} whose hierarchy click
+     * @param preferenceScreen A {@link PreferenceScreen} whose hierarchy click
      *            listener should be called in the proper order (between other
-     *            processing).
+     *            processing). May be null.
      */
     void performClick(PreferenceScreen preferenceScreen) {
         
@@ -824,18 +831,19 @@
     }
     
     /**
-     * Returns the context of this preference. Each preference in a preference hierarchy can be
-     * from different context (for example, if multiple activities provide preferences into a single
-     * {@link PreferenceActivity}). This context will be used to save the preference valus.
+     * Returns the {@link android.content.Context} of this Preference. 
+     * Each Preference in a Preference hierarchy can be
+     * from different Context (for example, if multiple activities provide preferences into a single
+     * {@link PreferenceActivity}). This Context will be used to save the Preference values.
      * 
-     * @return The context of this preference.
+     * @return The Context of this Preference.
      */
     public Context getContext() {
         return mContext;
     }
     
     /**
-     * Returns the {@link SharedPreferences} where this preference can read its
+     * Returns the {@link SharedPreferences} where this Preference can read its
      * value(s). Usually, it's easier to use one of the helper read methods:
      * {@link #getPersistedBoolean(boolean)}, {@link #getPersistedFloat(float)},
      * {@link #getPersistedInt(int)}, {@link #getPersistedLong(long)},
@@ -847,8 +855,8 @@
      * {@link SharedPreferences}, this is intended behavior to improve
      * performance.
      * 
-     * @return The {@link SharedPreferences} where this preference reads its
-     *         value(s), or null if it isn't attached to a preference hierarchy.
+     * @return The {@link SharedPreferences} where this Preference reads its
+     *         value(s), or null if it isn't attached to a Preference hierarchy.
      * @see #getEditor()
      */
     public SharedPreferences getSharedPreferences() {
@@ -860,7 +868,7 @@
     }
     
     /**
-     * Returns an {@link SharedPreferences.Editor} where this preference can
+     * Returns an {@link SharedPreferences.Editor} where this Preference can
      * save its value(s). Usually it's easier to use one of the helper save
      * methods: {@link #persistBoolean(boolean)}, {@link #persistFloat(float)},
      * {@link #persistInt(int)}, {@link #persistLong(long)},
@@ -869,11 +877,11 @@
      * true, it is this Preference's responsibility to commit.
      * <p>
      * In some cases, writes to this will not be committed right away and hence
-     * not show up in the shared preferences, this is intended behavior to
+     * not show up in the SharedPreferences, this is intended behavior to
      * improve performance.
      * 
      * @return A {@link SharedPreferences.Editor} where this preference saves
-     *         its value(s), or null if it isn't attached to a preference
+     *         its value(s), or null if it isn't attached to a Preference
      *         hierarchy.
      * @see #shouldCommit()
      * @see #getSharedPreferences()
@@ -903,9 +911,11 @@
     }
     
     /**
-     * Compares preferences based on order (if set), otherwise alphabetically on title.
-     * <p>
-     * {@inheritDoc}
+     * Compares Preference objects based on order (if set), otherwise alphabetically on the titles.
+     * 
+     * @param another The Preference to compare to this one.
+     * @return 0 if the same; less than 0 if this Preference sorts ahead of <var>another</var>;
+     *          greater than 0 if this Preference sorts after <var>another</var>.
      */
     public int compareTo(Preference another) {
         if (mOrder != DEFAULT_ORDER
@@ -942,7 +952,7 @@
     }
     
     /**
-     * Should be called this is a group a {@link Preference} has been
+     * Should be called when a Preference has been
      * added/removed from this group, or the ordering should be
      * re-evaluated.
      */
@@ -953,7 +963,7 @@
     }
 
     /**
-     * Gets the {@link PreferenceManager} that manages this preference's tree.
+     * Gets the {@link PreferenceManager} that manages this Preference object's tree.
      * 
      * @return The {@link PreferenceManager}.
      */
@@ -962,10 +972,10 @@
     }
     
     /**
-     * Called when this preference has been attached to a preference hierarchy.
+     * Called when this Preference has been attached to a Preference hierarchy.
      * Make sure to call the super implementation.
      * 
-     * @param preferenceManager The preference manager of the hierarchy.
+     * @param preferenceManager The PreferenceManager of the hierarchy.
      */
     protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
         mPreferenceManager = preferenceManager;
@@ -976,9 +986,9 @@
     }
     
     /**
-     * Called when the preference hierarchy has been attached to the
+     * Called when the Preference hierarchy has been attached to the
      * {@link PreferenceActivity}. This can also be called when this
-     * {@link Preference} has been attached to a group that was already attached
+     * Preference has been attached to a group that was already attached
      * to the {@link PreferenceActivity}.
      */
     protected void onAttachedToActivity() {
@@ -1010,15 +1020,14 @@
     }
     
     /**
-     * Find a Preference in this hierarchy (the whole thing,
+     * Finds a Preference in this hierarchy (the whole thing,
      * even above/below your {@link PreferenceScreen} screen break) with the given
      * key.
      * <p>
      * This only functions after we have been attached to a hierarchy.
      * 
-     * @param key The key of the {@link Preference} to find.
-     * @return The {@link Preference} object of a preference
-     *         with the given key.
+     * @param key The key of the Preference to find.
+     * @return The Preference that uses the given key.
      */
     protected Preference findPreferenceInHierarchy(String key) {
         if (TextUtils.isEmpty(key) || mPreferenceManager == null) {
@@ -1029,13 +1038,13 @@
     }
     
     /**
-     * Adds a dependent Preference on this preference so we can notify it.
-     * Usually, the dependent preference registers itself (it's good for it to
+     * Adds a dependent Preference on this Preference so we can notify it.
+     * Usually, the dependent Preference registers itself (it's good for it to
      * know it depends on something), so please use
-     * {@link Preference#setDependency(String)} on the dependent preference.
+     * {@link Preference#setDependency(String)} on the dependent Preference.
      * 
      * @param dependent The dependent Preference that will be enabled/disabled
-     *            according to the state of this preference.
+     *            according to the state of this Preference.
      */
     private void registerDependent(Preference dependent) {
         if (mDependents == null) {
@@ -1048,10 +1057,10 @@
     }
     
     /**
-     * Removes a dependent Preference on this preference.
+     * Removes a dependent Preference on this Preference.
      * 
      * @param dependent The dependent Preference that will be enabled/disabled
-     *            according to the state of this preference.
+     *            according to the state of this Preference.
      * @return Returns the same Preference object, for chaining multiple calls
      *         into a single statement.
      */
@@ -1065,7 +1074,7 @@
      * Notifies any listening dependents of a change that affects the
      * dependency.
      * 
-     * @param disableDependents Whether this {@link Preference} should disable
+     * @param disableDependents Whether this Preference should disable
      *            its dependents.
      */
     public void notifyDependencyChange(boolean disableDependents) {
@@ -1084,15 +1093,15 @@
     /**
      * Called when the dependency changes.
      * 
-     * @param dependency The preference that this preference depends on.
-     * @param disableDependent Whether to disable this preference.
+     * @param dependency The Preference that this Preference depends on.
+     * @param disableDependent Set true to disable this Preference.
      */
     public void onDependencyChanged(Preference dependency, boolean disableDependent) {
         setEnabled(!disableDependent);
     }
     
     /**
-     * Should return whether this preference's dependents should currently be
+     * Checks whether this preference's dependents should currently be
      * disabled.
      * 
      * @return True if the dependents should be disabled, otherwise false.
@@ -1117,7 +1126,7 @@
     }
     
     /**
-     * Returns the key of the dependency on this preference.
+     * Returns the key of the dependency on this Preference.
      * 
      * @return The key of the dependency.
      * @see #setDependency(String)
@@ -1136,7 +1145,7 @@
     }
     
     /**
-     * Sets the default value for the preference, which will be set either if
+     * Sets the default value for this Preference, which will be set either if
      * persistence is off or persistence is on and the preference is not found
      * in the persistent storage.
      * 
@@ -1159,17 +1168,21 @@
     }
     
     /**
-     * Implement this to set the initial value of the Preference. If the
-     * restoreValue flag is true, you should restore the value from the shared
-     * preferences. If false, you should set (and possibly store to shared
-     * preferences if {@link #shouldPersist()}) to defaultValue.
+     * Implement this to set the initial value of the Preference. 
+     * <p>
+     * If <var>restorePersistedValue</var> is true, you should restore the 
+     * Preference value from the {@link android.content.SharedPreferences}. If 
+     * <var>restorePersistedValue</var> is false, you should set the Preference 
+     * value to defaultValue that is given (and possibly store to SharedPreferences 
+     * if {@link #shouldPersist()} is true).
      * <p>
      * This may not always be called. One example is if it should not persist
      * but there is no default value given.
      * 
-     * @param restorePersistedValue Whether to restore the persisted value
-     *            (true), or use the given default value (false).
-     * @param defaultValue The default value. Only use if restoreValue is false.
+     * @param restorePersistedValue True to restore the persisted value;
+     *            false to use the given <var>defaultValue</var>.
+     * @param defaultValue The default value for this Preference. Only use this
+     *            if <var>restorePersistedValue</var> is false.
      */
     protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
     }
@@ -1181,14 +1194,14 @@
     }
     
     /**
-     * Attempts to persist a String to the SharedPreferences.
+     * Attempts to persist a String to the {@link android.content.SharedPreferences}.
      * <p>
-     * This will check if the Preference is persistent, get an editor from
-     * the preference manager, put the string, check if we should commit (and
+     * This will check if this Preference is persistent, get an editor from
+     * the {@link PreferenceManager}, put in the string, and check if we should commit (and
      * commit if so).
      * 
      * @param value The value to persist.
-     * @return Whether the Preference is persistent. (This is not whether the
+     * @return True if the Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
      *         will be a batch commit later.)
      * @see #getPersistedString(String)
@@ -1210,15 +1223,15 @@
     }
     
     /**
-     * Attempts to get a persisted String from the SharedPreferences.
+     * Attempts to get a persisted String from the {@link android.content.SharedPreferences}.
      * <p>
-     * This will check if the Preference is persistent, get the shared
-     * preferences from the preference manager, get the value.
+     * This will check if this Preference is persistent, get the SharedPreferences
+     * from the {@link PreferenceManager}, and get the value.
      * 
      * @param defaultReturnValue The default value to return if either the
      *            Preference is not persistent or the Preference is not in the
      *            shared preferences.
-     * @return The value from the shared preferences or the default return
+     * @return The value from the SharedPreferences or the default return
      *         value.
      * @see #persistString(String)
      */
@@ -1231,10 +1244,10 @@
     }
     
     /**
-     * Attempts to persist an int to the SharedPreferences.
+     * Attempts to persist an int to the {@link android.content.SharedPreferences}.
      * 
      * @param value The value to persist.
-     * @return Whether the Preference is persistent. (This is not whether the
+     * @return True if the Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
      *         will be a batch commit later.)
      * @see #persistString(String)
@@ -1256,12 +1269,12 @@
     }
     
     /**
-     * Attempts to get a persisted int from the SharedPreferences.
+     * Attempts to get a persisted int from the {@link android.content.SharedPreferences}.
      * 
-     * @param defaultReturnValue The default value to return if either the
-     *            Preference is not persistent or the Preference is not in the
-     *            shared preferences.
-     * @return The value from the shared preferences or the default return
+     * @param defaultReturnValue The default value to return if either this
+     *            Preference is not persistent or this Preference is not in the
+     *            SharedPreferences.
+     * @return The value from the SharedPreferences or the default return
      *         value.
      * @see #getPersistedString(String)
      * @see #persistInt(int)
@@ -1275,10 +1288,10 @@
     }
     
     /**
-     * Attempts to persist a float to the SharedPreferences.
+     * Attempts to persist a float to the {@link android.content.SharedPreferences}.
      * 
      * @param value The value to persist.
-     * @return Whether the Preference is persistent. (This is not whether the
+     * @return True if this Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
      *         will be a batch commit later.)
      * @see #persistString(String)
@@ -1300,12 +1313,12 @@
     }
     
     /**
-     * Attempts to get a persisted float from the SharedPreferences.
+     * Attempts to get a persisted float from the {@link android.content.SharedPreferences}.
      * 
-     * @param defaultReturnValue The default value to return if either the
-     *            Preference is not persistent or the Preference is not in the
-     *            shared preferences.
-     * @return The value from the shared preferences or the default return
+     * @param defaultReturnValue The default value to return if either this
+     *            Preference is not persistent or this Preference is not in the
+     *            SharedPreferences.
+     * @return The value from the SharedPreferences or the default return
      *         value.
      * @see #getPersistedString(String)
      * @see #persistFloat(float)
@@ -1319,10 +1332,10 @@
     }
     
     /**
-     * Attempts to persist a long to the SharedPreferences.
+     * Attempts to persist a long to the {@link android.content.SharedPreferences}.
      * 
      * @param value The value to persist.
-     * @return Whether the Preference is persistent. (This is not whether the
+     * @return True if this Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
      *         will be a batch commit later.)
      * @see #persistString(String)
@@ -1344,12 +1357,12 @@
     }
     
     /**
-     * Attempts to get a persisted long from the SharedPreferences.
+     * Attempts to get a persisted long from the {@link android.content.SharedPreferences}.
      * 
-     * @param defaultReturnValue The default value to return if either the
-     *            Preference is not persistent or the Preference is not in the
-     *            shared preferences.
-     * @return The value from the shared preferences or the default return
+     * @param defaultReturnValue The default value to return if either this
+     *            Preference is not persistent or this Preference is not in the
+     *            SharedPreferences.
+     * @return The value from the SharedPreferences or the default return
      *         value.
      * @see #getPersistedString(String)
      * @see #persistLong(long)
@@ -1363,10 +1376,10 @@
     }
     
     /**
-     * Attempts to persist a boolean to the SharedPreferences.
+     * Attempts to persist a boolean to the {@link android.content.SharedPreferences}.
      * 
      * @param value The value to persist.
-     * @return Whether the Preference is persistent. (This is not whether the
+     * @return True if this Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
      *         will be a batch commit later.)
      * @see #persistString(String)
@@ -1388,12 +1401,12 @@
     }
     
     /**
-     * Attempts to get a persisted boolean from the SharedPreferences.
+     * Attempts to get a persisted boolean from the {@link android.content.SharedPreferences}.
      * 
-     * @param defaultReturnValue The default value to return if either the
-     *            Preference is not persistent or the Preference is not in the
-     *            shared preferences.
-     * @return The value from the shared preferences or the default return
+     * @param defaultReturnValue The default value to return if either this
+     *            Preference is not persistent or this Preference is not in the
+     *            SharedPreferences.
+     * @return The value from the SharedPreferences or the default return
      *         value.
      * @see #getPersistedString(String)
      * @see #persistBoolean(boolean)
@@ -1416,7 +1429,7 @@
     }
         
     /**
-     * Returns the text that will be used to filter this preference depending on
+     * Returns the text that will be used to filter this Preference depending on
      * user input.
      * <p>
      * If overridding and calling through to the superclass, make sure to prepend
@@ -1442,9 +1455,9 @@
     }
 
     /**
-     * Store this preference hierarchy's frozen state into the given container.
+     * Store this Preference hierarchy's frozen state into the given container.
      * 
-     * @param container The Bundle in which to save the preference's icicles.
+     * @param container The Bundle in which to save the instance of this Preference.
      * 
      * @see #restoreHierarchyState
      * @see #dispatchSaveInstanceState
@@ -1455,11 +1468,11 @@
     }
 
     /**
-     * Called by {@link #saveHierarchyState} to store the icicles for this preference and its children.
-     * May be overridden to modify how freezing happens to a preference's children; for example, some
-     * preferences may want to not store icicles for their children.
+     * Called by {@link #saveHierarchyState} to store the instance for this Preference and its children.
+     * May be overridden to modify how the save happens for children. For example, some
+     * Preference objects may want to not store an instance for their children.
      * 
-     * @param container The Bundle in which to save the preference's icicles.
+     * @param container The Bundle in which to save the instance of this Preference.
      * 
      * @see #dispatchRestoreInstanceState
      * @see #saveHierarchyState
@@ -1480,13 +1493,13 @@
     }
 
     /**
-     * Hook allowing a preference to generate a representation of its internal
+     * Hook allowing a Preference to generate a representation of its internal
      * state that can later be used to create a new instance with that same
      * state. This state should only contain information that is not persistent
      * or can be reconstructed later.
      * 
-     * @return Returns a Parcelable object containing the preference's current
-     *         dynamic state, or null if there is nothing interesting to save.
+     * @return A Parcelable object containing the current dynamic state of
+     *         this Preference, or null if there is nothing interesting to save.
      *         The default implementation returns null.
      * @see #onRestoreInstanceState
      * @see #saveHierarchyState
@@ -1498,9 +1511,9 @@
     }
 
     /**
-     * Restore this preference hierarchy's frozen state from the given container.
+     * Restore this Preference hierarchy's previously saved state from the given container.
      * 
-     * @param container The Bundle which holds previously frozen icicles.
+     * @param container The Bundle that holds the previously saved state.
      * 
      * @see #saveHierarchyState
      * @see #dispatchRestoreInstanceState
@@ -1511,12 +1524,12 @@
     }
 
     /**
-     * Called by {@link #restoreHierarchyState} to retrieve the icicles for this
-     * preference and its children. May be overridden to modify how restoreing
-     * happens to a preference's children; for example, some preferences may
-     * want to not store icicles for their children.
+     * Called by {@link #restoreHierarchyState} to retrieve the saved state for this
+     * Preference and its children. May be overridden to modify how restoring
+     * happens to the children of a Preference. For example, some Preference objects may
+     * not want to save state for their children.
      * 
-     * @param container The Bundle which holds previously frozen icicles.
+     * @param container The Bundle that holds the previously saved state.
      * @see #dispatchSaveInstanceState
      * @see #restoreHierarchyState
      * @see #onRestoreInstanceState
@@ -1536,11 +1549,11 @@
     }
 
     /**
-     * Hook allowing a preference to re-apply a representation of its internal
+     * Hook allowing a Preference to re-apply a representation of its internal
      * state that had previously been generated by {@link #onSaveInstanceState}.
-     * This function will never be called with a null icicle.
+     * This function will never be called with a null state.
      * 
-     * @param state The frozen state that had previously been returned by
+     * @param state The saved state that had previously been returned by
      *            {@link #onSaveInstanceState}.
      * @see #onSaveInstanceState
      * @see #restoreHierarchyState
@@ -1553,6 +1566,9 @@
         }
     }
 
+    /**
+     * A base class for managing the instance state of a {@link Preference}.
+     */
     public static class BaseSavedState extends AbsSavedState {
         public BaseSavedState(Parcel source) {
             super(source);
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 98144ca..95970ea 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -27,7 +27,7 @@
 import android.view.Window;
 
 /**
- * The {@link PreferenceActivity} activity shows a hierarchy of preferences as
+ * Shows a hierarchy of {@link Preference} objects as
  * lists, possibly spanning multiple screens. These preferences will
  * automatically save to {@link SharedPreferences} as the user interacts with
  * them. To retrieve an instance of {@link SharedPreferences} that the
@@ -108,7 +108,7 @@
         setContentView(com.android.internal.R.layout.preference_list_content);
         
         mPreferenceManager = onCreatePreferenceManager();
-        getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
+        getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
     }
 
     @Override
diff --git a/core/java/android/preference/PreferenceCategory.java b/core/java/android/preference/PreferenceCategory.java
index a1b6f09..237c5ce 100644
--- a/core/java/android/preference/PreferenceCategory.java
+++ b/core/java/android/preference/PreferenceCategory.java
@@ -22,7 +22,7 @@
 import android.util.AttributeSet;
 
 /**
- * The {@link PreferenceCategory} class is used to group {@link Preference}s
+ * Used to group {@link Preference} objects
  * and provide a disabled title above the group.
  */
 public class PreferenceCategory extends PreferenceGroup {
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index 55b3753..4258b41 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -28,8 +28,8 @@
 import android.util.AttributeSet;
 
 /**
- * The {@link PreferenceGroup} class is a container for multiple
- * {@link Preference}s. It is a base class for {@link Preference} that are
+ * A container for multiple
+ * {@link Preference} objects. It is a base class for  Preference objects that are
  * parents, such as {@link PreferenceCategory} and {@link PreferenceScreen}.
  * 
  * @attr ref android.R.styleable#PreferenceGroup_orderingFromXml
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 9963544..a7a3eef 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -35,7 +35,7 @@
 import android.util.Log;
 
 /**
- * The {@link PreferenceManager} is used to help create preference hierarchies
+ * Used to help create {@link Preference} hierarchies
  * from activities or XML.
  * <p>
  * In most cases, clients should use
@@ -643,17 +643,23 @@
      * event.
      */
     void dispatchActivityDestroy() {
-        List<OnActivityDestroyListener> list;
+        List<OnActivityDestroyListener> list = null;
         
         synchronized (this) {
-            if (mActivityDestroyListeners == null) return;
-            list = new ArrayList<OnActivityDestroyListener>(mActivityDestroyListeners);
+            if (mActivityDestroyListeners != null) {
+                list = new ArrayList<OnActivityDestroyListener>(mActivityDestroyListeners);
+            }
         }
 
-        final int N = list.size();
-        for (int i = 0; i < N; i++) {
-            list.get(i).onActivityDestroy();
+        if (list != null) {
+            final int N = list.size();
+            for (int i = 0; i < N; i++) {
+                list.get(i).onActivityDestroy();
+            }
         }
+
+        // Dismiss any PreferenceScreens still showing
+        dismissAllScreens();
     }
     
     /**
@@ -697,10 +703,13 @@
      * @param intent The new Intent.
      */
     void dispatchNewIntent(Intent intent) {
+        dismissAllScreens();
+    }
 
+    private void dismissAllScreens() {
         // Remove any of the previously shown preferences screens
         ArrayList<DialogInterface> screensToDismiss;
-        
+
         synchronized (this) {
             
             if (mPreferencesScreens == null) {
@@ -715,7 +724,7 @@
             screensToDismiss.get(i).dismiss();
         }
     }
-
+    
     /**
      * Sets the callback to be invoked when a {@link Preference} in the
      * hierarchy rooted at this {@link PreferenceManager} is clicked.
diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java
index e4ecb88..9929b96 100644
--- a/core/java/android/preference/PreferenceScreen.java
+++ b/core/java/android/preference/PreferenceScreen.java
@@ -30,11 +30,11 @@
 import android.widget.ListView;
 
 /**
- * The {@link PreferenceScreen} class represents a top-level {@link Preference} that
- * is the root of a {@link Preference} hierarchy. A {@link PreferenceActivity}
+ * Represents a top-level {@link Preference} that
+ * is the root of a Preference hierarchy. A {@link PreferenceActivity}
  * points to an instance of this class to show the preferences. To instantiate
  * this class, use {@link PreferenceManager#createPreferenceScreen(Context)}.
- * <p>
+ * <ul>
  * This class can appear in two places:
  * <li> When a {@link PreferenceActivity} points to this, it is used as the root
  * and is not shown (only the contained preferences are shown).
@@ -45,24 +45,25 @@
  * {@link Preference#getIntent()}). The children of this {@link PreferenceScreen}
  * are NOT shown in the screen that this {@link PreferenceScreen} is shown in.
  * Instead, a separate screen will be shown when this preference is clicked.
+ * </ul>
+ * <p>Here's an example XML layout of a PreferenceScreen:</p>
+ * <pre>
+&lt;PreferenceScreen
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:key="first_preferencescreen"&gt;
+    &lt;CheckBoxPreference
+            android:key="wifi enabled"
+            android:title="WiFi" /&gt;
+    &lt;PreferenceScreen
+            android:key="second_preferencescreen"
+            android:title="WiFi settings"&gt;
+        &lt;CheckBoxPreference
+                android:key="prefer wifi"
+                android:title="Prefer WiFi" /&gt;
+        ... other preferences here ...
+    &lt;/PreferenceScreen&gt;
+&lt;/PreferenceScreen&gt; </pre>
  * <p>
- * <code>
- &lt;PreferenceScreen
-         xmlns:android="http://schemas.android.com/apk/res/android"
-         android:key="first_preferencescreen"&gt;
-     &lt;CheckBoxPreference
-             android:key="wifi enabled"
-             android:title="WiFi" /&gt;
-     &lt;PreferenceScreen
-             android:key="second_preferencescreen"
-             android:title="WiFi settings"&gt;
-         &lt;CheckBoxPreference
-                 android:key="prefer wifi"
-                 android:title="Prefer WiFi" /&gt;
-         ... other preferences here ...
-     &lt;/PreferenceScreen&gt;
- &lt;/PreferenceScreen&gt;
- * </code>
  * In this example, the "first_preferencescreen" will be used as the root of the
  * hierarchy and given to a {@link PreferenceActivity}. The first screen will
  * show preferences "WiFi" (which can be used to quickly enable/disable WiFi)
diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java
index 97674ce..6beb06d 100644
--- a/core/java/android/preference/RingtonePreference.java
+++ b/core/java/android/preference/RingtonePreference.java
@@ -27,8 +27,8 @@
 import android.util.Log;
 
 /**
- * The {@link RingtonePreference} allows the user to choose one from all of the
- * available ringtones. The chosen ringtone's URI will be persisted as a string.
+ * A {@link Preference} that allows the user to choose a ringtone from those on the device. 
+ * The chosen ringtone's URI will be persisted as a string.
  * <p>
  * If the user chooses the "Default" item, the saved string will be one of
  * {@link System#DEFAULT_RINGTONE_URI} or
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 5a0a089..6e215dc 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -16,7 +16,6 @@
 
 package android.preference;
 
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.database.ContentObserver;
@@ -35,33 +34,15 @@
 /**
  * @hide
  */
-public class VolumePreference extends SeekBarPreference implements OnSeekBarChangeListener,
-        Runnable, PreferenceManager.OnActivityStopListener {
+public class VolumePreference extends SeekBarPreference implements 
+        PreferenceManager.OnActivityStopListener {
 
     private static final String TAG = "VolumePreference";
     
-    private ContentResolver mContentResolver;
-    private Handler mHandler = new Handler();
-
-    private AudioManager mVolume;
     private int mStreamType;
-    private int mOriginalStreamVolume; 
-    private Ringtone mRingtone;
-
-    private int mLastProgress;
-    private SeekBar mSeekBar;
     
-    private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
-        @Override
-        public void onChange(boolean selfChange) {
-            super.onChange(selfChange);
-
-            if (mSeekBar != null) {
-                mSeekBar.setProgress(System.getInt(mContentResolver,
-                        System.VOLUME_SETTINGS[mStreamType], 0));
-            }
-        }
-    };
+    /** May be null if the dialog isn't visible. */
+    private SeekBarVolumizer mSeekBarVolumizer;
     
     public VolumePreference(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -70,39 +51,32 @@
                 com.android.internal.R.styleable.VolumePreference, 0, 0);
         mStreamType = a.getInt(android.R.styleable.VolumePreference_streamType, 0);
         a.recycle();        
-    
-        mContentResolver = context.getContentResolver();
-        
-        mVolume = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
     }
     
+    public void setStreamType(int streamType) {
+        mStreamType = streamType;
+    }
+
     @Override
     protected void onBindDialogView(View view) {
         super.onBindDialogView(view);
     
-        final SeekBar seekBar = mSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
-        seekBar.setMax(mVolume.getStreamMaxVolume(mStreamType));
-        mOriginalStreamVolume = mVolume.getStreamVolume(mStreamType);
-        seekBar.setProgress(mOriginalStreamVolume);
-        seekBar.setOnSeekBarChangeListener(this);
+        final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
+        mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType);
         
-        mContentResolver.registerContentObserver(System.getUriFor(System.VOLUME_SETTINGS[mStreamType]), false, mVolumeObserver);
-
         getPreferenceManager().registerOnActivityStopListener(this);
-        mRingtone = RingtoneManager.getRingtone(getContext(), Settings.System.DEFAULT_RINGTONE_URI);
     }
 
     @Override
     protected void onDialogClosed(boolean positiveResult) {
         super.onDialogClosed(positiveResult);
         
-        if (!positiveResult) {
-            mVolume.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
+        if (!positiveResult && mSeekBarVolumizer != null) {
+            mSeekBarVolumizer.revertVolume();
         }
         
         cleanup();
     }
-    
 
     public void onActivityStop() {
         cleanup();
@@ -112,50 +86,134 @@
      * Do clean up.  This can be called multiple times!
      */
     private void cleanup() {
-        stopSample();
-        if (mVolumeObserver != null) {
-            mContentResolver.unregisterContentObserver(mVolumeObserver);
-        }
-        getPreferenceManager().unregisterOnActivityStopListener(this);
-        mSeekBar = null;
+       getPreferenceManager().unregisterOnActivityStopListener(this);
+       
+       if (mSeekBarVolumizer != null) {
+           mSeekBarVolumizer.stop();
+           mSeekBarVolumizer = null;
+       }
     }
-
-    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
-        if (!fromTouch) {
-            return;
-        }
-
-        postSetVolume(progress);
-    }
-
-    private void postSetVolume(int progress) {
-        // Do the volume changing separately to give responsive UI
-        mLastProgress = progress;
-        mHandler.removeCallbacks(this);
-        mHandler.post(this);
-    }
-    
-    public void onStartTrackingTouch(SeekBar seekBar) {
-    }
-
-    public void onStopTrackingTouch(SeekBar seekBar) {
-        if (mRingtone != null && !mRingtone.isPlaying()) {
-            sample();
-        }
-    }
-
-    public void run() {
-        mVolume.setStreamVolume(mStreamType, mLastProgress, 0);
-    }
-    
-    private void sample() {
-        mRingtone.play();
-    }
-
-    private void stopSample() {
-        if (mRingtone != null) {
-            mRingtone.stop();
+   
+    protected void onSampleStarting(SeekBarVolumizer volumizer) {
+        if (mSeekBarVolumizer != null && volumizer != mSeekBarVolumizer) {
+            mSeekBarVolumizer.stopSample();
         }
     }
     
+    /**
+     * Turns a {@link SeekBar} into a volume control.
+     */
+    public class SeekBarVolumizer implements OnSeekBarChangeListener, Runnable {
+
+        private Context mContext;
+        private Handler mHandler = new Handler();
+    
+        private AudioManager mAudioManager;
+        private int mStreamType;
+        private int mOriginalStreamVolume; 
+        private Ringtone mRingtone;
+    
+        private int mLastProgress;
+        private SeekBar mSeekBar;
+        
+        private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
+            @Override
+            public void onChange(boolean selfChange) {
+                super.onChange(selfChange);
+    
+                if (mSeekBar != null) {
+                    mSeekBar.setProgress(System.getInt(mContext.getContentResolver(),
+                            System.VOLUME_SETTINGS[mStreamType], 0));
+                }
+            }
+        };
+    
+        public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType) {
+            mContext = context;
+            mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+            mStreamType = streamType;
+            mSeekBar = seekBar;
+            
+            initSeekBar(seekBar);
+        }
+
+        private void initSeekBar(SeekBar seekBar) {
+            seekBar.setMax(mAudioManager.getStreamMaxVolume(mStreamType));
+            mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
+            seekBar.setProgress(mOriginalStreamVolume);
+            seekBar.setOnSeekBarChangeListener(this);
+            
+            mContext.getContentResolver().registerContentObserver(
+                    System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
+                    false, mVolumeObserver);
+    
+            mRingtone = RingtoneManager.getRingtone(mContext,
+                    mStreamType == AudioManager.STREAM_NOTIFICATION
+                            ? Settings.System.DEFAULT_NOTIFICATION_URI
+                            : Settings.System.DEFAULT_RINGTONE_URI);
+            mRingtone.setStreamType(mStreamType);
+        }
+        
+        public void stop() {
+            stopSample();
+            mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
+            mSeekBar.setOnSeekBarChangeListener(null);
+        }
+        
+        public void revertVolume() {
+            mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
+        }
+        
+        public void onProgressChanged(SeekBar seekBar, int progress,
+                boolean fromTouch) {
+            if (!fromTouch) {
+                return;
+            }
+    
+            postSetVolume(progress);
+        }
+
+        private void postSetVolume(int progress) {
+            // Do the volume changing separately to give responsive UI
+            mLastProgress = progress;
+            mHandler.removeCallbacks(this);
+            mHandler.post(this);
+        }
+    
+        public void onStartTrackingTouch(SeekBar seekBar) {
+        }
+
+        public void onStopTrackingTouch(SeekBar seekBar) {
+            if (mRingtone != null && !mRingtone.isPlaying()) {
+                sample();
+            }
+        }
+        
+        public void run() {
+            mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
+        }
+        
+        private void sample() {
+    
+            // Only play a preview sample when controlling the ringer stream
+            if (mStreamType != AudioManager.STREAM_RING
+                    && mStreamType != AudioManager.STREAM_NOTIFICATION) {
+                return;
+            }
+    
+            onSampleStarting(this);
+            mRingtone.play();
+        }
+    
+        public void stopSample() {
+            if (mRingtone != null) {
+                mRingtone.stop();
+            }
+        }
+
+        public SeekBar getSeekBar() {
+            return mSeekBar;
+        }
+        
+    }
 }
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index b07f1b8..b137b34 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -38,11 +38,11 @@
 import android.content.Intent;
 import android.database.Cursor;
 import android.net.Uri;
-import android.pim.DateUtils;
 import android.pim.ICalendar;
 import android.pim.RecurrenceSet;
-import android.pim.Time;
 import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.text.format.Time;
 import android.util.Config;
 import android.util.Log;
 
@@ -429,18 +429,27 @@
         public static final String EXDATE = "exdate";
 
         /**
-         * The original event this event is an exception for
+         * The _sync_id of the original recurring event for which this event is
+         * an exception.
          * <P>Type: TEXT</P>
          */
         public static final String ORIGINAL_EVENT = "originalEvent";
 
         /**
-         * The time of the original instance time this event is an exception for
+         * The original instance time of the recurring event for which this
+         * event is an exception.
          * <P>Type: INTEGER (long; millis since epoch)</P>
          */
         public static final String ORIGINAL_INSTANCE_TIME = "originalInstanceTime";
 
         /**
+         * The allDay status (true or false) of the original recurring event
+         * for which this event is an exception.
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String ORIGINAL_ALL_DAY = "originalAllDay";
+
+        /**
          * The last date this event repeats on, or NULL if it never ends
          * <P>Type: INTEGER (long; millis since epoch)</P>
          */
@@ -543,7 +552,7 @@
                         time.clear(tzidParam.value);
                     }
                     try {
-                        time.parse2445(dtstart);
+                        time.parse(dtstart);
                     } catch (Exception e) {
                         if (Config.LOGD) {
                             Log.d(TAG, "Cannot parse dtstart " + dtstart, e);
@@ -564,7 +573,7 @@
                         // TODO: make sure the timezones are the same for
                         // start, end.
                         try {
-                            time.parse2445(dtend);
+                            time.parse(dtend);
                         } catch (Exception e) {
                             if (Config.LOGD) {
                                 Log.d(TAG, "Cannot parse dtend " + dtend, e);
diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java
index 5b79482..ef5eded 100644
--- a/core/java/android/provider/Checkin.java
+++ b/core/java/android/provider/Checkin.java
@@ -96,8 +96,6 @@
             SYSTEM_SERVICE_LOOPING,
             SYSTEM_TOMBSTONE,
             TEST,
-            NETWORK_RX_MOBILE,
-            NETWORK_TX_MOBILE,
         }
     }
 
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 91b1853..6d24ba8 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -16,6 +16,8 @@
 
 package android.provider;
 
+import com.android.internal.R;
+
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -29,8 +31,6 @@
 import android.util.Log;
 import android.widget.ImageView;
 
-import com.android.internal.R;
-
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 
@@ -1229,7 +1229,7 @@
                 try {
                     display = labels[type - 1];
                 } catch (ArrayIndexOutOfBoundsException e) {
-                    display = labels[People.Phones.TYPE_HOME - 1];
+                    display = labels[Organizations.TYPE_WORK - 1];
                 }
             } else {
                 if (!TextUtils.isEmpty(label)) {
@@ -1546,6 +1546,32 @@
             public static final String PHONE_ISPRIMARY = "phone_isprimary";
 
             /**
+             * The extra field for an optional second contact phone number.
+             * <P>Type: String</P>
+             */
+            public static final String SECONDARY_PHONE = "secondary_phone";
+
+            /**
+             * The extra field for an optional second contact phone number type.
+             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+             *  or a string specifying a type and label.</P>
+             */
+            public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
+
+            /**
+             * The extra field for an optional third contact phone number.
+             * <P>Type: String</P>
+             */
+            public static final String TERTIARY_PHONE = "tertiary_phone";
+
+            /**
+             * The extra field for an optional third contact phone number type.
+             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+             *  or a string specifying a type and label.</P>
+             */
+            public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
+
+            /**
              * The extra field for the contact email address.
              * <P>Type: String</P>
              */
@@ -1565,6 +1591,32 @@
             public static final String EMAIL_ISPRIMARY = "email_isprimary";
 
             /**
+             * The extra field for an optional second contact email address.
+             * <P>Type: String</P>
+             */
+            public static final String SECONDARY_EMAIL = "secondary_email";
+
+            /**
+             * The extra field for an optional second contact email type.
+             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+             *  or a string specifying a type and label.</P>
+             */
+            public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
+
+            /**
+             * The extra field for an optional third contact email address.
+             * <P>Type: String</P>
+             */
+            public static final String TERTIARY_EMAIL = "tertiary_email";
+
+            /**
+             * The extra field for an optional third contact email type.
+             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+             *  or a string specifying a type and label.</P>
+             */
+            public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
+
+            /**
              * The extra field for the contact postal address.
              * <P>Type: String</P>
              */
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 42e9d95a..a5a30b9 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -29,6 +29,29 @@
 // this API is hidden.
 public final class Downloads implements BaseColumns {
     private Downloads() {}
+
+    /**
+     * The permission to access the download manager
+     */
+    public static final String PERMISSION_ACCESS = "android.permission.ACCESS_DOWNLOAD_MANAGER";
+
+    /**
+     * The permission to access the download manager's advanced functions
+     */
+    public static final String PERMISSION_ACCESS_ADVANCED =
+            "android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED";
+
+    /**
+     * The permission to directly access the download manager's cache directory
+     */
+    public static final String PERMISSION_CACHE = "android.permission.ACCESS_CACHE_FILESYSTEM";
+
+    /**
+     * The permission to send broadcasts on download completion
+     */
+    public static final String PERMISSION_SEND_INTENTS =
+            "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS";
+
     /**
      * The content:// URI for the data table in the provider
      */
@@ -64,21 +87,11 @@
     public static final String URI = "uri";
 
     /**
-     * The name of the column containing the HTTP method to use for this
-     * download. See the METHOD_* constants for a list of legal values.
-     * <P>Type: INTEGER</P>
-     * <P>Owner can Init/Read</P>
-     */
-    public static final String METHOD = "method";
-
-    /**
-     * The name of the column containing the entity to be sent with the
-     * request of this download. Only use for methods that support sending
-     * entities, i.e. POST.
+     * The name of the column containing application-specific data.
      * <P>Type: TEXT</P>
-     * <P>Owner can Init</P>
+     * <P>Owner can Init/Read/Write</P>
      */
-    public static final String ENTITY = "entity";
+    public static final String APP_DATA = "entity";
 
     /**
      * The name of the column containing the flags that indicates whether
@@ -89,7 +102,7 @@
      * a byte-range request without an ETag, or when it can't determine
      * whether a download fully completed).
      * <P>Type: BOOLEAN</P>
-     * <P>Owner can Init/Read</P>
+     * <P>Owner can Init</P>
      */
     public static final String NO_INTEGRITY = "no_integrity";
 
@@ -98,7 +111,7 @@
      * application recommends. When possible, the download manager will attempt
      * to use this filename, or a variation, as the actual name for the file.
      * <P>Type: TEXT</P>
-     * <P>Owner can Init/Read</P>
+     * <P>Owner can Init</P>
      */
     public static final String FILENAME_HINT = "hint";
 
@@ -107,15 +120,13 @@
      * was actually stored.
      * <P>Type: TEXT</P>
      * <P>Owner can Read</P>
-     * <P>UI can Read</P>
      */
-    public static final String FILENAME = "_data";
+    public static final String _DATA = "_data";
 
     /**
      * The name of the column containing the MIME type of the downloaded data.
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read</P>
-     * <P>UI can Read</P>
      */
     public static final String MIMETYPE = "mimetype";
 
@@ -123,51 +134,25 @@
      * The name of the column containing the flag that controls the destination
      * of the download. See the DESTINATION_* constants for a list of legal values.
      * <P>Type: INTEGER</P>
-     * <P>Owner can Init/Read</P>
-     * <P>UI can Read</P>
+     * <P>Owner can Init</P>
      */
     public static final String DESTINATION = "destination";
 
     /**
-     * The name of the column containing the flags that controls whether
-     * the download must be saved with the filename used for OTA updates.
-     * Must be used with INTERNAL, and the initiating application must hold the
-     * android.permission.DOWNLOAD_OTA_UPDATE permission.
-     * <P>Type: BOOLEAN</P>
-     * <P>Owner can Init/Read</P>
-     * <P>UI can Read</P>
-     */
-    public static final String OTA_UPDATE = "otaupdate";
-
-    /**
-     * The name of the columns containing the flag that controls whether
-     * files with private/inernal/system MIME types can be downloaded.
-     * <P>Type: BOOLEAN</P>
-     * <P>Owner can Init/Read</P>
-     */
-    public static final String NO_SYSTEM_FILES = "no_system";
-
-    /**
      * The name of the column containing the flags that controls whether the
      * download is displayed by the UI. See the VISIBILITY_* constants for
      * a list of legal values.
      * <P>Type: INTEGER</P>
      * <P>Owner can Init/Read/Write</P>
-     * <P>UI can Read/Write (only for entries that are visible)</P>
      */
     public static final String VISIBILITY = "visibility";
 
     /**
-     * The name of the column containing the command associated with the
-     * download. After a download is initiated, this is the only column that
-     * applications can modify. See the CONTROL_* constants for a list of legal
-     * values. Note: doesn't do anything in 1.0. The API will be hooked up
-     * in a future version, and is provided here as an indication of things
-     * to come.
+     * The name of the column containing the current control state  of the download.
+     * Applications can write to this to control (pause/resume) the download.
+     * the CONTROL_* constants for a list of legal values.
      * <P>Type: INTEGER</P>
-     * <P>Owner can Init/Read/Write</P>
-     * <P>UI can Init/Read/Write</P>
-     * @hide
+     * <P>Owner can Read</P>
      */
     public static final String CONTROL = "control";
 
@@ -177,7 +162,6 @@
      * the STATUS_* constants for a list of legal values.
      * <P>Type: INTEGER</P>
      * <P>Owner can Read</P>
-     * <P>UI can Read</P>
      */
     public static final String STATUS = "status";
 
@@ -187,24 +171,15 @@
      * value.
      * <P>Type: BIGINT</P>
      * <P>Owner can Read</P>
-     * <P>UI can Read</P>
      */
     public static final String LAST_MODIFICATION = "lastmod";
 
     /**
-     * The name of the column containing the number of consecutive connections
-     * that have failed.
-     * <P>Type: INTEGER</P>
-     */
-    public static final String FAILED_CONNECTIONS = "numfailed";
-
-    /**
      * The name of the column containing the package name of the application
      * that initiating the download. The download manager will send
      * notifications to a component in this package when the download completes.
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read</P>
-     * <P>UI can Read</P>
      */
     public static final String NOTIFICATION_PACKAGE = "notificationpackage";
 
@@ -215,13 +190,14 @@
      * Intent.setClassName(String,String).
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read</P>
-     * <P>UI can Read</P>
      */
     public static final String NOTIFICATION_CLASS = "notificationclass";
 
     /**
      * If extras are specified when requesting a download they will be provided in the intent that
      * is sent to the specified class and package when a download has finished.
+     * <P>Type: TEXT</P>
+     * <P>Owner can Init</P>
      */
     public static final String NOTIFICATION_EXTRAS = "notificationextras";
 
@@ -255,7 +231,6 @@
      * downloaded.
      * <P>Type: INTEGER</P>
      * <P>Owner can Read</P>
-     * <P>UI can Read</P>
      */
     public static final String TOTAL_BYTES = "total_bytes";
 
@@ -264,33 +239,18 @@
      * has been downloaded so far.
      * <P>Type: INTEGER</P>
      * <P>Owner can Read</P>
-     * <P>UI can Read</P>
      */
     public static final String CURRENT_BYTES = "current_bytes";
 
     /**
-     * The name of the column containing the entity tag for the response.
-     * <P>Type: TEXT</P>
-     * @hide
-     */
-    public static final String ETAG = "etag";
-
-    /**
-     * The name of the column containing the UID of the application that
-     * initiated the download.
-     * <P>Type: INTEGER</P>
-     * @hide
-     */
-    public static final String UID = "uid";
-
-    /**
      * The name of the column where the initiating application can provide the
      * UID of another application that is allowed to access this download. If
      * multiple applications share the same UID, all those applications will be
      * allowed to access this download. This column can be updated after the
-     * download is initiated.
+     * download is initiated. This requires the permission
+     * android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED.
      * <P>Type: INTEGER</P>
-     * <P>Owner can Init/Read/Write</P>
+     * <P>Owner can Init</P>
      */
     public static final String OTHER_UID = "otheruid";
 
@@ -300,7 +260,6 @@
      * list of downloads.
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read/Write</P>
-     * <P>UI can Read</P>
      */
     public static final String TITLE = "title";
 
@@ -310,18 +269,9 @@
      * user in the list of downloads.
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read/Write</P>
-     * <P>UI can Read</P>
      */
     public static final String DESCRIPTION = "description";
 
-    /**
-     * The name of the column where the download manager indicates whether the
-     * media scanner was notified about this download.
-     * <P>Type: BOOLEAN</P>
-     * @hide
-     */
-    public static final String MEDIA_SCANNED = "scanned";
-
     /*
      * Lists the destinations that an application can specify for a download.
      */
@@ -343,7 +293,8 @@
      * download private files that are used and deleted soon after they
      * get downloaded. All file types are allowed, and only the initiating
      * application can access the file (indirectly through a content
-     * provider).
+     * provider). This requires the
+     * android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED permission.
      */
     public static final int DESTINATION_CACHE_PARTITION = 1;
 
@@ -357,40 +308,21 @@
     public static final int DESTINATION_CACHE_PARTITION_PURGEABLE = 2;
 
     /**
-     * This download will be saved to the download manager's cache
-     * on the shared data partition. Use CACHE_PARTITION_PURGEABLE instead.
+     * This download will be saved to the download manager's private
+     * partition, as with DESTINATION_CACHE_PARTITION, but the download
+     * will not proceed if the user is on a roaming data connection.
      */
-    public static final int DESTINATION_DATA_CACHE = 3;
-
-    /* (not javadoc)
-     * This download will be saved to a file specified by the initiating
-     * applications.
-     * @hide
-     */
-    //public static final int DESTINATION_PROVIDER = 4;
-
-    /*
-     * Lists the commands that an application can set to control an ongoing
-     * download. Note: those aren't working.
-     */
+    public static final int DESTINATION_CACHE_PARTITION_NOROAMING = 3;
 
     /**
-     * This download can run
-     * @hide
+     * This download is allowed to run.
      */
     public static final int CONTROL_RUN = 0;
 
     /**
-     * This download must pause (might be restarted)
-     * @hide
+     * This download must pause at the first opportunity.
      */
-    public static final int CONTROL_PAUSE = 1;
-
-    /**
-     * This download must abort (will never be restarted)
-     * @hide
-     */
-    public static final int CONTROL_STOP = 2;
+    public static final int CONTROL_PAUSED = 1;
 
     /*
      * Lists the states that the download manager can set on a download
@@ -490,11 +422,6 @@
     public static final int STATUS_BAD_REQUEST = 400;
 
     /**
-     * The server returned an auth error.
-     */
-    public static final int STATUS_NOT_AUTHORIZED = 401;
-
-    /**
      * This download can't be performed because the content type cannot be
      * handled.
      */
@@ -522,11 +449,6 @@
      * This download was canceled
      */
     public static final int STATUS_CANCELED = 490;
-    /**
-     * @hide
-     * Alternate spelling
-     */
-    public static final int STATUS_CANCELLED = 490;
 
     /**
      * This download has completed with an error.
@@ -534,11 +456,6 @@
      * the future. Use isStatusError() to capture the entire category.
      */
     public static final int STATUS_UNKNOWN_ERROR = 491;
-    /**
-     * @hide
-     * Legacy name - use STATUS_UNKNOWN_ERROR
-     */
-    public static final int STATUS_ERROR = 491;
 
     /**
      * This download couldn't be completed because of a storage issue.
@@ -548,54 +465,40 @@
 
     /**
      * This download couldn't be completed because of an HTTP
-     * redirect code.
+     * redirect response that the download manager couldn't
+     * handle.
      */
     public static final int STATUS_UNHANDLED_REDIRECT = 493;
 
     /**
+     * This download couldn't be completed because there were
+     * too many redirects.
+     */
+    public static final int STATUS_TOO_MANY_REDIRECTS = 494;
+
+    /**
      * This download couldn't be completed because of an
      * unspecified unhandled HTTP code.
      */
-    public static final int STATUS_UNHANDLED_HTTP_CODE = 494;
+    public static final int STATUS_UNHANDLED_HTTP_CODE = 495;
 
     /**
      * This download couldn't be completed because of an
      * error receiving or processing data at the HTTP level.
      */
-    public static final int STATUS_HTTP_DATA_ERROR = 495;
+    public static final int STATUS_HTTP_DATA_ERROR = 496;
 
     /**
-     * This download couldn't be completed because of an
-     * HttpException while setting up the request.
+     * This download is visible and shows in the notifications while
+     * in progress and after completion.
      */
-    public static final int STATUS_HTTP_EXCEPTION = 496;
-
-    /*
-     * Lists the HTTP methods that the download manager can use.
-     */
-
-    /**
-     * GET
-     */
-    public static final int METHOD_GET = 0;
-
-    /**
-     * POST
-     */
-    public static final int METHOD_POST = 1;
+    public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 0;
 
     /**
      * This download is visible but only shows in the notifications
-     * while it's running (a separate download UI would still show it
-     * after completion).
+     * while it's in progress.
      */
-    public static final int VISIBILITY_VISIBLE = 0;
-
-    /**
-     * This download is visible and shows in the notifications after
-     * completion.
-     */
-    public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 1;
+    public static final int VISIBILITY_VISIBLE = 1;
 
     /**
      * This download doesn't show in the UI or in the notifications.
diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java
index 038ba21..0b6a758 100644
--- a/core/java/android/provider/Gmail.java
+++ b/core/java/android/provider/Gmail.java
@@ -72,6 +72,7 @@
     public static final String LABEL_STARRED = "^t";
     public static final String LABEL_CHAT = "^b"; // 'b' for 'buzz'
     public static final String LABEL_VOICEMAIL = "^vm";
+    public static final String LABEL_IGNORED = "^g";
     public static final String LABEL_ALL = "^all";
     // These constants (starting with "^^") are only used locally and are not understood by the
     // server.
@@ -142,6 +143,8 @@
     public static final String RESPOND_INPUT_COMMAND = "command";
     public static final String COMMAND_RETRY = "retry";
     public static final String COMMAND_ACTIVATE = "activate";
+    public static final String COMMAND_SET_VISIBLE = "setVisible";
+    public static final String SET_VISIBLE_PARAM_VISIBLE = "visible";
     public static final String RESPOND_OUTPUT_COMMAND_RESPONSE = "commandResponse";
     public static final String COMMAND_RESPONSE_OK =  "ok";
     public static final String COMMAND_RESPONSE_UNKNOWN =  "unknownCommand";
@@ -210,7 +213,8 @@
             Gmail.LABEL_UNREAD,
             Gmail.LABEL_TRASH,
             Gmail.LABEL_SPAM,
-            Gmail.LABEL_STARRED);
+            Gmail.LABEL_STARRED,
+            Gmail.LABEL_IGNORED);
 
     /**
      * Returns whether the label is user-settable. For example, labels such as LABEL_DRAFT should
@@ -337,6 +341,8 @@
         public static final String LABEL_IDS = "labelIds";
         public static final String JOINED_ATTACHMENT_INFOS = "joinedAttachmentInfos";
         public static final String ERROR = "error";
+        // TODO: add a method for accessing this
+        public static final String REF_MESSAGE_ID = "refMessageId";
 
         // Fake columns used only for saving or sending messages.
         public static final String FAKE_SAVE = "save";
@@ -773,7 +779,8 @@
         priorityToLength.clear();
 
         int maxFoundPriority = Integer.MIN_VALUE;
-        String numMessagesFragment = "";
+        int numMessages = 0;
+        int numDrafts = 0;
         CharSequence draftsFragment = "";
         CharSequence sendingFragment = "";
         CharSequence sendFailedFragment = "";
@@ -799,10 +806,10 @@
             } else if (Gmail.SENDER_LIST_TOKEN_ELIDED.equals(fragment0)) {
                 // ignore
             } else if (Gmail.SENDER_LIST_TOKEN_NUM_MESSAGES.equals(fragment0)) {
-                numMessagesFragment = " (" + fragments[i++] + ")";
+                numMessages = Integer.valueOf(fragments[i++]);
             } else if (Gmail.SENDER_LIST_TOKEN_NUM_DRAFTS.equals(fragment0)) {
                 String numDraftsString = fragments[i++];
-                int numDrafts = Integer.parseInt(numDraftsString);
+                numDrafts = Integer.parseInt(numDraftsString);
                 draftsFragment = numDrafts == 1 ? draftString :
                         draftPluralString + " (" + numDraftsString + ")";
             } else if (Gmail.SENDER_LIST_TOKEN_LITERAL.equals(fragment0)) {
@@ -821,6 +828,8 @@
                 maxFoundPriority = Math.max(maxFoundPriority, priority);
             }
         }
+        String numMessagesFragment =
+                (numMessages != 0) ? " (" + Integer.toString(numMessages + numDrafts) + ")" : "";
 
         // Don't allocate fixedFragment unless we need it
         SpannableStringBuilder fixedFragment = null;
@@ -1242,6 +1251,7 @@
         private long mLabelIdStarred;
         private long mLabelIdChat;
         private long mLabelIdVoicemail;
+        private long mLabelIdIgnored;
         private long mLabelIdVoicemailInbox;
         private long mLabelIdCached;
         private long mLabelIdOutbox;
@@ -1313,6 +1323,8 @@
                     mLabelIdStarred = labelId;
                 } else if (LABEL_CHAT.equals(canonicalName)) {
                     mLabelIdChat = labelId;
+                } else if (LABEL_IGNORED.equals(canonicalName)) {
+                    mLabelIdIgnored = labelId;
                 } else if (LABEL_VOICEMAIL.equals(canonicalName)) {
                     mLabelIdVoicemail = labelId;
                 } else if (LABEL_VOICEMAIL_INBOX.equals(canonicalName)) {
@@ -1330,6 +1342,7 @@
                     && mLabelIdSpam != 0
                     && mLabelIdStarred != 0
                     && mLabelIdChat != 0
+                    && mLabelIdIgnored != 0
                     && mLabelIdVoicemail != 0;
             }
         }
@@ -1374,6 +1387,11 @@
             return mLabelIdChat;
         }
 
+        public long getLabelIdIgnored() {
+            checkLabelsSynced();
+            return mLabelIdIgnored;
+        }
+
         public long getLabelIdVoicemail() {
             checkLabelsSynced();
             return mLabelIdVoicemail;
@@ -2237,9 +2255,28 @@
         }
 
         /**
-         * Gets the conversation id. This must be immutable. (For example, with
-         * GMail this should be the original conversation id rather than the
-         * default notion of converation id.)
+         * Tells the cursor whether its contents are visible to the user. The cursor will
+         * automatically broadcast intents to remove any matching new-mail notifications when this
+         * cursor's results become visible and, if they are visible, when the cursor is requeried.
+         *
+         * Note that contents shown in an activity that is resumed but not focused
+         * (onWindowFocusChanged/hasWindowFocus) then results shown in that activity do not count
+         * as visible. (This happens when the activity is behind the lock screen or a dialog.)
+         *
+         * @param visible whether the contents of this cursor are visible to the user.
+         */
+        public void setContentsVisibleToUser(boolean visible) {
+            Bundle input = new Bundle();
+            input.putString(RESPOND_INPUT_COMMAND, COMMAND_SET_VISIBLE);
+            input.putBoolean(SET_VISIBLE_PARAM_VISIBLE, visible);
+            Bundle output = mCursor.respond(input);
+            String response = output.getString(RESPOND_OUTPUT_COMMAND_RESPONSE);
+            assert COMMAND_RESPONSE_OK.equals(response);
+        }
+
+        /**
+         * Gets the conversation id. This is immutable. (The server calls it the original
+         * conversation id.)
          *
          * @return the conversation id
          */
diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java
index 8ca97e1..68b2acdf 100644
--- a/core/java/android/provider/Im.java
+++ b/core/java/android/provider/Im.java
@@ -43,16 +43,25 @@
     public interface ProviderColumns {
         /**
          * The name of the IM provider
+         * <P>Type: TEXT</P>
          */
         String NAME = "name";
 
         /**
          * The full name of the provider
+         * <P>Type: TEXT</P>
          */
         String FULLNAME = "fullname";
 
         /**
+         * The category for the provider, used to form intent.
+         * <P>Type: TEXT</P>
+         */
+        String CATEGORY = "category";
+
+        /**
          * The url users should visit to create a new account for this provider
+         * <P>Type: TEXT</P>
          */
         String SIGNUP_URL = "signup_url";
     }
@@ -187,6 +196,9 @@
         public static final String ACTIVE_ACCOUNT_ID = "account_id";
         public static final String ACTIVE_ACCOUNT_USERNAME = "account_username";
         public static final String ACTIVE_ACCOUNT_PW = "account_pw";
+        public static final String ACTIVE_ACCOUNT_LOCKED = "account_locked";
+        public static final String ACCOUNT_PRESENCE_STATUS = "account_presenceStatus";
+        public static final String ACCOUNT_CONNECTION_STATUS = "account_connStatus";
 
         /**
          * The content:// style URL for this table
@@ -204,6 +216,9 @@
         public static final String CONTENT_TYPE =
                 "vnd.android.cursor.dir/im-providers";
 
+        public static final String CONTENT_ITEM_TYPE =
+                "vnd.android.cursor.item/im-providers";
+
         /**
          * The default sort order for this table
          */
@@ -320,6 +335,76 @@
     }
 
     /**
+     * Connection status
+     */
+    public interface ConnectionStatus {
+        /**
+         * The connection is offline, not logged in.
+         */
+        int OFFLINE = 0;
+
+        /**
+         * The connection is attempting to connect.
+         */
+        int CONNECTING = 1;
+
+        /**
+         * The connection is suspended due to network not available.
+         */
+        int SUSPENDED = 2;
+
+        /**
+         * The connection is logged in and online.
+         */
+        int ONLINE = 3;
+    }
+
+    public interface AccountStatusColumns {
+        /**
+         * account id
+         * <P>Type: INTEGER</P>
+         */
+        String ACCOUNT = "account";
+
+        /**
+         * User's presence status, see definitions in {#link CommonPresenceColumn}
+         * <P>Type: INTEGER</P>
+         */
+        String PRESENCE_STATUS = "presenceStatus";
+
+        /**
+         * The connection status of this account, see {#link ConnectionStatus}
+         * <P>Type: INTEGER</P>
+         */
+        String CONNECTION_STATUS = "connStatus";
+    }
+
+    public static final class AccountStatus implements BaseColumns, AccountStatusColumns {
+        /**
+         * The content:// style URL for this table
+         */
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://im/accountStatus");
+
+        /**
+         * The MIME type of {@link #CONTENT_URI} providing a directory of account status.
+         */
+        public static final String CONTENT_TYPE =
+                "vnd.android.cursor.dir/im-account-status";
+
+        /**
+         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single account status.
+         */
+        public static final String CONTENT_ITEM_TYPE =
+                "vnd.android.cursor.item/im-account-status";
+
+        /**
+         * The default sort order for this table
+         */
+        public static final String DEFAULT_SORT_ORDER = "name ASC";
+    }
+
+    /**
      * Columns from the Contacts table.
      */
     public interface ContactsColumns {
@@ -451,9 +536,37 @@
          * <P>Type: INTEGER</P>
          */
         String REJECTED = "rejected";
+
+        /**
+         * Off The Record status: 0 for disabled, 1 for enabled
+         * <P>Type: INTEGER </P>
+         */
+        String OTR = "otr";
     }
 
     /**
+     * This defines the different type of values of {@link ContactsColumns#OTR}
+     */
+    public interface OffTheRecordType {
+        /*
+         * Off the record not turned on
+         */
+        int DISABLED = 0;
+        /**
+         * Off the record turned on, but we don't know who turned it on
+         */
+        int ENABLED = 1;
+        /**
+         * Off the record turned on by the user
+         */
+        int ENABLED_BY_USER = 2;
+        /**
+         * Off the record turned on by the buddy
+         */
+        int ENABLED_BY_BUDDY = 3;
+    };
+
+    /**
      * This table contains contacts.
      */
     public static final class Contacts implements BaseColumns,
@@ -755,15 +868,32 @@
      * Message type definition
      */
     public interface MessageType {
+        /* sent message */
         int OUTGOING = 0;
+        /* received message */
         int INCOMING = 1;
+        /* presence became available */
         int PRESENCE_AVAILABLE = 2;
+        /* presence became away */
         int PRESENCE_AWAY = 3;
+        /* presence became DND (busy) */
         int PRESENCE_DND = 4;
+        /* presence became unavailable */
         int PRESENCE_UNAVAILABLE = 5;
+        /* the message is converted to a group chat */
         int CONVERT_TO_GROUPCHAT = 6;
+        /* generic status */
         int STATUS = 7;
+        /* the message cannot be sent now, but will be sent later */
         int POSTPONED = 8;
+        /* off The Record status is turned off */
+        int OTR_IS_TURNED_OFF = 9;
+        /* off the record status is turned on */
+        int OTR_IS_TURNED_ON = 10;
+        /* off the record status turned on by user */
+        int OTR_TURNED_ON_BY_USER = 11;
+        /* off the record status turned on by buddy */
+        int OTR_TURNED_ON_BY_BUDDY = 12;
     }
 
     /**
@@ -1244,26 +1374,25 @@
     public interface ChatsColumns {
         /**
          * The contact ID this chat belongs to. The value is a long.
-         * <P>Type: TEXT</P>
+         * <P>Type: INT</P>
          */
         String CONTACT_ID = "contact_id";
 
         /**
          * The GTalk JID resource. The value is a string.
+         * <P>Type: TEXT</P>
          */
         String JID_RESOURCE = "jid_resource";
 
         /**
          * Whether this is a groupchat or not.
+         * <P>Type: INT</P>
          */
-        // TODO: remove this column since we already have a tag in contacts
-        // table to indicate it's a group chat.
         String GROUP_CHAT = "groupchat";
 
         /**
          * The last unread message. This both indicates that there is an
          * unread message, and what the message is.
-         *
          * <P>Type: TEXT</P>
          */
         String LAST_UNREAD_MESSAGE = "last_unread_message";
@@ -1278,10 +1407,17 @@
          * A message that is being composed.  This indicates that there was a
          * message being composed when the chat screen was shutdown, and what the
          * message is.
-         *
          * <P>Type: TEXT</P>
          */
         String UNSENT_COMPOSED_MESSAGE = "unsent_composed_message";
+        
+        /**
+         * A value from 0-9 indicating which quick-switch chat screen slot this
+         * chat is occupying.  If none (for instance, this is the 12th active chat)
+         * then the value is -1.
+         * <P>Type: INT</P>
+         */
+        String SHORTCUT = "shortcut";
     }
 
     /**
diff --git a/core/java/android/provider/LiveFolders.java b/core/java/android/provider/LiveFolders.java
new file mode 100644
index 0000000..6e95fb7
--- /dev/null
+++ b/core/java/android/provider/LiveFolders.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.annotation.SdkConstant;
+
+/**
+ * <p>A LiveFolder is a special folder whose content is provided by a
+ * {@link android.content.ContentProvider}. To create a live folder, two components
+ * are required:</p>
+ * <ul>
+ *  <li>An activity that can respond to the intent action {@link #ACTION_CREATE_LIVE_FOLDER}. The
+ *  activity is responsible for creating the live folder.</li>
+ *  <li>A {@link android.content.ContentProvider} to provide the live folder items.</li>
+ * </ul>
+ *
+ * <h3>Lifecycle</h3>
+ * <p>When a user wants to create a live folder, the system looks for all activities with the
+ * intent filter action {@link #ACTION_CREATE_LIVE_FOLDER} and presents the list to the user.
+ * When the user chooses one of the activities, the activity is invoked with the
+ * {@link #ACTION_CREATE_LIVE_FOLDER} action. The activity then creates the live folder and
+ * passes it back to the system by setting it as an
+ * {@link android.app.Activity#setResult(int, android.content.Intent) activity result}. The
+ * live folder is described by a content provider URI, a name, an icon and a display mode.
+ * Finally, when the user opens the live folder, the system queries the content provider
+ * to retrieve the folder's content.</p>
+ *
+ * <h3>Setting up the live folder activity</h3>
+ * <p>The following code sample shows how to write an activity that creates a live fodler:</p>
+ * <pre>
+ * public static class MyLiveFolder extends Activity {
+ *     public static final Uri CONTENT_URI = Uri.parse("content://my.app/live");
+ *
+ *     @Override
+ *     protected void onCreate(Bundle savedInstanceState) {
+ *         super.onCreate(savedInstanceState);
+ *
+ *         final Intent intent = getIntent();
+ *         final String action = intent.getAction();
+ *
+ *         if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {
+ *             setResult(RESULT_OK, createLiveFolder(this, CONTENT_URI, "My LiveFolder",
+ *                     R.drawable.ic_launcher_contacts_phones));
+ *         } else {
+ *             setResult(RESULT_CANCELED);
+ *         }
+ *
+ *         finish();
+ *     }
+ *
+ *     private static Intent createLiveFolder(Context context, Uri uri, String name,
+ *             int icon) {
+ *
+ *         final Intent intent = new Intent();
+ *
+ *         intent.setData(uri);
+ *         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);
+ *         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,
+ *                 Intent.ShortcutIconResource.fromContext(context, icon));
+ *         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, LiveFolders.DISPLAY_MODE_LIST);
+ *
+ *         return intent;
+ *     }
+ * }
+ * </pre>
+ * <p>The live folder is described by an {@link android.content.Intent} as follows:</p>
+ * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
+ *     <thead>
+ *     <tr><th>Component</th> <th>Type</th> <th>Description</th> <th>Required</th></tr>
+ *     </thead>
+ *
+ *     <tbody>
+ *     <tr><th>URI</th>
+ *         <td>URI</td>
+ *         <td>The ContentProvider URI</td>
+ *         <td align="center">Yes</td>
+ *     </tr>
+ *     <tr><th>{@link #EXTRA_LIVE_FOLDER_NAME}</th>
+ *         <td>Extra String</td>
+ *         <td>The name of the live folder</td>
+ *         <td align="center">Yes</td>
+ *     </tr>
+ *     <tr><th>{@link #EXTRA_LIVE_FOLDER_ICON}</th>
+ *         <td>Extra {@link android.content.Intent.ShortcutIconResource}</td>
+ *         <td>The icon of the live folder</td>
+ *         <td align="center">Yes</td>
+ *     </tr>
+ *     <tr><th>{@link #EXTRA_LIVE_FOLDER_DISPLAY_MODE}</th>
+ *         <td>Extra int</td>
+ *         <td>The display mode of the live folder. The value must be either
+ *         {@link #DISPLAY_MODE_GRID} or {@link #DISPLAY_MODE_LIST}.</td>
+ *         <td align="center">Yes</td>
+ *     </tr>
+ *     <tr><th>{@link #EXTRA_LIVE_FOLDER_BASE_INTENT}</th>
+ *         <td>Extra Intent</td>
+ *         <td>When the user clicks an item inside a live folder, the system will either fire
+ *         the intent associated with that item or, if present, the live folder's base intent
+ *         with the id of the item appended to the base intent's URI.</td>
+ *         <td align="center">No</td>
+ *     </tr>
+ *     </tbody>
+ * </table>
+ *
+ * <h3>Setting up the content provider</h3>
+ * <p>The live folder's content provider must, upon query, return a {@link android.database.Cursor}
+ * whose columns match the following names:</p>
+ * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
+ *     <thead>
+ *     <tr><th>Column</th> <th>Type</th> <th>Description</th> <th>Required</th></tr>
+ *     </thead>
+ *
+ *     <tbody>
+ *     <tr><th>{@link #NAME}</th>
+ *         <td>String</td>
+ *         <td>The name of the item</td>
+ *         <td align="center">Yes</td>
+ *     </tr>
+ *     <tr><th>{@link #DESCRIPTION}</th>
+ *         <td>String</td>
+ *         <td>The description of the item. The description is ignored when the live folder's
+ *         display mode is {@link #DISPLAY_MODE_GRID}.</td>
+ *         <td align="center">No</td>
+ *     </tr>
+ *     <tr><th>{@link #INTENT}</th>
+ *         <td>{@link android.content.Intent}</td>
+ *         <td>The intent to fire when the item is clicked. Ignored when the live folder defines
+ *         a base intent.</td>
+ *         <td align="center">No</td>
+ *     </tr>
+ *     <tr><th>{@link #ICON_BITMAP}</th>
+ *         <td>Bitmap</td>
+ *         <td>The icon for the item. When this column value is not null, the values for the
+ *         columns {@link #ICON_PACKAGE} and {@link #ICON_RESOURCE} must be null.</td>
+ *         <td align="center">No</td>
+ *     </tr>
+ *     <tr><th>{@link #ICON_PACKAGE}</th>
+ *         <td>String</td>
+ *         <td>The package of the item's icon. When this value is not null, the value for the
+ *         column {@link #ICON_RESOURCE} must be specified and the value for the column
+ *         {@link #ICON_BITMAP} must be null.</td>
+ *         <td align="center">No</td>
+ *     </tr>
+ *     <tr><th>{@link #ICON_RESOURCE}</th>
+ *         <td>String</td>
+ *         <td>The resource name of the item's icon. When this value is not null, the value for the
+ *         column {@link #ICON_PACKAGE} must be specified and the value for the column
+ *         {@link #ICON_BITMAP} must be null.</td>
+ *         <td align="center">No</td>
+ *     </tr>
+ *     </tbody>
+ * </table>
+ */
+public final class LiveFolders implements BaseColumns {
+    /**
+     * <p>Content provider column.</p>
+     * <p>Name of the live folder item.</p>
+     * <p>Required.</p>
+     * <p>Type: String.</p>
+     */
+    public static final String NAME = "name";
+
+    /**
+     * <p>Content provider column.</p>
+     * <p>Description of the live folder item. This value is ignored if the
+     * live folder's display mode is {@link LiveFolders#DISPLAY_MODE_GRID}.</p>
+     * <p>Optional.</p>
+     * <p>Type: String.</p>
+     *
+     * @see LiveFolders#EXTRA_LIVE_FOLDER_DISPLAY_MODE
+     */
+    public static final String DESCRIPTION = "description";
+
+    /**
+     * <p>Content provider column.</p>
+     * <p>Intent of the live folder item.</p>
+     * <p>Optional if the live folder has a base intent.</p>
+     * <p>Type: {@link android.content.Intent}.</p>
+     *
+     * @see LiveFolders#EXTRA_LIVE_FOLDER_BASE_INTENT
+     */
+    public static final String INTENT = "intent";
+
+    /**
+     * <p>Content provider column.</p>
+     * <p>Icon of the live folder item, as a custom bitmap.</p>
+     * <p>Optional.</p>
+     * <p>Type: {@link android.graphics.Bitmap}.</p>
+     */
+    public static final String ICON_BITMAP = "icon_bitmap";
+
+    /**
+     * <p>Content provider column.</p>
+     * <p>Package where to find the icon of the live folder item. This value can be
+     * obtained easily using
+     * {@link android.content.Intent.ShortcutIconResource#fromContext(android.content.Context, int)}.</p>
+     * <p>Optional.</p>
+     * <p>Type: String.</p>
+     *
+     * @see #ICON_RESOURCE
+     * @see android.content.Intent.ShortcutIconResource
+     */
+    public static final String ICON_PACKAGE = "icon_package";
+
+    /**
+     * <p>Content provider column.</p>
+     * <p>Resource name of the live folder item. This value can be obtained easily using
+     * {@link android.content.Intent.ShortcutIconResource#fromContext(android.content.Context, int)}.</p>
+     * <p>Optional.</p>
+     * <p>Type: String.</p>
+     *
+     * @see #ICON_PACKAGE
+     * @see android.content.Intent.ShortcutIconResource
+     */
+    public static final String ICON_RESOURCE = "icon_resource";
+
+    /**
+     * Displays a live folder's content in a grid.
+     *
+     * @see LiveFolders#EXTRA_LIVE_FOLDER_DISPLAY_MODE
+     */
+    public static final int DISPLAY_MODE_GRID = 0x1;
+
+    /**
+     * Displays a live folder's content in a list.
+     *
+     * @see LiveFolders#EXTRA_LIVE_FOLDER_DISPLAY_MODE
+     */
+    public static final int DISPLAY_MODE_LIST = 0x2;
+
+    /**
+     * The name of the extra used to define the name of a live folder.
+     *
+     * @see #ACTION_CREATE_LIVE_FOLDER
+     */
+    public static final String EXTRA_LIVE_FOLDER_NAME = "android.intent.extra.livefolder.NAME";
+
+    /**
+     * The name of the extra used to define the icon of a live folder.
+     *
+     * @see #ACTION_CREATE_LIVE_FOLDER
+     */
+    public static final String EXTRA_LIVE_FOLDER_ICON = "android.intent.extra.livefolder.ICON";
+
+    /**
+     * The name of the extra used to define the display mode of a live folder.
+     *
+     * @see #ACTION_CREATE_LIVE_FOLDER
+     * @see #DISPLAY_MODE_GRID
+     * @see #DISPLAY_MODE_LIST
+     */
+    public static final String EXTRA_LIVE_FOLDER_DISPLAY_MODE =
+            "android.intent.extra.livefolder.DISPLAY_MODE";
+
+    /**
+     * The name of the extra used to define the base Intent of a live folder.
+     *
+     * @see #ACTION_CREATE_LIVE_FOLDER
+     */
+    public static final String EXTRA_LIVE_FOLDER_BASE_INTENT =
+            "android.intent.extra.livefolder.BASE_INTENT";
+
+    /**
+     * Activity Action: Creates a live folder.
+     * <p>Input: Nothing.</p>
+     * <p>Output: An Intent representing the live folder. The intent must contain four
+     * extras: EXTRA_LIVE_FOLDER_NAME (value: String),
+     * EXTRA_LIVE_FOLDER_ICON (value: ShortcutIconResource),
+     * EXTRA_LIVE_FOLDER_URI (value: String) and
+     * EXTRA_LIVE_FOLDER_DISPLAY_MODE (value: int). The Intent can optionnally contain
+     * EXTRA_LIVE_FOLDER_BASE_INTENT (value: Intent).</p>
+     *
+     * @see #EXTRA_LIVE_FOLDER_NAME
+     * @see #EXTRA_LIVE_FOLDER_ICON
+     * @see #EXTRA_LIVE_FOLDER_DISPLAY_MODE
+     * @see #EXTRA_LIVE_FOLDER_BASE_INTENT
+     * @see android.content.Intent.ShortcutIconResource
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CREATE_LIVE_FOLDER =
+            "android.intent.action.CREATE_LIVE_FOLDER";
+
+    private LiveFolders() {
+    }
+}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index d99ad36..d4b728b 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -45,11 +45,70 @@
 public final class MediaStore
 {
     private final static String TAG = "MediaStore";
-    
+
     public static final String AUTHORITY = "media";
-    
+
     private static final String CONTENT_AUTHORITY_SLASH = "content://" + AUTHORITY + "/";
-    
+
+    /**
+     * Activity Action: Perform a search for media.
+     * Contains at least the {@link android.app.SearchManager#QUERY} extra.
+     * May also contain any combination of the following extras:
+     * EXTRA_MEDIA_ARTIST, EXTRA_MEDIA_ALBUM, EXTRA_MEDIA_TITLE, EXTRA_MEDIA_FOCUS
+     *
+     * @see android.provider.MediaStore#EXTRA_MEDIA_ARTIST
+     * @see android.provider.MediaStore#EXTRA_MEDIA_ALBUM
+     * @see android.provider.MediaStore#EXTRA_MEDIA_TITLE
+     * @see android.provider.MediaStore#EXTRA_MEDIA_FOCUS
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH";
+
+    /**
+     * The name of the Intent-extra used to define the artist
+     */
+    public static final String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist";
+    /**
+     * The name of the Intent-extra used to define the album
+     */
+    public static final String EXTRA_MEDIA_ALBUM = "android.intent.extra.album";
+    /**
+     * The name of the Intent-extra used to define the song title
+     */
+    public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
+    /**
+     * The name of the Intent-extra used to define the search focus. The search focus
+     * indicates whether the search should be for things related to the artist, album
+     * or song that is identified by the other extras.
+     */
+    public static final String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus";
+
+    /**
+     * The name of the Intent-extra used to control the orientation of a MovieView.
+     * This is an int property that overrides the MovieView activity's requestedOrientation.
+     * @see android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
+     */
+    public static final String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
+
+    /**
+     * The name of the Intent-extra used to control the onCompletion behavior of a MovieView.
+     * This is a boolean property that specifies whether or not to finish the MovieView activity
+     * when the movie completes playing. The default value is true, which means to automatically
+     * exit the movie player activity when the movie completes playing.
+     */
+    public static final String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
+
+    /**
+     * The name of the Intent action used to launch a camera in still image mode.
+     */
+    public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
+
+
+    /**
+     * The name of the Intent action used to launch a camera in video mode.
+     */
+    public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
+
     /**
      * Standard Intent action that can be sent to have the media application
      * capture an image and return it.  The image is returned as a Bitmap
@@ -57,11 +116,11 @@
      * @hide
      */
     public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
-    
-    /** 
+
+    /**
      * Common fields for most MediaProvider tables
      */
-     
+
      public interface MediaColumns extends BaseColumns {
         /**
          * The data stream for the file
@@ -108,7 +167,7 @@
          */
         public static final String MIME_TYPE = "mime_type";
      }
-    
+
     /**
      * Contains meta data for all available images.
      */
@@ -120,19 +179,19 @@
              * <P>Type: TEXT</P>
              */
             public static final String DESCRIPTION = "description";
-    
+
             /**
              * The picasa id of the image
              * <P>Type: TEXT</P>
              */
             public static final String PICASA_ID = "picasa_id";
-            
+
             /**
              * Whether the video should be published as public or private
              * <P>Type: INTEGER</P>
              */
             public static final String IS_PRIVATE = "isprivate";
-            
+
             /**
              * The latitude where the image was captured.
              * <P>Type: DOUBLE</P>
@@ -144,14 +203,14 @@
              * <P>Type: DOUBLE</P>
              */
             public static final String LONGITUDE = "longitude";
-            
+
             /**
              * The date & time that the image was taken in units
              * of milliseconds since jan 1, 1970.
              * <P>Type: INTEGER</P>
              */
             public static final String DATE_TAKEN = "datetaken";
-            
+
             /**
              * The orientation for the image expressed as degrees.
              * Only degrees 0, 90, 180, 270 will work.
@@ -164,15 +223,17 @@
              * <P>Type: INTEGER</P>
              */
             public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
-            
+
             /**
-             * The bucket id of the image
+             * The bucket id of the image. This is a read-only property that
+             * is automatically computed from the DATA column.
              * <P>Type: TEXT</P>
              */
             public static final String BUCKET_ID = "bucket_id";
-            
+
             /**
-             * The bucket display name of the image
+             * The bucket display name of the image. This is a read-only property that
+             * is automatically computed from the DATA column.
              * <P>Type: TEXT</P>
              */
             public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
@@ -183,14 +244,14 @@
             {
                 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
             }
-    
+
             public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
                                            String where, String orderBy)
             {
                 return cr.query(uri, projection, where,
                                              null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
             }
-            
+
             public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
                     String selection, String [] selectionArgs, String orderBy)
             {
@@ -200,7 +261,7 @@
 
             /**
              * Retrieves an image for the given url as a {@link Bitmap}.
-             * 
+             *
              * @param cr The content resolver to use
              * @param url The url of the image
              * @throws FileNotFoundException
@@ -214,10 +275,10 @@
                 input.close();
                 return bitmap;
             }
-            
+
             /**
              * Insert an image and create a thumbnail for it.
-             * 
+             *
              * @param cr The content resolver to use
              * @param imagePath The path to the image to insert
              * @param name The name of the image
@@ -239,38 +300,38 @@
                     }
                 }
             }
-            
+
             private static final Bitmap StoreThumbnail(
-                    ContentResolver cr, 
+                    ContentResolver cr,
                     Bitmap source,
                     long id,
-                    float width, float height, 
+                    float width, float height,
                     int kind) {
                 // create the matrix to scale it
                 Matrix matrix = new Matrix();
-                
+
                 float scaleX = width / source.getWidth();
                 float scaleY = height / source.getHeight();
-                
+
                 matrix.setScale(scaleX, scaleY);
-                
-                Bitmap thumb = Bitmap.createBitmap(source, 0, 0, 
+
+                Bitmap thumb = Bitmap.createBitmap(source, 0, 0,
                                                    source.getWidth(),
                                                    source.getHeight(), matrix,
                                                    true);
-                
+
                 ContentValues values = new ContentValues(4);
                 values.put(Images.Thumbnails.KIND,     kind);
                 values.put(Images.Thumbnails.IMAGE_ID, (int)id);
                 values.put(Images.Thumbnails.HEIGHT,   thumb.getHeight());
                 values.put(Images.Thumbnails.WIDTH,    thumb.getWidth());
-                
+
                 Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values);
-                
+
                 try {
                     OutputStream thumbOut = cr.openOutputStream(url);
-                
-                    thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);   
+
+                    thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
                     thumbOut.close();
                     return thumb;
                 }
@@ -281,10 +342,10 @@
                     return null;
                 }
             }
-            
+
             /**
              * Insert an image and create a thumbnail for it.
-             * 
+             *
              * @param cr The content resolver to use
              * @param source The stream to use for the image
              * @param title The name of the image
@@ -306,7 +367,7 @@
                 try
                 {
                     url = cr.insert(EXTERNAL_CONTENT_URI, values);
-             
+
                     if (source != null) {
                         OutputStream imageOut = cr.openOutputStream(url);
                         try {
@@ -337,11 +398,11 @@
 
                 return stringUrl;
             }
-    
+
             /**
-             * Get the content:// style URI for the image media table on the 
+             * Get the content:// style URI for the image media table on the
              * given volume.
-             * 
+             *
              * @param volumeName the name of the volume to get the URI for
              * @return the URI to the image media table on the given volume
              */
@@ -355,7 +416,7 @@
              */
             public static final Uri INTERNAL_CONTENT_URI =
                     getContentUri("internal");
-            
+
             /**
              * The content:// style URI for the "primary" external storage
              * volume.
@@ -369,7 +430,7 @@
              * image MIME type as appropriate -- for example, image/jpeg.
              */
             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/image";
-    
+
             /**
              * The default sort order for this table
              */
@@ -382,23 +443,23 @@
             {
                 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
             }
-    
+
             public static final Cursor queryMiniThumbnails(ContentResolver cr, Uri uri, int kind, String[] projection)
             {
                 return cr.query(uri, projection, "kind = " + kind, null, DEFAULT_SORT_ORDER);
             }
-    
+
             public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind, String[] projection)
             {
                 return cr.query(EXTERNAL_CONTENT_URI, projection,
                         IMAGE_ID + " = " + origId + " AND " + KIND + " = " +
                         kind, null, null);
             }
-    
+
             /**
-             * Get the content:// style URI for the image media table on the 
+             * Get the content:// style URI for the image media table on the
              * given volume.
-             * 
+             *
              * @param volumeName the name of the volume to get the URI for
              * @return the URI to the image media table on the given volume
              */
@@ -406,13 +467,13 @@
                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                         "/images/thumbnails");
             }
-    
+
             /**
              * The content:// style URI for the internal storage.
              */
             public static final Uri INTERNAL_CONTENT_URI =
                     getContentUri("internal");
-            
+
             /**
              * The content:// style URI for the "primary" external storage
              * volume.
@@ -424,35 +485,35 @@
              * The default sort order for this table
              */
             public static final String DEFAULT_SORT_ORDER = "image_id ASC";
-    
+
             /**
              * The data stream for the thumbnail
              * <P>Type: DATA STREAM</P>
              */
             public static final String DATA = "_data";
-    
+
             /**
              * The original image for the thumbnal
              * <P>Type: INTEGER (ID from Images table)</P>
              */
             public static final String IMAGE_ID = "image_id";
-    
+
             /**
              * The kind of the thumbnail
              * <P>Type: INTEGER (One of the values below)</P>
              */
             public static final String KIND = "kind";
-    
+
             public static final int MINI_KIND = 1;
             public static final int FULL_SCREEN_KIND = 2;
             public static final int MICRO_KIND = 3;
-    
+
             /**
              * The width of the thumbnal
              * <P>Type: INTEGER (long)</P>
              */
             public static final String WIDTH = "width";
-    
+
             /**
              * The height of the thumbnail
              * <P>Type: INTEGER (long)</P>
@@ -460,7 +521,7 @@
             public static final String HEIGHT = "height";
         }
     }
-    
+
     /**
      * Container for all audio content.
      */
@@ -532,7 +593,7 @@
              * <P>Type: TEXT</P>
              */
             public static final String ALBUM_ART = "album_art";
-            
+
             /**
              * The track number of this song on the album, if any.
              * This number encodes both the track number and the
@@ -632,9 +693,9 @@
 
         public static final class Media implements AudioColumns {
             /**
-             * Get the content:// style URI for the audio media table on the 
+             * Get the content:// style URI for the audio media table on the
              * given volume.
-             * 
+             *
              * @param volumeName the name of the volume to get the URI for
              * @return the URI to the audio media table on the given volume
              */
@@ -642,46 +703,56 @@
                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                         "/audio/media");
             }
-            
+
             public static Uri getContentUriForPath(String path) {
                 return (path.startsWith(Environment.getExternalStorageDirectory().getPath()) ?
                         EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI);
             }
-            
+
             /**
              * The content:// style URI for the internal storage.
              */
             public static final Uri INTERNAL_CONTENT_URI =
                     getContentUri("internal");
-            
+
             /**
              * The content:// style URI for the "primary" external storage
              * volume.
              */
             public static final Uri EXTERNAL_CONTENT_URI =
                     getContentUri("external");
-            
+
             /**
              * The MIME type for this table.
              */
             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
-            
+
             /**
              * The default sort order for this table
              */
             public static final String DEFAULT_SORT_ORDER = TITLE;
-            
+
             /**
              * Activity Action: Start SoundRecorder application.
              * <p>Input: nothing.
              * <p>Output: An uri to the recorded sound stored in the Media Library
              * if the recording was successful.
-             * 
+             * May also contain the extra EXTRA_MAX_BYTES.
+             * @see #EXTRA_MAX_BYTES
              */
-            public static final String RECORD_SOUND_ACTION = 
+            public static final String RECORD_SOUND_ACTION =
                     "android.provider.MediaStore.RECORD_SOUND";
+
+            /**
+             * The name of the Intent-extra used to define a maximum file size for
+             * a recording made by the SoundRecorder application.
+             *
+             * @see #RECORD_SOUND_ACTION
+             */
+             public static final String EXTRA_MAX_BYTES =
+                    "android.provider.MediaStore.extra.MAX_BYTES";
         }
-    
+
         /**
          * Columns representing an audio genre
          */
@@ -698,9 +769,9 @@
          */
         public static final class Genres implements BaseColumns, GenresColumns {
             /**
-             * Get the content:// style URI for the audio genres table on the 
+             * Get the content:// style URI for the audio genres table on the
              * given volume.
-             * 
+             *
              * @param volumeName the name of the volume to get the URI for
              * @return the URI to the audio genres table on the given volume
              */
@@ -714,7 +785,7 @@
              */
             public static final Uri INTERNAL_CONTENT_URI =
                     getContentUri("internal");
-            
+
             /**
              * The content:// style URI for the "primary" external storage
              * volume.
@@ -726,7 +797,7 @@
              * The MIME type for this table.
              */
             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/genre";
-            
+
             /**
              * The MIME type for entries in this table.
              */
@@ -794,7 +865,7 @@
              * <P>Type: INTEGER (long)</P>
              */
             public static final String DATE_ADDED = "date_added";
-    
+
             /**
              * The time the file was last modified
              * Units are seconds since 1970.
@@ -803,16 +874,16 @@
              */
             public static final String DATE_MODIFIED = "date_modified";
         }
-        
+
         /**
          * Contains playlists for audio files
          */
         public static final class Playlists implements BaseColumns,
                 PlaylistsColumns {
             /**
-             * Get the content:// style URI for the audio playlists table on the 
+             * Get the content:// style URI for the audio playlists table on the
              * given volume.
-             * 
+             *
              * @param volumeName the name of the volume to get the URI for
              * @return the URI to the audio playlists table on the given volume
              */
@@ -826,7 +897,7 @@
              */
             public static final Uri INTERNAL_CONTENT_URI =
                     getContentUri("internal");
-            
+
             /**
              * The content:// style URI for the "primary" external storage
              * volume.
@@ -838,7 +909,7 @@
              * The MIME type for this table.
              */
             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist";
-            
+
             /**
              * The MIME type for entries in this table.
              */
@@ -863,7 +934,7 @@
                  * The ID within the playlist.
                  */
                 public static final String _ID = "_id";
-                
+
                 /**
                  * A subdirectory of each playlist containing all member audio
                  * files.
@@ -881,7 +952,7 @@
                  * <P>Type: INTEGER (long)</P>
                  */
                 public static final String PLAYLIST_ID = "playlist_id";
-                
+
                 /**
                  * The order of the songs in the playlist
                  * <P>Type: INTEGER (long)></P>
@@ -922,15 +993,15 @@
              */
             public static final String NUMBER_OF_TRACKS = "number_of_tracks";
         }
-        
+
         /**
          * Contains artists for audio files
          */
         public static final class Artists implements BaseColumns, ArtistColumns {
             /**
-             * Get the content:// style URI for the artists table on the 
+             * Get the content:// style URI for the artists table on the
              * given volume.
-             * 
+             *
              * @param volumeName the name of the volume to get the URI for
              * @return the URI to the audio artists table on the given volume
              */
@@ -944,7 +1015,7 @@
              */
             public static final Uri INTERNAL_CONTENT_URI =
                     getContentUri("internal");
-            
+
             /**
              * The content:// style URI for the "primary" external storage
              * volume.
@@ -956,7 +1027,7 @@
              * The MIME type for this table.
              */
             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/artists";
-            
+
             /**
              * The MIME type for entries in this table.
              */
@@ -979,7 +1050,7 @@
                 }
             }
         }
-        
+
         /**
          * Columns representing an album
          */
@@ -1010,6 +1081,16 @@
             public static final String NUMBER_OF_SONGS = "numsongs";
 
             /**
+             * This column is available when getting album info via artist,
+             * and indicates the number of songs on the album by the given
+             * artist.
+             * <P>Type: INTEGER</P>
+             *
+             * @hide pending API Council approval
+             */
+            public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist";
+
+            /**
              * The year in which the earliest and latest songs
              * on this album were released. These will often
              * be the same, but for compilation albums they
@@ -1025,22 +1106,22 @@
              * <P>Type: TEXT</P>
              */
             public static final String ALBUM_KEY = "album_key";
-            
+
             /**
              * Cached album art.
              * <P>Type: TEXT</P>
              */
             public static final String ALBUM_ART = "album_art";
         }
-        
+
         /**
          * Contains artists for audio files
          */
         public static final class Albums implements BaseColumns, AlbumColumns {
             /**
-             * Get the content:// style URI for the albums table on the 
+             * Get the content:// style URI for the albums table on the
              * given volume.
-             * 
+             *
              * @param volumeName the name of the volume to get the URI for
              * @return the URI to the audio albums table on the given volume
              */
@@ -1054,7 +1135,7 @@
              */
             public static final Uri INTERNAL_CONTENT_URI =
                     getContentUri("internal");
-            
+
             /**
              * The content:// style URI for the "primary" external storage
              * volume.
@@ -1066,7 +1147,7 @@
              * The MIME type for this table.
              */
             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/albums";
-            
+
             /**
              * The MIME type for entries in this table.
              */
@@ -1145,7 +1226,7 @@
              * <P>Type: TEXT</P>
              */
             public static final String LANGUAGE = "language";
-            
+
             /**
              * The latitude where the image was captured.
              * <P>Type: DOUBLE</P>
@@ -1157,7 +1238,7 @@
              * <P>Type: DOUBLE</P>
              */
             public static final String LONGITUDE = "longitude";
-            
+
             /**
              * The date & time that the image was taken in units
              * of milliseconds since jan 1, 1970.
@@ -1170,13 +1251,27 @@
              * <P>Type: INTEGER</P>
              */
             public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
+
+            /**
+             * The bucket id of the video. This is a read-only property that
+             * is automatically computed from the DATA column.
+             * <P>Type: TEXT</P>
+             */
+            public static final String BUCKET_ID = "bucket_id";
+
+            /**
+             * The bucket display name of the video. This is a read-only property that
+             * is automatically computed from the DATA column.
+             * <P>Type: TEXT</P>
+             */
+            public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
         }
 
         public static final class Media implements VideoColumns {
             /**
-             * Get the content:// style URI for the video media table on the 
+             * Get the content:// style URI for the video media table on the
              * given volume.
-             * 
+             *
              * @param volumeName the name of the volume to get the URI for
              * @return the URI to the video media table on the given volume
              */
@@ -1190,7 +1285,7 @@
              */
             public static final Uri INTERNAL_CONTENT_URI =
                     getContentUri("internal");
-            
+
             /**
              * The content:// style URI for the "primary" external storage
              * volume.
diff --git a/core/java/android/provider/SearchRecentSuggestions.java b/core/java/android/provider/SearchRecentSuggestions.java
index 1439b26..0632d94 100644
--- a/core/java/android/provider/SearchRecentSuggestions.java
+++ b/core/java/android/provider/SearchRecentSuggestions.java
@@ -190,6 +190,11 @@
     
     /**
      * Completely delete the history.  Use this call to implement a "clear history" UI.
+     * 
+     * Any application that implements search suggestions based on previous actions (such as
+     * recent queries, page/items viewed, etc.) should provide a way for the user to clear the
+     * history.  This gives the user a measure of privacy, if they do not wish for their recent
+     * searches to be replayed by other users of the device (via suggestions).
      */
     public void clearHistory() {
         ContentResolver cr = mContext.getContentResolver();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6897bd5..e93bbeb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -40,6 +40,7 @@
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.HashMap;
+import java.util.HashSet;
 
 
 /**
@@ -100,6 +101,20 @@
             "android.settings.WIRELESS_SETTINGS";
 
     /**
+     * Activity Action: Show settings to allow entering/exiting airplane mode.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_AIRPLANE_MODE_SETTINGS =
+            "android.settings.AIRPLANE_MODE_SETTINGS";
+
+    /**
      * Activity Action: Show settings to allow configuration of security and
      * location privacy.
      * <p>
@@ -116,6 +131,7 @@
 
     /**
      * Activity Action: Show settings to allow configuration of Wi-Fi.
+
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
      * safeguard against this.
@@ -123,10 +139,26 @@
      * Input: Nothing.
      * <p>
      * Output: Nothing.
+
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_WIFI_SETTINGS =
             "android.settings.WIFI_SETTINGS";
+    
+    /**
+     * Activity Action: Show settings to allow configuration of a static IP
+     * address for Wi-Fi.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard
+     * against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_WIFI_IP_SETTINGS =
+            "android.settings.WIFI_IP_SETTINGS";
 
     /**
      * Activity Action: Show settings to allow configuration of Bluetooth.
@@ -213,7 +245,50 @@
             "android.settings.APPLICATION_SETTINGS";
 
     /**
-     * Activity Action: Show settings to allow configuration of sync settings.
+     * Activity Action: Show settings to allow configuration of application
+     * development-related settings.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard
+     * against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_APPLICATION_DEVELOPMENT_SETTINGS =
+            "android.settings.APPLICATION_DEVELOPMENT_SETTINGS";
+
+    /**
+     * Activity Action: Show settings to allow configuration of quick launch shortcuts.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_QUICK_LAUNCH_SETTINGS =
+            "android.settings.QUICK_LAUNCH_SETTINGS";
+    
+    /**
+     * Activity Action: Show settings to manage installed applications.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS =
+            "android.settings.MANAGE_APPLICATIONS_SETTINGS";
+    
+    /**
+     * Activity Action: Show settings for system update functionality.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
      * safeguard against this.
@@ -225,9 +300,78 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SYSTEM_UPDATE_SETTINGS =
+            "android.settings.SYSTEM_UPDATE_SETTINGS";
+
+    /**
+     * Activity Action: Show settings to allow configuration of sync settings.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_SYNC_SETTINGS =
             "android.settings.SYNC_SETTINGS";
     
+    /**
+     * Activity Action: Show settings for selecting the network operator.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_NETWORK_OPERATOR_SETTINGS =
+            "android.settings.NETWORK_OPERATOR_SETTINGS";
+
+    /**
+     * Activity Action: Show settings for selection of 2G/3G.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_DATA_ROAMING_SETTINGS =
+            "android.settings.DATA_ROAMING_SETTINGS";
+
+    /**
+     * Activity Action: Show settings for internal storage.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_INTERNAL_STORAGE_SETTINGS =
+            "android.settings.INTERNAL_STORAGE_SETTINGS";
+    /**
+     * Activity Action: Show settings for memory card storage.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MEMORY_CARD_SETTINGS =
+            "android.settings.MEMORY_CARD_SETTINGS";
+    
     // End of Intent actions for Settings
 
     private static final String JID_RESOURCE_PREFIX = "android";
@@ -246,8 +390,6 @@
 
     /**
      * Common base for tables of name/value settings.
-     *
-     * 
      */
     public static class NameValueTable implements BaseColumns {
         public static final String NAME = "name";
@@ -296,7 +438,7 @@
                 try {
                     c = cr.query(mUri, new String[] { Settings.NameValueTable.VALUE },
                             Settings.NameValueTable.NAME + "=?", new String[]{name}, null);
-                    if (c.moveToNext()) value = c.getString(0);
+                    if (c != null && c.moveToNext()) value = c.getString(0);
                     mValues.put(name, value);
                 } catch (SQLException e) {
                     // SQL error: return null, but don't cache it.
@@ -320,6 +462,41 @@
         public static final String SYS_PROP_SETTING_VERSION = "sys.settings_system_version";
 
         private static volatile NameValueCache mNameValueCache = null;
+        
+        private static final HashSet<String> MOVED_TO_SECURE;
+        static {
+            MOVED_TO_SECURE = new HashSet<String>(30);
+            MOVED_TO_SECURE.add(Secure.ADB_ENABLED);
+            MOVED_TO_SECURE.add(Secure.ANDROID_ID);
+            MOVED_TO_SECURE.add(Secure.BLUETOOTH_ON);
+            MOVED_TO_SECURE.add(Secure.DATA_ROAMING);
+            MOVED_TO_SECURE.add(Secure.DEVICE_PROVISIONED);
+            MOVED_TO_SECURE.add(Secure.HTTP_PROXY);
+            MOVED_TO_SECURE.add(Secure.INSTALL_NON_MARKET_APPS);
+            MOVED_TO_SECURE.add(Secure.LOCATION_PROVIDERS_ALLOWED);
+            MOVED_TO_SECURE.add(Secure.LOGGING_ID);
+            MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_ENABLED);
+            MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_LAST_UPDATE);
+            MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_REDIRECT_URL);
+            MOVED_TO_SECURE.add(Secure.SETTINGS_CLASSNAME);
+            MOVED_TO_SECURE.add(Secure.USB_MASS_STORAGE_ENABLED);
+            MOVED_TO_SECURE.add(Secure.USE_GOOGLE_MAIL);
+            MOVED_TO_SECURE.add(Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
+            MOVED_TO_SECURE.add(Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY);
+            MOVED_TO_SECURE.add(Secure.WIFI_NUM_OPEN_NETWORKS_KEPT);
+            MOVED_TO_SECURE.add(Secure.WIFI_ON);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_AP_COUNT);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_MAX_AP_CHECKS);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_ON);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_COUNT);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_DELAY_MS);
+            MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS);
+        }
 
         /**
          * Look up a name in the database.
@@ -328,6 +505,11 @@
          * @return the corresponding value, or null if not present
          */
         public synchronized static String getString(ContentResolver resolver, String name) {
+            if (MOVED_TO_SECURE.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+                        + " to android.provider.Settings.Secure, returning read-only value.");
+                return Secure.getString(resolver, name);
+            }
             if (mNameValueCache == null) {
                 mNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI);
             }
@@ -341,8 +523,12 @@
          * @param value to associate with the name
          * @return true if the value was set, false on database errors
          */
-        public static boolean putString(ContentResolver resolver,
-                String name, String value) {
+        public static boolean putString(ContentResolver resolver, String name, String value) {
+            if (MOVED_TO_SECURE.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+                        + " to android.provider.Settings.Secure, value is unchanged.");
+                return false;
+            }
             return putString(resolver, CONTENT_URI, name, value);
         }
 
@@ -353,6 +539,11 @@
          * @return the corresponding content URI, or null if not present
          */
         public static Uri getUriFor(String name) {
+            if (MOVED_TO_SECURE.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+                    + " to android.provider.Settings.Secure, returning Secure URI.");
+                return Secure.getUriFor(Secure.CONTENT_URI, name);
+            }
             return getUriFor(CONTENT_URI, name);
         }
 
@@ -426,6 +617,75 @@
 
         /**
          * Convenience function for retrieving a single system settings value
+         * as a {@code long}.  Note that internally setting values are always
+         * stored as strings; this function converts the string to a {@code long}
+         * for you.  The default value will be returned if the setting is
+         * not defined or not a {@code long}.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         * @param def Value to return if the setting is not defined.
+         *
+         * @return The setting's current value, or 'def' if it is not defined
+         * or not a valid {@code long}.
+         */
+        public static long getLong(ContentResolver cr, String name, long def) {
+            String valString = getString(cr, name);
+            long value;
+            try {
+                value = valString != null ? Long.parseLong(valString) : def;
+            } catch (NumberFormatException e) {
+                value = def;
+            }
+            return value;
+        }
+
+        /**
+         * Convenience function for retrieving a single system settings value
+         * as a {@code long}.  Note that internally setting values are always
+         * stored as strings; this function converts the string to a {@code long}
+         * for you.
+         * <p>
+         * This version does not take a default value.  If the setting has not
+         * been set, or the string value is not a number,
+         * it throws {@link SettingNotFoundException}.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         *
+         * @return The setting's current value.
+         * @throws SettingNotFoundException Thrown if a setting by the given
+         * name can't be found or the setting value is not an integer.
+         */
+        public static long getLong(ContentResolver cr, String name)
+                throws SettingNotFoundException {
+            String valString = getString(cr, name);
+            try {
+                return Long.parseLong(valString);
+            } catch (NumberFormatException e) {
+                throw new SettingNotFoundException(name);
+            }
+        }
+
+        /**
+         * Convenience function for updating a single settings value as a long
+         * integer. This will either create a new entry in the table if the
+         * given name does not exist, or modify the value of the existing row
+         * with that name.  Note that internally setting values are always
+         * stored as strings, so this function converts the given value to a
+         * string before storing it.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to modify.
+         * @param value The new value for the setting.
+         * @return true if the value was set, false on database errors
+         */
+        public static boolean putLong(ContentResolver cr, String name, long value) {
+            return putString(cr, name, Long.toString(value));
+        }
+
+        /**
+         * Convenience function for retrieving a single system settings value
          * as a floating point number.  Note that internally setting values are
          * always stored as strings; this function converts the string to an
          * float for you. The default value will be returned if the setting
@@ -536,7 +796,13 @@
 
         /**
          * Whether we keep the device on while the device is plugged in.
-         * 0=no  1=yes
+         * Supported values are:
+         * <ul>
+         * <li>{@code 0} to never stay on while plugged in</li>
+         * <li>{@link BatteryManager#BATTERY_PLUGGED_AC} to stay on for AC charger</li>
+         * <li>{@link BatteryManager#BATTERY_PLUGGED_USB} to stay on for USB charger</li>
+         * </ul>
+         * These values can be OR-ed together.
          */
         public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
 
@@ -580,104 +846,15 @@
         public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
 
         /**
-         * Whether the Wi-Fi should be on.  Only the Wi-Fi service should touch this.
+         * The interval in milliseconds after which Wi-Fi is considered idle.
+         * When idle, it is possible for the device to be switched from Wi-Fi to
+         * the mobile data network.
+         * 
+         * @hide pending API Council approval
          */
-        public static final String WIFI_ON = "wifi_on";
+        public static final String WIFI_IDLE_MS = "wifi_idle_ms";
 
         /**
-         * Whether to notify the user of open networks.
-         * <p>
-         * If not connected and the scan results have an open network, we will
-         * put this notification up. If we attempt to connect to a network or
-         * the open network(s) disappear, we remove the notification. When we
-         * show the notification, we will not show it again for
-         * {@link #WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} time.
-         */
-        public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
-                "wifi_networks_available_notification_on";
-
-        /**
-         * Delay (in seconds) before repeating the Wi-Fi networks available notification.
-         * Connecting to a network will reset the timer.
-         */
-        public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
-                "wifi_networks_available_repeat_delay";
-
-        /**
-         * When the number of open networks exceeds this number, the
-         * least-recently-used excess networks will be removed.
-         */
-        public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
-
-        /**
-         * Whether the Wi-Fi watchdog is enabled.
-         */
-        public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
-
-        /**
-         * The number of access points required for a network in order for the
-         * watchdog to monitor it.
-         */
-        public static final String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count";
-
-        /**
-         * The number of initial pings to perform that *may* be ignored if they
-         * fail. Again, if these fail, they will *not* be used in packet loss
-         * calculation. For example, one network always seemed to time out for
-         * the first couple pings, so this is set to 3 by default.
-         */
-        public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = "wifi_watchdog_initial_ignored_ping_count";
-        
-        /**
-         * The number of pings to test if an access point is a good connection.
-         */
-        public static final String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count";
-        
-        /**
-         * The timeout per ping.
-         */
-        public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
-
-        /**
-         * The delay between pings.
-         */
-        public static final String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms";
-
-        /**
-         * The acceptable packet loss percentage (range 0 - 100) before trying
-         * another AP on the same network.
-         */
-        public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE =
-                "wifi_watchdog_acceptable_packet_loss_percentage";
-
-        /**
-         * The maximum number of access points (per network) to attempt to test.
-         * If this number is reached, the watchdog will no longer monitor the
-         * initial connection state for the network. This is a safeguard for
-         * networks containing multiple APs whose DNS does not respond to pings.
-         */
-        public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks";
-
-        /**
-         * Whether the Wi-Fi watchdog is enabled for background checking even
-         * after it thinks the user has connected to a good access point.
-         */
-        public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED =
-                "wifi_watchdog_background_check_enabled";
-
-        /**
-         * The timeout for a background ping
-         */
-        public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS =
-                "wifi_watchdog_background_check_timeout_ms";
-        
-        /**
-         * The delay between background checks.
-         */
-        public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS =
-                "wifi_watchdog_background_check_delay_ms";
-        
-        /**
          * Whether to use static IP and other static network attributes.
          * <p>
          * Set to 1 for true and 0 for false.
@@ -720,16 +897,11 @@
         public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2";
 
         /**
-         * User preference for which network(s) should be used. Only the
-         * connectivity service should touch this.
+         * The number of radio channels that are allowed in the local
+         * 802.11 regulatory domain.
+         * @hide
          */
-        public static final String NETWORK_PREFERENCE = "network_preference";
-
-        /**
-         * Whether bluetooth is enabled/disabled
-         * 0=disabled. 1=enabled.
-         */
-        public static final String BLUETOOTH_ON = "bluetooth_on";
+        public static final String WIFI_NUM_ALLOWED_CHANNELS = "wifi_num_allowed_channels";
 
         /**
          * Determines whether remote devices may discover and/or connect to
@@ -756,15 +928,16 @@
         public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
 
         /**
-         * Whether the device has been provisioned (0 = false, 1 = true)
-         */
-        public static final String DEVICE_PROVISIONED = "device_provisioned";
-
-        /**
          * Whether lock pattern is visible as user enters (0 = false, 1 = true)
          */
         public static final String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
 
+        /**
+         * Whether lock pattern will vibrate as user enters (0 = false, 1 = true)
+         */
+        public static final String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED =
+            "lock_pattern_tactile_feedback_enabled";
+
 
         /**
          * A formatted string of the next alarm that is set, or the empty string
@@ -773,16 +946,6 @@
         public static final String NEXT_ALARM_FORMATTED = "next_alarm_formatted";
 
         /**
-         * Comma-separated list of location providers that activities may access.
-         */
-        public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
-
-        /**
-         * Whether or not data roaming is enabled. (0 = false, 1 = true)
-         */
-        public static final String DATA_ROAMING = "data_roaming";
-
-        /**
          * Scaling factor for fonts, float.
          */
         public static final String FONT_SCALE = "font_scale";
@@ -884,10 +1047,33 @@
         public static final String VOLUME_ALARM = "volume_alarm";
 
         /**
+         * Notification volume. This is used internally, changing this
+         * value will not change the volume. See AudioManager.
+         */
+        public static final String VOLUME_NOTIFICATION = "volume_notification";
+
+        /**
+         * Whether the notifications should use the ring volume (value of 1) or
+         * a separate notification volume (value of 0). In most cases, users
+         * will have this enabled so the notification and ringer volumes will be
+         * the same. However, power users can disable this and use the separate
+         * notification volume control.
+         * <p>
+         * Note: This is a one-off setting that will be removed in the future
+         * when there is profile support. For this reason, it is kept hidden
+         * from the public APIs.
+         * 
+         * @hide
+         */
+        public static final String NOTIFICATIONS_USE_RING_VOLUME = 
+            "notifications_use_ring_volume";
+        
+        /**
          * The mapping of stream type (integer) to its setting.
          */
         public static final String[] VOLUME_SETTINGS = {
-            VOLUME_VOICE, VOLUME_SYSTEM, VOLUME_RING, VOLUME_MUSIC, VOLUME_ALARM
+            VOLUME_VOICE, VOLUME_SYSTEM, VOLUME_RING, VOLUME_MUSIC,
+            VOLUME_ALARM, VOLUME_NOTIFICATION
         };
 
         /**
@@ -949,16 +1135,11 @@
          * feature converts two spaces to a "." and space.
          */
         public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
-
+        
         /**
          * Setting to showing password characters in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_SHOW_PASSWORD = "show_password";
-        /**
-         * USB Mass Storage Enabled
-         */
-        public static final String USB_MASS_STORAGE_ENABLED =
-                "usb_mass_storage_enabled";
 
         public static final String SHOW_GTALK_SERVICE_STATUS =
                 "SHOW_GTALK_SERVICE_STATUS";
@@ -969,11 +1150,6 @@
         public static final String WALLPAPER_ACTIVITY = "wallpaper_activity";
 
         /**
-         * Host name and port for a user-selected proxy.
-         */
-        public static final String HTTP_PROXY = "http_proxy";
-
-        /**
          * Value to specify if the user prefers the date, time and time zone
          * to be automatically fetched from the network (NITZ). 1=yes, 0=no
          */
@@ -995,13 +1171,6 @@
         public static final String DATE_FORMAT = "date_format";
 
         /**
-         * Settings classname to launch when Settings is clicked from All
-         * Applications.  Needed because of user testing between the old
-         * and new Settings apps. TODO: 881807
-         */
-        public static final String SETTINGS_CLASSNAME = "settings_classname";
-
-        /**
          * Whether the setup wizard has been run before (on first boot), or if
          * it still needs to be run.
          *
@@ -1011,35 +1180,6 @@
         public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
 
         /**
-         * The Android ID (a unique 64-bit value) as a hex string.
-         * Identical to that obtained by calling
-         * GoogleLoginService.getAndroidId(); it is also placed here
-         * so you can get it without binding to a service.
-         */
-        public static final String ANDROID_ID = "android_id";
-
-        /**
-         * The Logging ID (a unique 64-bit value) as a hex string.
-         * Used as a pseudonymous identifier for logging.
-         */
-        public static final String LOGGING_ID = "logging_id";
-
-        /**
-         * If this setting is set (to anything), then all references
-         * to Gmail on the device must change to Google Mail.
-         */
-        public static final String USE_GOOGLE_MAIL = "use_google_mail";
-
-        /**
-         * Whether the package installer should allow installation of apps downloaded from
-         * sources other than the Android Market (vending machine).
-         *
-         * 1 = allow installing from other sources
-         * 0 = only allow installing from the Android Market
-         */
-        public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
-
-        /**
          * Scaling factor for normal window animations. Setting to 0 will disable window
          * animations.
          */
@@ -1051,19 +1191,13 @@
          */
         public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
 
-        public static final String PARENTAL_CONTROL_ENABLED =
-            "parental_control_enabled";
-
-        public static final String PARENTAL_CONTROL_REDIRECT_URL =
-            "parental_control_redirect_url";
-
-        public static final String PARENTAL_CONTROL_LAST_UPDATE =
-          "parental_control_last_update";
-
         /**
-         * Whether ADB is enabled.
+         * Control whether the accelerometer will be used to change screen
+         * orientation.  If 0, it will not be used unless explicitly requested
+         * by the application; if 1, it will be used by default unless explicitly
+         * disabled by the application.
          */
-        public static final String ADB_ENABLED = "adb_enabled";
+        public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
 
         /**
          * Whether the audible DTMF tones are played by the dialer when dialing. The value is
@@ -1076,18 +1210,753 @@
          * boolean (1 or 0).
          */
         public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
+        
+        // Settings moved to Settings.Secure
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED}
+         * instead
+         */
+        @Deprecated
+        public static final String ADB_ENABLED = Secure.ADB_ENABLED;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#ANDROID_ID} instead
+         */
+        @Deprecated
+        public static final String ANDROID_ID = Secure.ANDROID_ID;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#BLUETOOTH_ON} instead
+         */
+        @Deprecated
+        public static final String BLUETOOTH_ON = Secure.BLUETOOTH_ON;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#DATA_ROAMING} instead
+         */
+        @Deprecated
+        public static final String DATA_ROAMING = Secure.DATA_ROAMING;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#DEVICE_PROVISIONED} instead
+         */
+        @Deprecated
+        public static final String DEVICE_PROVISIONED = Secure.DEVICE_PROVISIONED;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#HTTP_PROXY} instead
+         */
+        @Deprecated
+        public static final String HTTP_PROXY = Secure.HTTP_PROXY;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#INSTALL_NON_MARKET_APPS} instead
+         */
+        @Deprecated
+        public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS;
+        
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED}
+         * instead
+         */
+        @Deprecated
+        public static final String LOCATION_PROVIDERS_ALLOWED = Secure.LOCATION_PROVIDERS_ALLOWED;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#LOGGING_ID} instead
+         */
+        @Deprecated
+        public static final String LOGGING_ID = Secure.LOGGING_ID;
+        
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#NETWORK_PREFERENCE} instead
+         */
+        @Deprecated
+        public static final String NETWORK_PREFERENCE = Secure.NETWORK_PREFERENCE;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_ENABLED}
+         * instead
+         */
+        @Deprecated
+        public static final String PARENTAL_CONTROL_ENABLED = Secure.PARENTAL_CONTROL_ENABLED;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_LAST_UPDATE}
+         * instead
+         */
+        @Deprecated
+        public static final String PARENTAL_CONTROL_LAST_UPDATE = Secure.PARENTAL_CONTROL_LAST_UPDATE;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_REDIRECT_URL}
+         * instead
+         */
+        @Deprecated
+        public static final String PARENTAL_CONTROL_REDIRECT_URL =
+            Secure.PARENTAL_CONTROL_REDIRECT_URL;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#SETTINGS_CLASSNAME} instead
+         */
+        @Deprecated
+        public static final String SETTINGS_CLASSNAME = Secure.SETTINGS_CLASSNAME;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#USB_MASS_STORAGE_ENABLED} instead
+         */
+        @Deprecated
+        public static final String USB_MASS_STORAGE_ENABLED = Secure.USB_MASS_STORAGE_ENABLED;
+        
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#USE_GOOGLE_MAIL} instead
+         */
+        @Deprecated
+        public static final String USE_GOOGLE_MAIL = Secure.USE_GOOGLE_MAIL;
+
+//       /**
+//         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}
+//         * instead
+//         */
+        @Deprecated
+        public static final String WIFI_MAX_DHCP_RETRY_COUNT = Secure.WIFI_MAX_DHCP_RETRY_COUNT;
+
+//        /**
+//         * @deprecated Use
+//         * {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}
+//         * instead
+//         */
+        @Deprecated
+        public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
+                Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS;
+
+        /**
+         * @deprecated Use
+         * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} instead
+         */
+        @Deprecated
+        public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
+            Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
+
+        /**
+         * @deprecated Use
+         * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead
+         */
+        @Deprecated
+        public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
+            Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY;
+        
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_NUM_OPEN_NETWORKS_KEPT}
+         * instead
+         */
+        @Deprecated
+        public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = Secure.WIFI_NUM_OPEN_NETWORKS_KEPT;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_ON} instead
+         */
+        @Deprecated
+        public static final String WIFI_ON = Secure.WIFI_ON;
+
+        /**
+         * @deprecated Use
+         * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE}
+         * instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE =
+                Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_AP_COUNT} instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_AP_COUNT = Secure.WIFI_WATCHDOG_AP_COUNT;
+
+        /**
+         * @deprecated Use
+         * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS} instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS =
+                Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS;
+        
+        /**
+         * @deprecated Use
+         * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED} instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED =
+                Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED;
+
+        /**
+         * @deprecated Use
+         * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS}
+         * instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS =
+                Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS;
+
+        /**
+         * @deprecated Use
+         * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT =
+            Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS}
+         * instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = Secure.WIFI_WATCHDOG_MAX_AP_CHECKS;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_ON} instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_ON = Secure.WIFI_WATCHDOG_ON;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_COUNT} instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_PING_COUNT = Secure.WIFI_WATCHDOG_PING_COUNT;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_DELAY_MS}
+         * instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_PING_DELAY_MS = Secure.WIFI_WATCHDOG_PING_DELAY_MS;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_TIMEOUT_MS}
+         * instead
+         */
+        @Deprecated
+        public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS =
+            Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS;
     }
 
+    /**
+     * Secure system settings, containing system preferences that applications
+     * can read but are not allowed to write.  These are for preferences that
+     * the user must explicitly modify through the system UI or specialized
+     * APIs for those values, not modified directly by applications.
+     */
+    public static final class Secure extends NameValueTable {
+        public static final String SYS_PROP_SETTING_VERSION = "sys.settings_secure_version";
 
+        private static volatile NameValueCache mNameValueCache = null;
+
+        /**
+         * Look up a name in the database.
+         * @param resolver to access the database with
+         * @param name to look up in the table
+         * @return the corresponding value, or null if not present
+         */
+        public synchronized static String getString(ContentResolver resolver, String name) {
+            if (mNameValueCache == null) {
+                mNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI);
+            }
+            return mNameValueCache.getString(resolver, name);
+        }
+
+        /**
+         * Store a name/value pair into the database.
+         * @param resolver to access the database with
+         * @param name to store
+         * @param value to associate with the name
+         * @return true if the value was set, false on database errors
+         */
+        public static boolean putString(ContentResolver resolver,
+                String name, String value) {
+            return putString(resolver, CONTENT_URI, name, value);
+        }
+
+        /**
+         * Construct the content URI for a particular name/value pair,
+         * useful for monitoring changes with a ContentObserver.
+         * @param name to look up in the table
+         * @return the corresponding content URI, or null if not present
+         */
+        public static Uri getUriFor(String name) {
+            return getUriFor(CONTENT_URI, name);
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as an integer.  Note that internally setting values are always
+         * stored as strings; this function converts the string to an integer
+         * for you.  The default value will be returned if the setting is
+         * not defined or not an integer.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         * @param def Value to return if the setting is not defined.
+         *
+         * @return The setting's current value, or 'def' if it is not defined
+         * or not a valid integer.
+         */
+        public static int getInt(ContentResolver cr, String name, int def) {
+            String v = getString(cr, name);
+            try {
+                return v != null ? Integer.parseInt(v) : def;
+            } catch (NumberFormatException e) {
+                return def;
+            }
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as an integer.  Note that internally setting values are always
+         * stored as strings; this function converts the string to an integer
+         * for you.
+         * <p>
+         * This version does not take a default value.  If the setting has not
+         * been set, or the string value is not a number,
+         * it throws {@link SettingNotFoundException}.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         *
+         * @throws SettingNotFoundException Thrown if a setting by the given
+         * name can't be found or the setting value is not an integer.
+         *
+         * @return The setting's current value.
+         */
+        public static int getInt(ContentResolver cr, String name)
+                throws SettingNotFoundException {
+            String v = getString(cr, name);
+            try {
+                return Integer.parseInt(v);
+            } catch (NumberFormatException e) {
+                throw new SettingNotFoundException(name);
+            }
+        }
+
+        /**
+         * Convenience function for updating a single settings value as an
+         * integer. This will either create a new entry in the table if the
+         * given name does not exist, or modify the value of the existing row
+         * with that name.  Note that internally setting values are always
+         * stored as strings, so this function converts the given value to a
+         * string before storing it.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to modify.
+         * @param value The new value for the setting.
+         * @return true if the value was set, false on database errors
+         */
+        public static boolean putInt(ContentResolver cr, String name, int value) {
+            return putString(cr, name, Integer.toString(value));
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as a {@code long}.  Note that internally setting values are always
+         * stored as strings; this function converts the string to a {@code long}
+         * for you.  The default value will be returned if the setting is
+         * not defined or not a {@code long}.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         * @param def Value to return if the setting is not defined.
+         *
+         * @return The setting's current value, or 'def' if it is not defined
+         * or not a valid {@code long}.
+         */
+        public static long getLong(ContentResolver cr, String name, long def) {
+            String valString = getString(cr, name);
+            long value;
+            try {
+                value = valString != null ? Long.parseLong(valString) : def;
+            } catch (NumberFormatException e) {
+                value = def;
+            }
+            return value;
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as a {@code long}.  Note that internally setting values are always
+         * stored as strings; this function converts the string to a {@code long}
+         * for you.
+         * <p>
+         * This version does not take a default value.  If the setting has not
+         * been set, or the string value is not a number,
+         * it throws {@link SettingNotFoundException}.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         *
+         * @return The setting's current value.
+         * @throws SettingNotFoundException Thrown if a setting by the given
+         * name can't be found or the setting value is not an integer.
+         */
+        public static long getLong(ContentResolver cr, String name)
+                throws SettingNotFoundException {
+            String valString = getString(cr, name);
+            try {
+                return Long.parseLong(valString);
+            } catch (NumberFormatException e) {
+                throw new SettingNotFoundException(name);
+            }
+        }
+
+        /**
+         * Convenience function for updating a secure settings value as a long
+         * integer. This will either create a new entry in the table if the
+         * given name does not exist, or modify the value of the existing row
+         * with that name.  Note that internally setting values are always
+         * stored as strings, so this function converts the given value to a
+         * string before storing it.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to modify.
+         * @param value The new value for the setting.
+         * @return true if the value was set, false on database errors
+         */
+        public static boolean putLong(ContentResolver cr, String name, long value) {
+            return putString(cr, name, Long.toString(value));
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as a floating point number.  Note that internally setting values are
+         * always stored as strings; this function converts the string to an
+         * float for you. The default value will be returned if the setting
+         * is not defined or not a valid float.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         * @param def Value to return if the setting is not defined.
+         *
+         * @return The setting's current value, or 'def' if it is not defined
+         * or not a valid float.
+         */
+        public static float getFloat(ContentResolver cr, String name, float def) {
+            String v = getString(cr, name);
+            try {
+                return v != null ? Float.parseFloat(v) : def;
+            } catch (NumberFormatException e) {
+                return def;
+            }
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as a float.  Note that internally setting values are always
+         * stored as strings; this function converts the string to a float
+         * for you.
+         * <p>
+         * This version does not take a default value.  If the setting has not
+         * been set, or the string value is not a number,
+         * it throws {@link SettingNotFoundException}.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         *
+         * @throws SettingNotFoundException Thrown if a setting by the given
+         * name can't be found or the setting value is not a float.
+         *
+         * @return The setting's current value.
+         */
+        public static float getFloat(ContentResolver cr, String name)
+                throws SettingNotFoundException {
+            String v = getString(cr, name);
+            try {
+                return Float.parseFloat(v);
+            } catch (NumberFormatException e) {
+                throw new SettingNotFoundException(name);
+            }
+        }
+
+        /**
+         * Convenience function for updating a single settings value as a
+         * floating point number. This will either create a new entry in the
+         * table if the given name does not exist, or modify the value of the
+         * existing row with that name.  Note that internally setting values
+         * are always stored as strings, so this function converts the given
+         * value to a string before storing it.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to modify.
+         * @param value The new value for the setting.
+         * @return true if the value was set, false on database errors
+         */
+        public static boolean putFloat(ContentResolver cr, String name, float value) {
+            return putString(cr, name, Float.toString(value));
+        }
+
+        /**
+         * The content:// style URL for this table
+         */
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://" + AUTHORITY + "/secure");
+        
+        /**
+         * Whether ADB is enabled.
+         */
+        public static final String ADB_ENABLED = "adb_enabled";
+    
+        /**
+         * Setting to allow mock locations and location provider status to be injected into the
+         * LocationManager service for testing purposes during application development.  These
+         * locations and status values  override actual location and status information generated
+         * by network, gps, or other location providers.
+         */
+        public static final String ALLOW_MOCK_LOCATION = "mock_location";
+    
+        /**
+         * The Android ID (a unique 64-bit value) as a hex string.
+         * Identical to that obtained by calling
+         * GoogleLoginService.getAndroidId(); it is also placed here
+         * so you can get it without binding to a service.
+         */
+        public static final String ANDROID_ID = "android_id";
+    
+        /**
+         * Whether bluetooth is enabled/disabled
+         * 0=disabled. 1=enabled.
+         */
+        public static final String BLUETOOTH_ON = "bluetooth_on";
+    
+        /**
+         * Whether or not data roaming is enabled. (0 = false, 1 = true)
+         */
+        public static final String DATA_ROAMING = "data_roaming";
+    
+        /**
+         * Setting to record the input method used by default, holding the ID
+         * of the desired method.
+         */
+        public static final String DEFAULT_INPUT_METHOD = "default_input_method";
+    
+        /**
+         * Whether the device has been provisioned (0 = false, 1 = true)
+         */
+        public static final String DEVICE_PROVISIONED = "device_provisioned";
+    
+        /**
+         * List of input methods that are currently enabled.  This is a string
+         * containing the IDs of all enabled input methods, each ID separated
+         * by ':'.
+         */
+        public static final String ENABLED_INPUT_METHODS = "enabled_input_methods";
+    
+        /**
+         * Host name and port for a user-selected proxy.
+         */
+        public static final String HTTP_PROXY = "http_proxy";
+    
+        /**
+         * Whether the package installer should allow installation of apps downloaded from
+         * sources other than the Android Market (vending machine).
+         *
+         * 1 = allow installing from other sources
+         * 0 = only allow installing from the Android Market
+         */
+        public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+    
+        /**
+         * Comma-separated list of location providers that activities may access.
+         */
+        public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
+    
+        /**
+         * The Logging ID (a unique 64-bit value) as a hex string.
+         * Used as a pseudonymous identifier for logging.
+         */
+        public static final String LOGGING_ID = "logging_id";
+    
+        /**
+         * User preference for which network(s) should be used. Only the
+         * connectivity service should touch this.
+         */
+        public static final String NETWORK_PREFERENCE = "network_preference";
+    
+        /** 
+         */
+        public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
+    
+        /** 
+         */
+        public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
+    
+        /** 
+         */
+        public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
+    
+        /**
+         * Settings classname to launch when Settings is clicked from All
+         * Applications.  Needed because of user testing between the old
+         * and new Settings apps.
+         */
+        // TODO: 881807
+        public static final String SETTINGS_CLASSNAME = "settings_classname";
+    
+        /**
+         * USB Mass Storage Enabled
+         */
+        public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
+    
+        /**
+         * If this setting is set (to anything), then all references
+         * to Gmail on the device must change to Google Mail.
+         */
+        public static final String USE_GOOGLE_MAIL = "use_google_mail";
+    
+        /**
+         * Whether to notify the user of open networks.
+         * <p>
+         * If not connected and the scan results have an open network, we will
+         * put this notification up. If we attempt to connect to a network or
+         * the open network(s) disappear, we remove the notification. When we
+         * show the notification, we will not show it again for
+         * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} time.
+         */
+        public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
+                "wifi_networks_available_notification_on";
+    
+        /**
+         * Delay (in seconds) before repeating the Wi-Fi networks available notification.
+         * Connecting to a network will reset the timer.
+         */
+        public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
+                "wifi_networks_available_repeat_delay";
+    
+        /**
+         * The number of radio channels that are allowed in the local
+         * 802.11 regulatory domain.
+         * @hide
+         */
+        public static final String WIFI_NUM_ALLOWED_CHANNELS = "wifi_num_allowed_channels";
+    
+        /**
+         * When the number of open networks exceeds this number, the
+         * least-recently-used excess networks will be removed.
+         */
+        public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
+    
+        /**
+         * Whether the Wi-Fi should be on.  Only the Wi-Fi service should touch this.
+         */
+        public static final String WIFI_ON = "wifi_on";
+    
+        /**
+         * The acceptable packet loss percentage (range 0 - 100) before trying
+         * another AP on the same network.
+         */
+        public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE =
+                "wifi_watchdog_acceptable_packet_loss_percentage";
+    
+        /**
+         * The number of access points required for a network in order for the
+         * watchdog to monitor it.
+         */
+        public static final String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count";
+    
+        /**
+         * The delay between background checks.
+         */
+        public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS =
+                "wifi_watchdog_background_check_delay_ms";
+    
+        /**
+         * Whether the Wi-Fi watchdog is enabled for background checking even
+         * after it thinks the user has connected to a good access point.
+         */
+        public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED =
+                "wifi_watchdog_background_check_enabled";
+    
+        /**
+         * The timeout for a background ping
+         */
+        public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS =
+                "wifi_watchdog_background_check_timeout_ms";
+    
+        /**
+         * The number of initial pings to perform that *may* be ignored if they
+         * fail. Again, if these fail, they will *not* be used in packet loss
+         * calculation. For example, one network always seemed to time out for
+         * the first couple pings, so this is set to 3 by default.
+         */
+        public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT =
+            "wifi_watchdog_initial_ignored_ping_count";
+    
+        /**
+         * The maximum number of access points (per network) to attempt to test.
+         * If this number is reached, the watchdog will no longer monitor the
+         * initial connection state for the network. This is a safeguard for
+         * networks containing multiple APs whose DNS does not respond to pings.
+         */
+        public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks";
+    
+        /**
+         * Whether the Wi-Fi watchdog is enabled.
+         */
+        public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
+    
+        /**
+         * The number of pings to test if an access point is a good connection.
+         */
+        public static final String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count";
+    
+        /**
+         * The delay between pings.
+         */
+        public static final String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms";
+    
+        /**
+         * The timeout per ping.
+         */
+        public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
+    
+        /**
+         * The maximum number of times we will retry a connection to an access
+         * point for which we have failed in acquiring an IP address from DHCP.
+         * A value of N means that we will make N+1 connection attempts in all.
+         * 
+         * @hide pending API Council approval
+         */
+        public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
+    
+        /**
+         * Maximum amount of time in milliseconds to hold a wakelock while waiting for mobile
+         * data connectivity to be established after a disconnect from Wi-Fi.
+         * 
+         * @hide pending API Council approval
+         */
+        public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
+            "wifi_mobile_data_transition_wakelock_timeout_ms";
+    }
+    
     /**
      * Gservices settings, containing the network names for Google's
      * various services. This table holds simple name/addr pairs.
      * Addresses can be accessed through the getString() method.
+     *
+     * TODO: This should move to partner/google/... somewhere.
+     *
      * @hide
      */
     public static final class Gservices extends NameValueTable {
         public static final String SYS_PROP_SETTING_VERSION = "sys.settings_gservices_version";
 
+        /**
+         * Intent action broadcast when the Gservices table is updated by the server.
+         * This is broadcast once after settings change (so many values may have been updated).
+         */
+        @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+        public static final String CHANGED_ACTION =
+            "com.google.gservices.intent.action.GSERVICES_CHANGED";
+
         private static volatile NameValueCache mNameValueCache = null;
         private static final Object mNameValueCacheLock = new Object();
 
@@ -1173,132 +2042,6 @@
                 = "mms_x_wap_profile_url";
 
         /**
-         * YouTube - "most viewed" url
-         */
-        public static final String YOUTUBE_MOST_VIEWED_URL
-                = "youtube_most_viewed_url";
-
-        /**
-         * YouTube - "most recent" url
-         */
-        public static final String YOUTUBE_MOST_RECENT_URL
-                = "youtube_most_recent_url";
-
-        /**
-         * YouTube - "top favorites" url
-         */
-        public static final String YOUTUBE_TOP_FAVORITES_URL
-                = "youtube_top_favorites_url";
-
-        /**
-         * YouTube - "most discussed" url
-         */
-        public static final String YOUTUBE_MOST_DISCUSSED_URL
-                = "youtube_most_discussed_url";
-
-        /**
-         * YouTube - "most responded" url
-         */
-        public static final String YOUTUBE_MOST_RESPONDED_URL
-                = "youtube_most_responded_url";
-
-        /**
-         * YouTube - "most linked" url
-         */
-        public static final String YOUTUBE_MOST_LINKED_URL
-                = "youtube_most_linked_url";
-
-        /**
-         * YouTube - "top rated" url
-         */
-        public static final String YOUTUBE_TOP_RATED_URL
-                = "youtube_top_rated_url";
-
-        /**
-         * YouTube - "recently featured" url
-         */
-        public static final String YOUTUBE_RECENTLY_FEATURED_URL
-                = "youtube_recently_featured_url";
-
-        /**
-         * YouTube - my uploaded videos
-         */
-        public static final String YOUTUBE_MY_VIDEOS_URL
-                = "youtube_my_videos_url";
-
-        /**
-         * YouTube - "my favorite" videos url
-         */
-        public static final String YOUTUBE_MY_FAVORITES_URL
-                = "youtube_my_favorites_url";
-
-        /**
-         * YouTube - "by author" videos url -- used for My videos
-         */
-        public static final String YOUTUBE_BY_AUTHOR_URL
-                = "youtube_by_author_url";
-
-        /**
-         * YouTube - save a video to favorite videos url
-         */
-        public static final String YOUTUBE_SAVE_TO_FAVORITES_URL
-                = "youtube_save_to_favorites_url";
-
-        /**
-         * YouTube - "mobile" videos url
-         */
-        public static final String YOUTUBE_MOBILE_VIDEOS_URL
-                = "youtube_mobile_videos_url";
-
-        /**
-         * YouTube - search videos url
-         */
-        public static final String YOUTUBE_SEARCH_URL
-                = "youtube_search_url";
-
-        /**
-         * YouTube - category search videos url
-         */
-        public static final String YOUTUBE_CATEGORY_SEARCH_URL
-                = "youtube_category_search_url";
-
-        /**
-         * YouTube - url to get the list of categories
-         */
-        public static final String YOUTUBE_CATEGORY_LIST_URL
-                = "youtube_category_list_url";
-
-        /**
-         * YouTube - related videos url
-         */
-        public static final String YOUTUBE_RELATED_VIDEOS_URL
-                = "youtube_related_videos_url";
-
-        /**
-         * YouTube - individual video url
-         */
-        public static final String YOUTUBE_INDIVIDUAL_VIDEO_URL
-                = "youtube_individual_video_url";
-
-        /**
-         * YouTube - user's playlist url
-         */
-        public static final String YOUTUBE_MY_PLAYLISTS_URL
-                = "youtube_my_playlists_url";
-
-        /**
-         * YouTube - user's subscriptions url
-         */
-        public static final String YOUTUBE_MY_SUBSCRIPTIONS_URL
-                = "youtube_my_subscriptions_url";
-
-        /**
-         * YouTube - the url we use to contact YouTube to get a device id
-         */
-        public static final String YOUTUBE_REGISTER_DEVICE_URL
-                = "youtube_register_device_url";
-
-        /**
          * YouTube - the flag to indicate whether to use proxy
          */
         public static final String YOUTUBE_USE_PROXY
@@ -1325,7 +2068,8 @@
          * seconds.  This allows for throttling of logs when the device is
          * running for large amounts of time.
          */
-        public static final String MEMCHECK_LOG_REALTIME_INTERVAL = "memcheck_log_realtime_interval";
+        public static final String MEMCHECK_LOG_REALTIME_INTERVAL =
+                "memcheck_log_realtime_interval";
 
         /**
          * Boolean indicating whether rebooting due to system memory checks
@@ -1423,7 +2167,7 @@
          * the device is idle within the window.
          */
         public static final String REBOOT_WINDOW = "reboot_window";
-        
+
         /**
          * The minimum version of the server that is required in order for the device to accept
          * the server's recommendations about the initial sync settings to use. When this is unset,
@@ -1446,6 +2190,12 @@
         public static final String GMAIL_TIMEOUT_MS = "gmail_timeout_ms";
 
         /**
+         * Controls whether Gmail will request an expedited sync when a message is sent. Value must
+         * be an integer where non-zero means true. Defaults to 1.
+         */
+        public static final String GMAIL_SEND_IMMEDIATELY = "gmail_send_immediately";
+
+        /**
          * Hostname of the GTalk server.
          */
         public static final String GTALK_SERVICE_HOSTNAME = "gtalk_hostname";
@@ -1667,7 +2417,28 @@
          */
         public static final String SETTINGS_CONTRIBUTORS_PRETTY_URL =
                 "settings_contributors_pretty_url";
-
+        
+        /**
+         * URL that points to the Terms Of Service for the device.
+         * <p>
+         * This should be a pretty http URL. 
+         */
+        public static final String SETUP_GOOGLE_TOS_URL = "setup_google_tos_url";
+        
+        /**
+         * URL that points to the Android privacy policy for the device.
+         * <p>
+         * This should be a pretty http URL.
+         */
+        public static final String SETUP_ANDROID_PRIVACY_URL = "setup_android_privacy_url";
+        
+        /**
+         * URL that points to the Google privacy policy for the device.
+         * <p>
+         * This should be a pretty http URL. 
+         */
+        public static final String SETUP_GOOGLE_PRIVACY_URL = "setup_google_privacy_url";
+        
         /**
          * Request an MSISDN token for various Google services.
          */
@@ -1684,6 +2455,12 @@
         public static final String PARENTAL_CONTROL_CHECK_ENABLED =
                 "parental_control_check_enabled";
 
+        /**
+         * The list of applications we need to block if parental control is
+         * enabled.
+         */
+        public static final String PARENTAL_CONTROL_APPS_LIST =
+                "parental_control_apps_list";
 
         /**
          * Duration in which parental control status is valid.
@@ -1712,7 +2489,7 @@
          */
         public static final String DISK_FREE_CHANGE_REPORTING_THRESHOLD =
                 "disk_free_change_reporting_threshold";
-        
+
         /**
          * Prefix for new Google services published by the checkin
          * server.
@@ -1726,24 +2503,39 @@
          */
         public static final String SYNC_MAX_RETRY_DELAY_IN_SECONDS =
                 "sync_max_retry_delay_in_seconds";
-        
+
         /**
          * Minimum percentage of free storage on the device that is used to determine if
-         * the device is running low on storage. 
+         * the device is running low on storage.
          * Say this value is set to 10, the device is considered running low on storage
          * if 90% or more of the device storage is filled up.
          */
-        public static final String SYS_STORAGE_THRESHOLD_PERCENTAGE = 
+        public static final String SYS_STORAGE_THRESHOLD_PERCENTAGE =
                 "sys_storage_threshold_percentage";
-        
+
         /**
-         * The interval in minutes after which the amount of free storage left on the 
+         * The interval in minutes after which the amount of free storage left on the
          * device is logged to the event log
          */
-        public static final String SYS_FREE_STORAGE_LOG_INTERVAL = 
+        public static final String SYS_FREE_STORAGE_LOG_INTERVAL =
                 "sys_free_storage_log_interval";
 
         /**
+         * The interval in milliseconds at which to check the number of SMS sent
+         * out without asking for use permit, to limit the un-authorized SMS
+         * usage.
+         */
+        public static final String SMS_OUTGOING_CEHCK_INTERVAL_MS =
+                "sms_outgoing_check_interval_ms";
+
+        /**
+         * The number of outgoing SMS sent without asking for user permit
+         * (of {@link #SMS_OUTGOING_CEHCK_INTERVAL_MS}
+         */
+        public static final String SMS_OUTGOING_CEHCK_MAX_COUNT =
+                "sms_outgoing_check_max_count";
+
+        /**
          * The interval in milliseconds at which to check packet counts on the
          * mobile data interface when screen is on, to detect possible data
          * connection problems.
@@ -1757,22 +2549,22 @@
          * connection problems.
          */
         public static final String PDP_WATCHDOG_LONG_POLL_INTERVAL_MS =
-            "pdp_watchdog_long_poll_interval_ms";
-        
+                "pdp_watchdog_long_poll_interval_ms";
+
         /**
          * The interval in milliseconds at which to check packet counts on the
          * mobile data interface after {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT}
          * outgoing packets has been reached without incoming packets.
          */
-        public static final String PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS = 
+        public static final String PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS =
                 "pdp_watchdog_error_poll_interval_ms";
 
         /**
          * The number of outgoing packets sent without seeing an incoming packet
-         * that triggers a countdown (of {@link #PDP_WATCHDOG_ERROR_POLL_COUNT} 
+         * that triggers a countdown (of {@link #PDP_WATCHDOG_ERROR_POLL_COUNT}
          * device is logged to the event log
          */
-        public static final String PDP_WATCHDOG_TRIGGER_PACKET_COUNT = 
+        public static final String PDP_WATCHDOG_TRIGGER_PACKET_COUNT =
                 "pdp_watchdog_trigger_packet_count";
 
         /**
@@ -1780,50 +2572,44 @@
          * after hitting {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT} before
          * attempting data connection recovery.
          */
-        public static final String PDP_WATCHDOG_ERROR_POLL_COUNT = 
+        public static final String PDP_WATCHDOG_ERROR_POLL_COUNT =
                 "pdp_watchdog_error_poll_count";
 
         /**
          * The number of failed PDP reset attempts before moving to something more
          * drastic: re-registering to the network.
          */
-        public static final String PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT = 
+        public static final String PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT =
                 "pdp_watchdog_max_pdp_reset_fail_count";
 
         /**
          * Address to ping as a last sanity check before attempting any recovery.
          * Unset or set to "0.0.0.0" to skip this check.
          */
-        public static final String PDP_WATCHDOG_PING_ADDRESS = 
-                "pdp_watchdog_ping_address";
+        public static final String PDP_WATCHDOG_PING_ADDRESS = "pdp_watchdog_ping_address";
 
         /**
          * The "-w deadline" parameter for the ping, ie, the max time in
          * seconds to spend pinging.
          */
-        public static final String PDP_WATCHDOG_PING_DEADLINE = 
-                "pdp_watchdog_ping_deadline";
+        public static final String PDP_WATCHDOG_PING_DEADLINE = "pdp_watchdog_ping_deadline";
 
         /**
-         * The interval in milliseconds after which Wi-Fi is considered idle.
-         * When idle, it is possible for the device to be switched from Wi-Fi to
-         * the mobile data network.
+         * The interval in milliseconds at which to check gprs registration
+         * after the first registration mismatch of gprs and voice service,
+         * to detect possible data network registration problems.
+         *
          */
-        public static final String WIFI_IDLE_MS = "wifi_idle_ms";
+        public static final String GPRS_REGISTER_CHECK_PERIOD_MS =
+                "gprs_register_check_period_ms";
 
         /**
-         * The interval in milliseconds at which we forcefully release the
-         * transition-to-mobile-data wake lock.
+         * Screen timeout in milliseconds corresponding to the
+         * PowerManager's POKE_LOCK_SHORT_TIMEOUT flag (i.e. the fastest
+         * possible screen timeout behavior.)
          */
-        public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
-                "wifi_mobile_data_transition_wakelock_timeout_ms";
-
-        /**
-         * The maximum number of times we will retry a connection to an access
-         * point for which we have failed in acquiring an IP address from DHCP.
-         * A value of N means that we will make N+1 connection attempts in all.
-         */
-        public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
+        public static final String SHORT_KEYLIGHT_DELAY_MS =
+                "short_keylight_delay_ms";
 
         /**
          * @deprecated
diff --git a/core/java/android/provider/Sync.java b/core/java/android/provider/Sync.java
index b889293..2086a5d 100644
--- a/core/java/android/provider/Sync.java
+++ b/core/java/android/provider/Sync.java
@@ -489,9 +489,14 @@
          */
         public static final Uri CONTENT_URI = Uri.parse("content://sync/settings");
 
-        /** controls whether or not the devices listens for sync tickles */
+        /** controls whether or not the device listens for sync tickles */
         public static final String SETTING_LISTEN_FOR_TICKLES = "listen_for_tickles";
 
+        /** controls whether or not the device connect to Google in background for various
+         *  stuff, including GTalk, checkin, Market and data sync ...
+         */
+        public static final String SETTING_BACKGROUND_DATA = "background_data";
+
         /** controls whether or not the individual provider is synced when tickles are received */
         public static final String SETTING_SYNC_PROVIDER_PREFIX = "sync_provider_";
 
@@ -529,17 +534,28 @@
         }
 
         /**
-         * A convenience method to set whether or not the tickle xmpp connection
-         * should be established.
+         * A convenience method to set whether or not the device should listen to tickles.
          *
          * @param contentResolver the ContentResolver to use to access the settings table
-         * @param flag true if the tickle xmpp connection should be established
+         * @param flag true if it should listen.
          */
         static public void setListenForNetworkTickles(ContentResolver contentResolver,
                 boolean flag) {
             putBoolean(contentResolver, SETTING_LISTEN_FOR_TICKLES, flag);
         }
 
+        /**
+         * A convenience method to set whether or not the device should connect to Google
+         * in background.
+         *
+         * @param contentResolver the ContentResolver to use to access the settings table
+         * @param flag true if it should connect.
+         */
+        static public void setBackgroundData(ContentResolver contentResolver,
+                boolean flag) {
+            putBoolean(contentResolver, SETTING_BACKGROUND_DATA, flag);
+        }
+
         public static class QueryMap extends ContentQueryMap {
             private ContentResolver mContentResolver;
 
@@ -570,23 +586,42 @@
             }
 
             /**
-             * Set whether or not the tickle xmpp connection should be established.
+             * Set whether or not the device should listen for tickles.
              *
-             * @param flag true if the tickle xmpp connection should be established
+             * @param flag true if it should listen.
              */
             public void setListenForNetworkTickles(boolean flag) {
                 Settings.setListenForNetworkTickles(mContentResolver, flag);
             }
 
             /**
-             * Check if the tickle xmpp connection should be established
-             * @return true if it should be stablished
+             * Check if the device should listen to tickles.
+
+             * @return true if it should
              */
             public boolean getListenForNetworkTickles() {
                 return getBoolean(SETTING_LISTEN_FOR_TICKLES, true);
             }
 
             /**
+             * Set whether or not the device should connect to Google in background
+             *
+             * @param flag true if it should
+             */
+            public void setBackgroundData(boolean flag) {
+                Settings.setBackgroundData(mContentResolver, flag);
+            }
+
+            /**
+             * Check if the device should connect to Google in background.
+
+             * @return true if it should
+             */
+            public boolean getBackgroundData() {
+                return getBoolean(SETTING_BACKGROUND_DATA, true);
+            }
+
+            /**
              * Convenience function for retrieving a single settings value
              * as a boolean.
              *
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 776a266..18c64ed 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -16,7 +16,6 @@
 
 package android.provider;
 
-import com.android.internal.telephony.CallerInfo;
 import com.google.android.mms.util.SqliteWrapper;
 
 import android.annotation.SdkConstant;
@@ -27,8 +26,6 @@
 import android.content.Intent;
 import android.database.Cursor;
 import android.net.Uri;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.TelephonyManager;
 import android.telephony.gsm.SmsMessage;
 import android.text.TextUtils;
 import android.text.util.Regex;
@@ -264,49 +261,6 @@
         }
 
         /**
-         * Returns true if the address is an email address
-         *
-         * @param address the input address to be tested
-         * @return true if address is an email address
-         */
-        public static boolean isEmailAddress(String address) {
-            /*
-             * The '@' char isn't a valid char in phone numbers. However, in SMS
-             * messages sent by carrier, the originating-address can contain
-             * non-dialable alphanumeric chars. For the purpose of thread id
-             * grouping, we don't care about those. We only care about the
-             * legitmate/dialable phone numbers (which we use the special phone
-             * number comparison) and email addresses (which we do straight up
-             * string comparison).
-             */
-            return (address != null) && (address.indexOf('@') != -1);
-        }
-
-        /**
-         * Formats an address for displaying, doing a phone number lookup in the
-         * Address Book, etc.
-         *
-         * @param context the context to use
-         * @param address the address to format
-         * @return a nicely formatted version of the sender to display
-         */
-        public static String getDisplayAddress(Context context, String address) {
-            String result;
-            int index;
-            if (isEmailAddress(address)) {
-                index = address.indexOf('@');
-                if (index != -1) {
-                    result = address.substring(0, index);
-                } else {
-                    result = address;
-                }
-            } else {
-                result = CallerInfo.getCallerId(context, address);
-            }
-            return result;
-        }
-
-        /**
          * Contains all text based SMS messages in the SMS app's inbox.
          */
         public static final class Inbox implements BaseColumns, TextBasedSmsColumns {
@@ -1166,7 +1120,7 @@
          * name-addr       =       [display-name] angle-addr
          * angle-addr      =       [CFWS] "<" addr-spec ">" [CFWS]
          */
-        private static final Pattern NAME_ADDR_EMAIL_PATTERN =
+        public static final Pattern NAME_ADDR_EMAIL_PATTERN =
                 Pattern.compile("\\s*(\"[^\"]*\"|[^<>\"]+)\\s*<([^<>]+)>\\s*");
 
         /**
@@ -1174,7 +1128,7 @@
          *                         DQUOTE *([FWS] qcontent) [FWS] DQUOTE
          *                         [CFWS]
          */
-        private static final Pattern QUOTED_STRING_PATTERN =
+        public static final Pattern QUOTED_STRING_PATTERN =
                 Pattern.compile("\\s*\"([^\"]*)\"\\s*");
 
         public static final Cursor query(
@@ -1232,81 +1186,6 @@
         }
 
         /**
-         * Formats an address for displaying, doing a phone number lookup in the
-         * Address Book, etc.
-         *
-         * @param context the context to use
-         * @param address the address to format
-         * @return a nicely formatted version of the sender to display
-         */
-        public static String getDisplayAddress(Context context, String address) {
-            if (address == null) {
-                return "";
-            }
-
-            String localNumber = TelephonyManager.getDefault().getLine1Number();
-            String[] values = address.split(";");
-            String result = "";
-            for (int i = 0; i < values.length; i++) {
-                if (values[i].length() > 0) {
-                    if (PhoneNumberUtils.compare(values[i], localNumber)) {
-                        result = result + ";"
-                                    + context.getString(com.android.internal.R.string.me);
-                    } else if (isEmailAddress(values[i])) {
-                        result = result + ";" + getDisplayName(context, values[i]);
-                    } else {
-                        result = result + ";" + CallerInfo.getCallerId(context, values[i]);
-                    }
-                }
-            }
-
-            if (result.length() > 0) {
-                // Skip the first ';'
-                return result.substring(1);
-            }
-            return result;
-        }
-
-        private static String getEmailDisplayName(String displayString) {
-            Matcher match = QUOTED_STRING_PATTERN.matcher(displayString);
-            if (match.matches()) {
-                return match.group(1);
-            }
-
-            return displayString;
-        }
-
-        private static String getDisplayName(Context context, String email) {
-            Matcher match = NAME_ADDR_EMAIL_PATTERN.matcher(email);
-            if (match.matches()) {
-                // email has display name
-                return getEmailDisplayName(match.group(1));
-            }
-
-            Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
-                    Contacts.ContactMethods.CONTENT_EMAIL_URI,
-                    new String[] { Contacts.ContactMethods.NAME },
-                    Contacts.ContactMethods.DATA + " = \'" + email + "\'",
-                    null, null);
-
-            if (cursor != null) {
-                try {
-                    int columnIndex = cursor.getColumnIndexOrThrow(
-                            Contacts.ContactMethods.NAME);
-                    while (cursor.moveToNext()) {
-                        String name = cursor.getString(columnIndex);
-                        if (!TextUtils.isEmpty(name)) {
-                            return name;
-                        }
-                    }
-                } finally {
-                    cursor.close();
-                }
-            }
-            return email;
-        }
-
-        /**
          * Contains all MMS messages in the MMS app's inbox.
          */
         public static final class Inbox implements BaseMmsColumns {
@@ -1647,6 +1526,7 @@
 
         public static final String TYPE = "type";
 
+        public static final String CURRENT = "current";
     }
 
     public static final class Intents {
diff --git a/core/java/android/security/Md5MessageDigest.java b/core/java/android/security/Md5MessageDigest.java
index a7221ae..4fe0cb0 100644
--- a/core/java/android/security/Md5MessageDigest.java
+++ b/core/java/android/security/Md5MessageDigest.java
@@ -17,8 +17,7 @@
 package android.security;
 
 /**
- * This is a temporary class to provide SHA-1 hash.
- * It's not meant to be correct, and eventually doesn't belong in java.security
+ * Provides the MD5 hash encryption.
  */
 public class Md5MessageDigest extends MessageDigest
 {
diff --git a/core/java/android/security/MessageDigest.java b/core/java/android/security/MessageDigest.java
index 93040b9..cf2d0fe 100644
--- a/core/java/android/security/MessageDigest.java
+++ b/core/java/android/security/MessageDigest.java
@@ -18,8 +18,22 @@
 
 import java.security.NoSuchAlgorithmException;
 
+/**
+ * Base class for producing a message digest from different hash encryptions.
+ */
 public abstract class MessageDigest 
 {    
+    /**
+     * Returns a digest object of the specified type.
+     * 
+     * @param algorithm  The type of hash function to use. Valid values are
+     *                   <em>SHA-1</em> and <em>MD5</em>.
+     * @return The respective MessageDigest object. Either a 
+     *         {@link android.security.Sha1MessageDigest} or
+     *         {@link android.security.Md5MessageDigest} object.
+     * @throws NoSuchAlgorithmException If an invalid <var>algorithm</var>
+     *                                  is given.
+     */
     public static MessageDigest getInstance(String algorithm) 
         throws NoSuchAlgorithmException
     {
@@ -39,5 +53,12 @@
     
     public abstract void update(byte[] input);    
     public abstract byte[] digest();
+    
+    /**
+     * Produces a message digest for the given input.
+     * 
+     * @param input  The message to encrypt.
+     * @return The digest (hash sum).
+     */
     public abstract byte[] digest(byte[] input);
 }
diff --git a/core/java/android/security/Sha1MessageDigest.java b/core/java/android/security/Sha1MessageDigest.java
index 3b3fd6a..aa01fa6 100644
--- a/core/java/android/security/Sha1MessageDigest.java
+++ b/core/java/android/security/Sha1MessageDigest.java
@@ -17,8 +17,7 @@
 package android.security;
 
 /**
- * This is a temporary class to provide SHA-1 hash.
- * It's not meant to be correct, and eventually doesn't belong in java.security
+ * Provides the SHA-1 hash encyption.
  */
 public class Sha1MessageDigest extends MessageDigest
 {
diff --git a/core/java/android/security/package.html b/core/java/android/security/package.html
index 26b8a32..dfc6303 100644
--- a/core/java/android/security/package.html
+++ b/core/java/android/security/package.html
@@ -1,5 +1,6 @@
 <HTML>
 <BODY>
+Utilities for encrypting messages from hash functions.
 {@hide}
 </BODY>
-</HTML>
\ No newline at end of file
+</HTML>
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
new file mode 100644
index 0000000..3cbb855
--- /dev/null
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -0,0 +1,315 @@
+/*
+ * 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.
+ */
+
+/**
+ * TODO: Move this to
+ * java/services/com/android/server/BluetoothA2dpService.java
+ * and make the contructor package private again.
+ * @hide
+ */
+
+package android.server;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothError;
+import android.bluetooth.BluetoothIntent;
+import android.bluetooth.IBluetoothA2dp;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.os.Binder;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Iterator;
+
+public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
+    private static final String TAG = "BluetoothDeviceService";
+    private static final boolean DBG = true;
+
+    public static final String BLUETOOTH_A2DP_SERVICE = "bluetooth_a2dp";
+
+    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
+    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+
+    private final Context mContext;
+    private final IntentFilter mIntentFilter;
+    private HashMap<String, SinkState> mAudioDevices;
+    private final AudioManager mAudioManager;
+
+    private class SinkState {
+        public String address;
+        public int state;
+        public SinkState(String a, int s) {address = a; state = s;}
+    }
+
+    public BluetoothA2dpService(Context context) {
+        mContext = context;
+
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+
+        BluetoothDevice device =
+                (BluetoothDevice)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+        if (device == null) {
+            throw new RuntimeException("Platform does not support Bluetooth");
+        }
+
+        if (!initNative()) {
+            throw new RuntimeException("Could not init BluetoothA2dpService");
+        }
+
+        mIntentFilter = new IntentFilter(BluetoothIntent.ENABLED_ACTION);
+        mIntentFilter.addAction(BluetoothIntent.DISABLED_ACTION);
+        mContext.registerReceiver(mReceiver, mIntentFilter);
+
+        if (device.isEnabled()) {
+            onBluetoothEnable();
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            cleanupNative();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(BluetoothIntent.ENABLED_ACTION)) {
+                onBluetoothEnable();
+            } else if (action.equals(BluetoothIntent.DISABLED_ACTION)) {
+                onBluetoothDisable();
+            }
+        }
+    };
+
+    private synchronized void onBluetoothEnable() {
+        mAudioDevices = new HashMap<String, SinkState>();
+        String[] paths = (String[])listHeadsetsNative();
+        if (paths != null) {
+            for (String path : paths) {
+                mAudioDevices.put(path, new SinkState(getAddressNative(path),
+                        isSinkConnectedNative(path) ? BluetoothA2dp.STATE_CONNECTED :
+                                                      BluetoothA2dp.STATE_DISCONNECTED));
+            }
+        }
+    }
+
+    private synchronized void onBluetoothDisable() {
+        mAudioDevices = null;
+    }
+
+    public synchronized int connectSink(String address) {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
+        if (DBG) log("connectSink(" + address + ")");
+        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+            return BluetoothError.ERROR;
+        }
+        if (mAudioDevices == null) {
+            return BluetoothError.ERROR;
+        }
+        String path = lookupPath(address);
+        if (path == null) {
+            path = createHeadsetNative(address);
+            if (DBG) log("new bluez sink: " + address + " (" + path + ")");
+        }
+        if (path == null) {
+            return BluetoothError.ERROR;
+        }
+        if (!connectSinkNative(path)) {
+            return BluetoothError.ERROR;
+        } else {
+            updateState(path, BluetoothA2dp.STATE_CONNECTING);
+            return BluetoothError.SUCCESS;
+        }
+    }
+
+    public synchronized int disconnectSink(String address) {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
+        if (DBG) log("disconnectSink(" + address + ")");
+        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+            return BluetoothError.ERROR;
+        }
+        if (mAudioDevices == null) {
+            return BluetoothError.ERROR;
+        }
+        String path = lookupPath(address);
+        if (path == null) {
+            return BluetoothError.ERROR;
+        }
+        if (!disconnectSinkNative(path)) {
+            return BluetoothError.ERROR;
+        } else {
+            updateState(path, BluetoothA2dp.STATE_DISCONNECTING);
+            return BluetoothError.SUCCESS;
+        }
+    }
+
+    public synchronized List<String> listConnectedSinks() {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+        List<String> connectedSinks = new ArrayList<String>();
+        if (mAudioDevices == null) {
+            return connectedSinks;
+        }
+        for (SinkState sink : mAudioDevices.values()) {
+            if (sink.state == BluetoothA2dp.STATE_CONNECTED ||
+                sink.state == BluetoothA2dp.STATE_PLAYING) {
+                connectedSinks.add(sink.address);
+            }
+        }
+        return connectedSinks;
+    }
+
+    public synchronized int getSinkState(String address) {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+            return BluetoothError.ERROR;
+        }
+        if (mAudioDevices == null) {
+            return BluetoothA2dp.STATE_DISCONNECTED;
+        }
+        for (SinkState sink : mAudioDevices.values()) {
+            if (address.equals(sink.address)) {
+                return sink.state;
+            }
+        }
+        return BluetoothA2dp.STATE_DISCONNECTED;
+    }
+
+    public synchronized void onHeadsetCreated(String path) {
+        updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+    }
+
+    public synchronized void onHeadsetRemoved(String path) {
+        if (mAudioDevices == null) return;
+        mAudioDevices.remove(path);
+    }
+
+    public synchronized void onSinkConnected(String path) {
+        if (mAudioDevices == null) return;
+        // bluez 3.36 quietly disconnects the previous sink when a new sink
+        // is connected, so we need to mark all previously connected sinks as
+        // disconnected
+        for (String oldPath : mAudioDevices.keySet()) {
+            if (path.equals(oldPath)) {
+                continue;
+            }
+            int state = mAudioDevices.get(oldPath).state;
+            if (state == BluetoothA2dp.STATE_CONNECTED || state == BluetoothA2dp.STATE_PLAYING) {
+                updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+            }
+        }
+
+        mAudioManager.setBluetoothA2dpOn(true);
+        updateState(path, BluetoothA2dp.STATE_CONNECTED);
+    }
+
+    public synchronized void onSinkDisconnected(String path) {
+        mAudioManager.setBluetoothA2dpOn(false);
+        updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+    }
+
+    public synchronized void onSinkPlaying(String path) {
+        updateState(path, BluetoothA2dp.STATE_PLAYING);
+    }
+
+    public synchronized void onSinkStopped(String path) {
+        updateState(path, BluetoothA2dp.STATE_CONNECTED);
+    }
+
+    private synchronized final String lookupAddress(String path) {
+        if (mAudioDevices == null) return null;
+        String address = mAudioDevices.get(path).address;
+        if (address == null) Log.e(TAG, "Can't find address for " + path);
+        return address;
+    }
+
+    private synchronized final String lookupPath(String address) {
+        if (mAudioDevices == null) return null;
+
+        for (String path : mAudioDevices.keySet()) {
+            if (address.equals(mAudioDevices.get(path).address)) {
+                return path;
+            }
+        }
+        return null;
+    }
+
+    private synchronized void updateState(String path, int state) {
+        if (mAudioDevices == null) return;
+
+        SinkState s = mAudioDevices.get(path);
+        int prevState;
+        String address;
+        if (s == null) {
+            address = getAddressNative(path);
+            mAudioDevices.put(path, new SinkState(address, state));
+            prevState = BluetoothA2dp.STATE_DISCONNECTED;
+        } else {
+            address = lookupAddress(path);
+            prevState = s.state;
+            s.state = state;
+        }
+
+        if (DBG) log("state " + address + " (" + path + ") " + prevState + "->" + state);
+
+        Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+        intent.putExtra(BluetoothIntent.ADDRESS, address);
+        intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState);
+        intent.putExtra(BluetoothA2dp.SINK_STATE, state);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+    }
+
+    @Override
+    protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mAudioDevices == null) return;
+        pw.println("Cached audio devices:");
+        for (String path : mAudioDevices.keySet()) {
+            SinkState sink = mAudioDevices.get(path);
+            pw.println(path + " " + sink.address + " " + BluetoothA2dp.stateToString(sink.state));
+        }
+    }
+
+    private static void log(String msg) {
+        Log.d(TAG, msg);
+    }
+
+    private native boolean initNative();
+    private native void cleanupNative();
+    private synchronized native String[] listHeadsetsNative();
+    private synchronized native String createHeadsetNative(String address);
+    private synchronized native boolean removeHeadsetNative(String path);
+    private synchronized native String getAddressNative(String path);
+    private synchronized native boolean connectSinkNative(String path);
+    private synchronized native boolean disconnectSinkNative(String path);
+    private synchronized native boolean isSinkConnectedNative(String path);
+
+}
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
index 10f9f7c..9bdab9f 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothDeviceService.java
@@ -54,13 +54,17 @@
 public class BluetoothDeviceService extends IBluetoothDevice.Stub {
     private static final String TAG = "BluetoothDeviceService";
     private int mNativeData;
-    private Context mContext;
     private BluetoothEventLoop mEventLoop;
     private IntentFilter mIntentFilter;
     private boolean mIsAirplaneSensitive;
     private volatile boolean mIsEnabled;  // local cache of isEnabledNative()
     private boolean mIsDiscovering;
 
+    private final Context mContext;
+
+    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
+    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+
     static {
         classInitNative();
     }
@@ -97,7 +101,7 @@
     private native void cleanupNativeDataNative();
 
     public boolean isEnabled() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return mIsEnabled;
     }
     private native int isEnabledNative();
@@ -106,7 +110,8 @@
      * Disable bluetooth. Returns true on success.
      */
     public synchronized boolean disable() {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
 
         if (mEnableThread != null && mEnableThread.isAlive()) {
             return false;
@@ -117,9 +122,10 @@
         mEventLoop.stop();
         disableNative();
         mIsEnabled = false;
+        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON, 0);
         mIsDiscovering = false;
         Intent intent = new Intent(BluetoothIntent.DISABLED_ACTION);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
         return true;
     }
 
@@ -131,7 +137,8 @@
      * notified when complete.
      */
     public synchronized boolean enable(IBluetoothDeviceCallback callback) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
 
         // Airplane mode can prevent Bluetooth radio from being turned on.
         if (mIsAirplaneSensitive && isAirplaneModeOn()) {
@@ -164,6 +171,8 @@
     };
 
     private EnableThread mEnableThread;
+    private String mOutgoingBondingDevAddress = null;
+
     private class EnableThread extends Thread {
         private final IBluetoothDeviceCallback mEnableCallback;
         public EnableThread(IBluetoothDeviceCallback callback) {
@@ -185,9 +194,11 @@
 
             if (res) {
                 mIsEnabled = true;
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                                       Settings.Secure.BLUETOOTH_ON, 1);
                 mIsDiscovering = false;
                 Intent intent = new Intent(BluetoothIntent.ENABLED_ACTION);
-                mContext.sendBroadcast(intent);
+                mContext.sendBroadcast(intent, BLUETOOTH_PERM);
                 mHandler.sendMessageDelayed(mHandler.obtainMessage(REGISTER_SDP_RECORDS), 3000);
             }
             mEnableThread = null;
@@ -198,19 +209,20 @@
     private native int disableNative();
 
     public synchronized String getAddress() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return getAddressNative();
     }
     private native String getAddressNative();
 
     public synchronized String getName() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return getNameNative();
     }
     private native String getNameNative();
 
     public synchronized boolean setName(String name) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         if (name == null) {
             return false;
         }
@@ -220,19 +232,19 @@
     private native boolean setNameNative(String name);
 
     public synchronized String[] listBondings() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return listBondingsNative();
     }
     private native String[] listBondingsNative();
 
     public synchronized String getMajorClass() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return getMajorClassNative();
     }
     private native String getMajorClassNative();
 
     public synchronized String getMinorClass() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return getMinorClassNative();
     }
     private native String getMinorClassNative();
@@ -248,7 +260,7 @@
      * @return The user-friendly name of the specified remote device.
      */
     public synchronized String getRemoteName(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -277,7 +289,8 @@
      *         false otherwise.
      */
     public synchronized boolean startDiscovery(boolean resolveNames) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         return startDiscoveryNative(resolveNames);
     }
     private native boolean startDiscoveryNative(boolean resolveNames);
@@ -289,13 +302,14 @@
      *       started.
      */
     public synchronized boolean cancelDiscovery() {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         return cancelDiscoveryNative();
     }
     private native boolean cancelDiscoveryNative();
 
     public synchronized boolean isDiscovering() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return mIsDiscovering;
     }
 
@@ -304,19 +318,21 @@
     }
 
     public synchronized boolean startPeriodicDiscovery() {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         return startPeriodicDiscoveryNative();
     }
     private native boolean startPeriodicDiscoveryNative();
 
     public synchronized boolean stopPeriodicDiscovery() {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         return stopPeriodicDiscoveryNative();
     }
     private native boolean stopPeriodicDiscoveryNative();
 
     public synchronized boolean isPeriodicDiscovery() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return isPeriodicDiscoveryNative();
     }
     private native boolean isPeriodicDiscoveryNative();
@@ -331,7 +347,8 @@
      * @param timeout_s The discoverable timeout in seconds.
      */
     public synchronized boolean setDiscoverableTimeout(int timeout) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         return setDiscoverableTimeoutNative(timeout);
     }
     private native boolean setDiscoverableTimeoutNative(int timeout_s);
@@ -345,13 +362,13 @@
      *         value indicates an error.
      */
     public synchronized int getDiscoverableTimeout() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return getDiscoverableTimeoutNative();
     }
     private native int getDiscoverableTimeoutNative();
 
     public synchronized boolean isAclConnected(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
         }
@@ -378,7 +395,7 @@
      * @see #setMode
      */
     public synchronized boolean isConnectable() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return isConnectableNative();
     }
     private native boolean isConnectableNative();
@@ -401,7 +418,7 @@
      * @see #setMode
      */
     public synchronized boolean isDiscoverable() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return isDiscoverableNative();
     }
     private native boolean isDiscoverableNative();
@@ -415,7 +432,7 @@
      * @see #setMode
      */
     public synchronized int getMode() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         String mode = getModeNative();
         if (mode == null) {
             return BluetoothDevice.MODE_UNKNOWN;
@@ -451,7 +468,8 @@
      * @see #getMode
      */
     public synchronized boolean setMode(int mode) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         switch (mode) {
         case BluetoothDevice.MODE_OFF:
             return setModeNative("off");
@@ -477,7 +495,7 @@
      * @return The alias of the remote device.
      */
     public synchronized String getRemoteAlias(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -496,7 +514,8 @@
      * @param alias Alias for the remote device
      */
     public synchronized boolean setRemoteAlias(String address, String alias) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         if (alias == null || !BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
         }
@@ -513,7 +532,8 @@
      * @param address Bluetooth address of remote device
      */
     public synchronized boolean clearRemoteAlias(String address) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
         }
@@ -522,7 +542,8 @@
     private native boolean clearRemoteAliasNative(String address);
 
     public synchronized boolean disconnectRemoteDeviceAcl(String address) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
         }
@@ -546,7 +567,8 @@
      * @see android.bluetooth.PasskeyAgent
      */
     public synchronized boolean createBonding(String address, IBluetoothDeviceCallback callback) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
         }
@@ -568,9 +590,19 @@
             callbacks.remove(address);
             return false;
         }
+        mOutgoingBondingDevAddress = address;
         return true;
     }
+           
     private native boolean createBondingNative(String address, int timeout_ms);
+    
+    /*package*/ String getOutgoingBondingDevAddress() {
+        return mOutgoingBondingDevAddress;
+    }
+
+    /*package*/ void setOutgoingBondingDevAddress(String outgoingBondingDevAddress) {
+        mOutgoingBondingDevAddress = outgoingBondingDevAddress;
+    }
 
     /**
      * This method cancels a pending bonding request.
@@ -593,7 +625,8 @@
      * @see #listBondings
      */
     public synchronized boolean cancelBondingProcess(String address) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
         }
@@ -618,7 +651,8 @@
      * @see #listBondings
      */
     public synchronized boolean removeBonding(String address) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
         }
@@ -627,7 +661,7 @@
     private native boolean removeBondingNative(String address);
 
     public synchronized boolean hasBonding(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
         }
@@ -636,7 +670,7 @@
     private native boolean hasBondingNative(String address);
 
     public synchronized String[] listAclConnections() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return listConnectionsNative();
     }
     private native String[] listConnectionsNative();
@@ -652,7 +686,7 @@
      *         remote devices that this adapter is aware of.
      */
     public synchronized String[] listRemoteDevices() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return listRemoteDevicesNative();
     }
     private native String[] listRemoteDevicesNative();
@@ -666,7 +700,7 @@
      *         Bluetooth-chip version.
      */
     public synchronized String getVersion() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return getVersionNative();
     }
     private native String getVersionNative();
@@ -683,7 +717,7 @@
      * @return The HCI revision of this adapter.
      */
     public synchronized String getRevision() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return getRevisionNative();
     }
     private native String getRevisionNative();
@@ -697,7 +731,7 @@
      * @return Manufacturer name.
      */
     public synchronized String getManufacturer() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return getManufacturerNative();
     }
     private native String getManufacturerNative();
@@ -716,7 +750,7 @@
      * @return company name
      */
     public synchronized String getCompany() {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return getCompanyNative();
     }
     private native String getCompanyNative();
@@ -731,7 +765,7 @@
      * @see #getVersion
      */
     public synchronized String getRemoteVersion(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -749,7 +783,7 @@
      * @see #getRevision
      */
     public synchronized String getRemoteRevision(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -767,7 +801,7 @@
      * @see #getManufacturer
      */
     public synchronized String getRemoteManufacturer(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -785,7 +819,7 @@
      * @see #getCompany
      */
     public synchronized String getRemoteCompany(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -801,7 +835,7 @@
      * @return a String with the timestamp.
      */
     public synchronized String lastSeen(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -817,7 +851,7 @@
      * @return a String with the timestamp.
      */
     public synchronized String lastUsed(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -841,7 +875,7 @@
      */
     public synchronized String getRemoteMajorClass(String address) {
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
             return null;
         }
         return getRemoteMajorClassNative(address);
@@ -863,7 +897,7 @@
      * @see #getRemoteClass
      */
     public synchronized String getRemoteMinorClass(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -880,7 +914,7 @@
      * @see #getRemoteClass
      */
     public synchronized String[] getRemoteServiceClasses(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -904,7 +938,7 @@
      */
     public synchronized int getRemoteClass(String address) {
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
             return -1;
         }
         return getRemoteClassNative(address);
@@ -919,7 +953,7 @@
      * @return byte array of features.
      */
     public synchronized byte[] getRemoteFeatures(String address) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -944,7 +978,7 @@
      * @see #getRemoteServiceRecord
      */
     public synchronized int[] getRemoteServiceHandles(String address, String match) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -974,7 +1008,7 @@
      * @see #getRemoteServiceHandles
      */
     public synchronized byte[] getRemoteServiceRecord(String address, int handle) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
@@ -985,7 +1019,7 @@
     // AIDL does not yet support short's
     public synchronized boolean getRemoteServiceChannel(String address, int uuid16,
             IBluetoothDeviceCallback callback) {
-        checkPermissionBluetooth();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
         }
@@ -1011,7 +1045,8 @@
     private native boolean getRemoteServiceChannelNative(String address, short uuid16);
 
     public synchronized boolean setPin(String address, byte[] pin) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         if (pin == null || pin.length <= 0 || pin.length > 16 ||
             !BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
@@ -1036,7 +1071,8 @@
     private native boolean setPinNative(String address, String pin, int nativeData);
 
     public synchronized boolean cancelPin(String address) {
-        checkPermissionBluetoothAdmin();
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH_ADMIN permission");
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return false;
         }
@@ -1061,7 +1097,7 @@
                 // some random app is not sending this intent and disabling bluetooth
                 boolean enabled = !isAirplaneModeOn();
                 // If bluetooth is currently expected to be on, then enable or disable bluetooth
-                if (Settings.System.getInt(resolver, Settings.System.BLUETOOTH_ON, 0) > 0) {
+                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
                     if (enabled) {
                         enable(null);
                     } else {
@@ -1089,25 +1125,6 @@
                 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
     }
 
-    private static final String BLUETOOTH_ADMIN = android.Manifest.permission.BLUETOOTH_ADMIN;
-    private static final String BLUETOOTH = android.Manifest.permission.BLUETOOTH;
-
-    private void checkPermissionBluetoothAdmin() {
-        if (mContext.checkCallingOrSelfPermission(BLUETOOTH_ADMIN) !=
-                PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires BLUETOOTH_ADMIN permission");
-        }
-    }
-
-    private void checkPermissionBluetooth() {
-        if (mContext.checkCallingOrSelfPermission(BLUETOOTH_ADMIN) !=
-                PackageManager.PERMISSION_GRANTED &&
-                mContext.checkCallingOrSelfPermission(BLUETOOTH) !=
-                PackageManager.PERMISSION_GRANTED ) {
-            throw new SecurityException("Requires BLUETOOTH or BLUETOOTH_ADMIN permission");
-        }
-    }
-
     private static final String DISABLE_ESCO_PATH = "/sys/module/sco/parameters/disable_esco";
     private static void disableEsco() {
         try {
@@ -1124,7 +1141,7 @@
             pw.println("\nBluetooth ENABLED: " + getAddress() + " (" + getName() + ")");
             pw.println("\nisDiscovering() = " + isDiscovering());
 
-            BluetoothHeadset headset = new BluetoothHeadset(mContext);
+            BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
 
             pw.println("\n--Bondings--");
             String[] addresses = listBondings();
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 5722f51..2d8aacc 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -16,6 +16,7 @@
 
 package android.server;
 
+import android.bluetooth.BluetoothClass.Device;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothIntent;
 import android.bluetooth.IBluetoothDeviceCallback;
@@ -24,8 +25,6 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import java.io.IOException;
-import java.lang.Thread;
 import java.util.HashMap;
 
 /**
@@ -45,10 +44,13 @@
     private HashMap<String, IBluetoothDeviceCallback> mCreateBondingCallbacks;
     private HashMap<String, Integer> mPasskeyAgentRequestData;
     private HashMap<String, IBluetoothDeviceCallback> mGetRemoteServiceChannelCallbacks;
-    private BluetoothDeviceService mBluetoothService;
-
+    private HashMap<String, Boolean> mDefaultPinData;
+    private BluetoothDeviceService mBluetoothService;    
     private Context mContext;
 
+    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
+    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+
     static { classInitNative(); }
     private static native void classInitNative();
 
@@ -58,6 +60,7 @@
         mCreateBondingCallbacks = new HashMap();
         mPasskeyAgentRequestData = new HashMap();
         mGetRemoteServiceChannelCallbacks = new HashMap();
+        mDefaultPinData = new HashMap();        
         initializeNativeDataNative();
     }
     private native void initializeNativeDataNative();
@@ -146,27 +149,28 @@
             intMode = BluetoothDevice.MODE_DISCOVERABLE;
         }
         intent.putExtra(BluetoothIntent.MODE, intMode);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
 
     public void onDiscoveryStarted() {
         mBluetoothService.setIsDiscovering(true);
         Intent intent = new Intent(BluetoothIntent.DISCOVERY_STARTED_ACTION);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onDiscoveryCompleted() {
         mBluetoothService.setIsDiscovering(false);
         Intent intent = new Intent(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
 
     public void onPairingRequest() {
         Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
     }
+    
     public void onPairingCancel() {
         Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
     }
 
     public void onRemoteDeviceFound(String address, int deviceClass, short rssi) {
@@ -174,64 +178,65 @@
         intent.putExtra(BluetoothIntent.ADDRESS, address);
         intent.putExtra(BluetoothIntent.CLASS, deviceClass);
         intent.putExtra(BluetoothIntent.RSSI, rssi);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onRemoteDeviceDisappeared(String address) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onRemoteClassUpdated(String address, int deviceClass) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
         intent.putExtra(BluetoothIntent.CLASS, deviceClass);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onRemoteDeviceConnected(String address) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onRemoteDeviceDisconnectRequested(String address) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECT_REQUESTED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onRemoteDeviceDisconnected(String address) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onRemoteNameUpdated(String address, String name) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
         intent.putExtra(BluetoothIntent.NAME, name);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onRemoteNameFailed(String address) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_FAILED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onRemoteNameChanged(String address, String name) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
         intent.putExtra(BluetoothIntent.NAME, name);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onRemoteAliasChanged(String address, String alias) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_ALIAS_CHANGED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
         intent.putExtra(BluetoothIntent.ALIAS, alias);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
     public void onRemoteAliasCleared(String address) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_ALIAS_CLEARED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
 
     private void onCreateBondingResult(String address, boolean result) {
+        mBluetoothService.setOutgoingBondingDevAddress(null);
         IBluetoothDeviceCallback callback = mCreateBondingCallbacks.get(address);
         if (callback != null) {
             try {
@@ -240,39 +245,71 @@
                                  BluetoothDevice.RESULT_FAILURE);
             } catch (RemoteException e) {}
             mCreateBondingCallbacks.remove(address);
-        }
+        }        
     }
+    
     public void onBondingCreated(String address) {
         Intent intent = new Intent(BluetoothIntent.BONDING_CREATED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
+    
     public void onBondingRemoved(String address) {
         Intent intent = new Intent(BluetoothIntent.BONDING_REMOVED_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+
+        if (mDefaultPinData.containsKey(address)) {
+            mDefaultPinData.remove(address);        
+        }     
     }
 
     public void onNameChanged(String name) {
         Intent intent = new Intent(BluetoothIntent.NAME_CHANGED_ACTION);
         intent.putExtra(BluetoothIntent.NAME, name);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
 
     public void onPasskeyAgentRequest(String address, int nativeData) {
-        mPasskeyAgentRequestData.put(address, new Integer(nativeData));
+        mPasskeyAgentRequestData.put(address, new Integer(nativeData));        
+        
+        if (address.equals(mBluetoothService.getOutgoingBondingDevAddress())) {
+            int btClass = mBluetoothService.getRemoteClass(address);
+            int remoteDeviceClass = Device.getDevice(btClass);
+            if (remoteDeviceClass == Device.AUDIO_VIDEO_WEARABLE_HEADSET ||
+                remoteDeviceClass == Device.AUDIO_VIDEO_HANDSFREE ||
+                remoteDeviceClass == Device.AUDIO_VIDEO_HEADPHONES ||
+                remoteDeviceClass == Device.AUDIO_VIDEO_PORTABLE_AUDIO ||
+                remoteDeviceClass == Device.AUDIO_VIDEO_CAR_AUDIO ||
+                remoteDeviceClass == Device.AUDIO_VIDEO_HIFI_AUDIO) {
+                if (!mDefaultPinData.containsKey(address)) {
+                    mDefaultPinData.put(address, false);
+                }
+                if (!mDefaultPinData.get(address)) {
+                    mDefaultPinData.remove(address);
+                    mDefaultPinData.put(address, true);
 
+                    mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
+                    return;
+                }
+            }
+        }
         Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
     }
+    
     public void onPasskeyAgentCancel(String address) {
         mPasskeyAgentRequestData.remove(address);
-
+        if (mDefaultPinData.containsKey(address)) {
+            mDefaultPinData.remove(address);
+            mDefaultPinData.put(address, false);
+        }
         Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
         intent.putExtra(BluetoothIntent.ADDRESS, address);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
     }
+    
     private void onGetRemoteServiceChannelResult(String address, int channel) {
         IBluetoothDeviceCallback callback = mGetRemoteServiceChannelCallbacks.get(address);
         if (callback != null) {
diff --git a/core/java/android/server/checkin/FallbackCheckinService.java b/core/java/android/server/checkin/FallbackCheckinService.java
index b450913..65921af 100644
--- a/core/java/android/server/checkin/FallbackCheckinService.java
+++ b/core/java/android/server/checkin/FallbackCheckinService.java
@@ -42,4 +42,8 @@
         state.isEnabled = false;
         p.onResult(state);
     }
+    
+    public void getParentalControlState(IParentalControlCallback p, String requestingApp)
+            throws android.os.RemoteException {
+    }
 }
diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java
index 5b9942e..6c8f554 100644
--- a/core/java/android/server/search/SearchableInfo.java
+++ b/core/java/android/server/search/SearchableInfo.java
@@ -402,7 +402,7 @@
         // initialize as an "unsearchable" object
         mSearchable = false;
         mSearchActivity = cName;
-
+        
         // to access another activity's resources, I need its context.
         // BE SURE to release the cache sometime after construction - it's a large object to hold
         mCacheActivityContext = getActivityContext(context);
@@ -415,6 +415,7 @@
             mIconId = a.getResourceId(com.android.internal.R.styleable.Searchable_icon, 0);
             mSearchButtonText = a.getResourceId(
                     com.android.internal.R.styleable.Searchable_searchButtonText, 0);
+
             setSearchModeFlags();
             if (DBG_INHIBIT_SUGGESTIONS == 0) {
                 mSuggestAuthority = a.getString(
diff --git a/core/java/android/speech/recognition/AbstractEmbeddedGrammarListener.java b/core/java/android/speech/recognition/AbstractEmbeddedGrammarListener.java
deleted file mode 100644
index c25a7e3..0000000
--- a/core/java/android/speech/recognition/AbstractEmbeddedGrammarListener.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  AbstractEmbeddedGrammarListener.java                                     *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * An EmbeddedGrammarListener whose methods are empty. This class exists as
- * convenience for creating listener objects.
- */
-public abstract class AbstractEmbeddedGrammarListener implements EmbeddedGrammarListener
-{
-  public void onCompileAllSlots()
-  {
-  }
-
-  public void onError(Exception e)
-  {
-  }
-
-  public void onLoaded()
-  {
-  }
-
-  public void onResetAllSlots()
-  {
-  }
-
-  public void onSaved(String path)
-  {
-  }
-
-  public void onUnloaded()
-  {
-  }
-}
diff --git a/core/java/android/speech/recognition/AbstractGrammarListener.java b/core/java/android/speech/recognition/AbstractGrammarListener.java
deleted file mode 100644
index fe62290..0000000
--- a/core/java/android/speech/recognition/AbstractGrammarListener.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  AbstractGrammarListener.java                                             *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * A GrammarListener whose methods are empty. This class exists as convenience
- * for creating listener objects.
- */
-public abstract class AbstractGrammarListener implements GrammarListener
-{
-  public void onError(Exception e)
-  {
-  }
-
-  public void onLoaded()
-  {
-  }
-
-  public void onUnloaded()
-  {
-  }
-}
diff --git a/core/java/android/speech/recognition/AbstractRecognizerListener.java b/core/java/android/speech/recognition/AbstractRecognizerListener.java
deleted file mode 100644
index ee2b8d1..0000000
--- a/core/java/android/speech/recognition/AbstractRecognizerListener.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  AbstractRecognizerListener.java                                          *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import java.util.Hashtable;
-import java.util.Vector;
-
-/**
- * A RecognizerListener whose methods are empty. This class exists as
- * convenience for creating listener objects.
- */
-public abstract class AbstractRecognizerListener implements RecognizerListener
-{
-  public void onBeginningOfSpeech()
-  {
-  }
-
-  public void onEndOfSpeech()
-  {
-  }
-
-  public void onRecognitionSuccess(RecognitionResult result)
-  {
-  }
-
-  public void onRecognitionFailure(FailureReason reason)
-  {
-  }
-
-  public void onError(Exception e)
-  {
-  }
-
-  public void onParametersGetError(Vector<String> parameters, Exception e)
-  {
-  }
-
-  public void onParametersSetError(Hashtable<String, String> parameters,
-    Exception e)
-  {
-  }
-
-  public void onParametersGet(Hashtable<String, String> parameters)
-  {
-  }
-
-  public void onParametersSet(Hashtable<String, String> parameters)
-  {
-  }
-
-  public void onStartOfSpeechTimeout()
-  {
-  }
-
-  public void onAcousticStateReset()
-  {
-  }
-
-  public void onStarted()
-  {
-  }
-
-  public void onStopped()
-  {
-  }
-}
diff --git a/core/java/android/speech/recognition/AbstractSrecGrammarListener.java b/core/java/android/speech/recognition/AbstractSrecGrammarListener.java
deleted file mode 100644
index e62e4ba..0000000
--- a/core/java/android/speech/recognition/AbstractSrecGrammarListener.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  AbstractSrecGrammarListener.java                                         *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * An SrecGrammarListener whose methods are empty. This class exists as
- * convenience for creating listener objects.
- */
-public abstract class AbstractSrecGrammarListener implements SrecGrammarListener
-{
-  public void onCompileAllSlots()
-  {
-  }
-
-  public void onError(Exception e)
-  {
-  }
-
-  public void onLoaded()
-  {
-  }
-
-  public void onResetAllSlots()
-  {
-  }
-
-  public void onSaved(String path)
-  {
-  }
-
-  public void onUnloaded()
-  {
-  }
-  
-  public void onAddItemList()
-  {
-  }
-    
-  public void onAddItemListFailure(int index, Exception e)
-  {
-  }
-}
diff --git a/core/java/android/speech/recognition/AudioAlreadyInUseException.java b/core/java/android/speech/recognition/AudioAlreadyInUseException.java
deleted file mode 100644
index 90698a7..0000000
--- a/core/java/android/speech/recognition/AudioAlreadyInUseException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  AudioAlreadyInUseException.java                                          *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Thrown when an AudioStream is passed into a component when another component
- * is already using it.
- */
-public class AudioAlreadyInUseException extends IllegalArgumentException
-{
-  private static final long serialVersionUID = 0L;
-
-  public AudioAlreadyInUseException(String msg)
-  {
-    super(msg);
-  }
-}
diff --git a/core/java/android/speech/recognition/AudioDriverErrorException.java b/core/java/android/speech/recognition/AudioDriverErrorException.java
deleted file mode 100644
index a755e7f..0000000
--- a/core/java/android/speech/recognition/AudioDriverErrorException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  AudioDriverErrorException.java                                           *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Thrown if an error occurs in the audio driver.
- */
-public class AudioDriverErrorException extends Exception
-{
-  private static final long serialVersionUID = 0L;
-
-  public AudioDriverErrorException(String msg)
-  {
-    super(msg);
-  }
-}
diff --git a/core/java/android/speech/recognition/AudioSource.java b/core/java/android/speech/recognition/AudioSource.java
deleted file mode 100644
index c4cd802..0000000
--- a/core/java/android/speech/recognition/AudioSource.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  AudioSource.java                                                         *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Generates audio data.
- */
-public interface AudioSource
-{
-  /**
-   * Returns an object that contains the audio samples. This object
-   * is passed to other components that consumes it, such a Recognizer
-   * or a DeviceSpeaker.
-   *
-   * @return an AudioStream instance
-   */
-  AudioStream createAudio();
-
-  /**
-   * Tells the audio source to start collecting audio samples.
-   */
-  void start();
-
-  /**
-   * Tells the audio source to stop collecting audio samples.
-   */
-  void stop();
-}
diff --git a/core/java/android/speech/recognition/AudioSourceListener.java b/core/java/android/speech/recognition/AudioSourceListener.java
deleted file mode 100644
index 42e8ebe..0000000
--- a/core/java/android/speech/recognition/AudioSourceListener.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  AudioSourceListener.java                                                 *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Listens for Microphone events.
- */
-public interface AudioSourceListener
-{
-  /**
-   * Invoked after the microphone starts recording.
-   */
-  void onStarted();
-
-  /**
-   * Invoked after the microphone stops recording.
-   */
-  void onStopped();
-
-  /**
-   * Invoked when an unexpected error occurs. This is normally followed by
-   * onStopped() if the component shuts down successfully.
-   *
-   * @param e the cause of the failure
-   */
-  void onError(Exception e);
-}
diff --git a/core/java/android/speech/recognition/AudioStream.java b/core/java/android/speech/recognition/AudioStream.java
deleted file mode 100644
index 36afe21..0000000
--- a/core/java/android/speech/recognition/AudioStream.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  AudioStream.java                                                         *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Stream used to read audio data.
- */
-public interface AudioStream
-{
-  /**
-   * Releases resources associated with the object.
-   *
-   * @deprecated this method is deprecated and has no replacement. It will be 
-   * removed in a future release of the API.
-   */
-  @Deprecated
-  void dispose();
-}
diff --git a/core/java/android/speech/recognition/Codec.java b/core/java/android/speech/recognition/Codec.java
deleted file mode 100644
index 18d9e15..0000000
--- a/core/java/android/speech/recognition/Codec.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  Codec.java                                                               *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Audio formats.
- */
-public abstract class Codec
-{
-  /**
-   * PCM, 16 bits, 8KHz.
-   */
-  public static final Codec PCM_16BIT_8K = new Codec("PCM/16bit/8KHz")
-  {
-    @Override
-    public byte getBitsPerSample()
-    {
-      return 16;
-    }
-
-    @Override
-    public int getSampleRate()
-    {
-      return 8000;
-    }
-  };
-  /**
-   * PCM, 16 bits, 11KHz.
-   */
-  public static final Codec PCM_16BIT_11K = new Codec("PCM/16bit/11KHz")
-  {
-    @Override
-    public byte getBitsPerSample()
-    {
-      return 16;
-    }
-
-    @Override
-    public int getSampleRate()
-    {
-      return 11025;
-    }
-  };
-  /**
-   * PCM, 16 bits, 22KHz.
-   */
-  public static final Codec PCM_16BIT_22K = new Codec("PCM/16bit/22KHz")
-  {
-    @Override
-    public byte getBitsPerSample()
-    {
-      return 16;
-    }
-
-    @Override
-    public int getSampleRate()
-    {
-      return 22050;
-    }
-  };
-  /**
-   * ULAW, 8 bits, 8KHz.
-   */
-  public static final Codec ULAW_8BIT_8K = new Codec("ULAW/8bit/8KHz")
-  {
-    @Override
-    public byte getBitsPerSample()
-    {
-      return 8;
-    }
-
-    @Override
-    public int getSampleRate()
-    {
-      return 8000;
-    }
-  };
-  private final String message;
-
-  /**
-   * Creates a new Codec.
-   *
-   * @param message the message to associate with the codec
-   */
-  private Codec(String message)
-  {
-    this.message = message;
-  }
-
-  @Override
-  public String toString()
-  {
-    return message;
-  }
-
-  /**
-   * Returns the codec sample-rate.
-   * 
-   * @return the codec sample-rate
-   */
-  public abstract int getSampleRate();
-
-  /**
-   * Returns the codec bitrate.
-   * 
-   * @return the codec bitrate
-   */
-  public abstract byte getBitsPerSample();
-}
diff --git a/core/java/android/speech/recognition/DeviceSpeaker.java b/core/java/android/speech/recognition/DeviceSpeaker.java
deleted file mode 100644
index bd18687..0000000
--- a/core/java/android/speech/recognition/DeviceSpeaker.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  DeviceSpeaker.java                                                       *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import android.speech.recognition.impl.DeviceSpeakerImpl;
-
-/**
- * A device for transforming electric signals into audible sound, most
- * frequently used to reproduce speech and music.
- */
-public abstract class DeviceSpeaker
-{
-  private static DeviceSpeaker instance;
-
-  /**
-   * Returns the device speaker instance.
-   *
-   * @return an instance of a DeviceSpeaker class.
-   */
-  public static DeviceSpeaker getInstance()
-  {
-    instance = DeviceSpeakerImpl.getInstance();
-    return instance;
-  }
-
-  /**
-   * Starts the audio playback.
-   *
-   * @param source the audio to play
-   * @throws IllegalStateException if the component is already started
-   * @throws IllegalArgumentException if source audio is null, in-use by 
-   * another component or is empty.
-   *
-   */
-  public abstract void start(AudioStream source) throws IllegalStateException,
-    IllegalArgumentException;
-
-  /**
-   * Stops audio playback.
-   */
-  public abstract void stop();
-
-  /**
-   * Sets the playback codec. This must be called before start() is called.
-   *
-   * @param playbackCodec the codec to use for the playback operation.
-   * @throws IllegalStateException if the component is already stopped
-   * @throws IllegalArgumentException if the specified codec is not supported
-   */
-  public abstract void setCodec(Codec playbackCodec) throws IllegalStateException,
-    IllegalArgumentException;
-
-  /**
-   * Sets the microphone listener.
-   *
-   * @param listener the device speaker listener.
-   * @throws IllegalStateException if the component is started
-   */
-  public abstract void setListener(DeviceSpeakerListener listener) throws IllegalStateException;
-}
diff --git a/core/java/android/speech/recognition/DeviceSpeakerListener.java b/core/java/android/speech/recognition/DeviceSpeakerListener.java
deleted file mode 100644
index e2baa2e..0000000
--- a/core/java/android/speech/recognition/DeviceSpeakerListener.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  DeviceSpeakerListener.java                                               *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Listens for DeviceSpeaker events.
- */
-public interface DeviceSpeakerListener
-{
-  /**
-   * Invoked after playback begins.
-   */
-  void onStarted();
-
-  /**
-   * Invoked after playback terminates.
-   */
-  void onStopped();
-
-  /**
-   * Invoked when an unexpected error occurs. This is normally followed by
-   * onStopped() if the component shuts down successfully.
-   *
-   * @param e the cause of the failure
-   */
-  void onError(Exception e);
-}
diff --git a/core/java/android/speech/recognition/EmbeddedGrammar.java b/core/java/android/speech/recognition/EmbeddedGrammar.java
deleted file mode 100644
index c6f037b..0000000
--- a/core/java/android/speech/recognition/EmbeddedGrammar.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  EmbeddedGrammar.java                                                     *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Grammar on an embedded recognizer.
- */
-public interface EmbeddedGrammar extends Grammar
-{
-  /**
-   * Compiles items that were added to any of the grammar slots.
-   */
-  void compileAllSlots();
-
-  /**
-   * Removes all words added to all slots.
-   */
-  void resetAllSlots();
-
-  /**
-   * Saves the compiled grammar.
-   *
-   * @param url the url to save the grammar to
-   */
-  void save(String url);
-}
diff --git a/core/java/android/speech/recognition/EmbeddedGrammarListener.java b/core/java/android/speech/recognition/EmbeddedGrammarListener.java
deleted file mode 100644
index 5b8c1a4..0000000
--- a/core/java/android/speech/recognition/EmbeddedGrammarListener.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  EmbeddedGrammarListener.java                                             *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Listens for EmbeddedGrammar events.
- */
-public interface EmbeddedGrammarListener extends GrammarListener
-{
-  /**
-   * Invoked after the grammar is saved.
-   *
-   * @param path the path the grammar was saved to
-   */
-  void onSaved(String path);
-
-  /**
-   * Invoked when a grammar operation fails.
-   *
-   * @param e the cause of the failure.<br/>
-   * {@link GrammarOverflowException} if the grammar slot is full and no
-   * further items may be added to it.<br/>
-   * {@link java.lang.UnsupportedOperationException} if different words with
-   * the same pronunciation are added.<br/>
-   * {@link java.lang.IllegalStateException} if reseting or compiling the
-   * slots fails.<br/>
-   * {@link java.io.IOException} if the grammar could not be loaded or
-   * saved.</p>
-   */
-  void onError(Exception e);
-
-  /**
-   * Invokes after all grammar slots have been compiled.
-   */
-  void onCompileAllSlots();
-
-  /**
-   * Invokes after all grammar slots have been reset.
-   */
-  void onResetAllSlots();
-}
diff --git a/core/java/android/speech/recognition/EmbeddedRecognizer.java b/core/java/android/speech/recognition/EmbeddedRecognizer.java
deleted file mode 100644
index cd79edc..0000000
--- a/core/java/android/speech/recognition/EmbeddedRecognizer.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  EmbeddedRecognizer.java                                                  *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import android.speech.recognition.impl.EmbeddedRecognizerImpl;
-
-/**
- * Embedded recognizer.
- */
-public abstract class EmbeddedRecognizer implements Recognizer
-{
-  private static EmbeddedRecognizer instance;
-
-  /**
-   * Returns the embedded recognizer.
-   *
-   * @return the embedded recognizer
-   */
-  public static EmbeddedRecognizer getInstance()
-  {
-    instance = EmbeddedRecognizerImpl.getInstance();
-    return instance;
-  }
-
-  /**
-   * Configures the recognizer.
-   *
-   * @param config recognizer configuration file
-   * @throws IllegalArgumentException if config is null or an empty string
-   * @throws FileNotFoundException if the specified file could not be found
-   * @throws IOException if the specified file could not be opened
-   * @throws UnsatisfiedLinkError if the recognizer plugin could not be loaded
-   * @throws ClassNotFoundException if the recognizer plugin could not be found
-   */
-  public abstract void configure(String config) throws IllegalArgumentException,
-    FileNotFoundException, IOException, UnsatisfiedLinkError,
-    ClassNotFoundException;
-
-   /**
-   * The recognition accuracy improves over time as the recognizer adapts to
-   * the surrounding environment. This method enables developers to reset the
-   * adaptation when the environment is known to have changed.
-   *
-   * @throws IllegalArgumentException if recognizer instance is null
-   */
-  public abstract void resetAcousticState() throws IllegalArgumentException;
-}
diff --git a/core/java/android/speech/recognition/Grammar.java b/core/java/android/speech/recognition/Grammar.java
deleted file mode 100644
index 9f1b624..0000000
--- a/core/java/android/speech/recognition/Grammar.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  Grammar.java                                                             *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Speech recognition grammar.
- */
-public interface Grammar {
-    /**
-     * Load the grammar sets the grammar state to active, indicating that can be used in a recognition process.
-     * Multiple grammars can be loaded, but only one at a time can be used by the recognizer.
-     *
-     */
-    void load();
-    
-    /**
-     * Unload the grammar sets the grammar state to inactive (inactive grammars can not be used as a parameter of a recognition).
-     */
-    void unload();
-    
-    /**
-     * (Optional operation) Releases resources associated with the object. The
-     * grammar may not be used past this point.
-     */
-    void dispose();
-}
diff --git a/core/java/android/speech/recognition/GrammarErrorException.java b/core/java/android/speech/recognition/GrammarErrorException.java
deleted file mode 100644
index 6070758..0000000
--- a/core/java/android/speech/recognition/GrammarErrorException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  GrammarErrorException.java                                                 *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Thrown if an error occurs in the audio driver.
- */
-public class GrammarErrorException extends Exception
-{
-  private static final long serialVersionUID = 0L;
-
-  public GrammarErrorException(String msg)
-  {
-    super(msg);
-  }
-}
diff --git a/core/java/android/speech/recognition/GrammarListener.java b/core/java/android/speech/recognition/GrammarListener.java
deleted file mode 100644
index 871cbcb..0000000
--- a/core/java/android/speech/recognition/GrammarListener.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  GrammarListener.java                                                     *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Listens for Grammar events.
- */
-public interface GrammarListener
-{
-  /**
-   * Invoked after the Grammar is loaded.
-   */
-  void onLoaded();
-
-  /**
-   * Invoked after the Grammar is unloaded.
-   */
-  void onUnloaded();
-
-  /**
-   * Invoked when a grammar operation fails.
-   *
-   * @param e the cause of the failure.<br/>
-   * {@link java.io.IOException} if the grammar could not be loaded or
-   * saved.</p>
-   */
-  void onError(Exception e);
-}
diff --git a/core/java/android/speech/recognition/GrammarOverflowException.java b/core/java/android/speech/recognition/GrammarOverflowException.java
deleted file mode 100644
index 227820b..0000000
--- a/core/java/android/speech/recognition/GrammarOverflowException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  GrammarOverflowException.java                                            *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Thrown if a SlotItem is added into a grammar slot that is filled to capacity.
- */
-public class GrammarOverflowException extends Exception
-{
-  private static final long serialVersionUID = 0L;
-
-  public GrammarOverflowException(String message)
-  {
-    super(message);
-  }
-}
diff --git a/core/java/android/speech/recognition/InvalidURLException.java b/core/java/android/speech/recognition/InvalidURLException.java
deleted file mode 100644
index fec9411..0000000
--- a/core/java/android/speech/recognition/InvalidURLException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  InvalidURLException.java                                                 *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                         *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- */
-public class InvalidURLException extends Exception {
-    
-    private static final long serialVersionUID = 0L;
-      
-    /** Creates a new instance of InvalidURLException */
-    public InvalidURLException(String msg) 
-    {
-        super(msg);
-    }
-
-}
diff --git a/core/java/android/speech/recognition/Logger.java b/core/java/android/speech/recognition/Logger.java
deleted file mode 100644
index 8a09cb3..0000000
--- a/core/java/android/speech/recognition/Logger.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  Logger.java                                                              *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import android.speech.recognition.impl.LoggerImpl;
-
-/**
- * Logs debugging information.
- */
-public abstract class Logger
-{
-  /**
-   * Logging level
-   */
-  public static class LogLevel
-  {
-    /**
-     * Does not log.
-     */
-    public static LogLevel LEVEL_NONE = new LogLevel("Do not log");
-    /**
-     * Logs fatal issues. This level only logs ERROR.
-     */
-    public static LogLevel LEVEL_ERROR = new LogLevel("log  UAPI_ERROR logs");
-    /**
-     * Logs non-fatal issues. This level also logs ERROR.
-     */
-    public static LogLevel LEVEL_WARN =
-      new LogLevel("log  UAPI_ERROR, UAPI_WARN logs");
-    /**
-     * Logs debugging information, such as the values of variables. This level also logs ERROR, WARN.
-     */
-    public static LogLevel LEVEL_INFO =
-      new LogLevel("log  UAPI_ERROR, UAPI_WARN, UAPI_INFO logs");
-    /**
-     * Logs when loggers are created or destroyed. This level also logs INFO, WARN, ERROR.
-     */
-    public static LogLevel LEVEL_TRACE =
-      new LogLevel("log UAPI_ERROR, UAPI_WARN, UAPI_INFO, UAPI_TRACE logs");
-    private String message;
-
-    /**
-     * Creates a new LogLevel.
-     *
-     * @param message the message associated with the LogLevel.
-     */
-    private LogLevel(String message)
-    {
-      this.message = message;
-    }
-
-    @Override
-    public String toString()
-    {
-      return message;
-    }
-  }
-
-  /**
-   * Returns the singleton instance.
-   *
-   * @return the singleton instance
-   */
-  public static Logger getInstance()
-  {
-    return LoggerImpl.getInstance();
-  }
-
-  /**
-   * Sets the logging level.
-   *
-   * @param level the logging level
-   */
-  public abstract void setLoggingLevel(LogLevel level);
-
-  /**
-   * Sets the log path.
-   *
-   * @param path the path of the log file
-   */
-  public abstract void setPath(String path);
-
-  /**
-   * Logs an error message.
-   *
-   * @param message the message to log
-   */
-  public abstract void error(String message);
-
-  /**
-   * Logs a warning message.
-   *
-   * @param message the message to log
-   */
-  public abstract void warn(String message);
-
-  /**
-   * Logs an informational message.
-   *
-   * @param message the message to log
-   */
-  public abstract void info(String message);
-
-  /**
-   * Logs a method tracing message.
-   *
-   * @param message the message to log
-   */
-  public abstract void trace(String message);
-}
diff --git a/core/java/android/speech/recognition/MediaFileReader.java b/core/java/android/speech/recognition/MediaFileReader.java
deleted file mode 100644
index 216511f..0000000
--- a/core/java/android/speech/recognition/MediaFileReader.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  MediaFileReader.java                                                     *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import android.speech.recognition.impl.MediaFileReaderImpl;
-
-/**
- * Reads audio from a file.
- */
-public abstract class MediaFileReader implements AudioSource
-{
-  /**
-   * Reading mode
-   */
-  public static class Mode
-  {
-    /**
-     * Read the file in "real time".
-     */
-    public static Mode REAL_TIME = new Mode("real-time");
-    /**
-     * Read the file all at once.
-     */
-    public static Mode ALL_AT_ONCE = new Mode("all at once");
-    private String message;
-
-    /**
-     * Creates a new Mode.
-     *
-     * @param message the message associated with the reading mode.
-     */
-    private Mode(String message)
-    {
-      this.message = message;
-    }
-  }
-
-  /**
-   * Creates a new MediaFileReader to read audio samples from a file.
-   *
-   * @param filename the name of the file to read from Note: The file MUST be of type Microsoft WAVE RIFF
-   * format (PCM 16 bits 8000 Hz or PCM 16 bits 11025 Hz).
-   * @param listener listens for MediaFileReader events
-   * @return a new MediaFileReader
-   * @throws IllegalArgumentException if filename is null or is an empty string. Or if offset > file length. Or if codec is null or invalid
-   */
-  public static MediaFileReader create(String filename, AudioSourceListener listener) throws IllegalArgumentException
-  {
-    return new MediaFileReaderImpl(filename, listener);
-  }
-
-  /**
-   * Sets the reading mode.
-   *
-   * @param mode the reading mode
-   */
-  public abstract void setMode(Mode mode);
-
-  /**
-   * Creates an audio source.
-   */
-  public abstract AudioStream createAudio();
-
-  /**
-   * Starts collecting audio samples.
-   */
-  public abstract void start();
-
-  /**
-   * Stops collecting audio samples.
-   */
-  public abstract void stop();
-}
diff --git a/core/java/android/speech/recognition/MediaFileReaderListener.java b/core/java/android/speech/recognition/MediaFileReaderListener.java
deleted file mode 100644
index f76e65f..0000000
--- a/core/java/android/speech/recognition/MediaFileReaderListener.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  MediaFileReaderListener.java                                             *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import android.speech.recognition.AudioSourceListener;
-
-/**
- * Listens for MediaFileReader events.
- */
-public interface MediaFileReaderListener extends AudioSourceListener
-{
-}
diff --git a/core/java/android/speech/recognition/MediaFileWriter.java b/core/java/android/speech/recognition/MediaFileWriter.java
deleted file mode 100644
index b2d627c..0000000
--- a/core/java/android/speech/recognition/MediaFileWriter.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  MediaFileWriter.java                                                     *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import android.speech.recognition.impl.MediaFileWriterImpl;
-
-/**
- * Writes audio to a file.
- */
-public abstract class MediaFileWriter
-{
-  /**
-   * Creates a new MediaFileWriter to write audio samples into a file.
-   *
-   * @param listener listens for MediaFileWriter events
-   * @return a new MediaFileWriter
-   */
-  public static MediaFileWriter create(MediaFileWriterListener listener)
-  {
-    return new MediaFileWriterImpl(listener);
-  }
-
-  /**
-   * Saves audio to a file.
-   *
-   * @param source the audio stream to write
-   * @param filename the file to write to
-   * @throws IllegalArgumentException if source is null, in-use by another 
-   * component or contains no data. Or if filename is null or is empty.
-   */
-  public abstract void save(AudioStream source, String filename) throws IllegalArgumentException;
-}
diff --git a/core/java/android/speech/recognition/MediaFileWriterListener.java b/core/java/android/speech/recognition/MediaFileWriterListener.java
deleted file mode 100644
index e2104c8..0000000
--- a/core/java/android/speech/recognition/MediaFileWriterListener.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  MediaFileWriterListener.java                                             *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Listens for MediaFileWriter events.
- */
-public interface MediaFileWriterListener
-{
-  /**
-   * Invoked after the save() operation terminates
-   */
-  void onStopped();
-
-  /**
-   * Invoked when an unexpected error occurs. This is normally followed by
-   * onStopped() if the component shuts down successfully.
-   *
-   * @param e the cause of the failure.<br/>
-   * {@link java.io.IOException} if an error occured opening or writing to the file
-   */
-  void onError(Exception e);
-}
diff --git a/core/java/android/speech/recognition/Microphone.java b/core/java/android/speech/recognition/Microphone.java
deleted file mode 100644
index 1b713f5..0000000
--- a/core/java/android/speech/recognition/Microphone.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  Microphone.java                                                          *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import android.speech.recognition.impl.MicrophoneImpl;
-
-/**
- * Records live audio.
- */
-public abstract class Microphone implements AudioSource
-{
-  private static Microphone instance;
-
-  /**
-   * Returns the microphone instance
-   *
-   * @return an instance of a Microphone class.
-   */
-  public static Microphone getInstance()
-  {
-    instance = MicrophoneImpl.getInstance();
-    return instance;
-  }
-
-  /**
-   * Sets the recording codec. This must be called before start() is called.
-   *
-   * @param recordingCodec the codec in which the samples will be recorded.
-   * @throws IllegalStateException if Microphone is started
-   * @throws IllegalArgumentException if codec is not supported
-   */
-  public abstract void setCodec(Codec recordingCodec) throws IllegalStateException,
-    IllegalArgumentException;
-
-  /**
-   * Sets the microphone listener.
-   *
-   * @param listener the microphone listener.
-   * @throws IllegalStateException if Microphone is started
-   */
-  public abstract void setListener(AudioSourceListener listener) throws IllegalStateException;
-
-  /**
-   * Creates an audio source
-   */
-  public abstract AudioStream createAudio();
-
-  /**
-   * Start recording audio.
-   *
-   * @throws IllegalStateException if Microphone is already started
-   */
-  public abstract void start() throws IllegalStateException;
-
-  /**
-   * Stops recording audio.
-   */
-  public abstract void stop();
-}
diff --git a/core/java/android/speech/recognition/MicrophoneListener.java b/core/java/android/speech/recognition/MicrophoneListener.java
deleted file mode 100644
index f43eff9..0000000
--- a/core/java/android/speech/recognition/MicrophoneListener.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  MicrophoneListener.java                                                  *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import android.speech.recognition.AudioSourceListener;
-
-/**
- * Listens for Microphone events.
- */
-public interface MicrophoneListener extends AudioSourceListener
-{
-}
diff --git a/core/java/android/speech/recognition/NBestRecognitionResult.java b/core/java/android/speech/recognition/NBestRecognitionResult.java
deleted file mode 100644
index e679c19..0000000
--- a/core/java/android/speech/recognition/NBestRecognitionResult.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  NBestRecognitionResult.java                                              *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import java.util.Enumeration;
-
-/**
- * N-Best recognition results. Entries are sorted in decreasing order according
- * to their probability, from the most probable result to the least probable
- * result.
- */
-public interface NBestRecognitionResult extends RecognitionResult
-{
-  /**
-   * Recognition result entry
-   */
-  public static interface Entry
-  {
-    /**
-     * Returns the semantic meaning of a recognition result (i.e.&nbsp;the application-specific value
-     * associated with what the user said). In an example where a person's name is mapped
-     * to a phone-number, the phone-number is the semantic meaning.
-     *
-     * @return the semantic meaning of a recognition result.
-     * @throws IllegalStateException if the object has been disposed
-     */
-    String getSemanticMeaning() throws IllegalStateException;
-
-    /**
-     * The confidence score of a recognition result. Values range from 0 to 100
-     * (inclusive).
-     *
-     * @return the confidence score of a recognition result.
-     * @throws IllegalStateException if the object has been disposed
-     */
-    byte getConfidenceScore() throws IllegalStateException;
-
-    /**
-     * Returns the literal meaning of a recognition result (i.e.&nbsp;literally
-     * what the user said). In an example where a person's name is mapped to a 
-     * phone-number, the person's name is the literal meaning.
-     *
-     * @return the literal meaning of a recognition result.
-     * @throws IllegalStateException if the object has been disposed
-     */
-    String getLiteralMeaning() throws IllegalStateException;
-    
-    /**
-     * Returns the value associated with the specified key.
-     *
-     * @param key the key to look up
-     * @return the associated value or null if this entry does not contain
-     * any mapping for the key
-     */
-    String get(String key);
-    
-    /**
-     * Returns an enumeration of the keys in this Entry.
-     *
-     * @return an enumeration of the keys in this Entry.
-     */
-    Enumeration keys();
-  }
-
-  /**
-   * Returns the number of entries in the n-best list.
-   *
-   * @return the number of entries in the n-best list
-   */
-  int getSize();
-
-  /**
-   * Returns the n-best entry that contains key-value pairs associated with the
-   * recognition result.
-   *
-   * @param index the index of the n-best entry
-   * @return null if all active GrammarConfiguration.grammarToMeaning() return
-   * null
-   * @throws ArrayIndexOutOfBoundsException if index is greater than size of
-   * entries
-   */
-  Entry getEntry(int index) throws ArrayIndexOutOfBoundsException;
-
-  /**
-   * Creates a new VoicetagItem if the last recognition was an enrollment
-   * operation.
-   *
-   * @param VoicetagId string voicetag unique id value. 
-   * @param listener listens for Voicetag events
-   * @return the resulting VoicetagItem
-   * @throws IllegalArgumentException if VoicetagId is null or an empty string.
-   * @throws IllegalStateException if the last recognition was not an
-   * enrollment operation
-   */
-  VoicetagItem createVoicetagItem(String VoicetagId, VoicetagItemListener listener) throws IllegalArgumentException,IllegalStateException;
-}
diff --git a/core/java/android/speech/recognition/ParameterErrorException.java b/core/java/android/speech/recognition/ParameterErrorException.java
deleted file mode 100644
index 042ed31..0000000
--- a/core/java/android/speech/recognition/ParameterErrorException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  ParameterErrorException.java                                             *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Thrown if an error occurs in the audio driver.
- */
-public class ParameterErrorException extends Exception
-{
-  private static final long serialVersionUID = 0L;
-
-  public ParameterErrorException(String msg)
-  {
-    super(msg);
-  }
-}
diff --git a/core/java/android/speech/recognition/ParametersListener.java b/core/java/android/speech/recognition/ParametersListener.java
deleted file mode 100644
index bdb551e..0000000
--- a/core/java/android/speech/recognition/ParametersListener.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  ParametersListener.java                                                  *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import java.util.Hashtable;
-import java.util.Vector;
-
-/**
- * Listens for parameter events.
- */
-public interface ParametersListener
-{
-  /**
-   * Invoked if retrieving parameters has failed.
-   *
-   * @param parameters the parameters that could not be retrieved
-   * @param e the failure reason
-   */
-  void onParametersGetError(Vector<String> parameters, Exception e);
-
-  /**
-   * Invoked if setting parameters has failed.
-   *
-   * @param parameters the parameters that could not be set
-   * @param e the failure reason
-   */
-  void onParametersSetError(Hashtable<String, String> parameters, Exception e);
-
-  /**
-   * This method is called when the parameters specified in setParameters have
-   * successfully been set. This method is guaranteed to be invoked after
-   * onParametersSetError, even if count==0.
-   *
-   * @param parameters the set parameters
-   */
-  void onParametersSet(Hashtable<String, String> parameters);
-
-  /**
-   * This method is called when the parameters specified in getParameters have
-   * successfully been retrieved. This method is guaranteed to be invoked after
-   * onParametersGetError, even if count==0.
-   *
-   * @param parameters the retrieved parameters
-   */
-  void onParametersGet(Hashtable<String, String> parameters);
-}
diff --git a/core/java/android/speech/recognition/ParseErrorException.java b/core/java/android/speech/recognition/ParseErrorException.java
deleted file mode 100644
index 2288a90..0000000
--- a/core/java/android/speech/recognition/ParseErrorException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  ParseErrorException.java                                                 *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Thrown if an error occurs in the audio driver.
- */
-public class ParseErrorException extends Exception
-{
-  private static final long serialVersionUID = 0L;
-
-  public ParseErrorException(String msg)
-  {
-    super(msg);
-  }
-}
diff --git a/core/java/android/speech/recognition/RecognitionResult.java b/core/java/android/speech/recognition/RecognitionResult.java
deleted file mode 100644
index cbbc938..0000000
--- a/core/java/android/speech/recognition/RecognitionResult.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  RecognitionResult.java                                                   *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Recognition result interface.
- */
-public interface RecognitionResult
-{
-}
diff --git a/core/java/android/speech/recognition/Recognizer.java b/core/java/android/speech/recognition/Recognizer.java
deleted file mode 100644
index ab7f8f4..0000000
--- a/core/java/android/speech/recognition/Recognizer.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  Recognizer.java                                                          *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import java.util.Hashtable;
-import java.util.Vector;
-
-/**
- * Speech recognizer interface.
- */
-public interface Recognizer
-{
- /**
-   * Sets the recognizer event listener.
-   *
-   * @param listener listens for recognizer events
-   */
-  void setListener(RecognizerListener listener);
-
-  /**
-   * Creates an embedded grammar.
-   *
-   * @param value value of that grammarType. Could be a URL or an inline grammar.
-   * @return a grammar
-   * @throws IllegalArgumentException if value is null or listener is not of type
-   * GrammarListener.
-   */
-  Grammar createGrammar(String value, GrammarListener listener) throws IllegalArgumentException;
-  
-  /**
-   * Begins speech recognition.
-   *
-   * @param audio the audio stream to recognizer
-   * @param grammars a collection of grammar sets to recognize against
-   * @see #recognize(AudioStream, Grammar)
-   * @throws IllegalStateException if any of the grammars are not loaded
-   * @throws IllegalArgumentException if audio is null, in-use by another
-   * component or empty. Or if grammars is null or grammars count is less than
-   * one. Or if the audio codec differs from recognizer codec.
-   * @throws UnsupportedOperationException if the recognizer does not support
-   * the number of grammars specified.
-   */
-  void recognize(AudioStream audio,
-    Vector<Grammar> grammars) throws IllegalStateException,
-    IllegalArgumentException, UnsupportedOperationException;
-
-  /**
-   * This convenience method is equivalent to invoking
-   * recognize(audio, grammars) with a single grammar.
-   *
-   * @param audio the audio to recognizer
-   * @param grammar a grammar to recognize against
-   * @see #recognize(AudioStream, Vector)
-   * @throws IllegalStateException if grammar is not loaded
-   * @throws IllegalArgumentException if audio is null, in-use by another
-   * component or is empty. Or if grammar is null or if the audio codec differs
-   * from the recognizer codec.
-   */
-  void recognize(AudioStream audio, Grammar grammar) throws IllegalStateException,
-    IllegalArgumentException;
-
-  /**
-   * Terminates a recognition if one is in-progress.
-   * This must not be called until the recognize method
-   * returns; otherwise the result is not defined.
-   *
-   * @see RecognizerListener#onStopped
-   */
-  void stop();
-
-  /**
-   * Sets the values of recognition parameters.
-   *
-   * @param parameters the parameter key-value pairs to set
-   */
-  void setParameters(Hashtable<String, String> parameters);
-
-  /**
-   * Retrieves the values of recognition parameters.
-   *
-   * @param parameters the names of the parameters to retrieve
-   */
-  void getParameters(Vector<String> parameters);
-
-}
diff --git a/core/java/android/speech/recognition/RecognizerListener.java b/core/java/android/speech/recognition/RecognizerListener.java
deleted file mode 100644
index d7bbda9..0000000
--- a/core/java/android/speech/recognition/RecognizerListener.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  RecognizerListener.java                                                  *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Listens for recognizer events.
- */
-public interface RecognizerListener extends ParametersListener
-{
-  /**
-   * Recognition failure.
-   */
-  public static class FailureReason
-  {
-    /**
-     * The audio did not generate any results.
-     */
-    public static FailureReason NO_MATCH =
-      new FailureReason("The audio did not generate any results");
-    /**
-     * Beginning of speech occured too soon.
-     */
-    public static FailureReason SPOKE_TOO_SOON =
-      new FailureReason("Beginning of speech occurred too soon");
-    /**
-     * A timeout occured before the beginning of speech.
-     */
-    public static FailureReason BEGINNING_OF_SPEECH_TIMEOUT =
-      new FailureReason("A timeout occurred before the beginning of " + "speech");
-    /**
-     * A timeout occured before the recognition could complete.
-     */
-    public static FailureReason RECOGNITION_TIMEOUT =
-      new FailureReason("A timeout occurred before the recognition " +
-      "could complete");
-    /**
-     * The recognizer encountered more audio than was acceptable according to
-     * its configuration.
-     */
-    public static FailureReason TOO_MUCH_SPEECH =
-      new FailureReason("The " +
-      "recognizer encountered more audio than was acceptable according to " +
-      "its configuration");
-
-    public static FailureReason UNKNOWN =
-      new FailureReason("unknown failure reason");
-
-    private final String message;
-
-    private FailureReason(String message)
-    {
-      this.message = message;
-    }
-
-    @Override
-    public String toString()
-    {
-      return message;
-    }
-  }
-
-  /**
-   * Invoked after recognition begins.
-   */
-  void onStarted();
-
-  /**
-   * Invoked if the recognizer detects the beginning of speech.
-   */
-  void onBeginningOfSpeech();
-
-  /**
-   * Invoked if the recognizer detects the end of speech.
-   */
-  void onEndOfSpeech();
-
-  /**
-   * Invoked if the recognizer does not detect speech within the configured
-   * timeout period.
-   */
-  void onStartOfSpeechTimeout();
-
-  /**
-   * Invoked when the recognizer acoustic state is reset.
-   *
-   * @see android.speech.recognition.EmbeddedRecognizer#resetAcousticState()
-   */
-  void onAcousticStateReset();
-
-  /**
-   * Invoked when a recognition result is generated.
-   *
-   * @param result the recognition result. The result object can not be
-   * used outside of the scope of the onRecognitionSuccess() callback method.
-   * To be able to do so, copy it's contents to an user-defined object.<BR>
-   * An example of this object could be a vector of string arrays; where the
-   * vector represents a list of recognition result entries and each entry
-   * is an array of strings to hold the entry's values (the semantic
-   * meaning, confidence score and literal meaning).
-   */
-  void onRecognitionSuccess(RecognitionResult result);
-
-  /**
-   * Invoked when a recognition failure occurs.
-   *
-   * @param reason the failure reason
-   */
-  void onRecognitionFailure(FailureReason reason);
-
-  /**
-   * Invoked when an unexpected error occurs. This is normally followed by
-   * onStopped() if the component shuts down successfully.
-   *
-   * @param e the cause of the failure
-   */
-  void onError(Exception e);
-
-  /**
-   * Invoked when the recognizer stops (due to normal termination or an error).
-   *
-   * Invoking stop() on a recognizer that is already stopped will not result
-   * in a onStopped() event.
-   */
-  void onStopped();
-}
diff --git a/core/java/android/speech/recognition/SlotItem.java b/core/java/android/speech/recognition/SlotItem.java
deleted file mode 100644
index 3abd27a..0000000
--- a/core/java/android/speech/recognition/SlotItem.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  SlotItem.java                                                            *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Item that may be inserted into an embedded grammar slot.
- */
-public interface SlotItem
-{
-}
diff --git a/core/java/android/speech/recognition/SrecGrammar.java b/core/java/android/speech/recognition/SrecGrammar.java
deleted file mode 100644
index c591e05..0000000
--- a/core/java/android/speech/recognition/SrecGrammar.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  SrecGrammar.java                                                         *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-import java.util.Vector;
-
-/**
- * Grammar on an SREC recognizer.
- */
-public interface SrecGrammar extends EmbeddedGrammar
-{
-  /**
-  * SrecGrammar Item
-  */
-  public class Item
-  {
-      public SlotItem _item;
-      public int _weight;
-      public String _semanticMeaning;
-      
-       /**
-       * Creates a grammar item.
-       *
-       * @param item the Slotitem. 
-       * @param weight the weight of the item. Smaller values are more likely to get recognized.  This should be >= 0.
-       * @param semanticMeaning the value that will be returned if this item is recognized.
-       * @throws IllegalArgumentException if item or semanticMeaning are null; if semanticMeaning is empty."
-       */
-       public Item(SlotItem item, int weight, String semanticMeaning)
-             throws IllegalArgumentException
-      {
-         if (item == null)
-            throw new IllegalArgumentException("Item(): item can't be null.");
-         if (semanticMeaning == null || semanticMeaning.length()==0)
-            throw new IllegalArgumentException("Item(): semanticMeaning is null or empty.");
-          _item = item;
-          _weight = weight;
-          _semanticMeaning = semanticMeaning;
-          
-      }
-  }
-  
-  /**
-   * Adds an item to a slot.
-   *
-   * @param slotName the name of the slot
-   * @param item the item to add to the slot.
-   * @param weight the weight of the item. Smaller values are more likely to get recognized.  This should be >= 0.
-   * @param semanticMeaning the value that will be returned if this item is recognized.
-   * @throws IllegalArgumentException if slotName, item or semanticMeaning are null; if semanticMeaning is not of the format "V=&#039;Jen_Parker&#039;"
-   */
-  public void addItem(String slotName, SlotItem item, int weight,
-    String semanticMeaning) throws IllegalArgumentException;
-  
-  /**
-   * Add a list of item to a slot.
-   *
-   * @param slotName the name of the slot
-   * @param items the vector of SrecGrammar.Item to add to the slot.
-   * @throws IllegalArgumentException if slotName,items are null or any element in the items(_item, _semanticMeaning) is null; if any semanticMeaning of the list is not of the format "key=&#039;value&#039"
-   */
-  public void addItemList(String slotName, Vector<Item> items)
-          throws IllegalArgumentException;
-  
-}
diff --git a/core/java/android/speech/recognition/SrecGrammarListener.java b/core/java/android/speech/recognition/SrecGrammarListener.java
deleted file mode 100644
index e1f7d3f..0000000
--- a/core/java/android/speech/recognition/SrecGrammarListener.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  SrecGrammarListener.java                                                 *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Listens for SrecGrammar events.
- */
-public interface SrecGrammarListener extends EmbeddedGrammarListener {
-    
-   /**
-   * Invokes after all items of the list have been added.
-   */
-   void onAddItemList();
-   
-   /**
-   * Invoked when adding a SlotItem from a list fails. 
-   * This callback will be trigger for each element in the list that fails to be
-   * add in the slot, unless there is a grammar fail operation, which will be
-   * reported in the onError callback.
-   * @param index of the list that could not be added to the slot
-   * @param e the cause of the failure.
-   */
-   void onAddItemListFailure(int index, Exception e);
-
-    
-   /**
-   * Invoked when a grammar related operation fails.
-   *
-   * @param e the cause of the failure.<br/>
-   * {@link GrammarOverflowException} if the grammar slot is full and no
-   * further items may be added to it.<br/>
-   * {@link java.lang.UnsupportedOperationException} if different words with
-   * the same pronunciation are added.<br/>
-   * {@link java.lang.IllegalStateException} if reseting or compiling the
-   * slots fails.<br/>
-   * {@link java.io.IOException} if the grammar could not be loaded or
-   * saved.</p>
-   */
-   void onError(Exception e);
-  
-}
diff --git a/core/java/android/speech/recognition/VoicetagItem.java b/core/java/android/speech/recognition/VoicetagItem.java
deleted file mode 100644
index 0b89639..0000000
--- a/core/java/android/speech/recognition/VoicetagItem.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  VoicetagItem.java                                                        *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import android.speech.recognition.impl.VoicetagItemImpl;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-/**
- * Voicetag that may be inserted into an embedded grammar slot.
- */
-public abstract class VoicetagItem implements SlotItem
-{
-   /**
-   * Creates a VoicetagItem from a file
-   *
-   * @param filename filename for Voicetag
-   * @param listener listens for Voicetag events
-   * @return the resulting VoicetagItem
-   * @throws IllegalArgumentException if filename is null or an empty string.
-   * @throws FileNotFoundException if the specified filename could not be found
-   * @throws IOException if the specified filename could not be opened
-   */
-  public static VoicetagItem create(String filename, VoicetagItemListener listener) throws IllegalArgumentException,FileNotFoundException,IOException
-  {
-        return VoicetagItemImpl.create(filename,listener);
-  }
-  /**
-   * Returns the audio used to construct the VoicetagItem.
-   * The audio is in PCM format and is start-pointed and end-pointed. The audio
-   * is only generated if the enableGetWaveform recognition parameter
-   * is set prior to recognition.
-   *
-   * @throws IllegalStateException if the recognition parameter 'enableGetWaveform' is not set
-   * @return the audio used to construct the VoicetagItem.
-   */
-  public abstract byte[] getAudio() throws IllegalStateException;
-
-  /**
-   * Sets the audio used to construct the Voicetag. The
-   * audio is in PCM format and is start-pointed and end-pointed. The audio is
-   * only generated if the enableGetWaveform recognition parameter is set
-   * prior to recognition.
-   *
-   * @param waveform the endpointed waveform
-   * @throws IllegalArgumentException if waveform is null or empty.
-   * @throws IllegalStateException if the recognition parameter 'enableGetWaveform' is not set
-   */
-  public abstract void setAudio(byte[] waveform) throws IllegalArgumentException,IllegalStateException;
- 
-   /**
-   * Save the Voicetag Item.
-   *
-   * @param path where the Voicetag will be saved. We strongly recommend to set the filename with the same value of the VoicetagId.
-   * @throws IllegalArgumentException if path is null or an empty string.
-   */
-   public abstract void save(String path) throws IllegalArgumentException,IllegalStateException;
-  
-   /**
-   * Load a Voicetag Item.
-   *
-   * @throws IllegalStateException if voicetag has not been created from a file.
-   */
-   public abstract void load() throws IllegalStateException;
-
-}
diff --git a/core/java/android/speech/recognition/VoicetagItemListener.java b/core/java/android/speech/recognition/VoicetagItemListener.java
deleted file mode 100644
index 610d1c7..0000000
--- a/core/java/android/speech/recognition/VoicetagItemListener.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  VoicetagItemListener.java                                                 *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-/**
- * Listens for VoicetagItem events.
- */
-public interface VoicetagItemListener
-{
-   /**
-   * Invoked after the Voicetag is saved.
-   *
-   * @param path the path the Voicetag was saved to
-   */
-  void onSaved(String path);
-  
-   /**
-   * Invoked after the Voicetag is loaded.
-   */
-  void onLoaded();
-  
-  /**
-   * Invoked when a grammar operation fails.
-   *
-   * @param e the cause of the failure.<br/>
-   * {@link java.io.IOException} if the Voicetag could not be loaded or
-   * saved.</p>
-   * {@link java.io.FileNotFoundException} if the specified file could not be found
-   */
-  void onError(Exception e);
-  
-}
diff --git a/core/java/android/speech/recognition/WordItem.java b/core/java/android/speech/recognition/WordItem.java
deleted file mode 100644
index 5c21c98..0000000
--- a/core/java/android/speech/recognition/WordItem.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  WordItem.java                                                            *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition;
-
-import android.speech.recognition.impl.WordItemImpl;
-
-/**
- * Word that may be inserted into an embedded grammar slot.
- */
-public abstract class WordItem implements SlotItem
-{
-  /**
-   * Creates a new WordItem.
-   *
-   * @param word the word to insert
-   * @param pronunciations the pronunciations to associated with the item. If the list is
-   * is empty (example:new String[0]) the recognizer will attempt to guess the pronunciations.
-   * @return the WordItem
-   * @throws IllegalArgumentException if word is null or if pronunciations is
-   * null or pronunciations contains an element equal to null or empty string.
-   */
-  public static WordItem valueOf(String word, String[] pronunciations) throws IllegalArgumentException
-  {
-    return WordItemImpl.valueOf(word, pronunciations);
-  }
-
-  /**
-   * Creates a new WordItem.
-   *
-   * @param word the word to insert
-   * @param pronunciation the pronunciation to associate with the item. If it
-   * is null the recognizer will attempt to guess the pronunciations.
-   * @return the WordItem
-   * @throws IllegalArgumentException if word is null or if pronunciation is
-   * an empty string
-   */
-  public static WordItem valueOf(String word, String pronunciation) throws IllegalArgumentException
-  {
-    return WordItemImpl.valueOf(word, pronunciation);
-  }
-}
diff --git a/core/java/android/speech/recognition/impl/AudioStreamImpl.java b/core/java/android/speech/recognition/impl/AudioStreamImpl.java
deleted file mode 100644
index 730e2d9..0000000
--- a/core/java/android/speech/recognition/impl/AudioStreamImpl.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  AudioStreamImpl.java                                                     *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.AudioStream;
-
-/**
- */
-public class AudioStreamImpl implements AudioStream, Runnable
-{
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-
-  /**
-   * Creates a new AudioStreamImpl.
-   *
-   * @param nativeObj a reference to the native object
-   */
-  public AudioStreamImpl(long nativeObj)
-  {
-     nativeObject = nativeObj;
-  }
-
-  public synchronized void run()
-  {
-    dispose();
-  }
-
-  public long getNativeObject() { 
-     synchronized (AudioStreamImpl.class)
-     {
-        return nativeObject;
-     }
-  }
-  
-  /**
-   * Releases the native resources associated with the object.
-   */
-  @SuppressWarnings("deprecation")
-  public void dispose()
-  {
-    synchronized (AudioStreamImpl.class)
-    {
-        if (nativeObject != 0)
-        {
-            deleteNativeObject(nativeObject);
-            nativeObject = 0;
-        }
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  /**
-   * Deletes a native object.
-   *
-   * @param nativeObject pointer to the native object
-   */
-  private native void deleteNativeObject(long nativeObject);
-}
diff --git a/core/java/android/speech/recognition/impl/DeviceSpeakerImpl.java b/core/java/android/speech/recognition/impl/DeviceSpeakerImpl.java
deleted file mode 100644
index 5d72110..0000000
--- a/core/java/android/speech/recognition/impl/DeviceSpeakerImpl.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  DeviceSpeakerImpl.java                                                   *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.AudioStream;
-import android.speech.recognition.Codec;
-import android.speech.recognition.DeviceSpeaker;
-import android.speech.recognition.DeviceSpeakerListener;
-
-/**
- */
-public class DeviceSpeakerImpl extends DeviceSpeaker implements Runnable
-{
-  private static DeviceSpeakerImpl instance;
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-  private DeviceSpeakerListener locallistener;
-
-  /**
-   * Private constructor
-   */
-  private DeviceSpeakerImpl()
-  {
-    System system = System.getInstance();
-    nativeObject = initNativeObject();
-    if (nativeObject != 0)
-      system.register(this);
-  }
-
-  public void run()
-  {
-    dispose();
-  }
-
-  /**
-   * Returns the singleton instance.
-   *
-   * @return the singleton instance
-   */
-  public static DeviceSpeakerImpl getInstance()
-  {
-     synchronized (DeviceSpeakerImpl.class)
-     {
-        if (instance == null)
-            instance = new DeviceSpeakerImpl();
-        return instance;
-     }
-  }
-
-  /**
-   * Start audio playback.
-   *
-   * @param source the audio to play
-   */
-  public void start(AudioStream source)
-  {
-     synchronized (DeviceSpeakerImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        AudioStreamImpl src = (AudioStreamImpl)source;
-        startProxy(nativeObject,src.getNativeObject());
-        src = null;
-     }
-  }
-
-  /**
-   * Stops audio playback.
-   */
-  public void stop()
-  {
-     synchronized (DeviceSpeakerImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        stopProxy(nativeObject);
-     }
-  }
-
-  /**
-   * Set the playback codec. This must be called before start is called.
-   * @param playbackCodec the codec to use for the playback operation.
-   */
-  public void setCodec(Codec playbackCodec)
-  {
-     synchronized (DeviceSpeakerImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        setCodecProxy(nativeObject,playbackCodec);
-     }
-  }
-
-  /**
-   * set the microphone listener.
-   * @param listener the device speaker listener.
-   */
-  public void setListener(DeviceSpeakerListener listener)
-  {
-     synchronized (DeviceSpeakerImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        locallistener = listener;
-        setListenerProxy(nativeObject,listener);
-     }
-  }
-
-  /**
-   * Releases the native resources associated with the object.
-   */
-  private void dispose()
-  {
-     synchronized (DeviceSpeakerImpl.class)
-     {
-        if (nativeObject != 0)
-        {
-            deleteNativeObject(nativeObject);
-            nativeObject = 0;
-            instance = null;
-            locallistener = null;
-            System.getInstance().unregister(this);
-        }
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  private native long initNativeObject();
-
-  private native void startProxy(long nativeObject, long audioNativeObject);
-
-  private native void stopProxy(long nativeObject);
-
-  private native void setCodecProxy(long nativeObject,Codec playbackCodec);
-
-  private native void setListenerProxy(long nativeObject,DeviceSpeakerListener listener);
-
-  private native void deleteNativeObject(long nativeObject);
-}
diff --git a/core/java/android/speech/recognition/impl/EmbeddedGrammarImpl.java b/core/java/android/speech/recognition/impl/EmbeddedGrammarImpl.java
deleted file mode 100644
index 0b88cb2..0000000
--- a/core/java/android/speech/recognition/impl/EmbeddedGrammarImpl.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  EmbeddedGrammarImpl.java                                                 *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.EmbeddedGrammar;
-
-/**
- */
-public class EmbeddedGrammarImpl extends GrammarImpl implements EmbeddedGrammar
-{
-  /**
-   * Creates a new EmbeddedGrammarImpl.
-   *
-   * @param nativeObject a reference to the native object
-   */
-  public EmbeddedGrammarImpl(long nativeObject)
-  {
-    super(nativeObject);
-  }
-
-  public void compileAllSlots()
-  {
-     synchronized (GrammarImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        compileAllSlotsProxy(nativeObject);
-     }
-  }
-
-  public void resetAllSlots()
-  {
-     synchronized (GrammarImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        resetAllSlotsProxy(nativeObject);
-     }
-  }
-
-  public void save(String url)
-  {
-     synchronized (GrammarImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        saveProxy(nativeObject, url.toString());
-     }
-  }
-
-  private native void compileAllSlotsProxy(long nativeObject);
-
-  private native void resetAllSlotsProxy(long nativeObject);
-
-  private native void saveProxy(long nativeObject, String url);
-}
diff --git a/core/java/android/speech/recognition/impl/EmbeddedRecognizerImpl.java b/core/java/android/speech/recognition/impl/EmbeddedRecognizerImpl.java
deleted file mode 100644
index f04bfe4..0000000
--- a/core/java/android/speech/recognition/impl/EmbeddedRecognizerImpl.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  EmbeddedRecognizerImpl.java                                              *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Hashtable;
-import java.util.Vector;
-import android.speech.recognition.EmbeddedRecognizer;
-import android.speech.recognition.Grammar;
-import android.speech.recognition.AudioStream;
-import android.speech.recognition.Grammar;
-import android.speech.recognition.RecognizerListener;
-import android.speech.recognition.GrammarListener;
-
-/**
- */
-public class EmbeddedRecognizerImpl extends EmbeddedRecognizer implements Runnable
-{
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-  /**
-   * The singleton instance.
-   */
-  private static EmbeddedRecognizerImpl instance;
-
-  /**
-   * Creates a new instance.
-   */
-  EmbeddedRecognizerImpl()
-  {
-    System system = System.getInstance();
-    nativeObject = getInstanceProxy();
-    if (nativeObject != 0)
-      system.register(this);
-  }
-
-  /**
-   * Returns the singleton instance.
-   *
-   * @return the singleton instance
-   */
-  public synchronized static EmbeddedRecognizerImpl getInstance()
-  {
-     synchronized (EmbeddedRecognizerImpl.class)
-     {
-        if (instance == null)
-            instance = new EmbeddedRecognizerImpl();
-        return instance;
-     }
-  }
-
-  public void run()
-  {
-    dispose();
-  }
-
-  /**
-   * Releases the native resources associated with the object.
-   */
-  private void dispose()
-  {
-     synchronized (EmbeddedRecognizerImpl.class)
-     {
-        if (instance != null)
-        {
-            deleteNativeObject(nativeObject);
-            nativeObject = 0;
-            instance = null;
-            System.getInstance().unregister(this);
-        }
-     }
-  }
-
-  public void configure(String config) throws IllegalArgumentException,
-    FileNotFoundException, IOException, UnsatisfiedLinkError,
-    ClassNotFoundException
-  {
-     synchronized (EmbeddedRecognizerImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        if (config == null)
-            throw new IllegalArgumentException("Configuration Is Null.");
-        configureProxy(nativeObject,config);
-     }
-  }
-
-  public void setListener(RecognizerListener listener)
-  {
-     synchronized (EmbeddedRecognizerImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        setListenerProxy(nativeObject,listener);
-     }
-  }
-
-   public Grammar createGrammar(String value, GrammarListener listener) 
-        throws IllegalArgumentException
-  {
-     synchronized (EmbeddedRecognizerImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        long nativeGrammar = createEmbeddedGrammarProxy(nativeObject,value.toString(), listener);
-        return new SrecGrammarImpl(nativeGrammar);
-     }
-  }
-
-  public void resetAcousticState()
-  {
-    synchronized (EmbeddedRecognizerImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        resetAcousticStateProxy(nativeObject);
-    }
-  }
-
-  public void recognize(AudioStream audio,
-    Vector<Grammar> grammars)
-  {
-    synchronized (EmbeddedRecognizerImpl.class)
-    {
-        if (nativeObject == 0)
-         throw new IllegalStateException("Object was destroyed.");
-
-        if (audio == null)
-          throw new IllegalArgumentException("AudioStream cannot be null.");
-
-        if (grammars == null || grammars.isEmpty() == true)
-          throw new IllegalArgumentException("Grammars are null or empty.");
-        int grammarCount = grammars.size();
-
-        long[] nativeGrammars = new long[grammarCount];
-
-        for (int i = 0; i < grammarCount; ++i)
-          nativeGrammars[i] = ((GrammarImpl) grammars.get(i)).getNativeObject();
-
-        recognizeProxy(nativeObject,((AudioStreamImpl)audio).getNativeObject(), nativeGrammars);
-    }
-  }
-
-  public void recognize(AudioStream audio,
-    Grammar grammar)
-  {
-    synchronized (EmbeddedRecognizerImpl.class)
-    {
-        if (nativeObject == 0)
-         throw new IllegalStateException("Object was destroyed.");
-    }
-    Vector<Grammar> grammars = new Vector<Grammar>();
-    grammars.add(grammar);
-    recognize(audio, grammars);
-  }
-
-  public  void stop()
-  {
-    synchronized (EmbeddedRecognizerImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        stopProxy(nativeObject);
-    }
-  }
-
-  public void setParameters(Hashtable<String, String> params)
-  {
-    synchronized (EmbeddedRecognizerImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        setParametersProxy(nativeObject,params);
-    }
-  }
-
-  public void getParameters(Vector<String> params)
-  {
-    synchronized (EmbeddedRecognizerImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        getParametersProxy(nativeObject,params);
-    }
-  }
-
-  /**
-   * Returns the native EmbeddedRecognizer.
-   *
-   * @return a reference to the native object
-   */
-  private native long getInstanceProxy();
-
-  /**
-   * Configures the recognizer instance.
-   *
-   * @param config the recognizer configuration file
-   */
-  private native void configureProxy(long nativeObject, String config) throws IllegalArgumentException,
-    FileNotFoundException, IOException, UnsatisfiedLinkError,
-    ClassNotFoundException;
-
-  /**
-   * Sets the recognizer listener.
-   *
-   * @param listener listens for recognizer events
-   */
-  private native void setListenerProxy(long nativeObject, RecognizerListener listener);
-
-  private native void recognizeProxy(long nativeObject, long audioNativeObject,
-    long[] pGrammars);
-
-  private native long createEmbeddedGrammarProxy(long nativeObject, String url,
-    GrammarListener listener);
-
-  private native void stopProxy(long nativeObject);
-
-  private native void deleteNativeObject(long nativeObject);
-
-  private native void setParametersProxy(long nativeObject, Hashtable<String, String> params);
-
-  private native void getParametersProxy(long nativeObject, Vector<String> params);
-
-  private native void resetAcousticStateProxy(long nativeObject);
-
-}
diff --git a/core/java/android/speech/recognition/impl/EntryImpl.java b/core/java/android/speech/recognition/impl/EntryImpl.java
deleted file mode 100644
index 91b2b78..0000000
--- a/core/java/android/speech/recognition/impl/EntryImpl.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  EntryImpl.java                                                           *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.NBestRecognitionResult;
-import java.util.Enumeration;
-
-/**
- */
-public class EntryImpl implements NBestRecognitionResult.Entry, Runnable
-{
-  private long nativeObject;
-
-  /**
-   * This implementation is a work-around to solve Q bug with
-   * nested classes.
-   *
-   * @param nativeObject the native NBestRecognitionResult.Entry object
-   */
-  public EntryImpl(long nativeObject)
-  {
-    this.nativeObject = nativeObject;
-  }
-
-  public void run()
-  {
-    dispose();
-  }
-
-  public byte getConfidenceScore() throws IllegalStateException
-  {
-    synchronized (EntryImpl.class)
-    {
-        if (nativeObject == 0)
-          throw new IllegalStateException("Object has been disposed");
-        return getConfidenceScoreProxy(nativeObject);
-    }
-  }
-
-  public String getLiteralMeaning() throws IllegalStateException
-  {
-    synchronized (EntryImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        return getLiteralMeaningProxy(nativeObject);
-    }
-  }
-
-  public String getSemanticMeaning() throws IllegalStateException
-  {
-    synchronized (EntryImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        return getSemanticMeaningProxy(nativeObject);
-    }
-  }
- 
-  public String get(String key)
-  {
-    synchronized (EntryImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        return getProxy(nativeObject,key);
-    }
-  }
-
-  public Enumeration keys()
-  {
-    synchronized (EntryImpl.class)
-    {
-        if (nativeObject == 0)
-          throw new IllegalStateException("Object has been disposed");
-
-          return new Enumeration()
-          {
-            private String[] keys = keysProxy(nativeObject);
-            private int indexOfNextRead = 0;
-
-            public boolean hasMoreElements()
-            {
-              return indexOfNextRead <= keys.length-1;
-            }
-
-            public Object nextElement()
-            {
-              return keys[indexOfNextRead++];
-            }
-          };
-    }
-  }
-
-
-  /**
-   * Releases the native resources associated with the object.
-   */
-  private void dispose()
-  {
-    synchronized (EntryImpl.class)
-    {
-        if (nativeObject != 0)
-        {
-            deleteNativeObject(nativeObject);
-            nativeObject = 0;
-        }
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  private native void deleteNativeObject(long nativeObject);
-
-  private native String getLiteralMeaningProxy(long nativeObject);
-
-  private native String getSemanticMeaningProxy(long nativeObject);
-
-  private native byte getConfidenceScoreProxy(long nativeObject);
-  
-  private native String getProxy(long nativeObject,String key);
-
-  private native String[] keysProxy(long nativeObject);
-
-}
diff --git a/core/java/android/speech/recognition/impl/GrammarImpl.java b/core/java/android/speech/recognition/impl/GrammarImpl.java
deleted file mode 100644
index 563d5d9..0000000
--- a/core/java/android/speech/recognition/impl/GrammarImpl.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  GrammarImpl.java                                                         *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.Grammar;
-
-/**
- */
-public class GrammarImpl implements Grammar, Runnable
-{
-  /**
-   * Reference to the native object.
-   */
-  protected long nativeObject;
-
-  /**
-   * Creates a new GrammarImpl.
-   *
-   * @param nativeObj a reference to the native object
-   */
-  public GrammarImpl(long nativeObj)
-  {
-    nativeObject = nativeObj;
-  }
-
-  public void run()
-  {
-    dispose();
-  }
-
-  public long getNativeObject() 
-  { 
-     synchronized (GrammarImpl.class)
-     {
-        return nativeObject;
-     }
-  }
-  
-  /**
-   * Indicates that the grammar will be used in the near future.
-   */
-  public void load()
-  {
-     synchronized (GrammarImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        loadProxy(nativeObject);
-     }
-  }
-
-  /**
-   * The grammar will be removed from use.
-   */
-  public void unload()
-  {
-     synchronized (GrammarImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        unloadProxy(nativeObject);
-     }
-  }
-
-  /**
-   * Releases the native resources associated with the object.
-   */
-  public void dispose()
-  {
-    synchronized (GrammarImpl.class)
-    {
-        if (nativeObject != 0)
-        {
-            deleteNativeObject(nativeObject);
-            nativeObject = 0;
-        }
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  /**
-   * Deletes a native object.
-   *
-   * @param nativeObject pointer to the native object
-   */
-  private native void deleteNativeObject(long nativeObject);
-
-  private native void loadProxy(long nativeObject);
-
-  private native void unloadProxy(long nativeObject);
-}
diff --git a/core/java/android/speech/recognition/impl/LoggerImpl.java b/core/java/android/speech/recognition/impl/LoggerImpl.java
deleted file mode 100644
index 9933c56..0000000
--- a/core/java/android/speech/recognition/impl/LoggerImpl.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  LoggerImpl.java                                                          *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.Logger;
-
-/**
- */
-public class LoggerImpl extends Logger implements Runnable
-{
-  private static LoggerImpl instance;
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-
-  /**
-   * Creates a new instance of LoggerImpl.
-   *
-   * @param function the name of the enclosing function
-   */
-  private LoggerImpl()
-  {
-    System system = System.getInstance();
-    nativeObject = initNativeObject();
-    if (nativeObject!=0)
-         system.register(this);
-  }
-
-  public void run()
-  {
-    dispose();
-  }
-
-  /**
-   * Returns the singleton instance.
-   *
-   * @return the singleton instance
-   */
-  public static LoggerImpl getInstance()
-  {
-    synchronized (LoggerImpl.class)
-    {
-        if (instance == null)
-            instance = new LoggerImpl();
-        return instance;
-    }
-  }
-
-  public void setLoggingLevel(LogLevel level)
-  {
-    synchronized (LoggerImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        setLoggingLevelProxy(nativeObject,level);
-    }
-  }
-
-  public void setPath(String path)
-  {
-    synchronized (LoggerImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        setPathProxy(nativeObject,path);
-    }
-  }
-
-  public void error(String message)
-  {
-    synchronized (LoggerImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        errorProxy(nativeObject,message);
-    }
-  }
-
-  public void warn(String message)
-  {
-    synchronized (LoggerImpl.class)
-    {
-        if (nativeObject == 0)
-          throw new IllegalStateException("Object has been disposed");
-        warnProxy(nativeObject,message);
-    }
-  }
-
-  public  void info(String message)
-  {
-    synchronized (LoggerImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        infoProxy(nativeObject,message);
-    }
-  }
-
-  public void trace(String message)
-  {
-     synchronized (LoggerImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        traceProxy(nativeObject,message);
-     }
-  }
-
-  /**
-   * Releases the native resources associated with the object.
-   */
-  private void dispose()
-  {
-    synchronized (LoggerImpl.class)
-    {
-        if (nativeObject!=0) 
-        {
-            deleteNativeObject(nativeObject);
-            System.getInstance().unregister(this);
-        }
-        nativeObject = 0;
-        instance = null;
-    }
-  }
- 
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  private native long initNativeObject();
-
-  private native void setLoggingLevelProxy(long nativeObject, LogLevel level);
-
-  private native void setPathProxy(long nativeObject, String filename);
-
-  private native void errorProxy(long nativeObject, String message);
-
-  private native void warnProxy(long nativeObject, String message);
-
-  private native void infoProxy(long nativeObject, String message);
-
-  private native void traceProxy(long nativeObject,String message);
-
-  private native void deleteNativeObject(long nativeObject);
-}
diff --git a/core/java/android/speech/recognition/impl/MediaFileReaderImpl.java b/core/java/android/speech/recognition/impl/MediaFileReaderImpl.java
deleted file mode 100644
index 8ce643d..0000000
--- a/core/java/android/speech/recognition/impl/MediaFileReaderImpl.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  MediaFileReaderImpl.java                                                 *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.MediaFileReader;
-import android.speech.recognition.AudioStream;
-import android.speech.recognition.Codec;
-import android.speech.recognition.AudioSourceListener;
-
-/**
- */
-public class MediaFileReaderImpl extends MediaFileReader implements Runnable
-{
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-
-  /**
-   * Creates a new MediaFileReaderImpl.
-   *
-   * @param filename the name of the file to read from
-   * @param listener listens for MediaFileReader events
-   */
-  public MediaFileReaderImpl(String filename, AudioSourceListener listener)
-  {
-    System system = System.getInstance();
-    nativeObject =
-      createMediaFileReaderProxy(filename, listener);
-    if (nativeObject != 0)
-      system.register(this);
-  }
-
-  public void run()
-  {
-    dispose();
-  }
-
-  /**
-   * Set the reading mode
-   */
-  public void setMode(Mode mode)
-  {
-    synchronized (MediaFileReaderImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        setModeProxy(nativeObject,mode);
-    }
-  }
-
-  /**
-   * Creates an audioStream source
-   */
-  public AudioStream createAudio()
-  {
-    synchronized (MediaFileReaderImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        return new AudioStreamImpl(createAudioProxy(nativeObject));
-    }
-  }
-
-  /**
-   * Tells the audio source to start collecting audio samples.
-   */
-  public void start()
-  {
-     synchronized (MediaFileReaderImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        startProxy(nativeObject);
-     }
-  }
-
-  /**
-   * Stops this source from collecting audio samples.
-   */
-  public void stop()
-  {
-    synchronized (MediaFileReaderImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        stopProxy(nativeObject);
-    }
-  }
-
-  /**
-   * Releases the native resources associated with the object.
-   */
-  public void dispose()
-  {
-    synchronized (MediaFileReaderImpl.class)
-    {
-        if (nativeObject != 0)
-        {
-          deleteNativeObject(nativeObject);
-          nativeObject = 0;
-          System.getInstance().unregister(this);
-        }
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  /**
-   * Deletes a native object.
-   *
-   * @param nativeObject pointer to the native object
-   */
-  private native void deleteNativeObject(long nativeObject);
-
-  /**
-   * Creates a native MediaFileReader.
-   *
-   * @param filename the name of the file to read from
-   * @param offset the offset to begin reading from
-   * @param codec the file audio format
-   * @param listener listens for MediaFileReader events
-   * @return a reference to the native object
-   */
-  private native long createMediaFileReaderProxy(String filename, AudioSourceListener listener);
-
-  private native void setModeProxy(long nativeObject,Mode mode);
-
-  private native long createAudioProxy(long nativeObject);
-
-  private native void startProxy(long nativeObject);
-
-  private native void stopProxy(long nativeObject);
-}
diff --git a/core/java/android/speech/recognition/impl/MediaFileWriterImpl.java b/core/java/android/speech/recognition/impl/MediaFileWriterImpl.java
deleted file mode 100644
index c4bd836..0000000
--- a/core/java/android/speech/recognition/impl/MediaFileWriterImpl.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  MediaFileWriterImpl.java                                                 *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.AudioStream;
-import android.speech.recognition.MediaFileWriter;
-import android.speech.recognition.MediaFileWriterListener;
-
-/**
- */
-public class MediaFileWriterImpl extends MediaFileWriter implements Runnable
-{
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-
-  /**
-   * Creates a new MediaFileWriterImpl.
-   *
-   * @param listener listens for MediaFileWriter events
-   */
-  public MediaFileWriterImpl(MediaFileWriterListener listener)
-  {
-    System system = System.getInstance();
-    nativeObject = createMediaFileWriterProxy(listener);
-    if (nativeObject != 0)
-      system.register(this);
-  }
-
-  public void run()
-  {
-    dispose();
-  }
-
-  public void save(AudioStream source, String filename)
-  {
-    synchronized (MediaFileWriterImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        saveProxy(nativeObject,((AudioStreamImpl)source).getNativeObject(), filename);
-    }
-  }
-
-  /**
-   * Releases the native resources associated with the object.
-   */
-  public synchronized void dispose()
-  { 
-     synchronized (MediaFileWriterImpl.class)
-     {
-        if (nativeObject != 0)
-        {
-          deleteNativeObject(nativeObject);
-          nativeObject = 0;
-          System.getInstance().unregister(this);
-        }
-     }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  /**
-   * Creates a native MediaFileWriter.
-   *
-   * @param listener listens for MediaFileReader events
-   * @return a reference to the native object
-   */
-  private native long createMediaFileWriterProxy(MediaFileWriterListener listener);
-
-  /**
-   * Deletes a native object.
-   *
-   * @param nativeObject pointer to the native object
-   */
-  private native void deleteNativeObject(long nativeObject);
-
-  private native void saveProxy(long nativeObject, long audioNativeObject, String filename);
-}
diff --git a/core/java/android/speech/recognition/impl/MicrophoneImpl.java b/core/java/android/speech/recognition/impl/MicrophoneImpl.java
deleted file mode 100644
index a915484..0000000
--- a/core/java/android/speech/recognition/impl/MicrophoneImpl.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  MicrophoneImpl.java                                                      *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.AudioStream;
-import android.speech.recognition.Codec;
-import android.speech.recognition.Microphone;
-import android.speech.recognition.AudioSourceListener;
-
-/**
- */
-public class MicrophoneImpl extends Microphone implements Runnable
-{
-  private static MicrophoneImpl instance;
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-
-  /**
-   * Creates a new MicrophoneImpl.
-   *
-   * @param nativeObj a reference to the native object
-   */
-  private MicrophoneImpl()
-  {
-    System system = System.getInstance();
-    nativeObject = initNativeObject();
-    if (nativeObject != 0)
-      system.register(this);
-  }
-
-  public void run()
-  {
-    dispose();
-  }
-
-  /**
-   * Returns the singleton instance.
-   *
-   * @return the singleton instance
-   */
-  public static MicrophoneImpl getInstance()
-  {
-    synchronized (MicrophoneImpl.class)
-    {
-        if (instance == null)
-            instance = new MicrophoneImpl();
-        return instance;
-    }
-  }
-
-  /**
-   * set the recording codec. This must be called before Start is called.
-   * @param recordingCodec the codec in which the samples will be recorded.
-   */
-  public void setCodec(Codec recordingCodec)
-  {
-    synchronized (MicrophoneImpl.class)
-    {
-        if (nativeObject == 0)
-          throw new IllegalStateException("Object has been disposed");
-        setCodecProxy(nativeObject,recordingCodec);
-    }
-  }
-
-  /**
-   * set the microphone listener.
-   * @param listener the microphone listener.
-   */
-  public void setListener(AudioSourceListener listener)
-  {
-    synchronized (MicrophoneImpl.class)
-    {       
-        if (nativeObject == 0)
-          throw new IllegalStateException("Object has been disposed");
-        setListenerProxy(nativeObject,listener);
-    }
-  }
-
-  public AudioStream createAudio()
-  {
-    synchronized (MicrophoneImpl.class)
-    {
-        if (nativeObject == 0)
-          throw new IllegalStateException("Object has been disposed");
-        return new AudioStreamImpl(createAudioProxy(nativeObject));
-    }
-  }
-
-  public void start()
-  {
-     synchronized (MicrophoneImpl.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        startProxy(nativeObject);
-     }
-  }
-
-  public void stop()
-  {
-    synchronized (MicrophoneImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        stopProxy(nativeObject);
-    }
-  }
-
-  /**
-   * Releases the native resources associated with the object.
-   */
-  private void dispose()
-  {
-    synchronized (MicrophoneImpl.class)
-    {
-        if (nativeObject != 0)
-        {
-          deleteNativeObject(nativeObject);
-          nativeObject = 0;
-          instance = null;
-          System.getInstance().unregister(this);
-        }
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  private native long initNativeObject();
-
-  private native void setCodecProxy(long nativeObject,Codec recordingCodec);
-
-  private native void setListenerProxy(long nativeObject, AudioSourceListener listener);
-
-  private native long createAudioProxy(long nativeObject);
-
-  private native void startProxy(long nativeObject);
-
-  private native void stopProxy(long nativeObject);
-
-  private native void deleteNativeObject(long nativeObject);
-}
diff --git a/core/java/android/speech/recognition/impl/NBestRecognitionResultImpl.java b/core/java/android/speech/recognition/impl/NBestRecognitionResultImpl.java
deleted file mode 100644
index 4d2e00a..0000000
--- a/core/java/android/speech/recognition/impl/NBestRecognitionResultImpl.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  NBestRecognitionResultImpl.java                                          *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.NBestRecognitionResult;
-import android.speech.recognition.VoicetagItem;
-import android.speech.recognition.VoicetagItemListener;
-/**
- */
-public class NBestRecognitionResultImpl implements NBestRecognitionResult
-{
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-
-  /**
-   * Creates a new NBestRecognitionResultImpl.
-   *
-   * @param nativeObject a reference to the native object
-   */
-  public NBestRecognitionResultImpl(long nativeObject)
-  {
-    this.nativeObject = nativeObject;
-  }
-
-  public int getSize()
-  {
-    synchronized (NBestRecognitionResultImpl.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-        return getSizeProxy(nativeObject);
-    }
-  }
-
-  public Entry getEntry(int index)
-  {
-    synchronized (NBestRecognitionResultImpl.class)
-    {
-        if (nativeObject == 0)
-          throw new IllegalStateException("Object has been disposed");
-        long nativeEntryObject = getEntryProxy(nativeObject,index);
-        if (nativeEntryObject==0)
-          return null;
-        else
-          return new EntryImpl(nativeEntryObject);
-    }
-  }
-
-  public VoicetagItem createVoicetagItem(String VoicetagId, VoicetagItemListener listener)
-  {
-    synchronized (NBestRecognitionResultImpl.class)
-    {
-        if (nativeObject == 0)
-          throw new IllegalStateException("Object has been disposed");
-        if ((VoicetagId == null) || (VoicetagId.length() == 0))
-          throw new IllegalArgumentException("VoicetagId may not be null or empty string.");
-        return new VoicetagItemImpl(createVoicetagItemProxy(nativeObject,VoicetagId,listener),false);
-     }
-  }
-
-  /**
-   * Releases the native resources associated with the object.
-   */
-  private void dispose()
-  {
-    synchronized (NBestRecognitionResultImpl.class)
-    {
-        nativeObject = 0;
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  /**
-   * Returns a reference to the native VoicetagItem.
-   */
-  private native long createVoicetagItemProxy(long nativeObject, String VoicetagId, VoicetagItemListener listener);
-
-  private native long getEntryProxy(long nativeObject, int index);
-
-  private native int getSizeProxy(long nativeObject);
-}
diff --git a/core/java/android/speech/recognition/impl/SrecGrammarImpl.java b/core/java/android/speech/recognition/impl/SrecGrammarImpl.java
deleted file mode 100644
index cb6f4c6..0000000
--- a/core/java/android/speech/recognition/impl/SrecGrammarImpl.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  SrecGrammarImpl.java                                                     *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.SrecGrammar;
-import android.speech.recognition.SlotItem;
-import android.speech.recognition.VoicetagItem;
-import android.speech.recognition.WordItem;
-
-import java.util.Vector;
-
-/**
- */
-public class SrecGrammarImpl extends EmbeddedGrammarImpl implements SrecGrammar
-{
-  /**
-   * Creates a new SrecGrammarImpl.
-   *
-   * @param nativeObject the native object
-   */
-  public SrecGrammarImpl(long nativeObject)
-  {
-    super(nativeObject);
-  }
-
-  public void addItem(String slotName, SlotItem item, int weight,
-    String semanticValue)
-  {
-     synchronized (GrammarImpl.class)
-     {
-          if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-
-        if (slotName == null || slotName.length()==0)
-             throw new IllegalArgumentException("addItem() - Slot name is null or empty.");
-        if (item == null)
-             throw new IllegalArgumentException("addItem() - item can't be null.");
-        if (semanticValue == null || semanticValue.length()==0)
-             throw new IllegalArgumentException("addItem() - semanticValue is null or empty.");
-
-        long itemNativeObject = 0;
-        if  (item instanceof VoicetagItem)
-            itemNativeObject = ((VoicetagItemImpl)item).getNativeObject();
-        else if  (item instanceof WordItem)
-            itemNativeObject = ((WordItemImpl)item).getNativeObject();
-        else
-           throw new IllegalArgumentException("SlotItem - should be a WordItem or a VoicetagItem object.");
-
-        addItemProxy(nativeObject, slotName, itemNativeObject, weight, semanticValue);
-     }
-  }
- 
-  public void addItemList(String slotName, Vector<Item> items)
-  {
-     synchronized (GrammarImpl.class)
-     {
-          if (nativeObject == 0)
-            throw new IllegalStateException("Object has been disposed");
-
-          if (slotName == null || slotName.length()==0)
-                  throw new IllegalArgumentException("addItemList - Slot name is null or empty.");
-          if (items == null || items.isEmpty() == true)
-                throw new IllegalArgumentException("addItemList - Items is null or empty.");
-
-          int itemsCount = items.size();
-
-          long[]     nativeSlots    = new long[itemsCount];
-          int[]      nativeWeights  = new int[itemsCount];
-          String[]   nativeSemantic = new String[itemsCount];
-
-          Item element = null;
-          long itemNativeObject = 0;
-          SlotItem item = null;
-          for (int i = 0; i < itemsCount; ++i)
-          {
-            element = items.get(i);
-
-            item = element._item;
-            if  (item instanceof VoicetagItem)
-                itemNativeObject = ((VoicetagItemImpl)item).getNativeObject();
-            else if  (item instanceof WordItem)
-                itemNativeObject = ((WordItemImpl)item).getNativeObject();
-            else
-            {
-               throw new IllegalArgumentException("SlotItem ["+i+"] - should be a WordItem or a VoicetagItem object.");
-            }
-            nativeSlots[i] = itemNativeObject;
-            nativeWeights[i] = element._weight;
-            nativeSemantic[i]= element._semanticMeaning;
-            itemNativeObject = 0;
-            item = null;
-          }
-          addItemListProxy(nativeObject, slotName,nativeSlots,nativeWeights,nativeSemantic);
-     }
-  }
-  
-  private native void addItemProxy(long nativeObject, String slotName, long item, int weight,
-    String semanticValue);
-  
-  private native void addItemListProxy(long nativeObject, String slotName, long[] items,
-          int[] weights, String[] semanticValues);
-  
-}
diff --git a/core/java/android/speech/recognition/impl/System.java b/core/java/android/speech/recognition/impl/System.java
deleted file mode 100644
index 23418fea..0000000
--- a/core/java/android/speech/recognition/impl/System.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  System.java                                                              *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import java.lang.ref.WeakReference;
-import java.util.WeakHashMap;
-
-
-/**
- */
-public class System
-{
-  private static boolean libraryLoaded;
-  private static System instance;
-  private static WeakHashMap<Object, WeakReference> registerMap;
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-  private boolean shutdownRequested;
-
-  /**
-   * Creates a new instance of System
-   */
-  private System()
-  {
-    shutdownRequested = false;
-    registerMap =
-      new WeakHashMap<Object, WeakReference>();
-    initLibrary();
-    nativeObject = initNativeObject();
-        Runtime.getRuntime().
-      addShutdownHook(new Thread()
-    {
-      @Override
-      public void run()
-      {
-        try
-        {
-          dispose();
-        }
-        catch (Exception e)
-        {
-          e.printStackTrace();
-        }
-      }
-    });
-
-  }
-
-  /**
-   * Returns the singleton instance.
-   *
-   * @return the singleton instance
-   */
-  public static System getInstance()
-  {
-    synchronized (System.class)
-    {
-      if (instance == null)
-        instance = new System();
-      return instance;
-    }
-  }
-
-  /**
-   * Loads the native library if necessary.
-   */
-  private void initLibrary()
-  {
-    if (!libraryLoaded)
-    {
-      java.lang.System.loadLibrary("UAPI_jni");
-      libraryLoaded = true;
-    }
-  }
-
-  /**
-   * Registers an object for shutdown when System.dispose() is invoked.
-   *
-   * @param r the code to run on shutdown
-   * @throws IllegalStateException if the System is shutting down
-   */
-  public void register(Runnable r) throws IllegalStateException
-  {
-    synchronized (System.class)
-    {
-      if (shutdownRequested)
-        throw new IllegalStateException("System is shutting down");
-      registerMap.put(r,
-        new WeakReference<Runnable>(r));
-    }
-  }
-
-  /**
-   * Registers an object for shutdown when System.dispose() is invoked.
-   *
-   * @param r the code to run on shutdown
-   */
-  public void unregister(Runnable r)
-  {
-    synchronized (System.class)
-    {
-      if (shutdownRequested)
-      {
-        // System.dispose() will end up removing all entries
-        return;
-      }
-      if (r!=null) registerMap.remove(r);
-    }
-  }
-
-  /**
-   * Releases the native resources associated with the object.
-   *
-   * @throws java.util.concurrent.TimeoutException if the operation timeouts
-   * @throws IllegalThreadStateException if a native thread error occurs
-   */
-  public void dispose() throws java.util.concurrent.TimeoutException,
-    IllegalThreadStateException
-  {
-    synchronized (System.class)
-    {
-      if (nativeObject == 0)
-        return;
-      shutdownRequested = true;
-    }
-
-    // Traverse the list of WeakReferences
-    // cast to a Runnable object if the weakrerefence is not null
-    // then call the run method.
-    for (Object o: registerMap.keySet())
-    {
-      WeakReference weakReference = registerMap.get(o);
-      Runnable r = (Runnable) weakReference.get();
-      if (r != null)
-        r.run();
-    }
-    registerMap.clear();
-
-    // Call the native dispose method
-    disposeProxy();
-    synchronized (System.class)
-    {
-      nativeObject = 0;
-      instance = null;
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  public static native String getAPIVersion();
-  
-  private static native long initNativeObject();
-
-  private static native void disposeProxy();
-}
diff --git a/core/java/android/speech/recognition/impl/VoicetagItemImpl.java b/core/java/android/speech/recognition/impl/VoicetagItemImpl.java
deleted file mode 100644
index f9db399..0000000
--- a/core/java/android/speech/recognition/impl/VoicetagItemImpl.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  VoicetagItemImpl.java                                                    *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.VoicetagItem;
-import android.speech.recognition.VoicetagItemListener;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-/**
- */
-public class VoicetagItemImpl  extends VoicetagItem implements Runnable
-{
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-  /**
-   * Voicetag has a filename need to be loaded before use it.
-   */
-  private boolean needToBeLoaded;
-  
-  /**
-   * Creates a new VoicetagItemImpl.
-   *
-   * @param nativeObject the pointer to the native object
-   */
-  public VoicetagItemImpl(long nativeObject, boolean fromfile)
-  {
-    this.nativeObject = nativeObject;
-    needToBeLoaded = fromfile;
-  }
-
-  public void run()
-  {
-    dispose();
-  }
-
-   /**
-   * Creates a VoicetagItem from a file
-   *
-   * @param filename filename for Voicetag
-   * @param listener listens for Voicetag events
-   * @return the resulting VoicetagItem
-   * @throws IllegalArgumentException if filename is null or an empty string.
-   * @throws FileNotFoundException if the specified filename could not be found
-   * @throws IOException if the specified filename could not be opened
-   */
-  public static VoicetagItem create(String filename, VoicetagItemListener listener) throws IllegalArgumentException,FileNotFoundException,IOException
-  {
-      if ((filename == null) || (filename.length() == 0))
-        throw new IllegalArgumentException("Filename may not be null or empty string.");
-       
-      VoicetagItemImpl voicetag = null;
-      long nativeVoicetag = createVoicetagProxy(filename,listener);
-      if (nativeVoicetag!=0)
-      {
-        voicetag = new VoicetagItemImpl(nativeVoicetag,true);
-      }
-      return voicetag;
-  }
-  /**
-   * Returns the audio used to construct the VoicetagItem.
-   */
-  public byte[] getAudio() throws IllegalStateException
-  {
-     synchronized (VoicetagItem.class)
-     {
-        if (nativeObject == 0)
-         throw new IllegalStateException("Object was destroyed.");
-
-        return getAudioProxy(nativeObject);
-     }
-  }
-
-  /**
-   * Sets the audio used to construct the Voicetag.
-   */
-  public void setAudio(byte[] waveform) throws IllegalArgumentException,IllegalStateException
-  {
-    synchronized (VoicetagItem.class)
-    {
-        if (nativeObject == 0)
-         throw new IllegalStateException("Object was destroyed.");
-
-         if ((waveform == null) || (waveform.length == 0))
-            throw new IllegalArgumentException("Waveform may not be null or empty.");
-         setAudioProxy(nativeObject,waveform);
-    }
-  }
-  
-  /**
-  * Save the Voicetag.
-  */
-  public void save(String path) throws IllegalArgumentException
-  {
-    synchronized (VoicetagItem.class)
-    {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        if ((path == null) || (path.length() == 0))
-            throw new IllegalArgumentException("Path may not be null or empty string.");
-        saveVoicetagProxy(nativeObject,path);
-    }
-  }
-  
-  /**
-  * Load a Voicetag.
-  */
-  public void load() throws IllegalStateException
-  {
-     synchronized (VoicetagItem.class)
-     {
-        if (nativeObject == 0)
-            throw new IllegalStateException("Object was destroyed.");
-        if (!needToBeLoaded) 
-           throw new IllegalStateException("This Voicetag was not created from a file, does not need to be loaded.");
-        loadVoicetagProxy(nativeObject);
-     }
- }
-  
-  public long getNativeObject() 
-  { 
-     synchronized (VoicetagItem.class)
-     {
-      return nativeObject;
-     }
-  }
-  
-  /**
-   * Releases the native resources associated with the object.
-   */
-  private void dispose()
-  {
-    synchronized (VoicetagItem.class)
-    {
-        if (nativeObject != 0)
-        {
-          deleteNativeObject(nativeObject);
-          nativeObject = 0;
-        }
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  
-  private static native long createVoicetagProxy(String filename, VoicetagItemListener listener);
-  /**
-  * (Optional operation) Returns the audio used to construct the Voicetag. The
-  * audio is in PCM format and is start-pointed and end-pointed. The audio is
-  * only generated if the enableGetWaveform recognition parameter is set
-  * prior to recognition.
-  *
-  * @see RecognizerParameters.enableGetWaveform
-  */
-  private native byte[] getAudioProxy(long nativeObject);
-
-  /**
-  * (Optional operation) Sets the audio used to construct the Voicetag. The
-  * audio is in PCM format and is start-pointed and end-pointed. The audio is
-  * only generated if the enableGetWaveform recognition parameter is set
-  * prior to recognition.
-  *
-  * @param waveform the endpointed waveform
-  */
-  private native void setAudioProxy(long nativeObject, byte[] waveform);
-   
-  /**
-  * Save the Voicetag Item.
-  */
-  private native void saveVoicetagProxy(long nativeObject, String path);
-   
-  /**
-  * Load a Voicetag Item.
-  */
-  private native void loadVoicetagProxy(long nativeObject);
-  
-  /**
-   * Deletes a native object.
-   *
-   * @param nativeObject pointer to the native object
-   */
-  private native void deleteNativeObject(long nativeObject);
-}
diff --git a/core/java/android/speech/recognition/impl/WordItemImpl.java b/core/java/android/speech/recognition/impl/WordItemImpl.java
deleted file mode 100644
index f0daa34..0000000
--- a/core/java/android/speech/recognition/impl/WordItemImpl.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  WordItemImpl.java                                                        *
- *                                                                           *
- *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.recognition.impl;
-
-import android.speech.recognition.WordItem;
-
-/**
- */
-public class WordItemImpl extends WordItem implements Runnable
-{
-  /**
-   * Empty array that gets reused whenever the code requests that the underlying
-   * recognizer guess the pronunciations.
-   */
-  private static final String[] guessPronunciations = new String[0];
-  /**
-   * Reference to the native object.
-   */
-  private long nativeObject;
-
-  /**
-   * Creates a new WordItem.
-   *
-   * @param word the word to insert
-   * @throws IllegalArgumentException if word or pronunciations are null
-   */
-  private WordItemImpl(String word, String[] pronunciations) throws IllegalArgumentException
-  {
-    initNativeObject(word, pronunciations);
-  }
-
-  public void run()
-  {
-    dispose();
-  }
-
-   /**
-   * Creates a new WordItem.
-   *
-   * @param word the word to insert
-   * @param pronunciations the pronunciations to associated with the item. If the list is
-   * is empty (example:new String[0]) the recognizer will attempt to guess the pronunciations.
-   * @return the WordItem
-   * @throws IllegalArgumentException if word is null or if pronunciations is
-   * null or pronunciations contains an element equal to null or empty string.
-   */
-  public static WordItemImpl valueOf(String word, String[] pronunciations)
-    throws IllegalArgumentException
-  {
-    if (word == null)
-      throw new IllegalArgumentException("Word may not be null");
-    else if (pronunciations == null)
-      throw new IllegalArgumentException("Pronunciations may not be null");
-    for (int i = 0, size = pronunciations.length; i < size; ++i)
-    {
-       if (pronunciations[i]==null)
-       {
-           throw new IllegalArgumentException(
-                   "Pronunciations element may not be null");
-       }
-       else
-       {
-           if (pronunciations[i].trim().equals(""))
-             throw new IllegalArgumentException(
-                     "Pronunciations may not contain empty strings");
-       }
-    }
-    return new WordItemImpl(word, pronunciations);
-  }
-
-  /**
-   * Creates a new WordItem.
-   *
-   * @param word the word to insert
-   * @param pronunciation the pronunciation to associate with the item. If it
-   * is null the recognizer will attempt to guess the pronunciations.
-   * @return the WordItem
-   * @throws IllegalArgumentException if word is null or if pronunciation is
-   * an empty string
-   */
-  public static WordItemImpl valueOf(String word, String pronunciation) 
-          throws IllegalArgumentException
-  {
-    String[] pronunciations;
-    if (word == null)
-      throw new IllegalArgumentException("Word may not be null");
-    else if (pronunciation == null)
-      pronunciations = guessPronunciations;
-    else if (pronunciation.trim().equals(""))
-      throw new IllegalArgumentException(
-              "Pronunciation may not be an empty string");
-    else
-      pronunciations = new String[]{pronunciation};
-    return new WordItemImpl(word, pronunciations);
-  }
-
-  /**
-   * Allocates a reference to the native object.
-   *
-   * @param word the word to insert
-   */
-  private native void initNativeObject(String word, String[] pronunciations);
-
-  public long getNativeObject() 
-  {
-     synchronized (WordItemImpl.class)
-     {
-         return nativeObject;
-     }
-  }
-  
-  /**
-   * Releases the native resources associated with the object.
-   */
-  private void dispose()
-  {
-    synchronized (WordItemImpl.class)
-    {  
-        if (nativeObject != 0)
-        {
-            deleteNativeObject(nativeObject);
-            nativeObject = 0;
-        }
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable
-  {
-    dispose();
-    super.finalize();
-  }
-
-  /**
-   * Deletes a native object.
-   *
-   * @param nativeObject pointer to the native object
-   */
-  private native void deleteNativeObject(long nativeObject);
-}
diff --git a/core/java/android/speech/recognition/impl/package.html b/core/java/android/speech/recognition/impl/package.html
deleted file mode 100755
index 1c9bf9d..0000000
--- a/core/java/android/speech/recognition/impl/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-<body>
-    {@hide}
-</body>
-</html>
diff --git a/core/java/android/speech/recognition/package.html b/core/java/android/speech/recognition/package.html
deleted file mode 100644
index 3c59962..0000000
--- a/core/java/android/speech/recognition/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<BODY>
-{@hide}
-Provides classes for speech recogntion.
-</BODY>
-</HTML>
diff --git a/core/java/android/speech/srec/MicrophoneInputStream.java b/core/java/android/speech/srec/MicrophoneInputStream.java
new file mode 100644
index 0000000..160a003
--- /dev/null
+++ b/core/java/android/speech/srec/MicrophoneInputStream.java
@@ -0,0 +1,106 @@
+/*---------------------------------------------------------------------------*
+ *  MicrophoneInputStream.java                                              *
+ *                                                                           *
+ *  Copyright 2007 Nuance Communciations, Inc.                               *
+ *                                                                           *
+ *  Licensed under the Apache License, Version 2.0 (the 'License');          *
+ *  you may not use this file except in compliance with the License.         *
+ *                                                                           *
+ *  You may obtain a copy of the License at                                  *
+ *      http://www.apache.org/licenses/LICENSE-2.0                           *
+ *                                                                           *
+ *  Unless required by applicable law or agreed to in writing, software      *
+ *  distributed under the License is distributed on an 'AS IS' BASIS,        *
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ *  See the License for the specific language governing permissions and      *
+ *  limitations under the License.                                           *
+ *                                                                           *
+ *---------------------------------------------------------------------------*/
+
+
+package android.speech.srec;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.IllegalStateException;
+
+
+/**
+ * PCM input stream from the microphone, 16 bits per sample.
+ */
+public final class MicrophoneInputStream extends InputStream {
+    static {
+        System.loadLibrary("srec_jni");
+    }
+    
+    private final static String TAG = "MicrophoneInputStream";
+    private int mAudioRecord = 0;
+    private byte[] mOneByte = new byte[1];
+    
+    /**
+     * MicrophoneInputStream constructor.
+     * @param sampleRate sample rate of the microphone, typically 11025 or 8000.
+     * @param fifoDepth depth of the real time fifo, measured in sampleRate clock ticks.
+     * This determines how long an application may delay before losing data.
+     */
+    public MicrophoneInputStream(int sampleRate, int fifoDepth) throws IOException {
+        mAudioRecord = AudioRecordNew(sampleRate, fifoDepth);
+        if (mAudioRecord == 0) throw new IllegalStateException("not open");
+        AudioRecordStart(mAudioRecord);
+    }
+
+    @Override
+    public int read() throws IOException {
+        if (mAudioRecord == 0) throw new IllegalStateException("not open");
+        int rtn = AudioRecordRead(mAudioRecord, mOneByte, 0, 1);
+        return rtn == 1 ? ((int)mOneByte[0] & 0xff) : -1;
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException {
+        if (mAudioRecord == 0) throw new IllegalStateException("not open");
+        return AudioRecordRead(mAudioRecord, b, 0, b.length);
+    }
+    
+    @Override
+    public int read(byte[] b, int offset, int length) throws IOException {
+        if (mAudioRecord == 0) throw new IllegalStateException("not open");
+        // TODO: should we force all reads to be a multiple of the sample size?
+        return AudioRecordRead(mAudioRecord, b, offset, length);
+    }
+    
+    /**
+     * Closes this stream.
+     */
+    @Override
+    public void close() throws IOException {
+        if (mAudioRecord != 0) {
+            try {
+                AudioRecordStop(mAudioRecord);
+            } finally {
+                try {
+                    AudioRecordDelete(mAudioRecord);
+                } finally {
+                    mAudioRecord = 0;
+                }
+            }
+        }
+    }
+    
+    @Override
+    protected void finalize() throws Throwable {
+        if (mAudioRecord != 0) {
+            close();
+            throw new IOException("someone forgot to close MicrophoneInputStream");
+        }
+    }
+    
+    //
+    // AudioRecord JNI interface
+    //
+    private static native int AudioRecordNew(int sampleRate, int fifoDepth);
+    private static native void AudioRecordStart(int audioRecord);
+    private static native int AudioRecordRead(int audioRecord, byte[] b, int offset, int length) throws IOException;
+    private static native void AudioRecordStop(int audioRecord) throws IOException;
+    private static native void AudioRecordDelete(int audioRecord) throws IOException;
+}
diff --git a/core/java/android/speech/srec/Recognizer.java b/core/java/android/speech/srec/Recognizer.java
new file mode 100644
index 0000000..749c923
--- /dev/null
+++ b/core/java/android/speech/srec/Recognizer.java
@@ -0,0 +1,679 @@
+/*
+ * ---------------------------------------------------------------------------
+ * Recognizer.java
+ * 
+ * Copyright 2007 Nuance Communciations, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+ * use this file except in compliance with the License.
+ * 
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ * 
+ * ---------------------------------------------------------------------------
+ */
+
+
+package android.speech.srec;
+
+import android.util.Config;
+import android.util.Log;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Locale;
+
+/**
+ * Simple, synchronous speech recognizer, using the Nuance SREC package.
+ * Usages proceeds as follows:
+ * 
+ * <ul>
+ * <li>Create a <code>Recognizer</code>.
+ * <li>Create a <code>Recognizer.Grammar</code>.
+ * <li>Setup the <code>Recognizer.Grammar</code>.
+ * <li>Reset the <code>Recognizer.Grammar</code> slots, if needed.
+ * <li>Fill the <code>Recognizer.Grammar</code> slots, if needed.
+ * <li>Compile the <code>Recognizer.Grammar</code>, if needed.
+ * <li>Save the filled <code>Recognizer.Grammar</code>, if needed.
+ * <li>Start the <code>Recognizer</code>.
+ * <li>Loop over <code>advance</code> and <code>putAudio</code> until recognition complete.
+ * <li>Fetch and process results, or notify of failure.
+ * <li>Stop the <code>Recognizer</code>.
+ * <li>Destroy the <code>Recognizer</code>.
+ * </ul>
+ * 
+ * <p>Below is example code</p>
+ * 
+ * <pre class="prettyprint">
+ * 
+ * // create and start audio input
+ * InputStream audio = new MicrophoneInputStream(11025, 11025*5);
+ * // create a Recognizer
+ * String cdir = Recognizer.getConfigDir(null);
+ * Recognizer recognizer = new Recognizer(cdir + "/baseline11k.par");
+ * // create and load a Grammar
+ * Recognizer.Grammar grammar = recognizer.new Grammar(cdir + "/grammars/VoiceDialer.g2g");
+ * // setup the Grammar to work with the Recognizer
+ * grammar.setupRecognizer();
+ * // fill the Grammar slots with names and save, if required
+ * grammar.resetAllSlots();
+ * for (String name : names) grammar.addWordToSlot("@Names", name, null, 1, "V=1");
+ * grammar.compile();
+ * grammar.save(".../foo.g2g");
+ * // start the Recognizer
+ * recognizer.start();
+ * // loop over Recognizer events
+ * while (true) {
+ *     switch (recognizer.advance()) {
+ *     case Recognizer.EVENT_INCOMPLETE:
+ *     case Recognizer.EVENT_STARTED:
+ *     case Recognizer.EVENT_START_OF_VOICING:
+ *     case Recognizer.EVENT_END_OF_VOICING:
+ *         // let the Recognizer continue to run
+ *         continue;
+ *     case Recognizer.EVENT_RECOGNITION_RESULT:
+ *         // success, so fetch results here!
+ *         for (int i = 0; i < recognizer.getResultCount(); i++) {
+ *             String result = recognizer.getResult(i, Recognizer.KEY_LITERAL);
+ *         }
+ *         break;
+ *     case Recognizer.EVENT_NEED_MORE_AUDIO:
+ *         // put more audio in the Recognizer
+ *         recognizer.putAudio(audio);
+ *         continue;
+ *     default:
+ *         notifyFailure();
+ *         break;
+ *     }
+ *     break;
+ * }
+ * // stop the Recognizer
+ * recognizer.stop();
+ * // destroy the Recognizer
+ * recognizer.destroy();
+ * // stop the audio device
+ * audio.close();
+ * 
+ * </pre>
+ */
+public final class Recognizer {
+    static {
+        System.loadLibrary("srec_jni");
+    }
+
+    private static String TAG = "Recognizer";
+    
+    /**
+     * Result key corresponding to confidence score.
+     */
+    public static final String KEY_CONFIDENCE = "conf";
+    
+    /**
+     * Result key corresponding to literal text.
+     */
+    public static final String KEY_LITERAL = "literal";
+    
+    /**
+     * Result key corresponding to semantic meaning text.
+     */
+    public static final String KEY_MEANING = "meaning";
+
+    // handle to SR_Vocabulary object
+    private int mVocabulary = 0;
+    
+    // handle to SR_Recognizer object
+    private int mRecognizer = 0;
+    
+    // Grammar currently associated with Recognizer via SR_GrammarSetupRecognizer
+    private Grammar mActiveGrammar = null;
+    
+    /**
+     * Get the pathname of the SREC configuration directory corresponding to the
+     * language indicated by the Locale.
+     * This directory contains dictionaries, speech models,
+     * configuration files, and other data needed by the Recognizer.
+     * @param locale <code>Locale</code> corresponding to the desired language,
+     * or null for default, currently <code>Locale.US</code>.
+     * @return Pathname of the configuration directory.
+     */
+    public static String getConfigDir(Locale locale) {
+        if (locale == null) locale = Locale.US;
+        String dir = "/system/usr/srec/config/" +
+                locale.toString().replace('_', '.').toLowerCase();
+        if ((new File(dir)).isDirectory()) return dir;
+        return null;
+    }
+
+    /**
+     * Create an instance of a SREC speech recognizer.
+     * 
+     * @param configFile pathname of the baseline*.par configuration file,
+     * which in turn contains references to dictionaries, speech models,
+     * and other data needed to configure and operate the recognizer.
+     * A separate config file is needed for each audio sample rate.
+     * Two files, baseline11k.par and baseline8k.par, which correspond to
+     * 11025 and 8000 hz, are present in the directory indicated by
+     * {@link #getConfigDir}.
+     * @throws IOException
+     */
+    public Recognizer(String configFile) throws IOException {
+        PMemInit();
+        SR_SessionCreate(configFile);
+        mRecognizer = SR_RecognizerCreate();
+        SR_RecognizerSetup(mRecognizer);
+        mVocabulary = SR_VocabularyLoad();
+    }
+
+    /**
+     * Represents a grammar loaded into the Recognizer.
+     */
+    public class Grammar {
+        private int mGrammar = 0;
+
+        /**
+         * Create a <code>Grammar</code> instance.
+         * @param g2gFileName pathname of g2g file.
+         */
+        public Grammar(String g2gFileName) throws IOException {
+            mGrammar = SR_GrammarLoad(g2gFileName);
+            SR_GrammarSetupVocabulary(mGrammar, mVocabulary);
+        }
+
+        /**
+         * Reset all slots.
+         */
+        public void resetAllSlots() {
+            SR_GrammarResetAllSlots(mGrammar);
+        }
+
+        /**
+         * Add a word to a slot.
+         * 
+         * @param slot slot name.
+         * @param word word to insert.
+         * @param pron pronunciation, or null to derive from word.
+         * @param weight weight to give the word.  One is normal, 50 is low.
+         * @param tag semantic meaning tag string.
+         */
+        public void addWordToSlot(String slot, String word, String pron, int weight, String tag) {
+            SR_GrammarAddWordToSlot(mGrammar, slot, word, pron, weight, tag); 
+        }
+
+        /**
+         * Compile all slots.
+         */
+        public void compile() {
+            SR_GrammarCompile(mGrammar);
+        }
+
+        /**
+         * Setup <code>Grammar</code> with <code>Recognizer</code>.
+         */
+        public void setupRecognizer() {
+            SR_GrammarSetupRecognizer(mGrammar, mRecognizer);
+            mActiveGrammar = this;
+        }
+
+        /**
+         * Save <code>Grammar</code> to g2g file.
+         * 
+         * @param g2gFileName
+         * @throws IOException
+         */
+        public void save(String g2gFileName) throws IOException {
+            SR_GrammarSave(mGrammar, g2gFileName);
+        }
+
+        /**
+         * Release resources associated with this <code>Grammar</code>.
+         */
+        public void destroy() {
+            // TODO: need to do cleanup and disassociation with Recognizer
+            if (mGrammar != 0) {
+                SR_GrammarDestroy(mGrammar);
+                mGrammar = 0;
+            }
+        }
+
+        /**
+         * Clean up resources.
+         */
+        protected void finalize() {
+            if (mGrammar != 0) {
+                destroy();
+                throw new IllegalStateException("someone forgot to destroy Grammar");
+            }
+        }
+    }
+
+    /**
+     * Start recognition
+     */
+    public void start() {
+        // TODO: shouldn't be here?
+        SR_RecognizerActivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash", 1);
+        SR_RecognizerStart(mRecognizer);
+    }
+    
+    /**
+     * Process some audio and return the current status.
+     * @return recognition event, one of:
+     * <ul>
+     * <li><code>EVENT_INVALID</code>
+     * <li><code>EVENT_NO_MATCH</code>
+     * <li><code>EVENT_INCOMPLETE</code>
+     * <li><code>EVENT_STARTED</code>
+     * <li><code>EVENT_STOPPED</code>
+     * <li><code>EVENT_START_OF_VOICING</code>
+     * <li><code>EVENT_END_OF_VOICING</code>
+     * <li><code>EVENT_SPOKE_TOO_SOON</code>
+     * <li><code>EVENT_RECOGNITION_RESULT</code>
+     * <li><code>EVENT_START_OF_UTTERANCE_TIMEOUT</code>
+     * <li><code>EVENT_RECOGNITION_TIMEOUT</code>
+     * <li><code>EVENT_NEED_MORE_AUDIO</code>
+     * <li><code>EVENT_MAX_SPEECH</code>
+     * </ul>
+     */
+    public int advance() {
+        return SR_RecognizerAdvance(mRecognizer);
+    }
+    
+    /**
+     * Put audio samples into the <code>Recognizer</code>.
+     * @param buf holds the audio samples.
+     * @param offset offset of the first sample.
+     * @param length number of bytes containing samples.
+     * @param isLast indicates no more audio data, normally false.
+     * @return number of bytes accepted.
+     */
+    public int putAudio(byte[] buf, int offset, int length, boolean isLast) {
+        return SR_RecognizerPutAudio(mRecognizer, buf, offset, length, isLast);
+    }
+    
+    /**
+     * Read audio samples from an <code>InputStream</code> and put them in the
+     * <code>Recognizer</code>.
+     * @param audio <code>InputStream</code> containing PCM audio samples.
+     */
+    public void putAudio(InputStream audio) throws IOException {
+        // make sure the audio buffer is allocated
+        if (mPutAudioBuffer == null) mPutAudioBuffer = new byte[512];
+        // read some data
+        int nbytes = audio.read(mPutAudioBuffer);
+        // eof, so signal Recognizer
+        if (nbytes == -1) {
+            SR_RecognizerPutAudio(mRecognizer, mPutAudioBuffer, 0, 0, true);
+        }
+        // put it into the Recognizer
+        else if (nbytes != SR_RecognizerPutAudio(mRecognizer, mPutAudioBuffer, 0, nbytes, false)) {
+            throw new IOException("SR_RecognizerPutAudio failed nbytes=" + nbytes);
+        }
+    }
+    
+    // audio buffer for putAudio(InputStream)
+    private byte[] mPutAudioBuffer = null;
+
+    /**
+     * Get the number of recognition results.  Must be called after
+     * <code>EVENT_RECOGNITION_RESULT</code> is returned by
+     * <code>advance</code>, but before <code>stop</code>.
+     * 
+     * @return number of results in nbest list.
+     */
+    public int getResultCount() {
+        return SR_RecognizerResultGetSize(mRecognizer);
+    }
+
+    /**
+     * Get a set of keys for the result.  Must be called after
+     * <code>EVENT_RECOGNITION_RESULT</code> is returned by
+     * <code>advance</code>, but before <code>stop</code>.
+     * 
+     * @param index index of result.
+     * @return array of keys.
+     */
+    public String[] getResultKeys(int index) {
+        return SR_RecognizerResultGetKeyList(mRecognizer, index);
+    }
+
+    /**
+     * Get a result value.  Must be called after
+     * <code>EVENT_RECOGNITION_RESULT</code> is returned by
+     * <code>advance</code>, but before <code>stop</code>.
+     * 
+     * @param index index of the result.
+     * @param key key of the result.  This is typically one of
+     * <code>KEY_CONFIDENCE</code>, <code>KEY_LITERAL</code>, or
+     * <code>KEY_MEANING</code>, but the user can also define their own keys
+     * in a grxml file, or in the <code>tag</code> slot of
+     * <code>Grammar.addWordToSlot</code>.
+     * @return the result.
+     */
+    public String getResult(int index, String key) {
+        return SR_RecognizerResultGetValue(mRecognizer, index, key);
+    }
+
+    /**
+     * Stop the <code>Recognizer</code>.
+     */
+    public void stop() {
+        SR_RecognizerStop(mRecognizer);
+        SR_RecognizerDeactivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash");
+    }
+
+    /**
+     * Clean up resources.
+     */
+    public void destroy() {
+        try {
+            if (mVocabulary != 0) SR_VocabularyDestroy(mVocabulary);
+        } finally {
+            mVocabulary = 0;
+            try {
+                if (mRecognizer != 0) SR_RecognizerUnsetup(mRecognizer);
+            } finally {
+                try {
+                    if (mRecognizer != 0) SR_RecognizerDestroy(mRecognizer);
+                } finally {
+                    mRecognizer = 0;
+                    try {
+                        SR_SessionDestroy();
+                    } finally {
+                        PMemShutdown();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Clean up resources.
+     */
+    protected void finalize() throws Throwable {
+        if (mVocabulary != 0 || mRecognizer != 0) {
+            destroy();
+            throw new IllegalStateException("someone forgot to destroy Recognizer");
+        }
+    }
+    
+    /* an example session captured, for reference
+    void doall() {
+        if (PMemInit ( )
+           || lhs_audioinOpen ( WAVE_MAPPER, SREC_TEST_DEFAULT_AUDIO_FREQUENCY, &audio_in_handle )
+           || srec_test_init_application_data ( &applicationData, argc, argv )
+           || SR_SessionCreate ( "/system/usr/srec/config/en.us/baseline11k.par" )
+           || SR_RecognizerCreate ( &applicationData.recognizer )
+           || SR_RecognizerSetup ( applicationData.recognizer)
+           || ESR_SessionGetLCHAR ( L("cmdline.vocabulary"), filename, &flen )
+           || SR_VocabularyLoad ( filename, &applicationData.vocabulary )
+           || SR_VocabularyGetLanguage ( applicationData.vocabulary, &applicationData.locale )
+           || (applicationData.nametag = NULL)
+           || SR_NametagsCreate ( &applicationData.nametags )
+           || (LSTRCPY ( applicationData.grammars [0].grammar_path, "/system/usr/srec/config/en.us/grammars/VoiceDialer.g2g" ), 0)
+           || (LSTRCPY ( applicationData.grammars [0].grammarID, "BothTags" ), 0)
+           || (LSTRCPY ( applicationData.grammars [0].ruleName, "trash" ), 0)
+           || (applicationData.grammars [0].is_ve_grammar = ESR_FALSE, 0)
+           || SR_GrammarLoad (applicationData.grammars [0].grammar_path, &applicationData.grammars [applicationData.grammarCount].grammar )
+           || SR_GrammarSetupVocabulary ( applicationData.grammars [0].grammar, applicationData.vocabulary )
+           || SR_GrammarSetupRecognizer( applicationData.grammars [0].grammar, applicationData.recognizer )
+           || SR_GrammarSetDispatchFunction ( applicationData.grammars [0].grammar, L("myDSMCallback"), NULL, myDSMCallback )
+           || (applicationData.grammarCount++, 0)
+           || SR_RecognizerActivateRule ( applicationData.recognizer, applicationData.grammars [0].grammar,
+                           applicationData.grammars [0].ruleName, 1 )
+           || (applicationData.active_grammar_num = 0, 0)
+           || lhs_audioinStart ( audio_in_handle )
+           || SR_RecognizerStart ( applicationData.recognizer )
+           || strl ( applicationData.grammars [0].grammar, &applicationData, audio_in_handle, &recognition_count )
+           || SR_RecognizerStop ( applicationData.recognizer )
+           || lhs_audioinStop ( audio_in_handle )
+           || SR_RecognizerDeactivateRule ( applicationData.recognizer, applicationData.grammars [0].grammar, applicationData.grammars [0].ruleName )
+           || (applicationData.active_grammar_num = -1, 0)
+           || SR_GrammarDestroy ( applicationData.grammars [0].grammar )
+           || (applicationData.grammarCount--, 0)
+           || SR_NametagsDestroy ( applicationData.nametags )
+           || (applicationData.nametags = NULL, 0)
+           || SR_VocabularyDestroy ( applicationData.vocabulary )
+           || (applicationData.vocabulary = NULL)
+           || SR_RecognizerUnsetup ( applicationData.recognizer) // releases acoustic models
+           || SR_RecognizerDestroy ( applicationData.recognizer )
+           || (applicationData.recognizer = NULL)
+           || SR_SessionDestroy ( )
+           || srec_test_shutdown_application_data ( &applicationData )
+           || lhs_audioinClose ( &audio_in_handle )
+           || PMemShutdown ( )
+    }
+    */
+
+
+    //
+    // PMem native methods
+    //
+    private static native void PMemInit();
+    private static native void PMemShutdown();
+
+
+    //
+    // SR_Session native methods
+    //
+    private static native void SR_SessionCreate(String filename);
+    private static native void SR_SessionDestroy();
+
+
+    //
+    // SR_Recognizer native methods
+    //
+    
+    /**
+     * Reserved value.
+     */
+    public final static int EVENT_INVALID = 0;
+    
+    /**
+     * <code>Recognizer</code> could not find a match for the utterance.
+     */
+    public final static int EVENT_NO_MATCH = 1;
+    
+    /**
+     * <code>Recognizer</code> processed one frame of audio.
+     */
+    public final static int EVENT_INCOMPLETE = 2;
+    
+    /**
+     * <code>Recognizer</code> has just been started.
+     */
+    public final static int EVENT_STARTED = 3;
+    
+    /**
+     * <code>Recognizer</code> is stopped.
+     */
+    public final static int EVENT_STOPPED = 4;
+    
+    /**
+     * Beginning of speech detected.
+     */
+    public final static int EVENT_START_OF_VOICING = 5;
+    
+    /**
+     * End of speech detected.
+     */
+    public final static int EVENT_END_OF_VOICING = 6;
+    
+    /**
+     * Beginning of utterance occured too soon.
+     */
+    public final static int EVENT_SPOKE_TOO_SOON = 7;
+    
+    /**
+     * Recognition match detected.
+     */
+    public final static int EVENT_RECOGNITION_RESULT = 8;
+    
+    /**
+     * Timeout occured before beginning of utterance.
+     */
+    public final static int EVENT_START_OF_UTTERANCE_TIMEOUT = 9;
+    
+    /**
+     * Timeout occured before speech recognition could complete.
+     */
+    public final static int EVENT_RECOGNITION_TIMEOUT = 10;
+    
+    /**
+     * Not enough samples to process one frame.
+     */
+    public final static int EVENT_NEED_MORE_AUDIO = 11;
+    
+    /**
+     * More audio encountered than is allowed by 'swirec_max_speech_duration'.
+     */
+    public final static int EVENT_MAX_SPEECH = 12;
+
+    /**
+     * Produce a displayable string from an <code>advance</code> event.
+     * @param event
+     * @return String representing the event.
+     */
+    public static String eventToString(int event) {
+        switch (event) {
+            case EVENT_INVALID:
+                return "EVENT_INVALID";
+            case EVENT_NO_MATCH:
+                return "EVENT_NO_MATCH";
+            case EVENT_INCOMPLETE:
+                return "EVENT_INCOMPLETE";
+            case EVENT_STARTED:
+                return "EVENT_STARTED";
+            case EVENT_STOPPED:
+                return "EVENT_STOPPED";
+            case EVENT_START_OF_VOICING:
+                return "EVENT_START_OF_VOICING";
+            case EVENT_END_OF_VOICING:
+                return "EVENT_END_OF_VOICING";
+            case EVENT_SPOKE_TOO_SOON:
+                return "EVENT_SPOKE_TOO_SOON";
+            case EVENT_RECOGNITION_RESULT:
+                return "EVENT_RECOGNITION_RESULT";
+            case EVENT_START_OF_UTTERANCE_TIMEOUT:
+                return "EVENT_START_OF_UTTERANCE_TIMEOUT";
+            case EVENT_RECOGNITION_TIMEOUT:
+                return "EVENT_RECOGNITION_TIMEOUT";
+            case EVENT_NEED_MORE_AUDIO:
+                return "EVENT_NEED_MORE_AUDIO";
+            case EVENT_MAX_SPEECH:
+                return "EVENT_MAX_SPEECH";
+        }
+        return "EVENT_" + event;
+    }
+
+    private static native void SR_RecognizerStart(int recognizer);
+    private static native void SR_RecognizerStop(int recognizer);
+    private static native int SR_RecognizerCreate();
+    private static native void SR_RecognizerDestroy(int recognizer);
+    private static native void SR_RecognizerSetup(int recognizer);
+    private static native void SR_RecognizerUnsetup(int recognizer);
+    private static native boolean SR_RecognizerIsSetup(int recognizer);
+    private static native String SR_RecognizerGetParameter(int recognizer, String key);
+    private static native int SR_RecognizerGetSize_tParameter(int recognizer, String key);
+    private static native boolean SR_RecognizerGetBoolParameter(int recognizer, String key);
+    private static native void SR_RecognizerSetParameter(int recognizer, String key, String value);
+    private static native void SR_RecognizerSetSize_tParameter(int recognizer,
+            String key, int value);
+    private static native void SR_RecognizerSetBoolParameter(int recognizer, String key,
+            boolean value);
+    private static native void SR_RecognizerSetupRule(int recognizer, int grammar,
+            String ruleName);
+    private static native boolean SR_RecognizerHasSetupRules(int recognizer);
+    private static native void SR_RecognizerActivateRule(int recognizer, int grammar,
+            String ruleName, int weight);
+    private static native void SR_RecognizerDeactivateRule(int recognizer, int grammar,
+            String ruleName);
+    private static native void SR_RecognizerDeactivateAllRules(int recognizer);
+    private static native boolean SR_RecognizerIsActiveRule(int recognizer, int grammar,
+            String ruleName);
+    private static native boolean SR_RecognizerCheckGrammarConsistency(int recognizer,
+            int grammar);
+    private static native int SR_RecognizerPutAudio(int recognizer, byte[] buffer, int offset,
+            int length, boolean isLast);
+    private static native int SR_RecognizerAdvance(int recognizer);
+    // private static native void SR_RecognizerLoadUtterance(int recognizer,
+    //         const LCHAR* filename);
+    // private static native void SR_RecognizerLoadWaveFile(int recognizer,
+    //         const LCHAR* filename);
+    // private static native void SR_RecognizerSetLockFunction(int recognizer,
+    //         SR_RecognizerLockFunction function, void* data);
+    private static native boolean SR_RecognizerIsSignalClipping(int recognizer);
+    private static native boolean SR_RecognizerIsSignalDCOffset(int recognizer);
+    private static native boolean SR_RecognizerIsSignalNoisy(int recognizer);
+    private static native boolean SR_RecognizerIsSignalTooQuiet(int recognizer);
+    private static native boolean SR_RecognizerIsSignalTooFewSamples(int recognizer);
+    private static native boolean SR_RecognizerIsSignalTooManySamples(int recognizer);
+    // private static native void SR_Recognizer_Change_Sample_Rate (size_t new_sample_rate);
+
+
+    //
+    // SR_Grammar native methods
+    //
+    private static native void SR_GrammarCompile(int grammar);
+    private static native void SR_GrammarAddWordToSlot(int grammar, String slot,
+            String word, String pronunciation, int weight, String tag);
+    private static native void SR_GrammarResetAllSlots(int grammar);
+    // private static native void SR_GrammarAddNametagToSlot(int grammar, String slot,
+    // const struct SR_Nametag_t* nametag, int weight, String tag);
+    private static native void SR_GrammarSetupVocabulary(int grammar, int vocabulary);
+    // private static native void SR_GrammarSetupModels(int grammar, SR_AcousticModels* models);
+    private static native void SR_GrammarSetupRecognizer(int grammar, int recognizer);
+    private static native void SR_GrammarUnsetupRecognizer(int grammar);
+    // private static native void SR_GrammarGetModels(int grammar,SR_AcousticModels** models);
+    private static native int SR_GrammarCreate();
+    private static native void SR_GrammarDestroy(int grammar);
+    private static native int SR_GrammarLoad(String filename);
+    private static native void SR_GrammarSave(int grammar, String filename);
+    // private static native void SR_GrammarSetDispatchFunction(int grammar,
+    //         const LCHAR* name, void* userData, SR_GrammarDispatchFunction function);
+    // private static native void SR_GrammarSetParameter(int grammar, const
+    //         LCHAR* key, void* value);
+    // private static native void SR_GrammarSetSize_tParameter(int grammar,
+    //         const LCHAR* key, size_t value);
+    // private static native void SR_GrammarGetParameter(int grammar, const
+    //         LCHAR* key, void** value);
+    // private static native void SR_GrammarGetSize_tParameter(int grammar,
+    //         const LCHAR* key, size_t* value);
+    // private static native void SR_GrammarCheckParse(int grammar, const LCHAR*
+    //         transcription, SR_SemanticResult** result, size_t* resultCount);
+    private static native void SR_GrammarAllowOnly(int grammar, String transcription);
+    private static native void SR_GrammarAllowAll(int grammar);
+
+
+    //
+    // SR_Vocabulary native methods
+    //
+    // private static native int SR_VocabularyCreate();
+    private static native int SR_VocabularyLoad();
+    // private static native void SR_VocabularySave(SR_Vocabulary* self,
+    //         const LCHAR* filename);
+    // private static native void SR_VocabularyAddWord(SR_Vocabulary* self,
+    //         const LCHAR* word);
+    // private static native void SR_VocabularyGetLanguage(SR_Vocabulary* self,
+    //         ESR_Locale* locale);
+    private static native void SR_VocabularyDestroy(int vocabulary);
+    private static native String SR_VocabularyGetPronunciation(int vocabulary, String word);
+
+
+    //
+    // SR_RecognizerResult native methods
+    //
+    private static native byte[] SR_RecognizerResultGetWaveform(int recognizer);
+    private static native int SR_RecognizerResultGetSize(int recognizer);
+    private static native int SR_RecognizerResultGetKeyCount(int recognizer, int nbest);
+    private static native String[] SR_RecognizerResultGetKeyList(int recognizer, int nbest);
+    private static native String SR_RecognizerResultGetValue(int recognizer,
+            int nbest, String key);
+    // private static native void SR_RecognizerResultGetLocale(int recognizer, ESR_Locale* locale);
+}
diff --git a/core/java/android/speech/srec/Srec.java b/core/java/android/speech/srec/Srec.java
deleted file mode 100644
index a629214..0000000
--- a/core/java/android/speech/srec/Srec.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*---------------------------------------------------------------------------*
- *  EmbeddedRecognizerImpl.java                                              *
- *                                                                           *
- *  Copyright 2007 Nuance Communciations, Inc.                               *
- *                                                                           *
- *  Licensed under the Apache License, Version 2.0 (the 'License');          *
- *  you may not use this file except in compliance with the License.         *
- *                                                                           *
- *  You may obtain a copy of the License at                                  *
- *      http://www.apache.org/licenses/LICENSE-2.0                           *
- *                                                                           *
- *  Unless required by applicable law or agreed to in writing, software      *
- *  distributed under the License is distributed on an 'AS IS' BASIS,        *
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
- *  See the License for the specific language governing permissions and      *
- *  limitations under the License.                                           *
- *                                                                           *
- *---------------------------------------------------------------------------*/
-
-package android.speech.srec;
-
-import java.io.IOException;
-
-/**
- * Simple, synchronous speech recognizer, using the SREC package.
- * 
- * @hide
- */
-public class Srec
-{
-    private int mNative;
-    
-    
-    /**
-     * Create an instance of a SREC speech recognizer.
-     * @param configFile pathname of the baseline*.par configuration file.
-     * @throws IOException
-     */
-    Srec(String configFile) throws IOException {
-        
-    }
-    
-    /**
-     * Creates a Srec recognizer.
-     * @param g2gFileName pathname of a g2g grammar file.
-     * @return
-     * @throws IOException
-     */
-    public Grammar loadGrammar(String g2gFileName) throws IOException {
-        return null;
-    }
-    
-    /**
-     * Represents a grammar loaded into the recognizer.
-     */
-    public class Grammar {
-        private int mId = -1;
-        
-        /**
-         * Add a word to a slot
-         * @param slot slot name
-         * @param word word
-         * @param pron pronunciation, or null to derive from word
-         * @param weight weight to give the word
-         * @param meaning meaning string
-         */
-        public void addToSlot(String slot, String word, String pron, int weight, String meaning) {
-            
-        }
-        
-        /**
-         * Compile all slots.
-         */
-        public void compileSlots() {
-            
-        }
-        
-        /**
-         * Reset all slots.
-         */
-        public void resetAllSlots() {
-            
-        }
-        
-        /**
-         * Save grammar to g2g file.
-         * @param g2gFileName
-         * @throws IOException
-         */
-        public void save(String g2gFileName) throws IOException {
-            
-        }
-        
-        /**
-         * Release resources associated with this grammar.
-         */
-        public void unload() {
-            
-        }
-    }
-    
-    /**
-     * Start recognition
-     */
-    public void start() {
-        
-    }
-    
-    /**
-     * Process some audio and return the next state.
-     * @return true if complete
-     */
-    public boolean process() {
-        return false;
-    }
-    
-    /**
-     * Get the number of recognition results.
-     * @return
-     */
-    public int getResultCount() {
-        return 0;
-    }
-    
-    /**
-     * Get a set of keys for the result.
-     * @param index index of result.
-     * @return array of keys.
-     */
-    public String[] getResultKeys(int index) {
-        return null;
-    }
-    
-    /**
-     * Get a result value
-     * @param index index of the result.
-     * @param key key of the result.
-     * @return the result.
-     */
-    public String getResult(int index, String key) {
-        return null;
-    }
-    
-    /**
-     * Reset the recognizer to the idle state.
-     */
-    public void reset() {
-        
-    }
-    
-    /**
-     * Clean up resources.
-     */
-    public void dispose() {
-        
-    }
-    
-    protected void finalize() {
-        
-    }
-
-}
diff --git a/core/java/android/speech/srec/UlawEncoderInputStream.java b/core/java/android/speech/srec/UlawEncoderInputStream.java
new file mode 100644
index 0000000..132fe027
--- /dev/null
+++ b/core/java/android/speech/srec/UlawEncoderInputStream.java
@@ -0,0 +1,186 @@
+/*
+ * ---------------------------------------------------------------------------
+ * UlawEncoderInputStream.java
+ *
+ * Copyright 2008 Nuance Communciations, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); you may not
+ * use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ *
+ * ---------------------------------------------------------------------------
+ */
+
+package android.speech.srec;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * InputStream which transforms 16 bit pcm data to ulaw data.
+ *
+ * @hide pending API council approval
+ */
+public final class UlawEncoderInputStream extends InputStream {
+    private final static String TAG = "UlawEncoderInputStream";
+    
+    private final static int MAX_ULAW = 8192;
+    private final static int SCALE_BITS = 16;
+    
+    private InputStream mIn;
+    
+    private int mMax = 0;
+    
+    private final byte[] mBuf = new byte[1024];
+    private int mBufCount = 0; // should be 0 or 1
+    
+    private final byte[] mOneByte = new byte[1];
+
+    
+    public static void encode(byte[] pcmBuf, int pcmOffset,
+            byte[] ulawBuf, int ulawOffset, int length, int max) {
+        
+        // from  'ulaw' in wikipedia
+        // +8191 to +8159                          0x80
+        // +8158 to +4063 in 16 intervals of 256   0x80 + interval number
+        // +4062 to +2015 in 16 intervals of 128   0x90 + interval number
+        // +2014 to  +991 in 16 intervals of  64   0xA0 + interval number
+        //  +990 to  +479 in 16 intervals of  32   0xB0 + interval number
+        //  +478 to  +223 in 16 intervals of  16   0xC0 + interval number
+        //  +222 to   +95 in 16 intervals of   8   0xD0 + interval number
+        //   +94 to   +31 in 16 intervals of   4   0xE0 + interval number
+        //   +30 to    +1 in 15 intervals of   2   0xF0 + interval number
+        //     0                                   0xFF
+        
+        //    -1                                   0x7F
+        //   -31 to    -2 in 15 intervals of   2   0x70 + interval number
+        //   -95 to   -32 in 16 intervals of   4   0x60 + interval number
+        //  -223 to   -96 in 16 intervals of   8   0x50 + interval number
+        //  -479 to  -224 in 16 intervals of  16   0x40 + interval number
+        //  -991 to  -480 in 16 intervals of  32   0x30 + interval number
+        // -2015 to  -992 in 16 intervals of  64   0x20 + interval number
+        // -4063 to -2016 in 16 intervals of 128   0x10 + interval number
+        // -8159 to -4064 in 16 intervals of 256   0x00 + interval number
+        // -8192 to -8160                          0x00
+        
+        // set scale factors
+        if (max <= 0) max = MAX_ULAW;
+        
+        int coef = MAX_ULAW * (1 << SCALE_BITS) / max;
+        
+        for (int i = 0; i < length; i++) {
+            int pcm = (0xff & pcmBuf[pcmOffset++]) + (pcmBuf[pcmOffset++] << 8);
+            pcm = (pcm * coef) >> SCALE_BITS;
+            
+            int ulaw;
+            if (pcm >= 0) {
+                ulaw = pcm <= 0 ? 0xff :
+                        pcm <=   30 ? 0xf0 + ((  30 - pcm) >> 1) :
+                        pcm <=   94 ? 0xe0 + ((  94 - pcm) >> 2) :
+                        pcm <=  222 ? 0xd0 + (( 222 - pcm) >> 3) :
+                        pcm <=  478 ? 0xc0 + (( 478 - pcm) >> 4) :
+                        pcm <=  990 ? 0xb0 + (( 990 - pcm) >> 5) :
+                        pcm <= 2014 ? 0xa0 + ((2014 - pcm) >> 6) :
+                        pcm <= 4062 ? 0x90 + ((4062 - pcm) >> 7) :
+                        pcm <= 8158 ? 0x80 + ((8158 - pcm) >> 8) :
+                        0x80;
+            } else {
+                ulaw = -1 <= pcm ? 0x7f :
+                          -31 <= pcm ? 0x70 + ((pcm -   -31) >> 1) :
+                          -95 <= pcm ? 0x60 + ((pcm -   -95) >> 2) :
+                         -223 <= pcm ? 0x50 + ((pcm -  -223) >> 3) :
+                         -479 <= pcm ? 0x40 + ((pcm -  -479) >> 4) :
+                         -991 <= pcm ? 0x30 + ((pcm -  -991) >> 5) :
+                        -2015 <= pcm ? 0x20 + ((pcm - -2015) >> 6) :
+                        -4063 <= pcm ? 0x10 + ((pcm - -4063) >> 7) :
+                        -8159 <= pcm ? 0x00 + ((pcm - -8159) >> 8) :
+                        0x00;
+            }
+            ulawBuf[ulawOffset++] = (byte)ulaw;
+        }
+    }
+    
+    /**
+     * Compute the maximum of the absolute value of the pcm samples.
+     * The return value can be used to set ulaw encoder scaling.
+     * @param pcmBuf array containing 16 bit pcm data.
+     * @param offset offset of start of 16 bit pcm data.
+     * @param length number of pcm samples (not number of input bytes)
+     * @return maximum abs of pcm data values
+     */
+    public static int maxAbsPcm(byte[] pcmBuf, int offset, int length) {
+        int max = 0;
+        for (int i = 0; i < length; i++) {
+            int pcm = (0xff & pcmBuf[offset++]) + (pcmBuf[offset++] << 8);
+            if (pcm < 0) pcm = -pcm;
+            if (pcm > max) max = pcm;
+        }
+        return max;
+    }
+
+    /**
+     * Create an InputStream which takes 16 bit pcm data and produces ulaw data.
+     * @param in InputStream containing 16 bit pcm data.
+     * @param max pcm value corresponding to maximum ulaw value.
+     */
+    public UlawEncoderInputStream(InputStream in, int max) {
+        mIn = in;
+        mMax = max;
+    }
+    
+    @Override
+    public int read(byte[] buf, int offset, int length) throws IOException {
+        if (mIn == null) throw new IllegalStateException("not open");
+
+        // return at least one byte, but try to fill 'length'
+        while (mBufCount < 2) {
+            int n = mIn.read(mBuf, mBufCount, Math.min(length * 2, mBuf.length - mBufCount));
+            if (n == -1) return -1;
+            mBufCount += n;
+        }
+        
+        // compand data
+        int n = Math.min(mBufCount / 2, length);
+        encode(mBuf, 0, buf, offset, n, mMax);
+        
+        // move data to bottom of mBuf
+        mBufCount -= n * 2;
+        for (int i = 0; i < mBufCount; i++) mBuf[i] = mBuf[i + n * 2];
+        
+        return n;
+    }
+    
+    @Override
+    public int read(byte[] buf) throws IOException {
+        return read(buf, 0, buf.length);
+    }
+    
+    @Override
+    public int read() throws IOException {
+        int n = read(mOneByte, 0, 1);
+        if (n == -1) return -1;
+        return 0xff & (int)mOneByte[0];
+    }
+    
+    @Override
+    public void close() throws IOException {
+        if (mIn != null) {
+            InputStream in = mIn;
+            mIn = null;
+            in.close();
+        }
+    }
+    
+    @Override
+    public int available() throws IOException {
+        return (mIn.available() + mBufCount) / 2;
+    }
+}
diff --git a/core/java/android/speech/srec/package.html b/core/java/android/speech/srec/package.html
new file mode 100644
index 0000000..723b30b
--- /dev/null
+++ b/core/java/android/speech/srec/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+Simple, synchronous SREC speech recognition API.
+</BODY>
+</HTML>
diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java
index 08a8ad1..82f2ef9 100644
--- a/core/java/android/test/InstrumentationTestCase.java
+++ b/core/java/android/test/InstrumentationTestCase.java
@@ -31,8 +31,7 @@
 import java.lang.reflect.InvocationTargetException;
 
 /**
- * A test case that has access to {@link Instrumentation}.  See
- * <code>InstrumentationTestRunner</code>.
+ * A test case that has access to {@link Instrumentation}.
  */
 public class InstrumentationTestCase extends TestCase {
 
@@ -57,7 +56,13 @@
     }
 
     /**
-     * Utility method for launching an activity.
+     * Utility method for launching an activity.  
+     * 
+     * <p>The {@link Intent} used to launch the Activity is:
+     *  action = {@link Intent#ACTION_MAIN}
+     *  extras = null, unless a custom bundle is provided here
+     * All other fields are null or empty.
+     *
      * @param pkg The package hosting the activity to be launched.
      * @param activityCls The activity class to launch.
      * @param extras Optional extra stuff to pass to the activity.
@@ -69,20 +74,61 @@
             Class<T> activityCls,
             Bundle extras) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.setClassName(pkg, activityCls.getName());
         if (extras != null) {
             intent.putExtras(extras);
         }
+        return launchActivityWithIntent(pkg, activityCls, intent);
+    }
+
+    /**
+     * Utility method for launching an activity with a specific Intent.
+     * @param pkg The package hosting the activity to be launched.
+     * @param activityCls The activity class to launch.
+     * @param intent The intent to launch with
+     * @return The activity, or null if non launched.
+     */
+    @SuppressWarnings("unchecked")
+    public final <T extends Activity> T launchActivityWithIntent(
+            String pkg,
+            Class<T> activityCls,
+            Intent intent) {
+        intent.setClassName(pkg, activityCls.getName());
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         T activity = (T) getInstrumentation().startActivitySync(intent);
         getInstrumentation().waitForIdleSync();
         return activity;
     }
+    
+    /**
+     * Helper for running portions of a test on the UI thread.
+     * 
+     * Note, in most cases it is simpler to annotate the test method with 
+     * {@link android.test.UiThreadTest}, which will run the entire test method on the UI thread.
+     * Use this method if you need to switch in and out of the UI thread to perform your test.
+     * 
+     * @param r runnable containing test code in the {@link Runnable#run()} method
+     */
+    public void runTestOnUiThread(final Runnable r) throws Throwable {
+        final Throwable[] exceptions = new Throwable[1];
+        getInstrumentation().runOnMainSync(new Runnable() {
+            public void run() {
+                try {
+                    r.run();
+                } catch (Throwable throwable) {
+                    exceptions[0] = throwable;
+                }
+            }
+        });
+        if (exceptions[0] != null) {
+            throw exceptions[0];
+        }
+    }
 
     /**
      * Runs the current unit test. If the unit test is annotated with
      * {@link android.test.UiThreadTest}, the test is run on the UI thread.
      */
+    @Override
     protected void runTest() throws Throwable {
         String fName = getName();
         assertNotNull(fName);
diff --git a/core/java/android/test/suitebuilder/annotation/LargeTest.java b/core/java/android/test/suitebuilder/annotation/LargeTest.java
new file mode 100644
index 0000000..a6269e7
--- /dev/null
+++ b/core/java/android/test/suitebuilder/annotation/LargeTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a test that should run as part of the large tests.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface LargeTest {
+}
diff --git a/core/java/android/test/suitebuilder/annotation/MediumTest.java b/core/java/android/test/suitebuilder/annotation/MediumTest.java
new file mode 100644
index 0000000..8afeb91
--- /dev/null
+++ b/core/java/android/test/suitebuilder/annotation/MediumTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a test that should run as part of the medium tests.
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface MediumTest {
+}
diff --git a/core/java/android/test/suitebuilder/annotation/SmallTest.java b/core/java/android/test/suitebuilder/annotation/SmallTest.java
new file mode 100644
index 0000000..ad530e2
--- /dev/null
+++ b/core/java/android/test/suitebuilder/annotation/SmallTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a test that should run as part of the small tests.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SmallTest {
+}
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 2ee4f62..843754b 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -92,7 +92,7 @@
                                       int ellipsizedWidth) {
         boolean trust;
 
-        if (ellipsize == null) {
+        if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) {
             replaceWith(source, paint, outerwidth, align, spacingmult,
                         spacingadd);
 
@@ -145,7 +145,7 @@
 
         boolean trust;
 
-        if (ellipsize == null) {
+        if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) {
             mEllipsizedWidth = outerwidth;
             mEllipsizedStart = 0;
             mEllipsizedCount = 0;
diff --git a/core/java/android/text/InputFilter.java b/core/java/android/text/InputFilter.java
index e1563ae..2f55677 100644
--- a/core/java/android/text/InputFilter.java
+++ b/core/java/android/text/InputFilter.java
@@ -33,6 +33,11 @@
      * as this is what happens when you delete text.  Also beware that
      * you should not attempt to make any changes to <code>dest</code>
      * from this method; you may only examine it for context.
+     * 
+     * Note: If <var>source</var> is an instance of {@link Spanned} or
+     * {@link Spannable}, the span objects in the <var>source</var> should be 
+     * copied into the filtered result (i.e. the non-null return value). 
+     * {@link TextUtils#copySpansFrom} can be used for convenience.
      */
     public CharSequence filter(CharSequence source, int start, int end,
                                Spanned dest, int dstart, int dend);
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
new file mode 100644
index 0000000..0ffe4ac
--- /dev/null
+++ b/core/java/android/text/InputType.java
@@ -0,0 +1,227 @@
+package android.text;
+
+import android.text.TextUtils;
+
+/**
+ * Bit definitions for an integer defining the basic content type of text
+ * held in an {@link Editable} object.
+ */
+public interface InputType {
+    /**
+     * Mask of bits that determine the overall class
+     * of text being given.  Currently supported classes are:
+     * {@link #TYPE_CLASS_TEXT}, {@link #TYPE_CLASS_NUMBER},
+     * {@link #TYPE_CLASS_PHONE}, {@link #TYPE_CLASS_DATETIME}.
+     * If the class is not one you
+     * understand, assume {@link #TYPE_CLASS_TEXT} with NO variation
+     * or flags.
+     */
+    public static final int TYPE_MASK_CLASS = 0x0000000f;
+    
+    /**
+     * Mask of bits that determine the variation of
+     * the base content class.
+     */
+    public static final int TYPE_MASK_VARIATION = 0x00000ff0;
+    
+    /**
+     * Mask of bits that provide addition bit flags
+     * of options.
+     */
+    public static final int TYPE_MASK_FLAGS = 0x00fff000;
+    
+    /**
+     * Special content type for when no explicit type has been specified.
+     * This should be interpreted to mean that the target input connection
+     * is not rich, it can not process and show things like candidate text nor
+     * retrieve the current text, so the input method will need to run in a
+     * limited "generate key events" mode.
+     */
+    public static final int TYPE_NULL = 0x00000000;
+    
+    // ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
+    
+    /**
+     * Class for normal text.  This class supports the following flags (only
+     * one of which should be set):
+     * {@link #TYPE_TEXT_FLAG_CAP_CHARACTERS},
+     * {@link #TYPE_TEXT_FLAG_CAP_WORDS}, and.
+     * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}.  It also supports the
+     * following variations:
+     * {@link #TYPE_TEXT_VARIATION_NORMAL}, and
+     * {@link #TYPE_TEXT_VARIATION_URI}.  If you do not recognize the
+     * variation, normal should be assumed.
+     */
+    public static final int TYPE_CLASS_TEXT = 0x00000001;
+    
+    /**
+     * Flag for {@link #TYPE_CLASS_TEXT}: capitalize all characters.  Overrides
+     * {@link #TYPE_TEXT_FLAG_CAP_WORDS} and
+     * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}.  This value is explicitly defined
+     * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}.
+     */
+    public static final int TYPE_TEXT_FLAG_CAP_CHARACTERS = 0x00001000;
+    
+    /**
+     * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of
+     * all words.  Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}.  This
+     * value is explicitly defined
+     * to be the same as {@link TextUtils#CAP_MODE_WORDS}.
+     */
+    public static final int TYPE_TEXT_FLAG_CAP_WORDS = 0x00002000;
+    
+    /**
+     * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of
+     * each sentence.  This value is explicitly defined
+     * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}.
+     */
+    public static final int TYPE_TEXT_FLAG_CAP_SENTENCES = 0x00004000;
+    
+    /**
+     * Flag for {@link #TYPE_CLASS_TEXT}: the user is entering free-form
+     * text that should have auto-correction applied to it.
+     */
+    public static final int TYPE_TEXT_FLAG_AUTO_CORRECT = 0x00008000;
+    
+    /**
+     * Flag for {@link #TYPE_CLASS_TEXT}: the text editor is performing
+     * auto-completion of the text being entered based on its own semantics,
+     * which it will present to the user as they type.  This generally means
+     * that the input method should not be showing candidates itself, but can
+     * expect for the editor to supply its own completions/candidates from
+     * {@link android.view.inputmethod.InputMethodSession#displayCompletions
+     * InputMethodSession.displayCompletions()} as a result of the editor calling
+     * {@link android.view.inputmethod.InputMethodManager#displayCompletions
+     * InputMethodManager.displayCompletions()}.
+     */
+    public static final int TYPE_TEXT_FLAG_AUTO_COMPLETE = 0x00010000;
+    
+    /**
+     * Flag for {@link #TYPE_CLASS_TEXT}: multiple lines of text can be
+     * entered into the field.
+     */
+    public static final int TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000;
+    
+    // ----------------------------------------------------------------------
+    
+    /**
+     * Default variation of {@link #TYPE_CLASS_TEXT}: plain old normal text.
+     */
+    public static final int TYPE_TEXT_VARIATION_NORMAL = 0x00000000;
+    
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering a URI.
+     */
+    public static final int TYPE_TEXT_VARIATION_URI = 0x00000010;
+    
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering an e-mail address.
+     */
+    public static final int TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 0x00000020;
+    
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering the subject line of
+     * an e-mail.
+     */
+    public static final int TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 0x00000030;
+    
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering the content of
+     * an e-mail.
+     */
+    public static final int TYPE_TEXT_VARIATION_EMAIL_CONTENT = 0x00000040;
+    
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering the name of a person.
+     */
+    public static final int TYPE_TEXT_VARIATION_PERSON_NAME = 0x00000050;
+    
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering a postal mailing
+     * address.
+     */
+    public static final int TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x00000060;
+    
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering a password.
+     */
+    public static final int TYPE_TEXT_VARIATION_PASSWORD = 0x00000070;
+    
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering a search string
+     * for a web search.
+     */
+    public static final int TYPE_TEXT_VARIATION_WEB_SEARCH = 0x00000080;
+    
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering text inside of
+     * a web form.
+     */
+    public static final int TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x00000090;
+    
+    // ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
+    
+    /**
+     * Class for numeric text.  This class supports the following flag:
+     * {@link #TYPE_NUMBER_FLAG_SIGNED} and
+     * {@link #TYPE_NUMBER_FLAG_DECIMAL}.
+     */
+    public static final int TYPE_CLASS_NUMBER = 0x00000002;
+    
+    /**
+     * Flag of {@link #TYPE_CLASS_NUMBER}: the number is signed, allowing
+     * a positive or negative sign at the start.
+     */
+    public static final int TYPE_NUMBER_FLAG_SIGNED = 0x00001000;
+    
+    /**
+     * Flag of {@link #TYPE_CLASS_NUMBER}: the number is decimal, allowing
+     * a decimal point to provide fractional values.
+     */
+    public static final int TYPE_NUMBER_FLAG_DECIMAL = 0x00002000;
+    
+    // ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
+    
+    /**
+     * Class for a phone number.  This class currently supports no variations
+     * or flags.
+     */
+    public static final int TYPE_CLASS_PHONE = 0x00000003;
+    
+    // ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
+    
+    /**
+     * Class for dates and times.  It supports the
+     * following variations:
+     * {@link #TYPE_DATETIME_VARIATION_NORMAL}
+     * {@link #TYPE_DATETIME_VARIATION_DATE}, and
+     * {@link #TYPE_DATETIME_VARIATION_TIME},.
+     */
+    public static final int TYPE_CLASS_DATETIME = 0x00000004;
+    
+    /**
+     * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering
+     * both a date and time.
+     */
+    public static final int TYPE_DATETIME_VARIATION_NORMAL = 0x00000000;
+    
+    /**
+     * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering
+     * only a date.
+     */
+    public static final int TYPE_DATETIME_VARIATION_DATE = 0x00000010;
+    
+    /**
+     * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering
+     * only a time.
+     */
+    public static final int TYPE_DATETIME_VARIATION_TIME = 0x00000020;
+}
diff --git a/core/java/android/text/LoginFilter.java b/core/java/android/text/LoginFilter.java
index dd2d77f..27c703f 100644
--- a/core/java/android/text/LoginFilter.java
+++ b/core/java/android/text/LoginFilter.java
@@ -83,8 +83,21 @@
         }
         
         onStop();
+
+        if (!changed) {
+            return null;
+        }
         
-        return changed ? new String(out, 0, outidx) : null;
+        String s = new String(out, 0, outidx);
+        
+        if (source instanceof Spanned) {
+            SpannableString sp = new SpannableString(s);
+            TextUtils.copySpansFrom((Spanned) source,
+                                    start, end, null, sp, 0);
+            return sp;
+        } else {
+            return s;
+        }
     }
     
     /**
diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java
index 0f4916a..44469ec 100644
--- a/core/java/android/text/Selection.java
+++ b/core/java/android/text/Selection.java
@@ -417,10 +417,13 @@
         }
     }
 
+    private static final class START { };
+    private static final class END { };
+    
     /*
      * Public constants
      */
 
-    public static final Object SELECTION_START = new Object();
-    public static final Object SELECTION_END = new Object();
+    public static final Object SELECTION_START = new START();
+    public static final Object SELECTION_END = new END();
 }
diff --git a/core/java/android/text/Spanned.java b/core/java/android/text/Spanned.java
index 2b4b4d2..bd0a16b 100644
--- a/core/java/android/text/Spanned.java
+++ b/core/java/android/text/Spanned.java
@@ -26,6 +26,12 @@
 extends CharSequence
 {
     /**
+     * Bitmask of bits that are relevent for controlling point/mark behavior
+     * of spans.
+     */
+    public static final int SPAN_POINT_MARK_MASK = 0x33;
+    
+    /**
      * 0-length spans with type SPAN_MARK_MARK behave like text marks:
      * they remain at their original offset when text is inserted
      * at that offset.
@@ -92,6 +98,14 @@
     public static final int SPAN_EXCLUSIVE_INCLUSIVE = SPAN_POINT_POINT;
 
     /**
+     * This flag is set on spans that are being used to apply temporary
+     * styling information on the composing text of an input method, so that
+     * they can be found and removed when the composing text is being
+     * replaced.
+     */
+    public static final int SPAN_COMPOSING = 0x100;
+    
+    /**
      * The bits numbered SPAN_USER_SHIFT and above are available
      * for callers to use to store scalar data associated with their
      * span object.
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 2d18575..ceb9f4f 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -907,7 +907,8 @@
 
             mLineDirections[j] = linedirs;
 
-            if (ellipsize != null) {
+            // If ellipsize is in marquee mode, do not apply ellipsis on the first line
+            if (ellipsize != null && (ellipsize != TextUtils.TruncateAt.MARQUEE || j != 0)) {
                 calculateEllipsis(start, end, widths, widstart, widoff,
                                   ellipsiswidth, ellipsize, j,
                                   textwidth, paint);
@@ -950,7 +951,7 @@
 
             ellipsisStart = 0;
             ellipsisCount = i;
-        } else if (where == TextUtils.TruncateAt.END) {
+        } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE) {
             float sum = 0;
             int i;
 
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index e791aaf..64356d5 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -22,6 +22,7 @@
 import android.content.res.Resources;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.method.TextKeyListener.Capitalize;
 import android.text.style.AbsoluteSizeSpan;
 import android.text.style.AlignmentSpan;
 import android.text.style.BackgroundColorSpan;
@@ -42,13 +43,14 @@
 import android.text.style.TypefaceSpan;
 import android.text.style.URLSpan;
 import android.text.style.UnderlineSpan;
+import android.util.Printer;
+
 import com.android.internal.util.ArrayUtils;
 
 import java.util.regex.Pattern;
 import java.util.Iterator;
 
-public class TextUtils
-{
+public class TextUtils {
     private TextUtils() { /* cannot be instantiated */ }
 
     private static String[] EMPTY_STRING_ARRAY = new String[]{};
@@ -827,6 +829,30 @@
     };
 
     /**
+     * Debugging tool to print the spans in a CharSequence.  The output will
+     * be printed one span per line.  If the CharSequence is not a Spanned,
+     * then the entire string will be printed on a single line.
+     */
+    public static void dumpSpans(CharSequence cs, Printer printer, String prefix) {
+        if (cs instanceof Spanned) {
+            Spanned sp = (Spanned) cs;
+            Object[] os = sp.getSpans(0, cs.length(), Object.class);
+
+            for (int i = 0; i < os.length; i++) {
+                Object o = os[i];
+                printer.println(prefix + cs.subSequence(sp.getSpanStart(o),
+                        sp.getSpanEnd(o)) + ": "
+                        + Integer.toHexString(System.identityHashCode(o))
+                        + " " + o.getClass().getCanonicalName()
+                         + " (" + sp.getSpanStart(o) + "-" + sp.getSpanEnd(o)
+                         + ") fl=#" + sp.getSpanFlags(o));
+            }
+        } else {
+            printer.println(prefix + cs + ": (no spans)");
+        }
+    }
+
+    /**
      * Return a new CharSequence in which each of the source strings is
      * replaced by the corresponding element of the destinations.
      */
@@ -1021,6 +1047,7 @@
         START,
         MIDDLE,
         END,
+        MARQUEE,
     }
 
     public interface EllipsizeCallback {
@@ -1460,7 +1487,7 @@
             case '&':
                 sb.append("&amp;"); //$NON-NLS-1$
                 break;
-            case '\\':
+            case '\'':
                 sb.append("&apos;"); //$NON-NLS-1$
                 break;
             case '"':
@@ -1565,6 +1592,132 @@
         return true;
     }
 
+    /**
+     * Capitalization mode for {@link #getCapsMode}: capitalize all
+     * characters.  This value is explicitly defined to be the same as
+     * {@link InputType#TYPE_TEXT_FLAG_CAP_CHARACTERS}.
+     */
+    public static final int CAP_MODE_CHARACTERS
+            = InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
+    
+    /**
+     * Capitalization mode for {@link #getCapsMode}: capitalize the first
+     * character of all words.  This value is explicitly defined to be the same as
+     * {@link InputType#TYPE_TEXT_FLAG_CAP_WORDS}.
+     */
+    public static final int CAP_MODE_WORDS
+            = InputType.TYPE_TEXT_FLAG_CAP_WORDS;
+    
+    /**
+     * Capitalization mode for {@link #getCapsMode}: capitalize the first
+     * character of each sentence.  This value is explicitly defined to be the same as
+     * {@link InputType#TYPE_TEXT_FLAG_CAP_SENTENCES}.
+     */
+    public static final int CAP_MODE_SENTENCES
+            = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
+    
+    /**
+     * Determine what caps mode should be in effect at the current offset in
+     * the text.  Only the mode bits set in <var>reqModes</var> will be
+     * checked.  Note that the caps mode flags here are explicitly defined
+     * to match those in {@link InputType}.
+     * 
+     * @param cs The text that should be checked for caps modes.
+     * @param off Location in the text at which to check.
+     * @param reqModes The modes to be checked: may be any combination of
+     * {@link #CAP_MODE_CHARACTERS}, {@link #CAP_MODE_WORDS}, and
+     * {@link #CAP_MODE_SENTENCES}.
+     * 
+     * @return Returns the actual capitalization modes that can be in effect
+     * at the current position, which is any combination of
+     * {@link #CAP_MODE_CHARACTERS}, {@link #CAP_MODE_WORDS}, and
+     * {@link #CAP_MODE_SENTENCES}.
+     */
+    public static int getCapsMode(CharSequence cs, int off, int reqModes) {
+        int i;
+        char c;
+        int mode = 0;
+
+        if ((reqModes&CAP_MODE_CHARACTERS) != 0) {
+            mode |= CAP_MODE_CHARACTERS;
+        }
+        if ((reqModes&(CAP_MODE_WORDS|CAP_MODE_SENTENCES)) == 0) {
+            return mode;
+        }
+
+        // Back over allowed opening punctuation.
+
+        for (i = off; i > 0; i--) {
+            c = cs.charAt(i - 1);
+
+            if (c != '"' && c != '\'' &&
+                Character.getType(c) != Character.START_PUNCTUATION) {
+                break;
+            }
+        }
+
+        // Start of paragraph, with optional whitespace.
+
+        int j = i;
+        while (j > 0 && ((c = cs.charAt(j - 1)) == ' ' || c == '\t')) {
+            j--;
+        }
+        if (j == 0 || cs.charAt(j - 1) == '\n') {
+            return mode | CAP_MODE_WORDS;
+        }
+
+        // Or start of word if we are that style.
+
+        if ((reqModes&CAP_MODE_SENTENCES) == 0) {
+            if (i != j) mode |= CAP_MODE_WORDS;
+            return mode;
+        }
+
+        // There must be a space if not the start of paragraph.
+
+        if (i == j) {
+            return mode;
+        }
+
+        // Back over allowed closing punctuation.
+
+        for (; j > 0; j--) {
+            c = cs.charAt(j - 1);
+
+            if (c != '"' && c != '\'' &&
+                Character.getType(c) != Character.END_PUNCTUATION) {
+                break;
+            }
+        }
+
+        if (j > 0) {
+            c = cs.charAt(j - 1);
+
+            if (c == '.' || c == '?' || c == '!') {
+                // Do not capitalize if the word ends with a period but
+                // also contains a period, in which case it is an abbreviation.
+
+                if (c == '.') {
+                    for (int k = j - 2; k >= 0; k--) {
+                        c = cs.charAt(k);
+
+                        if (c == '.') {
+                            return mode;
+                        }
+
+                        if (!Character.isLetter(c)) {
+                            break;
+                        }
+                    }
+                }
+
+                return mode | CAP_MODE_SENTENCES;
+            }
+        }
+
+        return mode;
+    }
+    
     private static Object sLock = new Object();
     private static char[] sTemp = null;
 }
diff --git a/core/java/android/pim/DateFormat.java b/core/java/android/text/format/DateFormat.java
similarity index 82%
rename from core/java/android/pim/DateFormat.java
rename to core/java/android/text/format/DateFormat.java
index 802e045..3437978 100644
--- a/core/java/android/pim/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -14,19 +14,21 @@
  * limitations under the License.
  */
 
-package android.pim;
+package android.text.format;
 
 import android.content.Context;
 import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.SpannedString;
 
+import com.android.internal.R;
+
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.TimeZone;
+import java.text.SimpleDateFormat;
 
 /**
     Utility class for producing strings with formatted date/time.
@@ -187,12 +189,32 @@
     public  static final char    YEAR                   =    'y';
 
     /**
-     * @return true if the user has set the system to use a 24 hour time
-     * format, else false.
+     * Returns true if user preference is set to 24-hour format.
+     * @param context the context to use for the content resolver
+     * @return true if 24 hour time format is selected, false otherwise.
      */
     public static boolean is24HourFormat(Context context) {
         String value = Settings.System.getString(context.getContentResolver(),
                 Settings.System.TIME_12_24);
+
+        if (value == null) {
+            java.text.DateFormat natural =
+                java.text.DateFormat.getTimeInstance(
+                    java.text.DateFormat.LONG,
+                    context.getResources().getConfiguration().locale);
+
+            if (natural instanceof SimpleDateFormat) {
+                SimpleDateFormat sdf = (SimpleDateFormat) natural;
+                String pattern = sdf.toPattern();
+
+                if (pattern.indexOf('H') >= 0) {
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        }
+
         boolean b24 =  !(value == null || value.equals("12"));
         return b24;
     }
@@ -205,7 +227,15 @@
      */
     public static final java.text.DateFormat getTimeFormat(Context context) {
         boolean b24 = is24HourFormat(context);
-        return new java.text.SimpleDateFormat(b24 ? "H:mm" : "h:mm a");
+        int res;
+
+        if (b24) {
+            res = R.string.twenty_four_hour_time_format;
+        } else {
+            res = R.string.twelve_hour_time_format;
+        }
+
+        return new java.text.SimpleDateFormat(context.getString(res));
     }
 
     /**
@@ -228,13 +258,29 @@
     public static final java.text.DateFormat getLongDateFormat(Context context) {
         String value = getDateFormatString(context);
         if (value.indexOf('M') < value.indexOf('d')) {
-            value = "MMMM dd, yyyy";
+            value = context.getString(R.string.full_date_month_first);
         } else {
-            value = "dd MMMM, yyyy";
+            value = context.getString(R.string.full_date_day_first);
         }
         return new java.text.SimpleDateFormat(value);
     }
-    
+
+    /**
+     * Returns a {@link java.text.DateFormat} object that can format the date
+     * in medium form (such as Dec. 31, 1999) based on user preference.
+     * @param context the application context
+     * @return the {@link java.text.DateFormat} object that formats the date in long form.
+     */
+    public static final java.text.DateFormat getMediumDateFormat(Context context) {
+        String value = getDateFormatString(context);
+        if (value.indexOf('M') < value.indexOf('d')) {
+            value = context.getString(R.string.medium_date_month_first);
+        } else {
+            value = context.getString(R.string.medium_date_day_first);
+        }
+        return new java.text.SimpleDateFormat(value);
+    }
+
     /**
      * Gets the current date format stored as a char array. The array will contain
      * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order    
@@ -274,15 +320,33 @@
         String value = Settings.System.getString(context.getContentResolver(),
                 Settings.System.DATE_FORMAT);
         if (value == null || value.length() < 6) {
+            /*
+             * No need to localize -- this is an emergency fallback in case
+             * the setting is missing, but it should always be set.
+             */
             value = "MM-dd-yyyy";
         }
         return value;
     }
 
+    /**
+     * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a 
+     * CharSequence containing the requested date.
+     * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
+     * @param inTimeInMillis in milliseconds since Jan 1, 1970 GMT
+     * @return a {@link CharSequence} containing the requested text
+     */
     public static final CharSequence format(CharSequence inFormat, long inTimeInMillis) {
         return format(inFormat, new Date(inTimeInMillis));
     }
 
+    /**
+     * Given a format string and a {@link java.util.Date} object, returns a CharSequence containing
+     * the requested date.
+     * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
+     * @param inDate the date to format
+     * @return a {@link CharSequence} containing the requested text
+     */
     public static final CharSequence format(CharSequence inFormat, Date inDate) {
         Calendar    c = new GregorianCalendar();
         
@@ -291,6 +355,13 @@
         return format(inFormat, c);
     }
 
+    /**
+     * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence 
+     * containing the requested date.
+     * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
+     * @param inDate the date to format
+     * @return a {@link CharSequence} containing the requested text
+     */
     public static final CharSequence format(CharSequence inFormat, Calendar inDate) {
         SpannableStringBuilder      s = new SpannableStringBuilder(inFormat);
         int             c;
diff --git a/core/java/android/pim/DateUtils.java b/core/java/android/text/format/DateUtils.java
similarity index 82%
rename from core/java/android/pim/DateUtils.java
rename to core/java/android/text/format/DateUtils.java
index 2a01f12..48f65c6 100644
--- a/core/java/android/pim/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -14,25 +14,26 @@
  * limitations under the License.
  */
 
-package android.pim;
+package android.text.format;
+
+import com.android.internal.R;
 
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.pim.DateException;
 
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.TimeZone;
 
-import com.android.internal.R;
-
 /**
+ * This class contains various date-related utilities for creating text for things like
+ * elapsed time and date ranges, strings for days of the week and months, and AM/PM text etc.
  */
 public class DateUtils
 {
-    private static final String TAG = "DateUtils";
-
     private static final Object sLock = new Object();
     private static final int[] sDaysLong = new int[] {
             com.android.internal.R.string.day_of_week_long_sunday,
@@ -125,9 +126,7 @@
             com.android.internal.R.string.am,
             com.android.internal.R.string.pm,
         };
-    private static int sFirstDay;
     private static Configuration sLastConfig;
-    private static String sStatusDateFormat;
     private static String sStatusTimeFormat;
     private static String sElapsedFormatMMSS;
     private static String sElapsedFormatHMMSS;
@@ -153,17 +152,18 @@
     public static final int FORMAT_NO_YEAR        = 0x00008;
     public static final int FORMAT_SHOW_DATE      = 0x00010;
     public static final int FORMAT_NO_MONTH_DAY   = 0x00020;
-    public static final int FORMAT_24HOUR         = 0x00040;
-    public static final int FORMAT_CAP_AMPM       = 0x00080;
-    public static final int FORMAT_NO_NOON        = 0x00100;
-    public static final int FORMAT_CAP_NOON       = 0x00200;
-    public static final int FORMAT_NO_MIDNIGHT    = 0x00400;
-    public static final int FORMAT_CAP_MIDNIGHT   = 0x00800;
-    public static final int FORMAT_UTC            = 0x01000;
-    public static final int FORMAT_ABBREV_TIME    = 0x02000;
-    public static final int FORMAT_ABBREV_WEEKDAY = 0x04000;
-    public static final int FORMAT_ABBREV_MONTH   = 0x08000;
-    public static final int FORMAT_NUMERIC_DATE   = 0x10000;
+    public static final int FORMAT_12HOUR         = 0x00040;
+    public static final int FORMAT_24HOUR         = 0x00080;
+    public static final int FORMAT_CAP_AMPM       = 0x00100;
+    public static final int FORMAT_NO_NOON        = 0x00200;
+    public static final int FORMAT_CAP_NOON       = 0x00400;
+    public static final int FORMAT_NO_MIDNIGHT    = 0x00800;
+    public static final int FORMAT_CAP_MIDNIGHT   = 0x01000;
+    public static final int FORMAT_UTC            = 0x02000;
+    public static final int FORMAT_ABBREV_TIME    = 0x04000;
+    public static final int FORMAT_ABBREV_WEEKDAY = 0x08000;
+    public static final int FORMAT_ABBREV_MONTH   = 0x10000;
+    public static final int FORMAT_NUMERIC_DATE   = 0x20000;
     public static final int FORMAT_ABBREV_ALL     = (FORMAT_ABBREV_TIME
             | FORMAT_ABBREV_WEEKDAY | FORMAT_ABBREV_MONTH);
     public static final int FORMAT_CAP_NOON_MIDNIGHT = (FORMAT_CAP_NOON | FORMAT_CAP_MIDNIGHT);
@@ -172,10 +172,6 @@
     // Date and time format strings that are constant and don't need to be
     // translated.
     public static final String HOUR_MINUTE_24 = "%H:%M";
-    public static final String HOUR_MINUTE_AMPM = "%-l:%M%P";
-    public static final String HOUR_MINUTE_CAP_AMPM = "%-l:%M%p";
-    public static final String HOUR_AMPM = "%-l%P";
-    public static final String HOUR_CAP_AMPM = "%-l%p";
     public static final String MONTH_FORMAT = "%B";
     public static final String ABBREV_MONTH_FORMAT = "%b";
     public static final String NUMERIC_MONTH_FORMAT = "%m";
@@ -238,7 +234,7 @@
 
     /**
      * Request the full spelled-out name.
-     * For use with the 'abbrev' parameter of {@link #getDayOfWeekStr} and {@link #getMonthStr}.
+     * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}.
      * @more
      * <p>e.g. "Sunday" or "January"
      */
@@ -246,7 +242,7 @@
 
     /**
      * Request an abbreviated version of the name.
-     * For use with the 'abbrev' parameter of {@link #getDayOfWeekStr} and {@link #getMonthStr}.
+     * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}.
      * @more
      * <p>e.g. "Sun" or "Jan"
      */
@@ -254,7 +250,7 @@
 
     /**
      * Request a shorter abbreviated version of the name.
-     * For use with the 'abbrev' parameter of {@link #getDayOfWeekStr} and {@link #getMonthStr}.
+     * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}.
      * @more
      * <p>e.g. "Su" or "Jan"
      * <p>In some languages, the results returned for LENGTH_SHORT may be the same as
@@ -264,7 +260,7 @@
 
     /**
      * Request an even shorter abbreviated version of the name.
-     * For use with the 'abbrev' parameter of {@link #getDayOfWeekStr} and {@link #getMonthStr}.
+     * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}.
      * @more
      * <p>e.g. "M", "Tu", "Th" or "J"
      * <p>In some languages, the results returned for LENGTH_SHORTEST may be the same as
@@ -274,7 +270,7 @@
 
     /**
      * Request an even shorter abbreviated version of the name.
-     * For use with the 'abbrev' parameter of {@link #getDayOfWeekStr} and {@link #getMonthStr}.
+     * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}.
      * @more
      * <p>e.g. "S", "T", "T" or "J"
      * <p>In some languages, the results returned for LENGTH_SHORTEST may be the same as
@@ -282,11 +278,10 @@
      */
     public static final int LENGTH_SHORTEST = 50;
 
-
     /**
      * Return a string for the day of the week.
-     * @param dayOfWeek One of {@link #Calendar.SUNDAY Calendar.SUNDAY},
-     *               {@link #Calendar.MONDAY Calendar.MONDAY}, etc.
+     * @param dayOfWeek One of {@link Calendar#SUNDAY Calendar.SUNDAY},
+     *               {@link Calendar#MONDAY Calendar.MONDAY}, etc.
      * @param abbrev One of {@link #LENGTH_LONG}, {@link #LENGTH_SHORT}, {@link #LENGTH_SHORTER}
      *               or {@link #LENGTH_SHORTEST}.  For forward compatibility, anything else
      *               will return the same as {#LENGTH_MEDIUM}.
@@ -308,9 +303,10 @@
     }
 
     /**
-     * Return a string for AM or PM.
+     * Return a localized string for AM or PM.
      * @param ampm Either {@link Calendar#AM Calendar.AM} or {@link Calendar#PM Calendar.PM}.
      * @throws IndexOutOfBoundsException if the ampm is out of bounds.
+     * @return Localized version of "AM" or "PM".
      */
     public static String getAMPMString(int ampm) {
         Resources r = Resources.getSystem();
@@ -318,12 +314,13 @@
     }
 
     /**
-     * Return a string for the day of the week.
-     * @param month One of {@link #Calendar.JANUARY Calendar.JANUARY},
-     *               {@link #Calendar.FEBRUARY Calendar.FEBRUARY}, etc.
+     * Return a localized string for the day of the week.
+     * @param month One of {@link Calendar#JANUARY Calendar.JANUARY},
+     *               {@link Calendar#FEBRUARY Calendar.FEBRUARY}, etc.
      * @param abbrev One of {@link #LENGTH_LONG}, {@link #LENGTH_SHORT}, {@link #LENGTH_SHORTER}
      *               or {@link #LENGTH_SHORTEST}.  For forward compatibility, anything else
      *               will return the same as {#LENGTH_MEDIUM}.
+     * @return Localized day of the week.
      */
     public static String getMonthString(int month, int abbrev) {
         // Note that here we use sMonthsMedium for MEDIUM, SHORT and SHORTER. 
@@ -344,6 +341,12 @@
         return r.getString(list[month - Calendar.JANUARY]);
     }
 
+    /**
+     * Returns a string describing the elapsed time since startTime.
+     * @param startTime some time in the past.
+     * @return a String object containing the elapsed time.
+     * @see #getRelativeTimeSpanString(long, long, long)
+     */
     public static CharSequence getRelativeTimeSpanString(long startTime) {
         return getRelativeTimeSpanString(startTime, System.currentTimeMillis(), MINUTE_IN_MILLIS);
     }
@@ -363,67 +366,50 @@
     public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution) {
         Resources r = Resources.getSystem();
 
-        // TODO: Assembling strings by hand like this is bad style for i18n.
-        boolean past = (now > time);
-        String prefix = past ? null : r.getString(com.android.internal.R.string.in);
-        String postfix = past ? r.getString(com.android.internal.R.string.ago) : null;
-        return getRelativeTimeSpanString(time, now, minResolution, prefix, postfix);
-    }
-
-    public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution, 
-            String prefix, String postfix) {
-        Resources r = Resources.getSystem(); 
-        
+        boolean past = (now >= time);
         long duration = Math.abs(now - time);
         
+        int resId;
+        long count;
         if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) {
-            long count = duration / SECOND_IN_MILLIS;
-            String singular = r.getString(com.android.internal.R.string.second);
-            String plural = r.getString(com.android.internal.R.string.seconds);
-            return pluralizedSpan(count, singular, plural, prefix, postfix);
-        }
-
-        if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) {
-            long count = duration / MINUTE_IN_MILLIS;
-            String singular = r.getString(com.android.internal.R.string.minute);
-            String plural = r.getString(com.android.internal.R.string.minutes);
-            return pluralizedSpan(count, singular, plural, prefix, postfix);
-        }
-
-        if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) {
-            long count = duration / HOUR_IN_MILLIS;
-            String singular = r.getString(com.android.internal.R.string.hour);
-            String plural = r.getString(com.android.internal.R.string.hours);
-            return pluralizedSpan(count, singular, plural, prefix, postfix);
-        }
-
-        if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
-            return getRelativeDayString(r, time, now);
+            count = duration / SECOND_IN_MILLIS;
+            if (past) {
+                resId = com.android.internal.R.plurals.num_seconds_ago;
+            } else {
+                resId = com.android.internal.R.plurals.in_num_seconds;
+            }
+        } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) {
+            count = duration / MINUTE_IN_MILLIS;
+            if (past) {
+                resId = com.android.internal.R.plurals.num_minutes_ago;
+            } else {
+                resId = com.android.internal.R.plurals.in_num_minutes;
+            }
+        } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) {
+            count = duration / HOUR_IN_MILLIS;
+            if (past) {
+                resId = com.android.internal.R.plurals.num_hours_ago;
+            } else {
+                resId = com.android.internal.R.plurals.in_num_hours;
+            }
+        } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
+            count = duration / DAY_IN_MILLIS;
+            if (past) {
+                resId = com.android.internal.R.plurals.num_days_ago;
+            } else {
+                resId = com.android.internal.R.plurals.in_num_days;
+            }
+        } else {
+            // Longer than a week ago, so just show the date.
+            int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_ABBREV_MONTH;
+            
+            // We know that we won't be showing the time, so it is safe to pass
+            // in a null context.
+            return formatDateRange(null, time, time, flags);
         }
         
-        return dateString(time);
-    }
-    
-
-    private static final String pluralizedSpan(long count, String singular, String plural, 
-            String prefix, String postfix) {
-        StringBuilder s = new StringBuilder();
-
-        if (prefix != null) {
-            s.append(prefix);
-            s.append(" ");
-        }
-        
-        s.append(count);
-        s.append(' ');
-        s.append(count == 0 || count > 1 ? plural : singular);
-        
-        if (postfix != null) {
-            s.append(" ");
-            s.append(postfix);
-        }
-
-        return s.toString();
+        String format = r.getQuantityString(resId, (int) count);
+        return String.format(format, count);
     }
 
     /**
@@ -457,12 +443,16 @@
         } else if (days == 0) {
             return r.getString(com.android.internal.R.string.today);
         }
-        
-        if (!past) {
-            return r.getString(com.android.internal.R.string.daysDurationFuturePlural, days);
+
+        int resId;
+        if (past) {
+            resId = com.android.internal.R.plurals.num_days_ago;
         } else {
-            return r.getString(com.android.internal.R.string.daysDurationPastPlural, days);
+            resId = com.android.internal.R.plurals.in_num_days;
         }
+        
+        String format = r.getQuantityString(resId, days);
+        return String.format(format, days);
     }
 
     private static void initFormatStrings() {
@@ -472,7 +462,6 @@
             if (sLastConfig == null || !sLastConfig.equals(cfg)) {
                 sLastConfig = cfg;
                 sStatusTimeFormat = r.getString(com.android.internal.R.string.status_bar_time_format);
-                sStatusDateFormat = r.getString(com.android.internal.R.string.status_bar_date_format);
                 sElapsedFormatMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_mm_ss);
                 sElapsedFormatHMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_h_mm_ss);
             }
@@ -488,20 +477,11 @@
         initFormatStrings();
         return DateFormat.format(sStatusTimeFormat, millis);
     }
-    
-    /**
-     * Format a date so it appears like it would in the status bar clock.
-     * @deprecated use {@link #DateFormat.getDateFormat(Context)} instead.
-     * @hide
-     */
-    public static final CharSequence dateString(long startTime) {
-        initFormatStrings();
-        return DateFormat.format(sStatusDateFormat, startTime);
-    }
 
     /**
-     * Formats an elapsed time like MM:SS or H:MM:SS
+     * Formats an elapsed time in the form "MM:SS" or "H:MM:SS"
      * for display on the call-in-progress screen.
+     * @param elapsedSeconds the elapsed time in seconds.
      */
     public static String formatElapsedTime(long elapsedSeconds) {
         initFormatStrings();
@@ -584,7 +564,7 @@
         return (char) (digit + '0');
     }
     
-    /*
+    /**
      * Format a date / time such that if the then is on the same day as now, it shows
      * just the time and if it's a different day, it shows just the date.
      * 
@@ -623,7 +603,7 @@
 
     /**
      * @hide
-     * @deprecated use {@link android.pim.Time}
+     * @deprecated use {@link android.text.format.Time}
      */
     public static Calendar newCalendar(boolean zulu)
     {
@@ -652,7 +632,7 @@
     
     /**
      * @hide
-     * @deprecated use {@link android.pim.Time}
+     * @deprecated use {@link android.text.format.Time}
      */
     private static final int ctoi(String str, int index)
                                                 throws DateException
@@ -667,7 +647,7 @@
 
     /**
      * @hide
-     * @deprecated use {@link android.pim.Time}
+     * @deprecated use {@link android.text.format.Time}
      */
     private static final int check(int lowerBound, int upperBound, int value)
                                                 throws DateException
@@ -681,7 +661,7 @@
 
     /**
      * @hide
-     * @deprecated use {@link android.pim.Time}
+     * @deprecated use {@link android.text.format.Time}
      * Return true if this date string is local time
      */
     public static boolean isUTC(String s)
@@ -702,7 +682,7 @@
     // Returns if the Z was present, meaning that the time is in UTC
     /**
      * @hide
-     * @deprecated use {@link android.pim.Time}
+     * @deprecated use {@link android.text.format.Time}
      */
     public static boolean parseDateTime(String str, Calendar cal)
                                                 throws DateException
@@ -748,7 +728,7 @@
      * Given a timezone string which can be null, and a dateTime string,
      * set that time into a calendar.
      * @hide
-     * @deprecated use {@link android.pim.Time}
+     * @deprecated use {@link android.text.format.Time}
      */
     public static void parseDateTime(String tz, String dateTime, Calendar out)
                                                 throws DateException
@@ -778,7 +758,7 @@
      *
      * @param cal the date and time to write
      * @hide
-     * @deprecated use {@link android.pim.Time}
+     * @deprecated use {@link android.text.format.Time}
      */
     public static String writeDateTime(Calendar cal)
     {
@@ -796,7 +776,7 @@
      * be written at the end as per RFC2445.  Otherwise, the time is
      * considered in localtime.
      * @hide
-     * @deprecated use {@link android.pim.Time}
+     * @deprecated use {@link android.text.format.Time}
      */
     public static String writeDateTime(Calendar cal, boolean zulu)
     {
@@ -819,7 +799,7 @@
      *           has already been called on sb to the appropriate length
      *           which is sb.setLength(zulu ? 16 : 15)
      * @hide
-     * @deprecated use {@link android.pim.Time}
+     * @deprecated use {@link android.text.format.Time}
      */
     public static String writeDateTime(Calendar cal, StringBuilder sb)
     {
@@ -866,7 +846,7 @@
 
     /**
      * @hide
-     * @deprecated use {@link android.pim.Time}
+     * @deprecated use {@link android.text.format.Time}
      */
     public static void assign(Calendar lval, Calendar rval)
     {
@@ -876,8 +856,31 @@
     }
 
     /**
-     * Creates a string describing a date/time range.  The flags argument
-     * is a bitmask of options from the following list:
+     * Formats a date or a time range according to the local conventions.
+     * 
+     * <p>
+     * Example output strings (date formats in these examples are shown using
+     * the US date format convention but that may change depending on the
+     * local settings):
+     * <ul>
+     *   <li>10:15am</li>
+     *   <li>3:00pm - 4:00pm</li>
+     *   <li>3pm - 4pm</li>
+     *   <li>3PM - 4PM</li>
+     *   <li>08:00 - 17:00</li>
+     *   <li>Oct 9</li>
+     *   <li>Tue, Oct 9</li>
+     *   <li>October 9, 2007</li>
+     *   <li>Oct 9 - 10</li>
+     *   <li>Oct 9 - 10, 2007</li>
+     *   <li>Oct 28 - Nov 3, 2007</li>
+     *   <li>Dec 31, 2007 - Jan 1, 2008</li>
+     *   <li>Oct 9, 8:00am - Oct 10, 5:00pm</li>
+     *   <li>12/31/2007 - 01/01/2008</li>
+     * </ul>
+     * 
+     * <p>
+     * The flags argument is a bitmask of options from the following list:
      * 
      * <ul>
      *   <li>FORMAT_SHOW_TIME</li>
@@ -886,6 +889,7 @@
      *   <li>FORMAT_NO_YEAR</li>
      *   <li>FORMAT_SHOW_DATE</li>
      *   <li>FORMAT_NO_MONTH_DAY</li>
+     *   <li>FORMAT_12HOUR</li>
      *   <li>FORMAT_24HOUR</li>
      *   <li>FORMAT_CAP_AMPM</li>
      *   <li>FORMAT_NO_NOON</li>
@@ -946,15 +950,25 @@
      * shown instead of "midnight".
      * 
      * <p>
+     * If FORMAT_12HOUR is set and the time is shown, then the time is
+     * shown in the 12-hour time format. You should not normally set this.
+     * Instead, let the time format be chosen automatically according to the
+     * system settings. If both FORMAT_12HOUR and FORMAT_24HOUR are set, then
+     * FORMAT_24HOUR takes precedence.
+     * 
+     * <p>
      * If FORMAT_24HOUR is set and the time is shown, then the time is
-     * shown in the 24-hour time format.
+     * shown in the 24-hour time format. You should not normally set this.
+     * Instead, let the time format be chosen automatically according to the
+     * system settings. If both FORMAT_12HOUR and FORMAT_24HOUR are set, then
+     * FORMAT_24HOUR takes precedence.
      * 
      * <p>
      * If FORMAT_UTC is set, then the UTC timezone is used for the start
      * and end milliseconds.
      * 
      * <p>
-     * If FORMAT_ABBREV_TIME is set and FORMAT_24HOUR is not set, then the
+     * If FORMAT_ABBREV_TIME is set and 12-hour time format is used, then the
      * start and end times (if shown) are abbreviated by not showing the minutes
      * if they are zero.  For example, instead of "3:00pm" the time would be
      * abbreviated to "3pm".
@@ -976,30 +990,15 @@
      * instead of using the name of the month.  For example, "12/31/2008"
      * instead of "December 31, 2008".
      * 
-     * <p>
-     * Example output strings:
-     * <ul>
-     *   <li>10:15am</li>
-     *   <li>3:00pm - 4:00pm</li>
-     *   <li>3pm - 4pm</li>
-     *   <li>3PM - 4PM</li>
-     *   <li>08:00 - 17:00</li>
-     *   <li>Oct 9</li>
-     *   <li>Tue, Oct 9</li>
-     *   <li>October 9, 2007</li>
-     *   <li>Oct 9 - 10</li>
-     *   <li>Oct 9 - 10, 2007</li>
-     *   <li>Oct 28 - Nov 3, 2007</li>
-     *   <li>Dec 31, 2007 - Jan 1, 2008</li>
-     *   <li>Oct 9, 8:00am - Oct 10, 5:00pm</li>
-     * </ul>
+     * @param context the context is required only if the time is shown
      * @param startMillis the start time in UTC milliseconds
      * @param endMillis the end time in UTC milliseconds
      * @param flags a bit mask of options
      *   
-     * @return a string with the formatted date/time range.
+     * @return a string containing the formatted date/time range.
      */
-    public static String formatDateRange(long startMillis, long endMillis, int flags) {
+    public static String formatDateRange(Context context, long startMillis,
+                long endMillis, int flags) {
         Resources res = Resources.getSystem();
         boolean showTime = (flags & FORMAT_SHOW_TIME) != 0;
         boolean showWeekDay = (flags & FORMAT_SHOW_WEEKDAY) != 0;
@@ -1008,7 +1007,6 @@
         boolean useUTC = (flags & FORMAT_UTC) != 0;
         boolean abbrevWeekDay = (flags & FORMAT_ABBREV_WEEKDAY) != 0;
         boolean abbrevMonth = (flags & FORMAT_ABBREV_MONTH) != 0;
-        boolean use24Hour = (flags & FORMAT_24HOUR) != 0;
         boolean noMonthDay = (flags & FORMAT_NO_MONTH_DAY) != 0;
         boolean numericDate = (flags & FORMAT_NUMERIC_DATE) != 0;
     
@@ -1039,7 +1037,7 @@
         // the end of Nov 11?).
         // If we are not showing the time then also adjust the end date
         // for multiple-day events.  This is to allow us to display, for
-        // example, "Nov 10 -11" for an event with an start date of Nov 10
+        // example, "Nov 10 -11" for an event with a start date of Nov 10
         // and an end date of Nov 12 at 00:00.
         // If the start and end time are the same, then skip this and don't
         // adjust the date.
@@ -1075,6 +1073,16 @@
         if (showTime) {
             String startTimeFormat = "";
             String endTimeFormat = "";
+            boolean force24Hour = (flags & FORMAT_24HOUR) != 0;
+            boolean force12Hour = (flags & FORMAT_12HOUR) != 0;
+            boolean use24Hour;
+            if (force24Hour) {
+                use24Hour = true;
+            } else if (force12Hour) {
+                use24Hour = false;
+            } else {
+                use24Hour = DateFormat.is24HourFormat(context);
+            }
             if (use24Hour) {
                 startTimeFormat = HOUR_MINUTE_24;
                 endTimeFormat = HOUR_MINUTE_24;
@@ -1090,28 +1098,28 @@
                 boolean endOnTheHour = endDate.minute == 0 && endDate.second == 0;
                 if (abbrevTime && startOnTheHour) {
                     if (capAMPM) {
-                        startTimeFormat = HOUR_CAP_AMPM;
+                        startTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm);
                     } else {
-                        startTimeFormat = HOUR_AMPM;
+                        startTimeFormat = res.getString(com.android.internal.R.string.hour_ampm);
                     }
                 } else {
                     if (capAMPM) {
-                        startTimeFormat = HOUR_MINUTE_CAP_AMPM;
+                        startTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm);
                     } else {
-                        startTimeFormat = HOUR_MINUTE_AMPM;
+                        startTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm);
                     }
                 }
                 if (abbrevTime && endOnTheHour) {
                     if (capAMPM) {
-                        endTimeFormat = HOUR_CAP_AMPM;
+                        endTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm);
                     } else {
-                        endTimeFormat = HOUR_AMPM;
+                        endTimeFormat = res.getString(com.android.internal.R.string.hour_ampm);
                     }
                 } else {
                     if (capAMPM) {
-                        endTimeFormat = HOUR_MINUTE_CAP_AMPM;
+                        endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm);
                     } else {
-                        endTimeFormat = HOUR_MINUTE_AMPM;
+                        endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm);
                     }
                 }
                 
@@ -1346,63 +1354,117 @@
     }
 
     /**
+     * Formats a date or a time according to the local conventions. There are
+     * lots of options that allow the caller to control, for example, if the
+     * time is shown, if the day of the week is shown, if the month name is
+     * abbreviated, if noon is shown instead of 12pm, and so on. For the
+     * complete list of options, see the documentation for
+     * {@link #formatDateRange}.
+     * <p>
+     * Example output strings (date formats in these examples are shown using
+     * the US date format convention but that may change depending on the
+     * local settings):
+     * <ul>
+     *   <li>10:15am</li>
+     *   <li>3:00pm</li>
+     *   <li>3pm</li>
+     *   <li>3PM</li>
+     *   <li>08:00</li>
+     *   <li>17:00</li>
+     *   <li>noon</li>
+     *   <li>Noon</li>
+     *   <li>midnight</li>
+     *   <li>Midnight</li>
+     *   <li>Oct 31</li>
+     *   <li>Oct 31, 2007</li>
+     *   <li>October 31, 2007</li>
+     *   <li>10am, Oct 31</li>
+     *   <li>17:00, Oct 31</li>
+     *   <li>Wed</li>
+     *   <li>Wednesday</li>
+     *   <li>10am, Wed, Oct 31</li>
+     *   <li>Wed, Oct 31</li>
+     *   <li>Wednesday, Oct 31</li>
+     *   <li>Wed, Oct 31, 2007</li>
+     *   <li>Wed, October 31</li>
+     *   <li>10/31/2007</li>
+     * </ul>
+     * 
+     * @param context the context is required only if the time is shown
+     * @param millis a point in time in UTC milliseconds
+     * @param flags a bit mask of formatting options
+     * @return a string containing the formatted date/time.
+     */
+    public static String formatDateTime(Context context, long millis, int flags) {
+        return formatDateRange(context, millis, millis, flags);
+    }
+
+    /**
      * @return a relative time string to display the time expressed by millis.  Times
      * are counted starting at midnight, which means that assuming that the current
      * time is March 31st, 0:30:
-     * "millis=0:10 today" will be displayed as "0:10" 
-     * "millis=11:30pm the day before" will be displayed as "Mar 30"
-     * A similar scheme is used to dates that are a week, a month or more than a year old. 
+     * <ul>
+     *   <li>"millis=0:10 today" will be displayed as "0:10"</li> 
+     *   <li>"millis=11:30pm the day before" will be displayed as "Mar 30"</li>
+     * </ul>
+     * If the given millis is in a different year, then the full date is
+     * returned in numeric format (e.g., "10/12/2008").
      * 
      * @param withPreposition If true, the string returned will include the correct 
-     * preposition ("at 9:20am", "in 2008" or "on May 29").
+     * preposition ("at 9:20am", "on 10/12/2008" or "on May 29").
      */
     public static CharSequence getRelativeTimeSpanString(Context c, long millis,
             boolean withPreposition) {
 
-        long span = System.currentTimeMillis() - millis;
+        long now = System.currentTimeMillis();
+        long span = now - millis;
 
         Resources res = c.getResources();
         if (sNowTime == null) {
             sNowTime = new Time();
             sThenTime = new Time();
-            sMonthDayFormat = res.getString(com.android.internal.R.string.abbrev_month_day);
         }
 
-        sNowTime.setToNow();
+        sNowTime.set(now);
         sThenTime.set(millis);
 
+        String result;
+        int prepositionId;
         if (span < DAY_IN_MILLIS && sNowTime.weekDay == sThenTime.weekDay) {
             // Same day
-            return getPrepositionDate(res, sThenTime, R.string.preposition_for_time,
-                    HOUR_MINUTE_CAP_AMPM, withPreposition);
+            int flags = FORMAT_SHOW_TIME;
+            result = formatDateRange(c, millis, millis, flags);
+            prepositionId = R.string.preposition_for_time;
         } else if (sNowTime.year != sThenTime.year) {
             // Different years
-            // TODO: take locale into account so that the display will adjust correctly.
-            return getPrepositionDate(res, sThenTime, R.string.preposition_for_year,
-                    NUMERIC_MONTH_FORMAT + "/" + MONTH_DAY_FORMAT + "/" + YEAR_FORMAT_TWO_DIGITS,
-                    withPreposition);
+            int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE;
+            result = formatDateRange(c, millis, millis, flags);
+
+            // This is a date (like "10/31/2008" so use the date preposition)
+            prepositionId = R.string.preposition_for_date;
         } else {
             // Default
-            return getPrepositionDate(res, sThenTime, R.string.preposition_for_date,
-                sMonthDayFormat, withPreposition);
+            int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH;
+            result = formatDateRange(c, millis, millis, flags);
+            prepositionId = R.string.preposition_for_date;
         }
+        if (withPreposition) {
+            result = res.getString(prepositionId, result);
+        }
+        return result;
     }
     
     /**
-     * @return A date string suitable for display based on the format and including the
-     * date preposition if withPreposition is true.
+     * Convenience function to return relative time string without preposition. 
+     * @param c context for resources
+     * @param millis time in milliseconds
+     * @return {@link CharSequence} containing relative time.
+     * @see #getRelativeTimeSpanString(Context, long, boolean)
      */
-    private static String getPrepositionDate(Resources res, Time thenTime, int id,
-            String formatString, boolean withPreposition) {
-        String result = thenTime.format(formatString);
-        return withPreposition ? res.getString(id, result) : result;
-    }
-    
     public static CharSequence getRelativeTimeSpanString(Context c, long millis) {
         return getRelativeTimeSpanString(c, millis, false /* no preposition */);
     }
     
     private static Time sNowTime;
     private static Time sThenTime;
-    private static String sMonthDayFormat;
 }
diff --git a/core/java/android/content/Formatter.java b/core/java/android/text/format/Formatter.java
similarity index 71%
rename from core/java/android/content/Formatter.java
rename to core/java/android/text/format/Formatter.java
index 8ad9f40..1b30aa0 100644
--- a/core/java/android/content/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-package android.content;
+package android.text.format;
+
+import android.content.Context;
 
 /**
  * Utility class to aid in formatting common values that are not covered
- * by the standard java.util.Formatter
- * @hide
+ * by the standard java.util.Formatter.
  */
 public final class Formatter {
 
     /**
-     * Formats a content size to be in the form of bytes, kilobytes, 
-     * megabytes, etc
+     * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc
      * 
      * @param context Context to use to load the localized units
      * @param number size value to be formated
@@ -63,4 +63,21 @@
         }
         return String.format("%.0f%s", result, context.getText(suffix).toString());
     }
+    
+    /**
+     * Returns a string in the canonical IP format ###.###.###.### from a packed integer containing
+     * the IP address.  The IP address is expected to be in little-endian format (LSB first). That
+     * is, 0x01020304 will return "4.3.2.1".
+     * 
+     * @param addr the IP address as a packed integer with LSB first.
+     * @return string with canonical IP address format.
+     */
+    public static String formatIpAddress(int addr) {
+        StringBuffer buf = new StringBuffer();
+        buf.append(addr  & 0xff).append('.').
+            append((addr >>>= 8) & 0xff).append('.').
+            append((addr >>>= 8) & 0xff).append('.').
+            append((addr >>>= 8) & 0xff);
+        return buf.toString();
+    }
 }
diff --git a/core/java/android/pim/Time.java b/core/java/android/text/format/Time.java
similarity index 64%
rename from core/java/android/pim/Time.java
rename to core/java/android/text/format/Time.java
index 59ba87b..5bf9b20 100644
--- a/core/java/android/pim/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package android.pim;
+package android.text.format;
 
+import android.content.res.Resources;
 
-
+import java.util.Locale;
 import java.util.TimeZone;
 
 /**
- * {@hide}
- *
  * The Time class is a faster replacement for the java.util.Calendar and
  * java.util.GregorianCalendar classes. An instance of the Time class represents
  * a moment in time, specified with second precision. It is modelled after
@@ -30,6 +29,10 @@
  * functionality.
  */
 public class Time {
+    private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000";
+    private static final String Y_M_D_T_H_M_S_000_Z = "%Y-%m-%dT%H:%M:%S.000Z";
+    private static final String Y_M_D = "%Y-%m-%d";
+    
     public static final String TIMEZONE_UTC = "UTC";
 
     /**
@@ -90,6 +93,7 @@
      * <li><b>positive</b> - in dst</li>
      * <li><b>0</b> - not in dst</li>
      * <li><b>negative</b> - unknown</li>
+     * </ul>
      */
     public int isDst;
 
@@ -125,9 +129,26 @@
     public static final int FRIDAY = 5;
     public static final int SATURDAY = 6;
 
+    /*
+     * The Locale for which date formatting strings have been loaded.
+     */
+    private static Locale sLocale;
+    private static String[] sShortMonths;
+    private static String[] sLongMonths;
+    private static String[] sShortWeekdays;
+    private static String[] sLongWeekdays;
+    private static String sTimeOnlyFormat;
+    private static String sDateOnlyFormat;
+    private static String sDateTimeFormat;
+    private static String sAm;
+    private static String sPm;
+    private static String sDateCommand = "%a %b %e %H:%M:%S %Z %Y";
+
     /**
      * Construct a Time object in the timezone named by the string
      * argument "timezone". The time is initialized to Jan 1, 1970.
+     * @param timezone string containing the timezone to use.
+     * @see TimeZone
      */
     public Time(String timezone) {
         if (timezone == null) {
@@ -142,7 +163,7 @@
     }
 
     /**
-     * Construct a Time object in the local timezone. The time is initialized to
+     * Construct a Time object in the default timezone. The time is initialized to
      * Jan 1, 1970.
      */
     public Time() {
@@ -191,6 +212,8 @@
      * Return the maximum possible value for the given field given the value of
      * the other fields. Requires that it be normalized for MONTH_DAY and
      * YEAR_DAY.
+     * @param field one of the constants for HOUR, MINUTE, SECOND, etc.
+     * @return the maximum value for the field.
      */
     public int getActualMaximum(int field) {
         switch (field) {
@@ -230,6 +253,7 @@
     /**
      * Clears all values, setting the timezone to the given timezone. Sets isDst
      * to a negative value to mean "unknown".
+     * @param timezone the timezone to use.
      */
     public void clear(String timezone) {
         if (timezone == null) {
@@ -259,8 +283,76 @@
      * Print the current value given the format string provided. See man
      * strftime for what means what. The final string must be less than 256
      * characters.
+     * @param format a string containing the desired format.
+     * @return a String containing the current time expressed in the current locale.
      */
-    native public String format(String format);
+    public String format(String format) {
+        synchronized (Time.class) {
+            Locale locale = Locale.getDefault();
+
+            if (sLocale == null || locale == null || !(locale.equals(sLocale))) {
+                Resources r = Resources.getSystem();
+
+                sShortMonths = new String[] {
+                    r.getString(com.android.internal.R.string.month_medium_january),
+                    r.getString(com.android.internal.R.string.month_medium_february),
+                    r.getString(com.android.internal.R.string.month_medium_march),
+                    r.getString(com.android.internal.R.string.month_medium_april),
+                    r.getString(com.android.internal.R.string.month_medium_may),
+                    r.getString(com.android.internal.R.string.month_medium_june),
+                    r.getString(com.android.internal.R.string.month_medium_july),
+                    r.getString(com.android.internal.R.string.month_medium_august),
+                    r.getString(com.android.internal.R.string.month_medium_september),
+                    r.getString(com.android.internal.R.string.month_medium_october),
+                    r.getString(com.android.internal.R.string.month_medium_november),
+                    r.getString(com.android.internal.R.string.month_medium_december),
+                };
+                sLongMonths = new String[] {
+                    r.getString(com.android.internal.R.string.month_long_january),
+                    r.getString(com.android.internal.R.string.month_long_february),
+                    r.getString(com.android.internal.R.string.month_long_march),
+                    r.getString(com.android.internal.R.string.month_long_april),
+                    r.getString(com.android.internal.R.string.month_long_may),
+                    r.getString(com.android.internal.R.string.month_long_june),
+                    r.getString(com.android.internal.R.string.month_long_july),
+                    r.getString(com.android.internal.R.string.month_long_august),
+                    r.getString(com.android.internal.R.string.month_long_september),
+                    r.getString(com.android.internal.R.string.month_long_october),
+                    r.getString(com.android.internal.R.string.month_long_november),
+                    r.getString(com.android.internal.R.string.month_long_december),
+                };
+                sShortWeekdays = new String[] {
+                    r.getString(com.android.internal.R.string.day_of_week_medium_sunday),
+                    r.getString(com.android.internal.R.string.day_of_week_medium_monday),
+                    r.getString(com.android.internal.R.string.day_of_week_medium_tuesday),
+                    r.getString(com.android.internal.R.string.day_of_week_medium_wednesday),
+                    r.getString(com.android.internal.R.string.day_of_week_medium_thursday),
+                    r.getString(com.android.internal.R.string.day_of_week_medium_friday),
+                    r.getString(com.android.internal.R.string.day_of_week_medium_saturday),
+                };
+                sLongWeekdays = new String[] {
+                    r.getString(com.android.internal.R.string.day_of_week_long_sunday),
+                    r.getString(com.android.internal.R.string.day_of_week_long_monday),
+                    r.getString(com.android.internal.R.string.day_of_week_long_tuesday),
+                    r.getString(com.android.internal.R.string.day_of_week_long_wednesday),
+                    r.getString(com.android.internal.R.string.day_of_week_long_thursday),
+                    r.getString(com.android.internal.R.string.day_of_week_long_friday),
+                    r.getString(com.android.internal.R.string.day_of_week_long_saturday),
+                };
+                sTimeOnlyFormat = r.getString(com.android.internal.R.string.time_of_day);
+                sDateOnlyFormat = r.getString(com.android.internal.R.string.month_day_year);
+                sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time);
+                sAm = r.getString(com.android.internal.R.string.am);
+                sPm = r.getString(com.android.internal.R.string.pm);
+
+                sLocale = locale;
+            }
+
+            return format1(format);
+        }
+    }
+
+    native private String format1(String format);
 
     /**
      * Return the current time in YYYYMMDDTHHMMSS<tz> format
@@ -269,33 +361,79 @@
     native public String toString();
 
     /**
-     * Parse a time in the current zone in YYYYMMDDTHHMMSS format.
-     */
-    native public void parse(String s);
-
-    /**
-     * Parse a time in RFC 2445 format. Returns whether or not the time is in
-     * UTC (ends with Z).
+     * Parses a date-time string in either the RFC 2445 format or an abbreviated
+     * format that does not include the "time" field.  For example, all of the
+     * following strings are valid:
+     * 
+     * <ul>
+     *   <li>"20081013T160000Z"</li>
+     *   <li>"20081013T160000"</li>
+     *   <li>"20081013"</li>
+     * </ul>
+     * 
+     * Returns whether or not the time is in UTC (ends with Z).  If the string
+     * ends with "Z" then the timezone is set to UTC.  If the date-time string
+     * included only a date and no time field, then the <code>allDay</code>
+     * field of this Time class is set to true and the <code>hour</code>,
+     * <code>minute</code>, and <code>second</code> fields are set to zero;
+     * otherwise (a time field was included in the date-time string)
+     * <code>allDay</code> is set to false. The fields <code>weekDay</code>,
+     * <code>yearDay</code>, and <code>gmtoff</code> are always set to zero,
+     * and the field <code>isDst</code> is set to -1 (unknown).  To set those
+     * fields, call {@link #normalize(boolean)} after parsing.
+     * 
+     * To parse a date-time string and convert it to UTC milliseconds, do
+     * something like this:
+     * 
+     * <pre>
+     *   Time time = new Time();
+     *   String date = "20081013T160000Z";
+     *   time.parse(date);
+     *   long millis = time.normalize(false);
+     * </pre>
      *
      * @param s the string to parse
      * @return true if the resulting time value is in UTC time
      */
-    public boolean parse2445(String s) {
-        if (nativeParse2445(s)) {
+    public boolean parse(String s) {
+        if (nativeParse(s)) {
             timezone = TIMEZONE_UTC;
             return true;
         }
         return false;
     }
 
-    native private boolean nativeParse2445(String s);
+    /**
+     * Parse a time in the current zone in YYYYMMDDTHHMMSS format.
+     */
+    native private boolean nativeParse(String s);
 
     /**
      * Parse a time in RFC 3339 format.  This method also parses simple dates
-     * (that is, strings that contain no time or time offset).  If the string
-     * contains a time and time offset, then the time offset will be used to
-     * convert the time value to UTC.
+     * (that is, strings that contain no time or time offset).  For example,
+     * all of the following strings are valid:
+     * 
+     * <ul>
+     *   <li>"2008-10-13T16:00:00.000Z"</li>
+     *   <li>"2008-10-13T16:00:00.000+07:00"</li>
+     *   <li>"2008-10-13T16:00:00.000-07:00"</li>
+     *   <li>"2008-10-13"</li>
+     * </ul>
+     * 
+     * <p>
+     * If the string contains a time and time offset, then the time offset will
+     * be used to convert the time value to UTC.
+     * </p>
+     * 
+     * <p>
+     * If the given string contains just a date (with no time field), then
+     * the {@link #allDay} field is set to true and the {@link #hour},
+     * {@link #minute}, and  {@link #second} fields are set to zero.
+     * </p>
+     * 
+     * <p>
      * Returns true if the resulting time value is in UTC time.
+     * </p>
      *
      * @param s the string to parse
      * @return true if the resulting time value is in UTC time
@@ -408,8 +546,8 @@
     }
 
     /**
-     * Set the fields. Sets weekDay, yearDay and gmtoff to 0. Call
-     * normalize() if you need those.
+     * Sets the fields. Sets weekDay, yearDay and gmtoff to 0, and isDst to -1.
+     * Call {@link #normalize(boolean)} if you need those.
      */
     public void set(int second, int minute, int hour, int monthDay, int month, int year) {
         this.allDay = false;
@@ -425,6 +563,15 @@
         this.gmtoff = 0;
     }
 
+    /**
+     * Sets the date from the given fields.  Also sets allDay to true.
+     * Sets weekDay, yearDay and gmtoff to 0, and isDst to -1.
+     * Call {@link #normalize(boolean)} if you need those.
+     * 
+     * @param monthDay the day of the month (in the range [1,31])
+     * @param month the zero-based month number (in the range [0,11])
+     * @param year the year
+     */
     public void set(int monthDay, int month, int year) {
         this.allDay = true;
         this.second = 0;
@@ -439,10 +586,25 @@
         this.gmtoff = 0;
     }
 
+    /**
+     * Returns true if the time represented by this Time object occurs before
+     * the given time.
+     * 
+     * @param that a given Time object to compare against
+     * @return true if this time is less than the given time
+     */
     public boolean before(Time that) {
         return Time.compare(this, that) < 0;
     }
 
+
+    /**
+     * Returns true if the time represented by this Time object occurs after
+     * the given time.
+     * 
+     * @param that a given Time object to compare against
+     * @return true if this time is greater than the given time
+     */
     public boolean after(Time that) {
         return Time.compare(this, that) > 0;
     }
@@ -459,14 +621,18 @@
      * object must already be normalized because this method uses the
      * yearDay and weekDay fields.
      * 
+     * <p>
      * In IS0 8601, weeks start on Monday.
      * The first week of the year (week 1) is defined by ISO 8601 as the
      * first week with four or more of its days in the starting year.
      * Or equivalently, the week containing January 4.  Or equivalently,
      * the week with the year's first Thursday in it.
+     * </p>
      * 
+     * <p>
      * The week number can be calculated by counting Thursdays.  Week N
      * contains the Nth Thursday of the year.
+     * </p>
      *   
      * @return the ISO week number.
      */
@@ -486,13 +652,24 @@
         return temp.yearDay / 7 + 1;
     }
 
+    /**
+     * Return a string in the RFC 3339 format. 
+     * <p>
+     * If allDay is true, expresses the time as Y-M-D</p>
+     * <p>
+     * Otherwise, if the timezone is UTC, expresses the time as Y-M-D-T-H-M-S UTC</p>
+     * <p>
+     * Otherwise the time is expressed the time as Y-M-D-T-H-M-S +- GMT</p>
+     * @param allDay
+     * @return string in the RFC 3339 format.
+     */
     public String format3339(boolean allDay) {
         if (allDay) {
-            return format("%Y-%m-%d");
+            return format(Y_M_D);
         } else if (TIMEZONE_UTC.equals(timezone)) {
-            return format("%Y-%m-%dT%H:%M:%S.000Z");
+            return format(Y_M_D_T_H_M_S_000_Z);
         } else {
-            String base = format("%Y-%m-%dT%H:%M:%S.000");
+            String base = format(Y_M_D_T_H_M_S_000);
             String sign = (gmtoff < 0) ? "-" : "+";
             int offset = (int)Math.abs(gmtoff);
             int minutes = (offset % 3600) / 60;
@@ -502,6 +679,13 @@
         }
     }
     
+    /**
+     * Returns true if the day of the given time is the epoch on the Julian Calendar 
+     * (January 1, 1970 on the Gregorian calendar).
+     *
+     * @param time the time to test
+     * @return true if epoch.
+     */
     public static boolean isEpoch(Time time) {
         long millis = time.toMillis(true);
         return getJulianDay(millis, 0) == EPOCH_JULIAN_DAY;
@@ -536,6 +720,7 @@
      * GMT offset than whatever is currently stored in this Time object anyway.
      * After this method returns all the fields will be normalized and the time
      * will be set to 12am at the beginning of the given Julian day.
+     * </p>
      * 
      * <p>
      * The only exception to this is if 12am does not exist for that day because
@@ -543,6 +728,7 @@
      * hour at 12am on April 25, 2008 and there are a few other places that
      * also change daylight saving time at 12am.  In those cases, the time
      * will be set to 1am.
+     * </p>
      * 
      * @param julianDay the Julian day in the timezone for this Time object
      * @return the UTC milliseconds for the beginning of the Julian day
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index ac2e499..652413e 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -155,34 +155,11 @@
         return false;
     }
 
-    public boolean onTrackballEvent(TextView widget, Spannable buffer,
-                                    MotionEvent event) {
-        boolean handled = false;
-        int x = (int) event.getX();
-        int y = (int) event.getY();
-
-        for (; y < 0; y++) {
-            handled |= up(widget, buffer);
-        }
-        for (; y > 0; y--) {
-            handled |= down(widget, buffer);
-        }
-
-        for (; x < 0; x++) {
-            handled |= left(widget, buffer);
-        }
-        for (; x > 0; x--) {
-            handled |= right(widget, buffer);
-        }
-
-        if (handled) {
-            MetaKeyKeyListener.adjustMetaAfterKeypress(buffer);
-            MetaKeyKeyListener.resetLockedMeta(buffer);
-        }
-
-        return handled;
+    public boolean onTrackballEvent(TextView widget, Spannable text,
+            MotionEvent event) {
+        return false;
     }
-
+    
     public boolean onTouchEvent(TextView widget, Spannable buffer,
                                 MotionEvent event) {
         boolean handled = Touch.onTouchEvent(widget, buffer, event);
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 3e92b7b..a875368 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -18,9 +18,9 @@
 
 import android.view.KeyEvent;
 import android.view.View;
-import android.os.Message;
-import android.util.Log;
+import android.text.InputType;
 import android.text.*;
+import android.text.method.TextKeyListener.Capitalize;
 import android.widget.TextView;
 
 public abstract class BaseKeyListener
@@ -99,6 +99,25 @@
         return true;
     }
 
+    static int makeTextContentType(Capitalize caps, boolean autoText) {
+        int contentType = InputType.TYPE_CLASS_TEXT;
+        switch (caps) {
+            case CHARACTERS:
+                contentType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
+                break;
+            case WORDS:
+                contentType |= InputType.TYPE_TEXT_FLAG_CAP_WORDS;
+                break;
+            case SENTENCES:
+                contentType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
+                break;
+        }
+        if (autoText) {
+            contentType |= InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
+        }
+        return contentType;
+    }
+    
     public boolean onKeyDown(View view, Editable content,
                              int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DEL) {
diff --git a/core/java/android/text/method/CharacterPickerDialog.java b/core/java/android/text/method/CharacterPickerDialog.java
index d787132..3c406751 100644
--- a/core/java/android/text/method/CharacterPickerDialog.java
+++ b/core/java/android/text/method/CharacterPickerDialog.java
@@ -69,7 +69,7 @@
 
         WindowManager.LayoutParams params = getWindow().getAttributes();
         params.token = mView.getApplicationWindowToken();
-        params.type = params.TYPE_APPLICATION_PANEL;
+        params.type = params.TYPE_APPLICATION_ATTACHED_DIALOG;
 
         setTitle(R.string.select_character);
         setContentView(R.layout.character_picker);
diff --git a/core/java/android/text/method/DateKeyListener.java b/core/java/android/text/method/DateKeyListener.java
index 0ca0332..7c11434 100644
--- a/core/java/android/text/method/DateKeyListener.java
+++ b/core/java/android/text/method/DateKeyListener.java
@@ -17,12 +17,18 @@
 package android.text.method;
 
 import android.view.KeyEvent;
+import android.text.InputType;
 
 /**
  * For entering dates in a text field.
  */
 public class DateKeyListener extends NumberKeyListener
 {
+    public int getInputType() {
+        return InputType.TYPE_CLASS_DATETIME
+                | InputType.TYPE_DATETIME_VARIATION_DATE;
+    }
+    
     @Override
     protected char[] getAcceptedChars()
     {
diff --git a/core/java/android/text/method/DateTimeKeyListener.java b/core/java/android/text/method/DateTimeKeyListener.java
index 304d326..f8ebc40 100644
--- a/core/java/android/text/method/DateTimeKeyListener.java
+++ b/core/java/android/text/method/DateTimeKeyListener.java
@@ -16,6 +16,7 @@
 
 package android.text.method;
 
+import android.text.InputType;
 import android.view.KeyEvent;
 
 /**
@@ -23,6 +24,11 @@
  */
 public class DateTimeKeyListener extends NumberKeyListener
 {
+    public int getInputType() {
+        return InputType.TYPE_CLASS_DATETIME
+                | InputType.TYPE_DATETIME_VARIATION_NORMAL;
+    }
+    
     @Override
     protected char[] getAcceptedChars()
     {
diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java
index e805ad7..b121e60 100644
--- a/core/java/android/text/method/DialerKeyListener.java
+++ b/core/java/android/text/method/DialerKeyListener.java
@@ -18,7 +18,7 @@
 
 import android.view.KeyEvent;
 import android.view.KeyCharacterMap.KeyData;
-import android.util.SparseIntArray;
+import android.text.InputType;
 import android.text.Spannable;
 
 /**
@@ -40,6 +40,10 @@
         return sInstance;
     }
 
+    public int getInputType() {
+        return InputType.TYPE_CLASS_PHONE;
+    }
+    
     /**
      * Overrides the superclass's lookup method to prefer the number field
      * from the KeyEvent.
diff --git a/core/java/android/text/method/DigitsKeyListener.java b/core/java/android/text/method/DigitsKeyListener.java
index 99a3f1a..f0f072c 100644
--- a/core/java/android/text/method/DigitsKeyListener.java
+++ b/core/java/android/text/method/DigitsKeyListener.java
@@ -16,6 +16,7 @@
 
 package android.text.method;
 
+import android.text.InputType;
 import android.text.Spanned;
 import android.text.SpannableStringBuilder;
 import android.view.KeyEvent;
@@ -109,6 +110,17 @@
         return dim;
     }
 
+    public int getInputType() {
+        int contentType = InputType.TYPE_CLASS_NUMBER;
+        if (mSign) {
+            contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
+        }
+        if (mDecimal) {
+            contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
+        }
+        return contentType;
+    }
+    
     @Override
     public CharSequence filter(CharSequence source, int start, int end,
                                Spanned dest, int dstart, int dend) {
diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java
index 05ab72d..4ae6191 100644
--- a/core/java/android/text/method/KeyListener.java
+++ b/core/java/android/text/method/KeyListener.java
@@ -16,14 +16,39 @@
 
 package android.text.method;
 
+import android.text.Editable;
 import android.view.KeyEvent;
 import android.view.View;
-import android.os.Message;
-import android.text.*;
-import android.widget.TextView;
 
-public interface KeyListener
-{
+/**
+ * Interface for converting text key events into edit operations on an
+ * Editable class.  Note that for must cases this interface has been
+ * superceded by general soft input methods as defined by
+ * {@link android.view.inputmethod.InputMethod}; it should only be used
+ * for cases where an application has its own on-screen keypad and also wants
+ * to process hard keyboard events to match it.
+ */
+public interface KeyListener {
+    /**
+     * Return the type of text that this key listener is manipulating,
+     * as per {@link android.text.InputType}.  This is used to
+     * determine the mode of the soft keyboard that is shown for the editor.
+     * 
+     * <p>If you return
+     * {@link android.text.InputType#TYPE_NULL}
+     * then <em>no</em> soft keyboard will provided.  In other words, you
+     * must be providing your own key pad for on-screen input and the key
+     * listener will be used to handle input from a hard keyboard.
+     * 
+     * <p>If you
+     * return any other value, a soft input method will be created when the
+     * user puts focus in the editor, which will provide a keypad and also
+     * consume hard key events.  This means that the key listener will generally
+     * not be used, instead the soft input method will take care of managing
+     * key input as per the content type returned here.
+     */
+    public int getInputType();
+    
     /**
      * If the key listener wants to handle this key, return true,
      * otherwise return false and the caller (i.e. the widget host)
@@ -39,4 +64,9 @@
      */
     public boolean onKeyUp(View view, Editable text,
                            int keyCode, KeyEvent event);
+    
+    /**
+     * Remove the given shift states from the edited text.
+     */
+    public void clearMetaKeyState(View view, Editable content, int states);
 }
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index 2d75b873..f0305d9 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -221,6 +221,12 @@
             content.setSpan(what, 0, 0, RELEASED);
     }
 
+    public void clearMetaKeyState(View view, Editable content, int states) {
+        if ((states&META_SHIFT_ON) != 0) resetLock(content, CAP);
+        if ((states&META_ALT_ON) != 0) resetLock(content, ALT);
+        if ((states&META_SYM_ON) != 0) resetLock(content, SYM);
+    }
+    
     /**
      * The meta key has been pressed but has not yet been used.
      */
diff --git a/core/java/android/text/method/MultiTapKeyListener.java b/core/java/android/text/method/MultiTapKeyListener.java
index 7137d40..6d94788 100644
--- a/core/java/android/text/method/MultiTapKeyListener.java
+++ b/core/java/android/text/method/MultiTapKeyListener.java
@@ -18,14 +18,11 @@
 
 import android.view.KeyEvent;
 import android.view.View;
-import android.os.Message;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.text.*;
 import android.text.method.TextKeyListener.Capitalize;
-import android.widget.TextView;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
 
 /**
  * This is the standard key listener for alphabetic input on 12-key
@@ -77,6 +74,10 @@
         return sInstance[off];
     }
 
+    public int getInputType() {
+        return makeTextContentType(mCapitalize, mAutoText);
+    }
+    
     public boolean onKeyDown(View view, Editable content,
                              int keyCode, KeyEvent event) {
         int selStart, selEnd;
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index ae7ba8f..863b2e2 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -58,6 +58,10 @@
         return sInstance[off];
     }
 
+    public int getInputType() {
+        return makeTextContentType(mAutoCap, mAutoText);
+    }
+    
     public boolean onKeyDown(View view, Editable content,
                              int keyCode, KeyEvent event) {
         int selStart, selEnd;
@@ -219,7 +223,7 @@
             if ((pref & TextKeyListener.AUTO_TEXT) != 0 && mAutoText &&
                 (i == ' ' || i == '\t' || i == '\n' ||
                  i == ',' || i == '.' || i == '!' || i == '?' ||
-                 i == '"' || i == ')' || i == ']') &&
+                 i == '"' || Character.getType(i) == Character.END_PUNCTUATION) &&
                  content.getSpanEnd(TextKeyListener.INHIBIT_REPLACEMENT)
                      != oldStart) {
                 int x;
@@ -257,7 +261,16 @@
                         content.charAt(selEnd - 2) == ' ') {
                         char c = content.charAt(selEnd - 3);
 
-                        if (Character.isLetter(c)) {
+                        for (int j = selEnd - 3; j > 0; j--) {
+                            if (c == '"' ||
+                                Character.getType(c) == Character.END_PUNCTUATION) {
+                                c = content.charAt(j - 1);
+                            } else {
+                                break;
+                            }
+                        }
+
+                        if (Character.isLetter(c) || Character.isDigit(c)) {
                             content.replace(selEnd - 2, selEnd - 1, ".");
                         }
                     }
diff --git a/core/java/android/text/method/ScrollingMovementMethod.java b/core/java/android/text/method/ScrollingMovementMethod.java
index 0438e1e..db470be 100644
--- a/core/java/android/text/method/ScrollingMovementMethod.java
+++ b/core/java/android/text/method/ScrollingMovementMethod.java
@@ -171,34 +171,16 @@
         return false;
     }
 
+    public boolean onTrackballEvent(TextView widget, Spannable text,
+            MotionEvent event) {
+        return false;
+    }
+    
     public boolean onTouchEvent(TextView widget, Spannable buffer,
                                  MotionEvent event) {
         return Touch.onTouchEvent(widget, buffer, event);
     }
 
-    public boolean onTrackballEvent(TextView widget, Spannable buffer,
-                                    MotionEvent event) {
-        boolean handled = false;
-        int x = (int) event.getX();
-        int y = (int) event.getY();
-
-        for (; y < 0; y++) {
-            handled |= up(widget, buffer);
-        }
-        for (; y > 0; y--) {
-            handled |= down(widget, buffer);
-        }
-
-        for (; x < 0; x++) {
-            handled |= left(widget, buffer);
-        }
-        for (; x > 0; x--) {
-            handled |= right(widget, buffer);
-        }
-
-        return handled;
-    }
-
     public void initialize(TextView widget, Spannable text) { }
 
     public boolean canSelectArbitrarily() {
diff --git a/core/java/android/text/method/TextKeyListener.java b/core/java/android/text/method/TextKeyListener.java
index 012e41d..b1c380a 100644
--- a/core/java/android/text/method/TextKeyListener.java
+++ b/core/java/android/text/method/TextKeyListener.java
@@ -26,6 +26,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.View;
+import android.text.InputType;
 
 import java.lang.ref.WeakReference;
 
@@ -114,76 +115,15 @@
             return true;
         }
 
-        // Back over allowed opening punctuation.
-
-        for (i = off; i > 0; i--) {
-            c = cs.charAt(i - 1);
-
-            if (c != '"' && c != '(' && c != '[' && c != '\'') {
-                break;
-            }
-        }
-
-        // Start of paragraph, with optional whitespace.
-
-        int j = i;
-        while (j > 0 && ((c = cs.charAt(j - 1)) == ' ' || c == '\t')) {
-            j--;
-        }
-        if (j == 0 || cs.charAt(j - 1) == '\n') {
-            return true;
-        }
-
-        // Or start of word if we are that style.
-
-        if (cap == Capitalize.WORDS) {
-            return i != j;
-        }
-
-        // There must be a space if not the start of paragraph.
-
-        if (i == j) {
-            return false;
-        }
-
-        // Back over allowed closing punctuation.
-
-        for (; j > 0; j--) {
-            c = cs.charAt(j - 1);
-
-            if (c != '"' && c != ')' && c != ']' && c != '\'') {
-                break;
-            }
-        }
-
-        if (j > 0) {
-            c = cs.charAt(j - 1);
-
-            if (c == '.' || c == '?' || c == '!') {
-                // Do not capitalize if the word ends with a period but
-                // also contains a period, in which case it is an abbreviation.
-
-                if (c == '.') {
-                    for (int k = j - 2; k >= 0; k--) {
-                        c = cs.charAt(k);
-
-                        if (c == '.') {
-                            return false;
-                        }
-
-                        if (!Character.isLetter(c)) {
-                            break;
-                        }
-                    }
-                }
-
-                return true;
-            }
-        }
-
-        return false;
+        return TextUtils.getCapsMode(cs, off, cap == Capitalize.WORDS
+                ? TextUtils.CAP_MODE_WORDS : TextUtils.CAP_MODE_SENTENCES)
+                != 0;
     }
 
+    public int getInputType() {
+        return makeTextContentType(mAutoCap, mAutoText);
+    }
+    
     @Override
     public boolean onKeyDown(View view, Editable content,
                              int keyCode, KeyEvent event) {
@@ -251,6 +191,10 @@
 
     private static class NullKeyListener implements KeyListener
     {
+        public int getInputType() {
+            return InputType.TYPE_NULL;
+        }
+        
         public boolean onKeyDown(View view, Editable content,
                                  int keyCode, KeyEvent event) {
             return false;
@@ -261,6 +205,9 @@
             return false;
         }
 
+        public void clearMetaKeyState(View view, Editable content, int states) {
+        }
+        
         public static NullKeyListener getInstance() {
             if (sInstance != null)
                 return sInstance;
diff --git a/core/java/android/text/method/TimeKeyListener.java b/core/java/android/text/method/TimeKeyListener.java
index 9ba1fe6..3fbfd8c 100644
--- a/core/java/android/text/method/TimeKeyListener.java
+++ b/core/java/android/text/method/TimeKeyListener.java
@@ -17,12 +17,18 @@
 package android.text.method;
 
 import android.view.KeyEvent;
+import android.text.InputType;
 
 /**
  * For entering times in a text field.
  */
 public class TimeKeyListener extends NumberKeyListener
 {
+    public int getInputType() {
+        return InputType.TYPE_CLASS_DATETIME
+        | InputType.TYPE_DATETIME_VARIATION_TIME;
+    }
+    
     @Override
     protected char[] getAcceptedChars()
     {
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index bd01728..8b097c5 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -17,6 +17,7 @@
 package android.text.method;
 
 import android.text.Layout;
+import android.text.Layout.Alignment;
 import android.text.Spannable;
 import android.view.MotionEvent;
 import android.view.View;
@@ -41,15 +42,31 @@
 
         int left = Integer.MAX_VALUE;
         int right = 0;
+        Alignment a = null;
 
         for (int i = top; i <= bottom; i++) {
             left = (int) Math.min(left, layout.getLineLeft(i));
             right = (int) Math.max(right, layout.getLineRight(i));
+
+            if (a == null) {
+                a = layout.getParagraphAlignment(i);
+            }
         }
 
         padding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight();
-        x = Math.min(x, right - (widget.getWidth() - padding));
-        x = Math.max(x, left);
+        int width = widget.getWidth();
+        int diff = 0;
+
+        if (right - left < width - padding) {
+            if (a == Alignment.ALIGN_CENTER) {
+                diff = (width - padding - (right - left)) / 2;
+            } else if (a == Alignment.ALIGN_OPPOSITE) {
+                diff = width - padding - (right - left);
+            }
+        }
+
+        x = Math.min(x, right - (width - padding) - diff);
+        x = Math.max(x, left - diff);
 
         widget.scrollTo(x, y);
     }
diff --git a/core/java/android/text/style/DynamicDrawableSpan.java b/core/java/android/text/style/DynamicDrawableSpan.java
index 3bcc335..dd89b68 100644
--- a/core/java/android/text/style/DynamicDrawableSpan.java
+++ b/core/java/android/text/style/DynamicDrawableSpan.java
@@ -16,11 +16,12 @@
 
 package android.text.style;
 
-import java.lang.ref.WeakReference;
-
-import android.graphics.drawable.Drawable;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+
+import java.lang.ref.WeakReference;
 
 /**
  *
@@ -35,48 +36,51 @@
      */
     public abstract Drawable getDrawable();
 
+    @Override
     public int getSize(Paint paint, CharSequence text,
                          int start, int end,
                          Paint.FontMetricsInt fm) {
-        Drawable b = getCachedDrawable();
+        Drawable d = getCachedDrawable();
+        Rect rect = d.getBounds();
 
         if (fm != null) {
-            fm.ascent = -b.getIntrinsicHeight();
-            fm.descent = 0;
+            fm.ascent = -rect.bottom; 
+            fm.descent = 0; 
 
             fm.top = fm.ascent;
             fm.bottom = 0;
         }
 
-        return b.getIntrinsicWidth();
+        return rect.right;
     }
 
+    @Override
     public void draw(Canvas canvas, CharSequence text,
                      int start, int end, float x, 
                      int top, int y, int bottom, Paint paint) {
         Drawable b = getCachedDrawable();
         canvas.save();
         
-        canvas.translate(x, bottom-b.getIntrinsicHeight());;
+        canvas.translate(x, bottom - b.getBounds().bottom);
         b.draw(canvas);
         canvas.restore();
     }
 
     private Drawable getCachedDrawable() {
-        WeakReference wr = mDrawableRef;
-        Drawable b = null;
+        WeakReference<Drawable> wr = mDrawableRef;
+        Drawable d = null;
 
         if (wr != null)
-            b = (Drawable) wr.get();
+            d = wr.get();
 
-        if (b == null) {
-            b = getDrawable();
-            mDrawableRef = new WeakReference(b);
+        if (d == null) {
+            d = getDrawable();
+            mDrawableRef = new WeakReference<Drawable>(d);
         }
 
-        return b;
+        return d;
     }
 
-    private WeakReference mDrawableRef;
+    private WeakReference<Drawable> mDrawableRef;
 }
 
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index 79ecfbd..d61e888 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -69,7 +69,7 @@
     public static final int PHONE_NUMBERS = 0x04;
 
     /**
-     *  Bit field indicating that phone numbers should be matched in methods that
+     *  Bit field indicating that street addresses should be matched in methods that
      *  take an options mask
      */
     public static final int MAP_ADDRESSES = 0x08;
@@ -78,8 +78,7 @@
      *  Bit mask indicating that all available patterns should be matched in
      *  methods that take an options mask
      */
-    public static final int ALL = WEB_URLS | EMAIL_ADDRESSES | PHONE_NUMBERS
-        | MAP_ADDRESSES;
+    public static final int ALL = WEB_URLS | EMAIL_ADDRESSES | PHONE_NUMBERS | MAP_ADDRESSES;
 
     /**
      * Don't treat anything with fewer than this many digits as a
@@ -109,8 +108,7 @@
      *  Filters out URL matches that don't have enough digits to be a
      *  phone number.
      */
-    public static final MatchFilter sPhoneNumberMatchFilter =
-            new MatchFilter() {
+    public static final MatchFilter sPhoneNumberMatchFilter = new MatchFilter() {
         public final boolean acceptMatch(CharSequence s, int start, int end) {
             int digitCount = 0;
 
@@ -133,8 +131,7 @@
      *  &apos;+1 (919) 555-1212&apos;
      *  becomes &apos;+19195551212&apos;
      */
-    public static final TransformFilter sPhoneNumberTransformFilter =
-            new TransformFilter() {
+    public static final TransformFilter sPhoneNumberTransformFilter = new TransformFilter() {
         public final String transformUrl(final Matcher match, String url) {
             return Regex.digitsAndPlusOnly(match);
         }
@@ -300,8 +297,7 @@
      *                      prepended to the url of links that do not have
      *                      a scheme specified in the link text
      */
-    public static final void addLinks(TextView text, Pattern pattern,
-            String scheme) {
+    public static final void addLinks(TextView text, Pattern pattern, String scheme) {
         addLinks(text, pattern, scheme, null, null);
     }
 
@@ -341,8 +337,7 @@
      *                      prepended to the url of links that do not have
      *                      a scheme specified in the link text
      */
-    public static final boolean addLinks(Spannable text, Pattern pattern,
-            String scheme) {
+    public static final boolean addLinks(Spannable text, Pattern pattern, String scheme) {
         return addLinks(text, pattern, scheme, null, null);
     }
 
@@ -388,8 +383,7 @@
         return hasMatches;
     }
 
-    private static final void applyLink(String url, int start, int end,
-            Spannable text) {
+    private static final void applyLink(String url, int start, int end, Spannable text) {
         URLSpan span = new URLSpan(url);
 
         text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -402,13 +396,22 @@
         }
 
         boolean hasPrefix = false;
+        
         for (int i = 0; i < prefixes.length; i++) {
             if (url.regionMatches(true, 0, prefixes[i], 0,
                                   prefixes[i].length())) {
                 hasPrefix = true;
+
+                // Fix capitalization if necessary
+                if (!url.regionMatches(false, 0, prefixes[i], 0,
+                                       prefixes[i].length())) {
+                    url = prefixes[i] + url.substring(prefixes[i].length());
+                }
+
                 break;
             }
         }
+
         if (!hasPrefix) {
             url = prefixes[0] + url;
         }
@@ -438,30 +441,35 @@
         }
     }
 
-    private static final void gatherMapLinks(ArrayList<LinkSpec> links,
-            Spannable s) {
+    private static final void gatherMapLinks(ArrayList<LinkSpec> links, Spannable s) {
         String string = s.toString();
         String address;
         int base = 0;
+
         while ((address = WebView.findAddress(string)) != null) {
             int start = string.indexOf(address);
+
             if (start < 0) {
                 break;
             }
+
             LinkSpec spec = new LinkSpec();
             int length = address.length();
             int end = start + length;
+            
             spec.start = base + start;
             spec.end = base + end;
             string = string.substring(end);
             base += end;
 
             String encodedAddress = null;
+
             try {
                 encodedAddress = URLEncoder.encode(address,"UTF-8");
             } catch (UnsupportedEncodingException e) {
                 continue;
             }
+
             spec.url = "geo:0,0?q=" + encodedAddress;
             links.add(spec);
         }
diff --git a/core/java/android/text/util/Regex.java b/core/java/android/text/util/Regex.java
index 55ad140..4c128ad 100644
--- a/core/java/android/text/util/Regex.java
+++ b/core/java/android/text/util/Regex.java
@@ -65,7 +65,7 @@
      */
     public static final Pattern WEB_URL_PATTERN
         = Pattern.compile(
-            "((?:(http|https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+            "((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
             + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2}))+(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
             + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2}))+)?\\@)?)?"
             + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+"   // named host
@@ -103,7 +103,9 @@
             + "(?:\\:\\d{1,5})?)" // plus option port number
             + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus option query params
             + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
-            + "\\b"); // and finally, a word boundary  this is to stop foo.sure from matching as foo.su
+            + "(?:\\b|$)"); // and finally, a word boundary or end of
+                            // input.  This is to stop foo.sure from
+                            // matching as foo.su
 
     public static final Pattern IP_ADDRESS_PATTERN
         = Pattern.compile(
@@ -134,10 +136,20 @@
      * might be phone numbers in arbitrary text, not for validating whether
      * something is in fact a phone number.  It will miss many things that
      * are legitimate phone numbers.
+     * 
+     * <p> The pattern matches the following:
+     * <ul>
+     * <li>Optionally, a + sign followed immediately by one or more digits. Spaces, dots, or dashes
+     * may follow.
+     * <li>Optionally, sets of digits in parentheses, separated by spaces, dots, or dashes.
+     * <li>A string starting and ending with a digit, containing digits, spaces, dots, and/or dashes.
+     * </ul>
      */
     public static final Pattern PHONE_PATTERN
-        = Pattern.compile(
-                "(?:\\+[0-9]+)|(?:[0-9()][0-9()\\- \\.][0-9()\\- \\.]+[0-9])");
+        = Pattern.compile(                                  // sdd = space, dot, or dash
+                "(\\+[0-9]+[\\- \\.]*)?"                    // +<digits><sdd>*
+                + "(\\([0-9]+\\)[\\- \\.]*)?"               // (<digits>)<sdd>*
+                + "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit> 
 
     /**
      *  Convenience method to take all of the non-null matching groups in a
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 3c4e337..0fc70d5 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -19,6 +19,7 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 
+import org.apache.harmony.luni.internal.util.ZoneInfoDB;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -28,14 +29,18 @@
 
 import com.android.internal.util.XmlUtils;
 
+/**
+ * A class containing utility methods related to time zones.
+ */
 public class TimeUtils {
+    private static final String TAG = "TimeUtils";
+
     /**
      * Tries to return a time zone that would have had the specified offset
      * and DST value at the specified moment in the specified country.
      * Returns null if no suitable zone could be found.
      */
-    public static TimeZone getTimeZone(int offset, boolean dst, long when,
-                                       String country) {
+    public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) {
         if (country == null) {
             return null;
         }
@@ -50,18 +55,18 @@
         String currentName = current.getID();
         int currentOffset = current.getOffset(when);
         boolean currentDst = current.inDaylightTime(d);
-        
+
         try {
             XmlUtils.beginDocument(parser, "timezones");
-            
+
             while (true) {
                 XmlUtils.nextElement(parser);
-                
+
                 String element = parser.getName();
                 if (element == null || !(element.equals("timezone"))) {
                     break;
                 }
-                
+
                 String code = parser.getAttributeValue(null, "code");
 
                 if (country.equals(code)) {
@@ -95,15 +100,34 @@
                 }
             }
         } catch (XmlPullParserException e) {
-            Log.e("TimeUtils",
-                  "Got exception while getting preferred time zone.", e);
+            Log.e(TAG, "Got exception while getting preferred time zone.", e);
         } catch (IOException e) {
-            Log.e("TimeUtils",
-                  "Got exception while getting preferred time zone.", e);
+            Log.e(TAG, "Got exception while getting preferred time zone.", e);
         } finally {
             parser.close();
         }
-        
+
         return best;
     }
+
+    /**
+     * Returns a String indicating the version of the time zone database currently
+     * in use.  The format of the string is dependent on the underlying time zone
+     * database implementation, but will typically contain the year in which the database
+     * was updated plus a letter from a to z indicating changes made within that year.
+     * 
+     * <p>Time zone database updates should be expected to occur periodically due to
+     * political and legal changes that cannot be anticipated in advance.  Therefore,
+     * when computing the UTC time for a future event, applications should be aware that
+     * the results may differ following a time zone database update.  This method allows
+     * applications to detect that a database change has occurred, and to recalculate any
+     * cached times accordingly.
+     * 
+     * <p>The time zone database may be assumed to change only when the device runtime
+     * is restarted.  Therefore, it is not necessary to re-query the database version
+     * during the lifetime of an activity.
+     */
+    public static String getTimeZoneDatabaseVersion() {
+        return ZoneInfoDB.getVersion();
+    }
 }
diff --git a/core/java/android/view/ContextMenu.java b/core/java/android/view/ContextMenu.java
index 9bfda40..dd1d7db 100644
--- a/core/java/android/view/ContextMenu.java
+++ b/core/java/android/view/ContextMenu.java
@@ -24,7 +24,7 @@
  * Extension of {@link Menu} for context menus providing functionality to modify
  * the header of the context menu.
  * <p>
- * Context menus do not support item shortcuts, item icons, and sub menus.
+ * Context menus do not support item shortcuts and item icons.
  * <p>
  * To show a context menu on long click, most clients will want to call
  * {@link Activity#registerForContextMenu} and override
diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java
index ff9ab18..36d8ce6 100644
--- a/core/java/android/view/Gravity.java
+++ b/core/java/android/view/Gravity.java
@@ -23,7 +23,7 @@
  */
 public class Gravity
 {
-    /** Contstant indicating that no gravity has been set **/
+    /** Constant indicating that no gravity has been set **/
     public static final int NO_GRAVITY = 0x0000;
     
     /** Raw bit indicating the gravity for an axis has been specified. */
@@ -33,6 +33,9 @@
     public static final int AXIS_PULL_BEFORE = 0x0002;
     /** Raw bit controlling how the right/bottom edge is placed. */
     public static final int AXIS_PULL_AFTER = 0x0004;
+    /** Raw bit controlling whether the right/bottom edge is clipped to its
+     * container, based on the gravity direction being applied. */
+    public static final int AXIS_CLIP = 0x0008;
 
     /** Bits defining the horizontal axis. */
     public static final int AXIS_X_SHIFT = 0;
@@ -66,10 +69,18 @@
      *  and horizontal axis, not changing its size. */
     public static final int CENTER = CENTER_VERTICAL|CENTER_HORIZONTAL;
 
-    /** Grow the horizontal and vertical size of the obejct if needed so it
+    /** Grow the horizontal and vertical size of the object if needed so it
      *  completely fills its container. */
     public static final int FILL = FILL_VERTICAL|FILL_HORIZONTAL;
 
+    /** Flag to clip the edges of the object to its container along the
+     *  vertical axis. */
+    public static final int CLIP_VERTICAL = AXIS_CLIP<<AXIS_Y_SHIFT;
+    
+    /** Flag to clip the edges of the object to its container along the
+     *  horizontal axis. */
+    public static final int CLIP_HORIZONTAL = AXIS_CLIP<<AXIS_X_SHIFT;
+    
     /**
      * Binary mask to get the horizontal gravity of a gravity.
      */
@@ -81,6 +92,20 @@
     public static final int VERTICAL_GRAVITY_MASK = (AXIS_SPECIFIED |
             AXIS_PULL_BEFORE | AXIS_PULL_AFTER) << AXIS_Y_SHIFT;
 
+    /** Special constant to enable clipping to an overall display along the
+     *  vertical dimension.  This is not applied by default by
+     *  {@link #apply(int, int, int, Rect, int, int, Rect)}; you must do so
+     *  yourself by calling {@link #applyDisplay}.
+     */
+    public static final int DISPLAY_CLIP_VERTICAL = 0x10000000;
+    
+    /** Special constant to enable clipping to an overall display along the
+     *  horizontal dimension.  This is not applied by default by
+     *  {@link #apply(int, int, int, Rect, int, int, Rect)}; you must do so
+     *  yourself by calling {@link #applyDisplay}.
+     */
+    public static final int DISPLAY_CLIP_HORIZONTAL = 0x01000000;
+    
     /**
      * Apply a gravity constant to an object.
      * 
@@ -122,28 +147,144 @@
      */
     public static void apply(int gravity, int w, int h, Rect container,
                              int xAdj, int yAdj, Rect outRect) {
-        if ((gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_X_SHIFT))
-             == ((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_X_SHIFT)) {
-            outRect.left = container.left;
-            outRect.right = container.right;
-        } else {
-            outRect.left = applyMovement(
-                gravity>>AXIS_X_SHIFT, w, container.left, container.right, xAdj);
-            outRect.right = outRect.left + w;
+        switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_X_SHIFT)) {
+            case 0:
+                outRect.left = container.left
+                        + ((container.right - container.left - w)/2) + xAdj;
+                outRect.right = outRect.left + w;
+                if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT))
+                        == (AXIS_CLIP<<AXIS_X_SHIFT)) {
+                    if (outRect.left < container.left) {
+                        outRect.left = container.left;
+                    }
+                    if (outRect.right > container.right) {
+                        outRect.right = container.right;
+                    }
+                }
+                break;
+            case AXIS_PULL_BEFORE<<AXIS_X_SHIFT:
+                outRect.left = container.left + xAdj;
+                outRect.right = outRect.left + w;
+                if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT))
+                        == (AXIS_CLIP<<AXIS_X_SHIFT)) {
+                    if (outRect.right > container.right) {
+                        outRect.right = container.right;
+                    }
+                }
+                break;
+            case AXIS_PULL_AFTER<<AXIS_X_SHIFT:
+                outRect.right = container.right - xAdj;
+                outRect.left = outRect.right - w;
+                if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT))
+                        == (AXIS_CLIP<<AXIS_X_SHIFT)) {
+                    if (outRect.left < container.left) {
+                        outRect.left = container.left;
+                    }
+                }
+                break;
+            default:
+                outRect.left = container.left + xAdj;
+                outRect.right = container.right + xAdj;
+                break;
         }
-
-        if ((gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_Y_SHIFT))
-             == ((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_Y_SHIFT)) {
-            outRect.top = container.top;
-            outRect.bottom = container.bottom;
-        } else {
-            outRect.top = applyMovement(
-                gravity>>AXIS_Y_SHIFT, h, container.top, container.bottom, yAdj);
-            outRect.bottom = outRect.top + h;
+        
+        switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_Y_SHIFT)) {
+            case 0:
+                outRect.top = container.top
+                        + ((container.bottom - container.top - h)/2) + yAdj;
+                outRect.bottom = outRect.top + h;
+                if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT))
+                        == (AXIS_CLIP<<AXIS_Y_SHIFT)) {
+                    if (outRect.top < container.top) {
+                        outRect.top = container.top;
+                    }
+                    if (outRect.bottom > container.bottom) {
+                        outRect.bottom = container.bottom;
+                    }
+                }
+                break;
+            case AXIS_PULL_BEFORE<<AXIS_Y_SHIFT:
+                outRect.top = container.top + yAdj;
+                outRect.bottom = outRect.top + h;
+                if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT))
+                        == (AXIS_CLIP<<AXIS_Y_SHIFT)) {
+                    if (outRect.bottom > container.bottom) {
+                        outRect.bottom = container.bottom;
+                    }
+                }
+                break;
+            case AXIS_PULL_AFTER<<AXIS_Y_SHIFT:
+                outRect.bottom = container.bottom - yAdj;
+                outRect.top = outRect.bottom - h;
+                if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT))
+                        == (AXIS_CLIP<<AXIS_Y_SHIFT)) {
+                    if (outRect.top < container.top) {
+                        outRect.top = container.top;
+                    }
+                }
+                break;
+            default:
+                outRect.top = container.top + yAdj;
+                outRect.bottom = container.bottom + yAdj;
+                break;
         }
     }
 
     /**
+     * Apply addition gravity behavior based on the overall "display" that an
+     * object exists in.  This can be used after
+     * {@link #apply(int, int, int, Rect, int, int, Rect)} to place the object
+     * within a visible display.  By default this moves or clips the object
+     * to be visible in the display; the gravity flags
+     * {@link #DISPLAY_CLIP_HORIZONTAL} and {@link #DISPLAY_CLIP_VERTICAL}
+     * can be used to change this behavior.
+     * 
+     * @param gravity Gravity constants to modify the placement within the
+     * display.
+     * @param display The rectangle of the display in which the object is
+     * being placed.
+     * @param inoutObj Supplies the current object position; returns with it
+     * modified if needed to fit in the display.
+     */
+    public static void applyDisplay(int gravity, Rect display, Rect inoutObj) {
+        if ((gravity&DISPLAY_CLIP_VERTICAL) != 0) {
+            if (inoutObj.top < display.top) inoutObj.top = display.top;
+            if (inoutObj.bottom > display.bottom) inoutObj.bottom = display.bottom;
+        } else {
+            int off = 0;
+            if (inoutObj.top < display.top) off = display.top-inoutObj.top;
+            else if (inoutObj.bottom > display.bottom) off = display.bottom-inoutObj.bottom;
+            if (off != 0) {
+                if (inoutObj.height() > (display.bottom-display.top)) {
+                    inoutObj.top = display.top;
+                    inoutObj.bottom = display.bottom;
+                } else {
+                    inoutObj.top += off;
+                    inoutObj.bottom += off;
+                }
+            }
+        }
+        
+        if ((gravity&DISPLAY_CLIP_HORIZONTAL) != 0) {
+            if (inoutObj.left < display.left) inoutObj.left = display.left;
+            if (inoutObj.right > display.right) inoutObj.right = display.right;
+        } else {
+            int off = 0;
+            if (inoutObj.left < display.left) off = display.left-inoutObj.left;
+            else if (inoutObj.right > display.right) off = display.right-inoutObj.right;
+            if (off != 0) {
+                if (inoutObj.width() > (display.right-display.left)) {
+                    inoutObj.left = display.left;
+                    inoutObj.right = display.right;
+                } else {
+                    inoutObj.left += off;
+                    inoutObj.right += off;
+                }
+            }
+        }
+    }
+    
+    /**
      * <p>Indicate whether the supplied gravity has a vertical pull.</p>
      *
      * @param gravity the gravity to check for vertical pull
@@ -162,18 +303,4 @@
     public static boolean isHorizontal(int gravity) {
         return gravity > 0 && (gravity & HORIZONTAL_GRAVITY_MASK) != 0;
     }
-
-    private static int applyMovement(int mode, int size,
-            int start, int end, int adj) {
-        if ((mode & AXIS_PULL_BEFORE) != 0) {
-            return start + adj;
-        }
-
-        if ((mode & AXIS_PULL_AFTER) != 0) {
-            return end - size - adj;
-        }
-
-        return start + ((end - start - size)/2) + adj;
-    }
 }
-
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index b4a3067..99d5c0c 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -17,6 +17,7 @@
 
 package android.view;
 
+import android.graphics.Rect;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
@@ -42,7 +43,8 @@
      */
     void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
 
-    void resized(int w, int h, boolean reportDraw);
+    void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets,
+            boolean reportDraw);
     void dispatchKey(in KeyEvent event);
     void dispatchPointer(in MotionEvent event, long eventTime);
     void dispatchTrackball(in MotionEvent event, long eventTime);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e6d52e2..d89c7b4 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -17,6 +17,9 @@
 
 package android.view;
 
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodClient;
+
 import android.content.res.Configuration;
 import android.view.IApplicationToken;
 import android.view.IOnKeyguardExitResult;
@@ -42,8 +45,10 @@
     boolean stopViewServer();            // Transaction #2
     boolean isViewServerRunning();       // Transaction #3
 
-    IWindowSession openSession(IBinder token);
-
+    IWindowSession openSession(in IInputMethodClient client,
+            in IInputContext inputContext);
+    boolean inputMethodClientHasFocus(IInputMethodClient client);
+    
     // These can only be called when injecting events to your own window,
     // or by holding the INJECT_EVENTS permission.
     boolean injectKeyEvent(in KeyEvent ev, boolean sync);
@@ -74,6 +79,8 @@
     void moveAppToken(int index, IBinder token);
     void moveAppTokensToTop(in List<IBinder> tokens);
     void moveAppTokensToBottom(in List<IBinder> tokens);
+    void addWindowToken(IBinder token, int type);
+    void removeWindowToken(IBinder token);
 
     // these require DISABLE_KEYGUARD permission
     void disableKeyguard(IBinder token, String tag);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index c2c0b97..7276f17 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -31,7 +31,7 @@
  */
 interface IWindowSession {
     int add(IWindow window, in WindowManager.LayoutParams attrs,
-            in int viewVisibility, out Rect outCoveredInsets);
+            in int viewVisibility, out Rect outContentInsets);
     void remove(IWindow window);
     
     /**
@@ -46,10 +46,22 @@
      * @param requestedWidth The width the window wants to be.
      * @param requestedHeight The height the window wants to be.
      * @param viewVisibility Window root view's visibility.
-     * @param outFrame Object in which is placed the new position/size on
-     *                 screen.
-     * @param outCoveredInsets Object in which is placed the insets for the areas covered by
- 	 *                 system windows (e.g. status bar)
+     * @param insetsPending Set to true if the client will be later giving
+     * internal insets; as a result, the window will not impact other window
+     * layouts until the insets are given.
+     * @param outFrame Rect in which is placed the new position/size on
+     * screen.
+     * @param outContentInsets Rect in which is placed the offsets from
+     * <var>outFrame</var> in which the content of the window should be
+     * placed.  This can be used to modify the window layout to ensure its
+     * contents are visible to the user, taking into account system windows
+     * like the status bar or a soft keyboard.
+     * @param outVisibleInsets Rect in which is placed the offsets from
+     * <var>outFrame</var> in which the window is actually completely visible
+     * to the user.  This can be used to temporarily scroll the window's
+     * contents to make sure the user can see it.  This is different than
+     * <var>outContentInsets</var> in that these insets change transiently,
+     * so complex relayout of the window should not happen based on them.
      * @param outSurface Object in which is placed the new display surface.
      * 
      * @return int Result flags: {@link WindowManagerImpl#RELAYOUT_SHOW_FOCUS},
@@ -57,16 +69,41 @@
      */
     int relayout(IWindow window, in WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility,
-            out Rect outFrame, out Rect outCoveredInsets, out Surface outSurface);
+            boolean insetsPending, out Rect outFrame, out Rect outContentInsets,
+            out Rect outVisibleInsets, out Surface outSurface);
 
+    /**
+     * Give the window manager a hint of the part of the window that is
+     * completely transparent, allowing it to work with the surface flinger
+     * to optimize compositing of this part of the window.
+     */
+    void setTransparentRegion(IWindow window, in Region region);
+    
+    /**
+     * Tell the window manager about the content and visible insets of the
+     * given window, which can be used to adjust the <var>outContentInsets</var>
+     * and <var>outVisibleInsets</var> values returned by
+     * {@link #relayout relayout()} for windows behind this one.
+     *
+     * @param touchableInsets Controls which part of the window inside of its
+     * frame can receive pointer events, as defined by
+     * {@link android.view.ViewTreeObserver.InternalInsetsInfo}.
+     */
+    void setInsets(IWindow window, int touchableInsets, in Rect contentInsets,
+            in Rect visibleInsets);
+    
+    /**
+     * Return the current display size in which the window is being laid out,
+     * accounting for screen decorations around it.
+     */
+    void getDisplayFrame(IWindow window, out Rect outDisplayFrame);
+    
     void finishDrawing(IWindow window);
 
     void finishKey(IWindow window);
     MotionEvent getPendingPointerMove(IWindow window);
     MotionEvent getPendingTrackballMove(IWindow window);
     
-    void setTransparentRegion(IWindow window, in Region region);
-
     void setInTouchMode(boolean showFocus);
     boolean getInTouchMode();
 }
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 24b0316..1575aad 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -111,15 +111,27 @@
     public static final int KEYCODE_MENU            = 82;
     public static final int KEYCODE_NOTIFICATION    = 83;
     public static final int KEYCODE_SEARCH          = 84;
+    public static final int KEYCODE_PLAYPAUSE       = 85;
+    public static final int KEYCODE_STOP            = 86;
+    public static final int KEYCODE_NEXTSONG        = 87;
+    public static final int KEYCODE_PREVIOUSSONG    = 88;
+    public static final int KEYCODE_REWIND          = 89;
+    public static final int KEYCODE_FORWARD         = 90;
+    private static final int LAST_KEYCODE           = KEYCODE_FORWARD;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
-    //  include/ui/KeycodeLabels.h
+    //  frameworks/base/include/ui/KeycodeLabels.h
     //  tools/puppet_master/PuppetMaster/nav_keys.py
-    //  apps/common/res/values/attrs.xml
+    //  frameworks/base/core/res/res/values/attrs.xml
     //  commands/monkey/Monkey.java
     //  emulator?
-    
+   
+    /**
+     * @deprecated There are now more than MAX_KEYCODE keycodes.
+     * Use {@link #getMaxKeyCode()} instead.
+     */
+    @Deprecated
     public static final int MAX_KEYCODE             = 84;
 
     /**
@@ -207,6 +219,18 @@
     public static final int FLAG_WOKE_HERE = 0x1;
     
     /**
+     * This mask is set if the key event was generated by a software keyboard.
+     */
+    public static final int FLAG_SOFT_KEYBOARD = 0x2;
+    
+    /**
+     * Returns the maximum keycode.
+     */
+    public static int getMaxKeyCode() {
+        return LAST_KEYCODE;
+    }
+
+    /**
      * Get the character that is produced by putting accent on the character
      * c.
      * For example, getDeadChar('`', 'e') returns &egrave;.
@@ -402,6 +426,24 @@
     }
 
     /**
+     * Copy an existing key event, modifying its action.
+     * 
+     * @param origEvent The existing event to be copied.
+     * @param action The new action code of the event.
+     */
+    public KeyEvent(KeyEvent origEvent, int action) {
+        mDownTime = origEvent.mDownTime;
+        mEventTime = origEvent.mEventTime;
+        mAction = action;
+        mKeyCode = origEvent.mKeyCode;
+        mRepeatCount = origEvent.mRepeatCount;
+        mMetaState = origEvent.mMetaState;
+        mDeviceId = origEvent.mDeviceId;
+        mScancode = origEvent.mScancode;
+        mFlags = origEvent.mFlags;
+    }
+
+    /**
      * Don't use in new code, instead explicitly check
      * {@link #getAction()}.
      * 
@@ -432,6 +474,12 @@
         case KEYCODE_VOLUME_DOWN:
         case KEYCODE_POWER:
         case KEYCODE_HEADSETHOOK:
+        case KEYCODE_PLAYPAUSE:
+        case KEYCODE_STOP:
+        case KEYCODE_NEXTSONG:
+        case KEYCODE_PREVIOUSSONG:
+        case KEYCODE_REWIND:
+        case KEYCODE_FORWARD:
         case KEYCODE_CAMERA:
         case KEYCODE_FOCUS:
         case KEYCODE_SEARCH:
diff --git a/core/java/android/view/Menu.java b/core/java/android/view/Menu.java
index f2ec076..ca2140b 100644
--- a/core/java/android/view/Menu.java
+++ b/core/java/android/view/Menu.java
@@ -32,8 +32,7 @@
  * <p>
  * Different menu types support different features:
  * <ol>
- * <li><b>Context menus</b>: Do not support item shortcuts, item icons, and sub
- * menus.
+ * <li><b>Context menus</b>: Do not support item shortcuts and item icons.
  * <li><b>Options menus</b>: The <b>icon menus</b> do not support item check
  * marks and only show the item's
  * {@link MenuItem#setTitleCondensed(CharSequence) condensed title}. The
@@ -380,6 +379,24 @@
     public int size();
 
     /**
+     * Gets the menu item at the given index.
+     * 
+     * @param index The index of the menu item to return.
+     * @return The menu item.
+     * @exception IndexOutOfBoundsException
+     *                when {@code index < 0 || >= size()}
+     * @hide pending API council
+     */
+    public MenuItem getItem(int index);
+    
+    /**
+     * Closes the menu, if open.
+     * 
+     * @hide pending API council
+     */
+    public void close();
+    
+    /**
      * Execute the menu item action associated with the given shortcut
      * character.
      *
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 92cf4af..fcebec5 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.view;
 
 import android.app.Activity;
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index ab05e16..882a079 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -27,10 +27,36 @@
  * it is being used for.
  */
 public final class MotionEvent implements Parcelable {
+    /**
+     * Constant for {@link #getAction}: A pressed gesture has started, the
+     * motion contains the initial starting location.
+     */
     public static final int ACTION_DOWN             = 0;
+    /**
+     * Constant for {@link #getAction}: A pressed gesture has finished, the
+     * motion contains the final release location as well as any intermediate
+     * points since the last down or move event.
+     */
     public static final int ACTION_UP               = 1;
+    /**
+     * Constant for {@link #getAction}: A change has happened during a
+     * press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}).
+     * The motion contains the most recent point, as well as any intermediate
+     * points since the last down or move event.
+     */
     public static final int ACTION_MOVE             = 2;
+    /**
+     * Constant for {@link #getAction}: The current gesture has been aborted.
+     * You will not receive any more points in it.  You should treat this as
+     * an up event, but not perform any action that you normally would.
+     */
     public static final int ACTION_CANCEL           = 3;
+    /**
+     * Constant for {@link #getAction}: A movement has happened outside of the
+     * normal bounds of the UI element.  This does not provide a full gesture,
+     * but only the initial location of the movement/touch.
+     */
+    public static final int ACTION_OUTSIDE          = 4;
 
     private static final boolean TRACK_RECYCLED_LOCATION = false;
     
diff --git a/core/java/android/view/OrientationListener.java b/core/java/android/view/OrientationListener.java
index 0add025..974c2e8 100644
--- a/core/java/android/view/OrientationListener.java
+++ b/core/java/android/view/OrientationListener.java
@@ -34,6 +34,7 @@
     private SensorManager mSensorManager;
     private int mOrientation = ORIENTATION_UNKNOWN;
     private boolean mEnabled = false;
+    private int mRate;
     
     /**
      * Returned from onOrientationChanged when the device orientation cannot be determined
@@ -50,6 +51,21 @@
      */
     public OrientationListener(Context context) {
         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+        mRate = SensorManager.SENSOR_DELAY_NORMAL;
+    }
+
+    /**
+     * Creates a new OrientationListener.
+     * 
+     * @param context for the OrientationListener.
+     * @param rate at which sensor events are processed (see also
+     * {@link android.hardware.SensorManager SensorManager}). Use the default
+     * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL 
+     * SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
+     */
+    public OrientationListener(Context context, int rate) {
+        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+        mRate = rate;
     }
 
     /**
@@ -59,7 +75,7 @@
     public void enable() {
         if (mEnabled == false) {
             if (localLOGV) Log.d(TAG, "OrientationListener enabled");
-            mSensorManager.registerListener(this, SensorManager.SENSOR_ACCELEROMETER);
+            mSensorManager.registerListener(this, SensorManager.SENSOR_ACCELEROMETER, mRate);
             mEnabled = true;
         }
     }
@@ -106,7 +122,6 @@
 
     public void onAccuracyChanged(int sensor, int accuracy) {
         // TODO Auto-generated method stub
-        
     }
 
     /**
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 57689f2..0d9e221 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -82,6 +82,8 @@
     final ArrayList<SurfaceHolder.Callback> mCallbacks
             = new ArrayList<SurfaceHolder.Callback>();
 
+    final int[] mLocation = new int[2];
+    
     final ReentrantLock mSurfaceLock = new ReentrantLock();
     final Surface mSurface = new Surface();
     boolean mDrawingStopped = true;
@@ -90,8 +92,9 @@
             = new WindowManager.LayoutParams();
     IWindowSession mSession;
     MyWindow mWindow;
+    final Rect mVisibleInsets = new Rect();
     final Rect mWinFrame = new Rect();
-    final Rect mCoveredInsets = new Rect();
+    final Rect mContentInsets = new Rect();
 
     static final int KEEP_SCREEN_ON_MSG = 1;
     static final int GET_NEW_SURFACE_MSG = 2;
@@ -309,7 +312,7 @@
                     mLayout.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
                     mLayout.gravity = Gravity.LEFT|Gravity.TOP;
                     mSession.add(mWindow, mLayout,
-                            mVisible ? VISIBLE : GONE, mCoveredInsets);
+                            mVisible ? VISIBLE : GONE, mContentInsets);
                 }
                 
                 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
@@ -321,8 +324,9 @@
                 mSurfaceLock.lock();
                 mDrawingStopped = !visible;
                 final int relayoutResult = mSession.relayout(
-                    mWindow, mLayout, mWidth, mHeight,
-                    visible ? VISIBLE : GONE, mWinFrame, mCoveredInsets, mSurface);
+                        mWindow, mLayout, mWidth, mHeight,
+                        visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
+                        mVisibleInsets, mSurface);
                 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
                         + ", vis=" + visible + ", frame=" + mWinFrame);
                 mSurfaceFrame.left = 0;
@@ -390,7 +394,8 @@
     }
     
     private class MyWindow extends IWindow.Stub {
-        public void resized(int w, int h, boolean reportDraw) {
+        public void resized(int w, int h, Rect coveredInsets,
+                Rect visibleInsets, boolean reportDraw) {
             if (localLOGV) Log.v(
                 "SurfaceView", SurfaceView.this + " got resized: w=" +
                 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 30402f8..f948b33 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -38,13 +38,18 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.animation.Animation;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.EditorInfo;
 import android.widget.ScrollBarDrawable;
 
 import com.android.internal.R;
@@ -58,9 +63,9 @@
  * The <code>View</code> class represents the basic UI building block. A view
  * occupies a rectangular area on the screen and is responsible for drawing and
  * event handling. <code>View</code> is the base class for <em>widgets</em>,
- * used to create interactive graphical user interfaces. 
+ * used to create interactive graphical user interfaces.
  * </p>
- * 
+ *
  * <a name="Using"></a>
  * <h3>Using Views</h3>
  * <p>
@@ -98,7 +103,7 @@
  * views yourself unless you are actually implementing a
  * {@link android.view.ViewGroup}.
  * </em></p>
- * 
+ *
  * <a name="Lifecycle"></a>
  * <h3>Implementing a Custom View</h3>
  *
@@ -111,7 +116,7 @@
  *     <thead>
  *         <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr>
  *     </thead>
- *     
+ *
  *     <tbody>
  *     <tr>
  *         <td rowspan="2">Creation</td>
@@ -127,7 +132,7 @@
  *         <td>Called after a view and all of its children has been inflated
  *         from XML.</td>
  *     </tr>
- *     
+ *
  *     <tr>
  *         <td rowspan="3">Layout</td>
  *         <td><code>{@link #onMeasure}</code></td>
@@ -146,7 +151,7 @@
  *         <td>Called when the size of this view has changed.
  *         </td>
  *     </tr>
- *     
+ *
  *     <tr>
  *         <td>Drawing</td>
  *         <td><code>{@link #onDraw}</code></td>
@@ -164,31 +169,31 @@
  *         <td><code>{@link #onKeyUp}</code></td>
  *         <td>Called when a key up event occurs.
  *         </td>
- *     </tr>   
+ *     </tr>
  *     <tr>
  *         <td><code>{@link #onTrackballEvent}</code></td>
  *         <td>Called when a trackball motion event occurs.
  *         </td>
- *     </tr>  
+ *     </tr>
  *     <tr>
  *         <td><code>{@link #onTouchEvent}</code></td>
  *         <td>Called when a touch screen motion event occurs.
  *         </td>
- *     </tr>  
- *     
+ *     </tr>
+ *
  *     <tr>
  *         <td rowspan="2">Focus</td>
  *         <td><code>{@link #onFocusChanged}</code></td>
  *         <td>Called when the view gains or loses focus.
  *         </td>
  *     </tr>
- *     
+ *
  *     <tr>
  *         <td><code>{@link #onWindowFocusChanged}</code></td>
  *         <td>Called when the window containing the view gains or loses focus.
  *         </td>
  *     </tr>
- *     
+ *
  *     <tr>
  *         <td rowspan="3">Attaching</td>
  *         <td><code>{@link #onAttachedToWindow()}</code></td>
@@ -200,26 +205,26 @@
  *         <td><code>{@link #onDetachedFromWindow}</code></td>
  *         <td>Called when the view is detached from its window.
  *         </td>
- *     </tr>     
+ *     </tr>
  *
  *     <tr>
  *         <td><code>{@link #onWindowVisibilityChanged}</code></td>
  *         <td>Called when the visibility of the window containing the view
  *         has changed.
  *         </td>
- *     </tr>     
+ *     </tr>
  *     </tbody>
- *     
+ *
  * </table>
  * </p>
- * 
+ *
  * <a name="IDs"></a>
  * <h3>IDs</h3>
  * Views may have an integer id associated with them. These ids are typically
  * assigned in the layout XML files, and are used to find specific views within
  * the view tree. A common pattern is to:
  * <ul>
- * <li>Define a Button in the layout file and assign it a unique ID. 
+ * <li>Define a Button in the layout file and assign it a unique ID.
  * <pre>
  * &lt;Button id="@+id/my_button"
  *     android:layout_width="wrap_content"
@@ -232,11 +237,11 @@
  * </pre></li>
  * </ul>
  * <p>
- * View IDs need not be unique throughout the tree, but it is good practice to 
+ * View IDs need not be unique throughout the tree, but it is good practice to
  * ensure that they are at least unique within the part of the tree you are
  * searching.
  * </p>
- * 
+ *
  * <a name="Position"></a>
  * <h3>Position</h3>
  * <p>
@@ -264,7 +269,7 @@
  * is similar to the following computation: <code>getLeft() + getWidth()</code>
  * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.)
  * </p>
- * 
+ *
  * <a name="SizePaddingMargins"></a>
  * <h3>Size, padding and margins</h3>
  * <p>
@@ -286,7 +291,7 @@
  * dimensions define the actual size of the view on screen, at drawing time and
  * after layout. These values may, but do not have to, be different from the
  * measured width and height. The width and height can be obtained by calling
- * {@link #getWidth()} and {@link #getHeight()}. 
+ * {@link #getWidth()} and {@link #getHeight()}.
  * </p>
  *
  * <p>
@@ -297,7 +302,7 @@
  * 2 pixels to the right of the left edge. Padding can be set using the
  * {@link #setPadding(int, int, int, int)} method and queried by calling
  * {@link #getPaddingLeft()}, {@link #getPaddingTop()},
- * {@link #getPaddingRight()} and {@link #getPaddingBottom()}.  
+ * {@link #getPaddingRight()} and {@link #getPaddingBottom()}.
  * </p>
  *
  * <p>
@@ -306,7 +311,7 @@
  * {@link android.view.ViewGroup} and
  * {@link android.view.ViewGroup.MarginLayoutParams} for further information.
  * </p>
- * 
+ *
  * <a name="Layout"></a>
  * <h3>Layout</h3>
  * <p>
@@ -319,7 +324,7 @@
  * this pass each parent is responsible for positioning all of its children
  * using the sizes computed in the measure pass.
  * </p>
- * 
+ *
  * <p>
  * When a view's measure() method returns, its {@link #getMeasuredWidth()} and
  * {@link #getMeasuredHeight()} values must be set, along with those for all of
@@ -332,7 +337,7 @@
  * measure() on them again with actual numbers if the sum of all the children's
  * unconstrained sizes is too big or too small.
  * </p>
- * 
+ *
  * <p>
  * The measure pass uses two classes to communicate dimensions. The
  * {@link MeasureSpec} class is used by views to tell their parents how they
@@ -350,7 +355,7 @@
  * For example, AbsoluteLayout has its own subclass of LayoutParams which adds
  * an X and Y value.
  * </p>
- * 
+ *
  * <p>
  * MeasureSpecs are used to push requirements down the tree from parent to
  * child. A MeasureSpec can be in one of three modes:
@@ -367,13 +372,13 @@
  * within this size.
  * </ul>
  * </p>
- * 
+ *
  * <p>
  * To intiate a layout, call {@link #requestLayout}. This method is typically
  * called by a view on itself when it believes that is can no longer fit within
  * its current bounds.
  * </p>
- * 
+ *
  * <a name="Drawing"></a>
  * <h3>Drawing</h3>
  * <p>
@@ -381,17 +386,18 @@
  * intersects the the invalid region. Because the tree is traversed in-order,
  * this means that parents will draw before (i.e., behind) their children, with
  * siblings drawn in the order they appear in the tree.
+ * If you set a background drawable for a View, then the View will draw it for you
+ * before calling back to its <code>onDraw()</code> method.
  * </p>
- * 
+ *
  * <p>
- * The framework will not draw views that are not in the invalid region, and also 
- * will take care of drawing the views background for you.
+ * Note that the framework will not draw views that are not in the invalid region. 
  * </p>
- * 
+ *
  * <p>
  * To force a view to draw, call {@link #invalidate()}.
  * </p>
- * 
+ *
  * <a name="EventHandlingThreading"></a>
  * <h3>Event Handling and Threading</h3>
  * <p>
@@ -408,13 +414,13 @@
  * as appropriate.</li>
  * </ol>
  * </p>
- * 
+ *
  * <p><em>Note: The entire view tree is single threaded. You must always be on
  * the UI thread when calling any method on any view.</em>
  * If you are doing work on other threads and want to update the state of a view
  * from that thread, you should use a {@link Handler}.
  * </p>
- * 
+ *
  * <a name="FocusHandling"></a>
  * <h3>Focus Handling</h3>
  * <p>
@@ -479,7 +485,7 @@
  * offset as well as mechanisms for drawing scrollbars. See
  * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)} for more details.
  * </p>
- * 
+ *
  * <a name="Tags"></a>
  * <h3>Tags</h3>
  * <p>
@@ -488,7 +494,7 @@
  * often used as a convenience to store data related to views in the views
  * themselves rather than by putting them in a separate structure.
  * </p>
- * 
+ *
  * <a name="Animation"></a>
  * <h3>Animation</h3>
  * <p>
@@ -543,7 +549,7 @@
      * setFlags.
      */
     private static final int FOCUSABLE = 0x00000001;
-    
+
     /**
      * Mask for use with setFlags indicating bits used for focus.
      */
@@ -599,7 +605,7 @@
     * {@hide}
     */
     static final int ENABLED_MASK = 0x00000020;
-     
+
     /**
      * This view won't draw. {@link #onDraw} won't be called and further
      * optimizations
@@ -615,7 +621,7 @@
      * {@hide}
      */
     static final int DRAW_MASK = 0x00000080;
-     
+
     /**
      * <p>This view doesn't show scrollbars.</p>
      * {@hide}
@@ -752,22 +758,22 @@
 
     /**
      * The scrollbar style to display the scrollbars inside the content area,
-     * without increasing the padding. The scrollbars will be overlaid with 
+     * without increasing the padding. The scrollbars will be overlaid with
      * translucency on the view's content.
      */
     public static final int SCROLLBARS_INSIDE_OVERLAY = 0;
-    
+
     /**
      * The scrollbar style to display the scrollbars inside the padded area,
-     * increasing the padding of the view. The scrollbars will not overlap the 
+     * increasing the padding of the view. The scrollbars will not overlap the
      * content area of the view.
      */
     public static final int SCROLLBARS_INSIDE_INSET = 0x01000000;
 
     /**
      * The scrollbar style to display the scrollbars at the edge of the view,
-     * without increasing the padding. The scrollbars will be overlaid with 
-     * translucency. 
+     * without increasing the padding. The scrollbars will be overlaid with
+     * translucency.
      */
     public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000;
 
@@ -789,7 +795,7 @@
      * {@hide}
      */
     static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000;
-    
+
     /**
      * Mask for scrollbar style.
      * {@hide}
@@ -841,7 +847,7 @@
      * Use with {@link #focusSearch}. Move focus down.
      */
     public static final int FOCUS_DOWN = 0x00000082;
-    
+
     /**
      * Base View state sets
      */
@@ -850,7 +856,7 @@
      * Indicates the view has no states set. States are used with
      * {@link android.graphics.drawable.Drawable} to change the drawing of the
      * view depending on its state.
-     * 
+     *
      * @see android.graphics.drawable.Drawable
      * @see #getDrawableState()
      */
@@ -1003,7 +1009,7 @@
 
     /**
      * Indicates the view is pressed and its window has the focus.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #WINDOW_FOCUSED_STATE_SET
      */
@@ -1021,7 +1027,7 @@
 
     /**
      * Indicates the view is pressed, selected and its window has the focus.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #SELECTED_STATE_SET
      * @see #WINDOW_FOCUSED_STATE_SET
@@ -1040,7 +1046,7 @@
 
     /**
      * Indicates the view is pressed, focused and its window has the focus.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #FOCUSED_STATE_SET
      * @see #WINDOW_FOCUSED_STATE_SET
@@ -1050,7 +1056,7 @@
 
     /**
      * Indicates the view is pressed, focused and selected.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #SELECTED_STATE_SET
      * @see #FOCUSED_STATE_SET
@@ -1060,7 +1066,7 @@
 
     /**
      * Indicates the view is pressed, focused, selected and its window has the focus.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #FOCUSED_STATE_SET
      * @see #SELECTED_STATE_SET
@@ -1071,7 +1077,7 @@
 
     /**
      * Indicates the view is pressed and enabled.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #ENABLED_STATE_SET
      */
@@ -1080,7 +1086,7 @@
 
     /**
      * Indicates the view is pressed, enabled and its window has the focus.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #ENABLED_STATE_SET
      * @see #WINDOW_FOCUSED_STATE_SET
@@ -1090,7 +1096,7 @@
 
     /**
      * Indicates the view is pressed, enabled and selected.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #ENABLED_STATE_SET
      * @see #SELECTED_STATE_SET
@@ -1101,7 +1107,7 @@
     /**
      * Indicates the view is pressed, enabled, selected and its window has the
      * focus.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #ENABLED_STATE_SET
      * @see #SELECTED_STATE_SET
@@ -1112,18 +1118,18 @@
 
     /**
      * Indicates the view is pressed, enabled and focused.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #ENABLED_STATE_SET
      * @see #FOCUSED_STATE_SET
      */
     protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET =
             stateSetUnion(PRESSED_ENABLED_STATE_SET, FOCUSED_STATE_SET);
-    
+
     /**
      * Indicates the view is pressed, enabled, focused and its window has the
      * focus.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #ENABLED_STATE_SET
      * @see #FOCUSED_STATE_SET
@@ -1134,7 +1140,7 @@
 
     /**
      * Indicates the view is pressed, enabled, focused and selected.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #ENABLED_STATE_SET
      * @see #SELECTED_STATE_SET
@@ -1146,7 +1152,7 @@
     /**
      * Indicates the view is pressed, enabled, focused, selected and its window
      * has the focus.
-     * 
+     *
      * @see #PRESSED_STATE_SET
      * @see #ENABLED_STATE_SET
      * @see #SELECTED_STATE_SET
@@ -1242,6 +1248,13 @@
      * @hide
      */
     protected static final int[] PRESSED_SINGLE_STATE_SET = {R.attr.state_single, R.attr.state_pressed};
+
+    /**
+     * Temporary Rect currently for use in setBackground().  This will probably
+     * be extended in the future to hold our own class with more than just
+     * a Rect. :)
+     */
+    static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>();
     
     /**
      * The animation currently associated with this view.
@@ -1264,20 +1277,11 @@
     protected int mMeasuredHeight;
 
     /**
-     * Used to store a pair of coordinates, for instance returned values
-     * returned by {@link #getLocationInWindow(int[])}.
-     * 
-     * This field should be made private, so it is hidden from the SDK.
-     * {@hide}
-     */
-    protected final int[] mLocation = new int[2];
-
-    /**
      * The view's identifier.
      * {@hide}
      *
      * @see #setId(int)
-     * @see #getId() 
+     * @see #getId()
      */
     @ViewDebug.ExportedProperty(resolveId = true)
     int mID = NO_ID;
@@ -1287,7 +1291,7 @@
      * {@hide}
      *
      * @see #setTag(Object)
-     * @see #getTag() 
+     * @see #getTag()
      */
     protected Object mTag;
 
@@ -1320,7 +1324,7 @@
     private static final int LAYOUT_REQUIRED        = 0x00002000;
 
     private static final int PRESSED                = 0x00004000;
-    
+
     /** {@hide} */
     static final int DRAWING_CACHE_VALID            = 0x00008000;
     /**
@@ -1329,7 +1333,7 @@
      * {@hide}
      */
     static final int ANIMATION_STARTED              = 0x00010000;
-    
+
     private static final int SAVE_STATE_CALLED      = 0x00020000;
 
     /**
@@ -1339,8 +1343,18 @@
      */
     static final int ALPHA_SET                      = 0x00040000;
 
+    /**
+     * Set by {@link #setScrollContainer(boolean)}.
+     */
+    static final int SCROLL_CONTAINER               = 0x00080000;
+
+    /**
+     * Set by {@link #setScrollContainer(boolean)}.
+     */
+    static final int SCROLL_CONTAINER_ADDED         = 0x00100000;
+
     // Note: flag 0x00000040 is available
-    
+
     /**
      * The parent this view is attached to.
      * {@hide}
@@ -1357,10 +1371,11 @@
     /**
      * {@hide}
      */
+    @ViewDebug.ExportedProperty
     int mPrivateFlags;
-    
+
     /**
-     * Count of how many windows this view has been attached to. 
+     * Count of how many windows this view has been attached to.
      */
     int mWindowAttachCount;
 
@@ -1376,6 +1391,7 @@
      * The view flags hold various views states.
      * {@hide}
      */
+    @ViewDebug.ExportedProperty
     int mViewFlags;
 
     /**
@@ -1450,7 +1466,7 @@
      */
     @ViewDebug.ExportedProperty
     protected int mPaddingBottom;
-    
+
     /**
      * Cache the paddingRight set by the user to append to the scrollbar's size.
      */
@@ -1462,7 +1478,7 @@
      */
     @ViewDebug.ExportedProperty
     int mUserPaddingBottom;
-    
+
     private int mOldWidthMeasureSpec = Integer.MIN_VALUE;
     private int mOldHeightMeasureSpec = Integer.MIN_VALUE;
 
@@ -1479,28 +1495,28 @@
      * {@hide}
      */
     protected OnFocusChangeListener mOnFocusChangeListener;
-    
+
     /**
      * Listener used to dispatch click events.
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
      */
     protected OnClickListener mOnClickListener;
-    
+
     /**
      * Listener used to dispatch long click events.
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
      */
     protected OnLongClickListener mOnLongClickListener;
-    
+
     /**
      * Listener used to build the context menu.
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
      */
     protected OnCreateContextMenuListener mOnCreateContextMenuListener;
-    
+
     private OnKeyListener mOnKeyListener;
 
     private OnTouchListener mOnTouchListener;
@@ -1519,11 +1535,6 @@
     private Bitmap mDrawingCache;
 
     /**
-     * Used for local (within a stackframe) calls that need a rect temporarily
-     */ 
-    private final Rect mTempRect = new Rect();
-
-    /**
      * When this view has focus and the next focus is {@link #FOCUS_LEFT},
      * the user may specify which view to go to next.
      */
@@ -1542,13 +1553,13 @@
     private int mNextFocusUpId = View.NO_ID;
 
     /**
-     * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 
+     * When this view has focus and the next focus is {@link #FOCUS_DOWN},
      * the user may specify which view to go to next.
      */
     private int mNextFocusDownId = View.NO_ID;
 
     private CheckForLongPress mPendingCheckForLongPress;
-    
+
     /**
      * Whether the long press's action has been invoked.  The tap's action is invoked on the
      * up event while a long press is invoked as soon as the long press duration is reached, so
@@ -1561,12 +1572,14 @@
      * The minimum height of the view. We'll try our best to have the height
      * of this view to at least this amount.
      */
+    @ViewDebug.ExportedProperty
     private int mMinHeight;
-    
+
     /**
      * The minimum width of the view. We'll try our best to have the width
      * of this view to at least this amount.
      */
+    @ViewDebug.ExportedProperty
     private int mMinWidth;
 
     /**
@@ -1574,7 +1587,7 @@
      * but should be handled by another view.
      */
     private TouchDelegate mTouchDelegate = null;
-    
+
     /**
      * Solid color to use as a background when creating the drawing cache. Enables
      * the cache to use 16 bit bitmaps instead of 32 bit.
@@ -1591,7 +1604,7 @@
 
     /**
      * Simple constructor to use when creating a view from code.
-     * 
+     *
      * @param context The Context the view is running in, through which it can
      *        access the current theme, resources, etc.
      */
@@ -1607,11 +1620,11 @@
      * that were specified in the XML file. This version uses a default style of
      * 0, so the only attribute values applied are those in the Context's Theme
      * and the given AttributeSet.
-     * 
+     *
      * <p>
      * The method onFinishInflate() will be called after all children have been
      * added.
-     * 
+     *
      * @param context The Context the view is running in, through which it can
      *        access the current theme, resources, etc.
      * @param attrs The attributes of the XML tag that is inflating the view.
@@ -1629,7 +1642,7 @@
      * <code>R.attr.buttonStyle</code> for <var>defStyle</var>; this allows
      * the theme's button style to modify all of the base view attributes (in
      * particular its background) as well as the Button class's attributes.
-     * 
+     *
      * @param context The Context the view is running in, through which it can
      *        access the current theme, resources, etc.
      * @param attrs The attributes of the XML tag that is inflating the view.
@@ -1663,7 +1676,7 @@
         int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY;
 
         viewFlagValues |= SOUND_EFFECTS_ENABLED;
-        viewFlagMasks |= SOUND_EFFECTS_ENABLED;      
+        viewFlagMasks |= SOUND_EFFECTS_ENABLED;
 
         final int N = a.getIndexCount();
         for (int i = 0; i < N; i++) {
@@ -1833,7 +1846,7 @@
         if (viewFlagMasks != 0) {
             setFlags(viewFlagValues, viewFlagMasks);
         }
-        
+
         // Needs to be called after mViewFlags is set
         if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) {
             recomputePadding();
@@ -1866,7 +1879,7 @@
      * being inflated from XML. This method is automatically called when the XML
      * is inflated.
      * </p>
-     * 
+     *
      * @param a the styled attributes set to initialize the fading edges from
      */
     protected void initializeFadingEdge(TypedArray a) {
@@ -1875,7 +1888,7 @@
         mScrollCache.fadingEdgeLength = a.getDimensionPixelSize(
                 R.styleable.View_fadingEdgeLength, ViewConfiguration.getFadingEdgeLength());
     }
-    
+
     /**
      * Returns the size of the vertical faded edges used to indicate that more
      * content in this view is visible.
@@ -1907,7 +1920,7 @@
         initScrollCache();
         mScrollCache.fadingEdgeLength = length;
     }
-    
+
     /**
      * Returns the size of the horizontal faded edges used to indicate that more
      * content in this view is visible.
@@ -1978,7 +1991,7 @@
      * being inflated from XML. This method is automatically called when the XML
      * is inflated.
      * </p>
-     * 
+     *
      * @param a the styled attributes set to initialize the scrollbars from
      */
     protected void initializeScrollbars(TypedArray a) {
@@ -1999,8 +2012,8 @@
         if (thumb != null) {
             mScrollCache.scrollBar.setHorizontalThumbDrawable(thumb);
         }
-        
-        boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 
+
+        boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack,
                 false);
         if (alwaysDraw) {
             mScrollCache.scrollBar.setAlwaysDrawHorizontalTrack(true);
@@ -2013,13 +2026,13 @@
         if (thumb != null) {
             mScrollCache.scrollBar.setVerticalThumbDrawable(thumb);
         }
-        
-        alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 
+
+        alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack,
                 false);
         if (alwaysDraw) {
             mScrollCache.scrollBar.setAlwaysDrawVerticalTrack(true);
         }
-        
+
         // Re-apply user/background padding so that scrollbar(s) get added
         recomputePadding();
     }
@@ -2037,16 +2050,16 @@
 
     /**
      * Register a callback to be invoked when focus of this view changed.
-     * 
+     *
      * @param l The callback that will run.
      */
     public void setOnFocusChangeListener(OnFocusChangeListener l) {
         mOnFocusChangeListener = l;
     }
-    
+
     /**
      * Returns the focus-change callback registered for this view.
-     * 
+     *
      * @return The callback, or null if one is not registered.
      */
     public OnFocusChangeListener getOnFocusChangeListener() {
@@ -2056,7 +2069,7 @@
     /**
      * Register a callback to be invoked when this view is clicked. If this view is not
      * clickable, it becomes clickable.
-     * 
+     *
      * @param l The callback that will run
      *
      * @see #setClickable(boolean)
@@ -2067,11 +2080,11 @@
         }
         mOnClickListener = l;
     }
-    
+
     /**
      * Register a callback to be invoked when this view is clicked and held. If this view is not
      * long clickable, it becomes long clickable.
-     * 
+     *
      * @param l The callback that will run
      *
      * @see #setLongClickable(boolean)
@@ -2084,9 +2097,9 @@
     }
 
     /**
-     * Register a callback to be invoked when the context menu for this view is 
+     * Register a callback to be invoked when the context menu for this view is
      * being built. If this view is not long clickable, it becomes long clickable.
-     * 
+     *
      * @param l The callback that will run
      *
      */
@@ -2096,10 +2109,10 @@
         }
         mOnCreateContextMenuListener = l;
     }
-    
+
     /**
      * Call this view's OnClickListener, if it is defined.
-     * 
+     *
      * @return True there was an assigned OnClickListener that was called, false
      *         otherwise is returned.
      */
@@ -2112,11 +2125,11 @@
 
         return false;
     }
-    
+
     /**
      * Call this view's OnLongClickListener, if it is defined. Invokes the context menu
      * if the OnLongClickListener did not consume the event.
-     * 
+     *
      * @return True there was an assigned OnLongClickListener that was called, false
      *         otherwise is returned.
      */
@@ -2130,10 +2143,10 @@
         }
         return handled;
     }
-    
+
     /**
      * Bring up the context menu for this view.
-     * 
+     *
      * @return Whether a context menu was displayed.
      */
     public boolean showContextMenu() {
@@ -2155,7 +2168,7 @@
     public void setOnTouchListener(OnTouchListener l) {
         mOnTouchListener = l;
     }
-    
+
     /**
      * Give this view focus. This will cause {@link #onFocusChanged} to be called.
      *
@@ -2191,7 +2204,7 @@
      * Request that a rectangle of this view be visible on the screen,
      * scrolling if necessary just enough.
      *
-     * A View should call this if it maintains some notion of which part
+     * <p>A View should call this if it maintains some notion of which part
      * of its content is interesting.  For example, a text editing view
      * should call this when its cursor moves.
      *
@@ -2206,11 +2219,11 @@
      * Request that a rectangle of this view be visible on the screen,
      * scrolling if necessary just enough.
      *
-     * A View should call this if it maintains some notion of which part
+     * <p>A View should call this if it maintains some notion of which part
      * of its content is interesting.  For example, a text editing view
      * should call this when its cursor moves.
      *
-     * When <code>immediate</code> is set to true, scrolling will not be
+     * <p>When <code>immediate</code> is set to true, scrolling will not be
      * animated.
      *
      * @param rectangle The rectangle.
@@ -2221,9 +2234,8 @@
         View child = this;
         ViewParent parent = mParent;
         boolean scrolled = false;
-        while (parent instanceof ViewGroup) {
-            ViewGroup vgParent = (ViewGroup) parent;
-            scrolled |= vgParent.requestChildRectangleOnScreen(child,
+        while (parent != null) {
+            scrolled |= parent.requestChildRectangleOnScreen(child,
                     rectangle, immediate);
 
             // offset rect so next call has the rectangle in the
@@ -2231,12 +2243,16 @@
             rectangle.offset(child.getLeft(), child.getTop());
             rectangle.offset(-child.getScrollX(), -child.getScrollY());
 
+            if (!(parent instanceof View)) {
+                break;
+            }
+            
             child = (View) parent;
             parent = child.getParent();
         }
         return scrolled;
     }
-    
+
     /**
      * Called when this view wants to give up focus. This will cause
      * {@link #onFocusChanged} to be called.
@@ -2257,7 +2273,7 @@
             refreshDrawableState();
         }
     }
-    
+
     /**
      * Called to clear the focus of a view that is about to be removed.
      * Doesn't call clearChildFocus, which prevents this view from taking
@@ -2271,7 +2287,7 @@
             refreshDrawableState();
         }
     }
-    
+
     /**
      * Called internally by the view system when a new view is getting focus.
      * This is what clears the old focus.
@@ -2292,7 +2308,7 @@
     /**
      * Returns true if this view has focus iteself, or is the ancestor of the
      * view that has focus.
-     * 
+     *
      * @return True if this view has or contains focus, false otherwise.
      */
     @ViewDebug.ExportedProperty
@@ -2315,17 +2331,19 @@
     public boolean hasFocusable() {
         return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable();
     }
-  
+
     /**
      * Called by the view system when the focus state of this view changes.
      * When the focus change event is caused by directional navigation, direction
      * and previouslyFocusedRect provide insight into where the focus is coming from.
+     * When overriding, be sure to call up through to the super class so that
+     * the standard focus handling will occur.
      * 
      * @param gainFocus True if the View has focus; false otherwise.
-     * @param direction The direction focus has moved when requestFocus() 
-     *                  is called to give this view focus. Values are 
-     *                  View.FOCUS_UP, View.FOCUS_DOWN, View.FOCUS_LEFT or 
-     *                  View.FOCUS_RIGHT. It may not always apply, in which 
+     * @param direction The direction focus has moved when requestFocus()
+     *                  is called to give this view focus. Values are
+     *                  View.FOCUS_UP, View.FOCUS_DOWN, View.FOCUS_LEFT or
+     *                  View.FOCUS_RIGHT. It may not always apply, in which
      *                  case use the default.
      * @param previouslyFocusedRect The rectangle, in this view's coordinate
      *        system, of the previously focused view.  If applicable, this will be
@@ -2333,20 +2351,29 @@
      *        from (in addition to direction).  Will be <code>null</code> otherwise.
      */
     protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+        InputMethodManager imm = InputMethodManager.peekInstance();
         if (!gainFocus) {
             if (isPressed()) {
                 setPressed(false);
             }
+            if (imm != null && mAttachInfo != null
+                    && mAttachInfo.mHasWindowFocus) {
+                imm.focusOut(this);
+            }
+        } else if (imm != null && mAttachInfo != null
+                && mAttachInfo.mHasWindowFocus) {
+            imm.focusIn(this);
         }
+        
         invalidate();
         if (mOnFocusChangeListener != null) {
             mOnFocusChangeListener.onFocusChange(this, gainFocus);
         }
     }
-   
+
     /**
      * Returns true if this view has focus
-     * 
+     *
      * @return True if this view has focus, false otherwise.
      */
     @ViewDebug.ExportedProperty
@@ -2357,7 +2384,7 @@
     /**
      * Find the view in the hierarchy rooted at this view that currently has
      * focus.
-     * 
+     *
      * @return The view that currently has focus, or null if no focused view can
      *         be found.
      */
@@ -2366,6 +2393,28 @@
     }
 
     /**
+     * Change whether this view is one of the set of scrollable containers in
+     * its window.  This will be used to determine whether the window can
+     * resize or must pan when a soft input area is open -- scrollable
+     * containers allow the window to use resize mode since the container
+     * will appropriately shrink.
+     */
+    public void setScrollContainer(boolean isScrollContainer) {
+        if (isScrollContainer) {
+            if (mAttachInfo != null && (mPrivateFlags&SCROLL_CONTAINER_ADDED) == 0) {
+                mAttachInfo.mScrollContainers.add(this);
+                mPrivateFlags |= SCROLL_CONTAINER_ADDED;
+            }
+            mPrivateFlags |= SCROLL_CONTAINER;
+        } else {
+            if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) {
+                mAttachInfo.mScrollContainers.remove(this);
+            }
+            mPrivateFlags &= ~(SCROLL_CONTAINER|SCROLL_CONTAINER_ADDED);
+        }
+    }
+
+    /**
      * Returns the quality of the drawing cache.
      *
      * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO},
@@ -2388,7 +2437,7 @@
      * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO},
      *        {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH}
      *
-     * @see #getDrawingCacheQuality() 
+     * @see #getDrawingCacheQuality()
      * @see #setDrawingCacheEnabled(boolean)
      * @see #isDrawingCacheEnabled()
      *
@@ -2418,7 +2467,7 @@
      *
      * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}.
      *
-     * @see #getKeepScreenOn() 
+     * @see #getKeepScreenOn()
      *
      * @attr ref android.R.styleable#View_keepScreenOn
      */
@@ -2508,10 +2557,10 @@
 
     /**
      * Returns the visibility of this view and all of its ancestors
-     * 
+     *
      * @return True if this view and all of its ancestors are {@link #VISIBLE}
      */
-    public boolean isShown() {        
+    public boolean isShown() {
         View current = this;
         //noinspection ConstantConditions
         do {
@@ -2522,7 +2571,7 @@
             if (parent == null) {
                 return false; // We are not attached to the view root
             }
-            if (parent instanceof ViewRoot) {
+            if (!(parent instanceof View)) {
                 return true;
             }
             current = (View) parent;
@@ -2534,7 +2583,7 @@
     /**
      * Apply the insets for system windows to this view, if the FITS_SYSTEM_WINDOWS flag
      * is set
-     * 
+     *
      * @param insets Insets for system windows
      *
      * @return True if this view applied the insets, false otherwise
@@ -2545,14 +2594,15 @@
             mPaddingTop = insets.top;
             mPaddingRight = insets.right;
             mPaddingBottom = insets.bottom;
+            requestLayout();
             return true;
         }
         return false;
     }
-    
+
     /**
      * Returns the visibility status for this view.
-     * 
+     *
      * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
      * @attr ref android.R.styleable#View_visibility
      */
@@ -2567,7 +2617,7 @@
 
     /**
      * Set the enabled state of this view.
-     * 
+     *
      * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
      * @attr ref android.R.styleable#View_visibility
      */
@@ -2578,40 +2628,40 @@
     /**
      * Returns the enabled status for this view. The interpretation of the
      * enabled state varies by subclass.
-     * 
+     *
      * @return True if this view is enabled, false otherwise.
      */
     @ViewDebug.ExportedProperty
     public boolean isEnabled() {
         return (mViewFlags & ENABLED_MASK) == ENABLED;
     }
-    
+
     /**
      * Set the enabled state of this view. The interpretation of the enabled
      * state varies by subclass.
-     * 
+     *
      * @param enabled True if this view is enabled, false otherwise.
      */
     public void setEnabled(boolean enabled) {
         setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK);
-        
+
         /*
          * The View most likely has to change its appearance, so refresh
          * the drawable state.
          */
         refreshDrawableState();
-        
+
         // Invalidate too, since the default behavior for views is to be
         // be drawn at 50% alpha rather than to change the drawable.
         invalidate();
     }
-    
+
     /**
      * Set whether this view can receive the focus.
      *
      * Setting this to false will also ensure that this view is not focusable
      * in touch mode.
-     * 
+     *
      * @param focusable If true, this view can receive the focus.
      *
      * @see #setFocusableInTouchMode(boolean)
@@ -2631,7 +2681,7 @@
      *
      * @param focusableInTouchMode If true, this view can receive the focus while
      *   in touch mode.
-     * 
+     *
      * @see #setFocusable(boolean)
      * @attr ref android.R.styleable#View_focusableInTouchMode
      */
@@ -2676,18 +2726,18 @@
     }
 
     /**
-     * If this view doesn't do any drawing on its own, set this flag to 
+     * If this view doesn't do any drawing on its own, set this flag to
      * allow further optimizations. By default, this flag is not set on
      * View, but could be set on some View subclasses such as ViewGroup.
-     * 
+     *
      * Typically, if you override {@link #onDraw} you should clear this flag.
-     * 
+     *
      * @param willNotDraw whether or not this View draw on its own
      */
     public void setWillNotDraw(boolean willNotDraw) {
         setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
     }
-    
+
     /**
      * Returns whether or not this View draws on its own.
      *
@@ -2739,7 +2789,7 @@
      * is clickable it will change its state to "pressed" on every click.
      * Subclasses should set the view clickable to visually react to
      * user's clicks.
-     * 
+     *
      * @param clickable true to make the view clickable, false otherwise
      *
      * @see #isClickable()
@@ -2766,7 +2816,7 @@
      * clickable it reacts to the user holding down the button for a longer
      * duration than a tap. This event can either launch the listener or a
      * context menu.
-     * 
+     *
      * @param longClickable true to make the view long clickable, false otherwise
      * @see #isLongClickable()
      * @attr ref android.R.styleable#View_longClickable
@@ -2777,10 +2827,10 @@
 
     /**
      * Sets the pressed that for this view.
-     * 
+     *
      * @see #isClickable()
      * @see #setClickable(boolean)
-     * 
+     *
      * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts
      *        the View's internal state from a previously set "pressed" state.
      */
@@ -2793,12 +2843,12 @@
         refreshDrawableState();
         dispatchSetPressed(pressed);
     }
-    
+
     /**
      * Dispatch setPressed to all of this View's children.
-     * 
+     *
      * @see #setPressed(boolean)
-     * 
+     *
      * @param pressed The new pressed state
      */
     protected void dispatchSetPressed(boolean pressed) {
@@ -2818,7 +2868,7 @@
     public boolean isPressed() {
         return (mPrivateFlags & PRESSED) == PRESSED;
     }
-    
+
     /**
      * Indicates whether this view will save its state (that is,
      * whether its {@link #onSaveInstanceState} method will be called).
@@ -2839,12 +2889,12 @@
      * view still must have an id assigned to it (via {@link #setId setId()})
      * for its state to be saved.  This flag can only disable the
      * saving of this view; any child views may still have their state saved.
-     * 
+     *
      * @param enabled Set to false to <em>disable</em> state saving, or true
      * (the default) to allow it.
      *
      * @see #isSaveEnabled()
-     * @see #setId(int) 
+     * @see #setId(int)
      * @see #onSaveInstanceState()
      * @attr ref android.R.styleable#View_saveEnabled
      */
@@ -2855,7 +2905,7 @@
 
     /**
      * Returns whether this View is able to take focus.
-     * 
+     *
      * @return True if this view can take focus, or false otherwise.
      * @attr ref android.R.styleable#View_focusable
      */
@@ -2880,9 +2930,9 @@
     /**
      * Find the nearest view in the specified direction that can take focus.
      * This does not actually give focus to that view.
-     * 
+     *
      * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
-     * 
+     *
      * @return The nearest focusable in the specified direction, or null if none
      *         can be found.
      */
@@ -2893,7 +2943,7 @@
             return null;
         }
     }
-    
+
     /**
      * This method is the last chance for the focused view and its ancestors to
      * respond to an arrow key. This is called when the focused view did not
@@ -2943,7 +2993,7 @@
         }
         return result;
     }
-    
+
     /**
      * Find and return all focusable views that are descendants of this view,
      * possibly including this view if it is focusable itself.
@@ -2961,7 +3011,7 @@
      * Add any focusable views that are descendants of this view (possibly
      * including this view if it is focusable itself) to views.  If we are in touch mode,
      * only add views that are also focusable in touch mode.
-     * 
+     *
      * @param views Focusable views found so far
      * @param direction The direction of the focus
      */
@@ -2972,11 +3022,11 @@
 
         views.add(this);
     }
-    
+
     /**
      * Find and return all touchable views that are descendants of this view,
      * possibly including this view if it is touchable itself.
-     * 
+     *
      * @return A list of touchable views
      */
     public ArrayList<View> getTouchables() {
@@ -2987,13 +3037,13 @@
 
     /**
      * Add any touchable views that are descendants of this view (possibly
-     * including this view if it is touchable itself) to views. 
-     * 
+     * including this view if it is touchable itself) to views.
+     *
      * @param views Touchable views found so far
      */
     public void addTouchables(ArrayList<View> views) {
         final int viewFlags = mViewFlags;
-        
+
         if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                 && (viewFlags & ENABLED_MASK) == ENABLED) {
             views.add(this);
@@ -3024,14 +3074,14 @@
     /**
      * Call this to try to give focus to a specific view or to one of its
      * descendants and give it a hint about what direction focus is heading.
-     * 
+     *
      * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns false),
      * or if it is focusable and it is not focusable in touch mode ({@link #isFocusableInTouchMode})
      * while the device is in touch mode.
      *
      * See also {@link #focusSearch}, which is what you call to say that you
      * have focus, and you want your parent to look for the next one.
-     * 
+     *
      * This is equivalent to calling {@link #requestFocus(int, Rect)} with
      * <code>null</code> set for the previously focused rectangle.
      *
@@ -3096,11 +3146,11 @@
      * Call this to try to give focus to a specific view or to one of its descendants. This is a
      * special variant of {@link #requestFocus() } that will allow views that are not focuable in
      * touch mode to request focus when they are touched.
-     * 
+     *
      * @return Whether this view or one of its descendants actually took focus.
-     * 
+     *
      * @see #isInTouchMode()
-     * 
+     *
      */
     public final boolean requestFocusFromTouch() {
         // Leave touch mode if we need to
@@ -3115,7 +3165,7 @@
         }
         return requestFocus(View.FOCUS_DOWN);
     }
-    
+
     /**
      * @return Whether any ancestor of this view blocks descendant focus.
      */
@@ -3131,42 +3181,74 @@
         }
         return false;
     }
-    
+
+    /**
+     * capture information of this view for later analysis: developement only
+     * check dynamic switch to make sure we only dump view
+     * when ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW) is set
+     */
+    private static void captureViewInfo(String subTag, View v) {
+        if (v == null ||
+           SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW, 0) == 0) {
+            return;
+        }
+        ViewDebug.dumpCapturedView(subTag, v);
+    }
+
+    /**
+     * Dispatch a key event before it is processed by any input method
+     * associated with the view hierarchy.  This can be used to intercept
+     * key events in special situations before the IME consumes them; a
+     * typical example would be handling the BACK key to update the application's
+     * UI instead of allowing the IME to see it and close itself.
+     *
+     * @param event The key event to be dispatched.
+     * @return True if the event was handled, false otherwise.
+     */
+    public boolean dispatchKeyEventPreIme(KeyEvent event) {
+        return onKeyPreIme(event.getKeyCode(), event);
+    }
+
     /**
      * Dispatch a key event to the next view on the focus path. This path runs
      * from the top of the view tree down to the currently focused view. If this
      * view has focus, it will dispatch to itself. Otherwise it will dispatch
      * the next node down the focus path. This method also fires any key
      * listeners.
-     * 
+     *
      * @param event The key event to be dispatched.
      * @return True if the event was handled, false otherwise.
      */
     public boolean dispatchKeyEvent(KeyEvent event) {
         // If any attached key listener a first crack at the event.
         //noinspection SimplifiableIfStatement
+
+        if (android.util.Config.LOGV) {
+            captureViewInfo("captureViewKeyEvent", this);
+        }
+
         if (mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                 && mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
             return true;
         }
-    
+
         return event.dispatch(this);
     }
 
     /**
      * Dispatches a key shortcut event.
-     * 
+     *
      * @param event The key event to be dispatched.
      * @return True if the event was handled by the view, false otherwise.
      */
     public boolean dispatchKeyShortcutEvent(KeyEvent event) {
         return onKeyShortcut(event.getKeyCode(), event);
     }
-        
+
     /**
      * Pass the touch screen motion event down to the target view, or this
      * view if it is the target.
-     * 
+     *
      * @param event The motion event to be dispatched.
      * @return True if the event was handled by the view, false otherwise.
      */
@@ -3180,7 +3262,7 @@
 
     /**
      * Pass a trackball motion event down to the focused view.
-     * 
+     *
      * @param event The motion event to be dispatched.
      * @return True if the event was handled by the view, false otherwise.
      */
@@ -3192,7 +3274,7 @@
     /**
      * Called when the window containing this view gains or loses window focus.
      * ViewGroups should override to route to their children.
-     * 
+     *
      * @param hasFocus True if the window containing this view now has focus,
      *        false otherwise.
      */
@@ -3206,23 +3288,29 @@
      * your view and its window must have focus.  If a window is displayed
      * on top of yours that takes input focus, then your own window will lose
      * focus but the view focus will remain unchanged.
-     * 
+     *
      * @param hasWindowFocus True if the window containing this view now has
      *        focus, false otherwise.
      */
     public void onWindowFocusChanged(boolean hasWindowFocus) {
+        InputMethodManager imm = InputMethodManager.peekInstance();
         if (!hasWindowFocus) {
             if (isPressed()) {
                 setPressed(false);
             }
+            if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
+                imm.focusOut(this);
+            }
+        } else if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
+            imm.focusIn(this);
         }
         refreshDrawableState();
     }
-    
+
     /**
      * Returns true if this view is in a window that currently has window focus.
      * Note that this is not the same as the view itself having focus.
-     * 
+     *
      * @return True if this view is in a window that currently has window focus.
      */
     public boolean hasWindowFocus() {
@@ -3232,9 +3320,9 @@
     /**
      * Dispatch a window visibility change down the view hierarchy.
      * ViewGroups should override to route to their children.
-     * 
+     *
      * @param visibility The new visibility of the window.
-     * 
+     *
      * @see #onWindowVisibilityChanged
      */
     public void dispatchWindowVisibilityChanged(int visibility) {
@@ -3248,22 +3336,59 @@
      * to the window manager; this does <em>not</em> tell you whether or not
      * your window is obscured by other windows on the screen, even if it
      * is itself visible.
-     * 
+     *
      * @param visibility The new visibility of the window.
      */
     protected void onWindowVisibilityChanged(int visibility) {
     }
-    
+
     /**
      * Returns the current visibility of the window this view is attached to
      * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}).
-     * 
+     *
      * @return Returns the current visibility of the view's window.
      */
     public int getWindowVisibility() {
         return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE;
     }
-    
+
+    /**
+     * Retrieve the overall visible display size in which the window this view is
+     * attached to has been positioned in.  This takes into account screen
+     * decorations above the window, for both cases where the window itself
+     * is being position inside of them or the window is being placed under
+     * then and covered insets are used for the window to position its content
+     * inside.  In effect, this tells you the available area where content can
+     * be placed and remain visible to users.
+     *
+     * <p>This function requires an IPC back to the window manager to retrieve
+     * the requested information, so should not be used in performance critical
+     * code like drawing.
+     *
+     * @param outRect Filled in with the visible display frame.  If the view
+     * is not attached to a window, this is simply the raw display size.
+     */
+    public void getWindowVisibleDisplayFrame(Rect outRect) {
+        if (mAttachInfo != null) {
+            try {
+                mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect);
+            } catch (RemoteException e) {
+                return;
+            }
+            // XXX This is really broken, and probably all needs to be done
+            // in the window manager, and we need to know more about whether
+            // we want the area behind or in front of the IME.
+            final Rect insets = mAttachInfo.mVisibleInsets;
+            outRect.left += insets.left;
+            outRect.top += insets.top;
+            outRect.right -= insets.right;
+            outRect.bottom -= insets.bottom;
+            return;
+        }
+        Display d = WindowManagerImpl.getDefault().getDefaultDisplay();
+        outRect.set(0, 0, d.getWidth(), d.getHeight());
+    }
+
     /**
      * Private function to aggregate all per-view attributes in to the view
      * root.
@@ -3278,7 +3403,7 @@
             mAttachInfo.mKeepScreenOn = true;
         }
     }
-    
+
     void needGlobalAttributesUpdate(boolean force) {
         AttachInfo ai = mAttachInfo;
         if (ai != null) {
@@ -3287,7 +3412,7 @@
             }
         }
     }
-    
+
     /**
      * Returns whether the device is currently in touch mode.  Touch mode is entered
      * once the user begins interacting with the device by touch, and affects various
@@ -3306,21 +3431,38 @@
 
     /**
      * Returns the context the view is running in, through which it can
-     * access the current theme, resources, etc.    
-     *        
+     * access the current theme, resources, etc.
+     *
      * @return The view's Context.
      */
+    @ViewDebug.CapturedViewProperty
     public final Context getContext() {
         return mContext;
     }
 
     /**
+     * Handle a key event before it is processed by any input method
+     * associated with the view hierarchy.  This can be used to intercept
+     * key events in special situations before the IME consumes them; a
+     * typical example would be handling the BACK key to update the application's
+     * UI instead of allowing the IME to see it and close itself.
+     *
+     * @param keyCode The value in event.getKeyCode().
+     * @param event Description of the key event.
+     * @return If you handled the event, return true. If you want to allow the
+     *         event to be handled by the next receiver, return false.
+     */
+    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    /**
      * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
      * KeyEvent.Callback.onKeyMultiple()}: perform press of the view
      * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER}
      * is released, if the view is enabled and clickable.
-     * 
-     * @param keyCode A key code that represents the button pressed, from 
+     *
+     * @param keyCode A key code that represents the button pressed, from
      *                {@link android.view.KeyEvent}.
      * @param event   The KeyEvent object that defines the button action.
      */
@@ -3354,8 +3496,8 @@
      * KeyEvent.Callback.onKeyMultiple()}: perform clicking of the view
      * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or
      * {@link KeyEvent#KEYCODE_ENTER} is released.
-     * 
-     * @param keyCode A key code that represents the button pressed, from 
+     *
+     * @param keyCode A key code that represents the button pressed, from
      *                {@link android.view.KeyEvent}.
      * @param event   The KeyEvent object that defines the button action.
      */
@@ -3390,8 +3532,8 @@
      * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
      * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle
      * the event).
-     * 
-     * @param keyCode     A key code that represents the button pressed, from 
+     *
+     * @param keyCode     A key code that represents the button pressed, from
      *                    {@link android.view.KeyEvent}.
      * @param repeatCount The number of times the action was made.
      * @param event       The KeyEvent object that defines the button action.
@@ -3402,7 +3544,7 @@
 
     /**
      * Called when an unhandled key shortcut event occurs.
-     * 
+     *
      * @param keyCode The value in event.getKeyCode().
      * @param event Description of the key event.
      * @return If you handled the event, return true. If you want to allow the
@@ -3411,11 +3553,23 @@
     public boolean onKeyShortcut(int keyCode, KeyEvent event) {
         return false;
     }
-    
+
+    /**
+     * Create a new InputConnection for an InputMethod to interact
+     * with the view.  The default implementation returns null, since it doesn't
+     * support input methods.  You can override this to implement such support.
+     * This is only needed for views that take focus and text input.
+     *
+     * @param outAttrs Fill in with attribute information about the connection.
+     */
+    public InputConnection createInputConnection(EditorInfo outAttrs) {
+        return null;
+    }
+
     /**
      * Show the context menu for this view. It is not safe to hold on to the
      * menu after returning from this method.
-     * 
+     *
      * @param menu The context menu to populate
      */
     public void createContextMenu(ContextMenu menu) {
@@ -3517,7 +3671,7 @@
                             if (mPendingCheckForLongPress != null) {
                                 removeCallbacks(mPendingCheckForLongPress);
                             }
-                            
+
                             // Only perform take click actions if we were in the pressed state
                             if (!focusTaken) {
                                 performClick();
@@ -3548,10 +3702,10 @@
                 case MotionEvent.ACTION_MOVE:
                     final int x = (int) event.getX();
                     final int y = (int) event.getY();
-                    
+
                     // Be lenient about moving outside of buttons
                     int slop = ViewConfiguration.getTouchSlop();
-                    if ((x < 0 - slop) || (x >= getWidth() + slop) || 
+                    if ((x < 0 - slop) || (x >= getWidth() + slop) ||
                             (y < 0 - slop) || (y >= getHeight() + slop)) {
                         // Outside button
                         if ((mPrivateFlags & PRESSED) != 0) {
@@ -3598,7 +3752,7 @@
     public void setTouchDelegate(TouchDelegate delegate) {
         mTouchDelegate = delegate;
     }
-    
+
     /**
      * Gets the TouchDelegate for this View.
      */
@@ -3608,7 +3762,7 @@
 
     /**
      * Set flags controlling behavior of this view.
-     * 
+     *
      * @param flags Constant indicating the value which should be set
      * @param mask Constant indicating the bit range that should be changed
      */
@@ -3648,7 +3802,7 @@
                 mPrivateFlags |= DRAWN;
 
                 needGlobalAttributesUpdate(true);
-                
+
                 // a view becoming visible is worth notifying the parent
                 // about in case nothing has focus.  even if this specific view
                 // isn't focusable, it may contain something that is, so let
@@ -3668,6 +3822,9 @@
             if (((mViewFlags & VISIBILITY_MASK) == GONE) && hasFocus()) {
                 clearFocus();
             }
+            if (mAttachInfo != null) {
+                mAttachInfo.mViewVisibilityChanged = true;
+            }
         }
 
         /* Check if the VISIBLE bit has changed */
@@ -3681,6 +3838,9 @@
                     clearFocus();
                 }
             }
+            if (mAttachInfo != null) {
+                mAttachInfo.mViewVisibilityChanged = true;
+            }
         }
 
         if ((changed & WILL_NOT_CACHE_DRAWING) != 0) {
@@ -3712,7 +3872,7 @@
                     mPrivateFlags &= ~SKIP_DRAW;
                     mPrivateFlags |= ONLY_DRAWS_BACKGROUND;
                 } else {
-                    mPrivateFlags |= SKIP_DRAW;                    
+                    mPrivateFlags |= SKIP_DRAW;
                 }
             } else {
                 mPrivateFlags &= ~SKIP_DRAW;
@@ -3720,7 +3880,7 @@
             requestLayout();
             invalidate();
         }
-        
+
         if ((changed & KEEP_SCREEN_ON) != 0) {
             if (mParent != null) {
                 mParent.recomputeViewAttributes(this);
@@ -3740,10 +3900,10 @@
 
     /**
      * This is called in response to an internal scroll in this view (i.e., the
-     * view scrolled its own contents). This is typically as a result of 
+     * view scrolled its own contents). This is typically as a result of
      * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been
      * called.
-     * 
+     *
      * @param l Current horizontal scroll origin.
      * @param t Current vertical scroll origin.
      * @param oldl Previous horizontal scroll origin.
@@ -3757,7 +3917,7 @@
      * This is called during layout when the size of this view has changed. If
      * you were just added to the view hierarchy, you're called with the old
      * values of 0.
-     * 
+     *
      * @param w Current width of this view.
      * @param h Current height of this view.
      * @param oldw Old width of this view.
@@ -3765,7 +3925,7 @@
      */
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
     }
-    
+
     /**
      * Called by draw to draw the child views. This may be overridden
      * by derived classes to gain control just before its children are drawn
@@ -3778,7 +3938,7 @@
     /**
      * Gets the parent of this view. Note that the parent is a
      * ViewParent and not necessarily a View.
-     * 
+     *
      * @return Parent of this view.
      */
     public final ViewParent getParent() {
@@ -3790,7 +3950,7 @@
      * the displayed part of your view. You do not need to draw any pixels
      * farther left, since those are outside of the frame of your view on
      * screen.
-     * 
+     *
      * @return The left edge of the displayed part of your view, in pixels.
      */
     public final int getScrollX() {
@@ -3801,7 +3961,7 @@
      * Return the scrolled top position of this view. This is the top edge of
      * the displayed part of your view. You do not need to draw any pixels above
      * it, since those are outside of the frame of your view on screen.
-     * 
+     *
      * @return The top edge of the displayed part of your view, in pixels.
      */
     public final int getScrollY() {
@@ -3810,7 +3970,7 @@
 
     /**
      * Return the width of the your view.
-     * 
+     *
      * @return The width of your view, in pixels.
      */
     @ViewDebug.ExportedProperty
@@ -3820,7 +3980,7 @@
 
     /**
      * Return the height of your view.
-     * 
+     *
      * @return The height of your view, in pixels.
      */
     @ViewDebug.ExportedProperty
@@ -3832,7 +3992,7 @@
      * Return the visible drawing bounds of your view. Fills in the output
      * rectangle with the values from getScrollX(), getScrollY(),
      * getWidth(), and getHeight().
-     * 
+     *
      * @param outRect The (scrolled) drawing bounds of the view.
      */
     public void getDrawingRect(Rect outRect) {
@@ -3846,69 +4006,73 @@
      * The width of this view as measured in the most recent call to measure().
      * This should be used during measurement and layout calculations only. Use
      * {@link #getWidth()} to see how wide a view is after layout.
-     * 
+     *
      * @return The measured width of this view.
      */
     public final int getMeasuredWidth() {
         return mMeasuredWidth;
     }
-    
+
     /**
      * The height of this view as measured in the most recent call to measure().
      * This should be used during measurement and layout calculations only. Use
      * {@link #getHeight()} to see how tall a view is after layout.
-     * 
+     *
      * @return The measured height of this view.
      */
     public final int getMeasuredHeight() {
         return mMeasuredHeight;
     }
-    
+
     /**
      * Top position of this view relative to its parent.
-     * 
+     *
      * @return The top of this view, in pixels.
      */
+    @ViewDebug.CapturedViewProperty
     public final int getTop() {
         return mTop;
     }
-    
+
     /**
      * Bottom position of this view relative to its parent.
-     * 
+     *
      * @return The bottom of this view, in pixels.
      */
+    @ViewDebug.CapturedViewProperty
     public final int getBottom() {
         return mBottom;
     }
-    
+
     /**
      * Left position of this view relative to its parent.
-     * 
+     *
      * @return The left edge of this view, in pixels.
      */
+    @ViewDebug.CapturedViewProperty
     public final int getLeft() {
         return mLeft;
     }
-    
+
     /**
      * Right position of this view relative to its parent.
-     * 
+     *
      * @return The right edge of this view, in pixels.
      */
+    @ViewDebug.CapturedViewProperty
     public final int getRight() {
         return mRight;
     }
 
     /**
      * Hit rectangle in parent's coordinates
-     * 
+     *
      * @param outRect The hit rectangle of the view.
      */
     public void getHitRect(Rect outRect) {
         outRect.set(mLeft, mTop, mRight, mBottom);
     }
-    
+
     /**
      * When a view has focus and the user navigates away from it, the next view is searched for
      * starting from the rectangle filled in by this method.
@@ -3929,7 +4093,7 @@
      * coordinates, offset it by -globalOffset (e.g. r.offset(-globalOffset.x,
      * -globalOffset.y)) If the view is completely clipped or translated out,
      * return false.
-     * 
+     *
      * @param r If true is returned, r holds the global coordinates of the
      *        visible portion of this view.
      * @param globalOffset If true is returned, globalOffset holds the dx,dy
@@ -3962,7 +4126,7 @@
         }
         return false;
     }
-    
+
     /**
      * Offset this view's vertical location by the specified number of pixels.
      *
@@ -3975,18 +4139,18 @@
 
     /**
      * Offset this view's horizontal location by the specified amount of pixels.
-     * 
+     *
      * @param offset the numer of pixels to offset the view by
      */
     public void offsetLeftAndRight(int offset) {
         mLeft += offset;
         mRight += offset;
     }
-    
+
     /**
      * Get the LayoutParams associated with this view. All views should have
-     * layout parameters. These supply parameters to the <i>parent</i> of this 
-     * view specifying how it should be arranged. There are many subclasses of 
+     * layout parameters. These supply parameters to the <i>parent</i> of this
+     * view specifying how it should be arranged. There are many subclasses of
      * ViewGroup.LayoutParams, and these correspond to the different subclasses
      * of ViewGroup that are responsible for arranging their children.
      * @return The LayoutParams associated with this view
@@ -4012,7 +4176,7 @@
         mLayoutParams = params;
         requestLayout();
     }
-    
+
     /**
      * Set the scrolled position of your view. This will cause a call to
      * {@link #onScrollChanged(int, int, int, int)} and the view will be
@@ -4047,7 +4211,7 @@
      * visible, {@link #onDraw} will be called at some point in the future.
      * This must be called from a UI thread. To call from a non-UI thread, call
      * {@link #postInvalidate()}.
-     * 
+     *
      * WARNING: This method is destructive to dirty.
      * @param dirty the rectangle representing the bounds of the dirty region
      */
@@ -4058,13 +4222,15 @@
 
         if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) {
             mPrivateFlags &= ~DRAWING_CACHE_VALID;
-            ViewParent p = mParent;
-            if (p != null) {
+            final ViewParent p = mParent;
+            final AttachInfo ai = mAttachInfo;
+            if (p != null && ai != null) {
                 final int scrollX = mScrollX;
                 final int scrollY = mScrollY;
-                mTempRect.set(dirty.left - scrollX, dirty.top - scrollY,
-                              dirty.right - scrollX, dirty.bottom - scrollY);
-                p.invalidateChild(this, mTempRect);
+                final Rect r = ai.mTmpInvalRect;
+                r.set(dirty.left - scrollX, dirty.top - scrollY,
+                        dirty.right - scrollX, dirty.bottom - scrollY);
+                mParent.invalidateChild(this, r);
             }
         }
     }
@@ -4087,12 +4253,14 @@
 
         if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) {
             mPrivateFlags &= ~DRAWING_CACHE_VALID;
-            ViewParent p = mParent;
-            if (p != null && l < r && t < b) {
+            final ViewParent p = mParent;
+            final AttachInfo ai = mAttachInfo;
+            if (p != null && ai != null && l < r && t < b) {
                 final int scrollX = mScrollX;
                 final int scrollY = mScrollY;
-                mTempRect.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY);
-                p.invalidateChild(this, mTempRect);
+                final Rect tmpr = ai.mTmpInvalRect;
+                tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY);
+                p.invalidateChild(this, tmpr);
             }
         }
     }
@@ -4109,25 +4277,27 @@
 
         if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) {
             mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
-            ViewParent p = mParent;
-            if (p != null) {
-                mTempRect.set(0, 0, mRight - mLeft, mBottom - mTop);
+            final ViewParent p = mParent;
+            final AttachInfo ai = mAttachInfo;
+            if (p != null && ai != null) {
+                final Rect r = ai.mTmpInvalRect;
+                r.set(0, 0, mRight - mLeft, mBottom - mTop);
                 // Don't call invalidate -- we don't want to internally scroll
                 // our own bounds
-                p.invalidateChild(this, mTempRect);
+                p.invalidateChild(this, r);
             }
         }
     }
-    
+
     /**
      * @return A handler associated with the thread running the View. This
      * handler can be used to pump events in the UI events queue.
      */
-    protected Handler getHandler() {
+    public Handler getHandler() {
         if (mAttachInfo != null) {
             return mAttachInfo.mHandler;
         }
-        return null; 
+        return null;
     }
 
     /**
@@ -4260,7 +4430,7 @@
     /**
      * Cause an invalidate to happen on a subsequent cycle through the event
      * loop. Waits for the specified amount of time.
-     * 
+     *
      * @param delayMilliseconds the duration in milliseconds to delay the
      *         invalidation by
      */
@@ -4304,7 +4474,7 @@
      * Called by a parent to request that a child update its values for mScrollX
      * and mScrollY if necessary. This will typically be done if the child is
      * animating a scroll using a {@link android.widget.Scroller Scroller}
-     * object. 
+     * object.
      */
     public void computeScroll() {
     }
@@ -4337,7 +4507,7 @@
     public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) {
         if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) {
             if (horizontalFadingEdgeEnabled) {
-                initScrollCache();                
+                initScrollCache();
             }
 
             mViewFlags ^= FADING_EDGE_HORIZONTAL;
@@ -4504,12 +4674,12 @@
      * inset. When inset, they add to the padding of the view. And the scrollbars
      * can be drawn inside the padding area or on the edge of the view. For example,
      * if a view has a background drawable and you want to draw the scrollbars
-     * inside the padding specified by the drawable, you can use 
+     * inside the padding specified by the drawable, you can use
      * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to
      * appear at the edge of the view, ignoring the padding, then you can use
-     * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 
-     * @param style the style of the scrollbars. Should be one of 
-     * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 
+     * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p>
+     * @param style the style of the scrollbars. Should be one of
+     * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET,
      * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.
      * @see #SCROLLBARS_INSIDE_OVERLAY
      * @see #SCROLLBARS_INSIDE_INSET
@@ -4517,12 +4687,12 @@
      * @see #SCROLLBARS_OUTSIDE_INSET
      */
     public void setScrollBarStyle(int style) {
-        if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 
+        if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) {
             mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK);
             recomputePadding();
         }
     }
-    
+
     /**
      * <p>Returns the current scrollbar style.</p>
      * @return the current scrollbar style
@@ -4534,7 +4704,7 @@
     public int getScrollBarStyle() {
         return mViewFlags & SCROLLBARS_STYLE_MASK;
     }
-    
+
     /**
      * <p>Compute the horizontal range that the horizontal scrollbar
      * represents.</p>
@@ -4670,10 +4840,10 @@
         final ScrollabilityCache cache = mScrollCache;
         if (cache != null) {
             final int viewFlags = mViewFlags;
-            
-            final boolean drawHorizontalScrollBar = 
+
+            final boolean drawHorizontalScrollBar =
                 (viewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL;
-            final boolean drawVerticalScrollBar = 
+            final boolean drawVerticalScrollBar =
                 (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL;
 
             if (drawVerticalScrollBar || drawHorizontalScrollBar) {
@@ -4728,12 +4898,12 @@
         final int scrollY = mScrollY;
         final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
         final int top = scrollY + height - size - (mUserPaddingBottom & inside);
-        
-        final int verticalScrollBarGap =  
+
+        final int verticalScrollBarGap =
             (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL ?
                     getVerticalScrollbarWidth() : 0;
-                    
-        scrollBar.setBounds(scrollX + (mPaddingLeft & inside) + getScrollBarPaddingLeft(), top, 
+
+        scrollBar.setBounds(scrollX + (mPaddingLeft & inside) + getScrollBarPaddingLeft(), top,
                 scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap, top + size);
         scrollBar.setParameters(
                 computeHorizontalScrollRange(),
@@ -4773,8 +4943,8 @@
         final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
         // TODO: Deal with RTL languages to position scrollbar on left
         final int left = scrollX + width - size - (mUserPaddingRight & inside);
-        
-        scrollBar.setBounds(left, scrollY + (mPaddingTop & inside), 
+
+        scrollBar.setBounds(left, scrollY + (mPaddingTop & inside),
                 left + size, scrollY + height - (mUserPaddingBottom & inside));
         scrollBar.setParameters(
                 computeVerticalScrollRange(),
@@ -4832,7 +5002,7 @@
             removeCallbacks(mPendingCheckForLongPress);
         }
     }
-    
+
     /**
      * @return The number of times this view has been attached to a window
      */
@@ -4855,7 +5025,7 @@
      * {@link #getWindowToken}, except if the window this view in is a panel
      * window (attached to another containing window), then the token of
      * the containing window is returned instead.
-     * 
+     *
      * @return Returns the associated window token, either
      * {@link #getWindowToken()} or the containing window's token.
      */
@@ -4892,6 +5062,10 @@
             info.mTreeObserver.merge(mFloatingTreeObserver);
             mFloatingTreeObserver = null;
         }
+        if ((mPrivateFlags&SCROLL_CONTAINER) != 0) {
+            mAttachInfo.mScrollContainers.add(this);
+            mPrivateFlags |= SCROLL_CONTAINER_ADDED;
+        }
         performCollectViewAttributes(visibility);
         onAttachedToWindow();
         int vis = info.mWindowVisibility;
@@ -4909,16 +5083,20 @@
                 onWindowVisibilityChanged(GONE);
             }
         }
-        
+
         onDetachedFromWindow();
+        if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) {
+            mAttachInfo.mScrollContainers.remove(this);
+            mPrivateFlags &= ~SCROLL_CONTAINER_ADDED;
+        }
         mAttachInfo = null;
     }
 
     /**
      * Store this view hierarchy's frozen state into the given container.
-     * 
+     *
      * @param container The SparseArray in which to save the view's state.
-     * 
+     *
      * @see #restoreHierarchyState
      * @see #dispatchSaveInstanceState
      * @see #onSaveInstanceState
@@ -4931,9 +5109,9 @@
      * Called by {@link #saveHierarchyState} to store the state for this view and its children.
      * May be overridden to modify how freezing happens to a view's children; for example, some
      * views may want to not store state for their children.
-     * 
+     *
      * @param container The SparseArray in which to save the view's state.
-     * 
+     *
      * @see #dispatchRestoreInstanceState
      * @see #saveHierarchyState
      * @see #onSaveInstanceState
@@ -4966,7 +5144,7 @@
      * in a text view (but usually not the text itself since that is stored in a
      * content provider or other persistent storage), the currently selected
      * item in a list view.
-     * 
+     *
      * @return Returns a Parcelable object containing the view's current dynamic
      *         state, or null if there is nothing interesting to save. The
      *         default implementation returns null.
@@ -4982,9 +5160,9 @@
 
     /**
      * Restore this view hierarchy's frozen state from the given container.
-     * 
+     *
      * @param container The SparseArray which holds previously frozen states.
-     * 
+     *
      * @see #saveHierarchyState
      * @see #dispatchRestoreInstanceState
      * @see #onRestoreInstanceState
@@ -4997,9 +5175,9 @@
      * Called by {@link #restoreHierarchyState} to retrieve the state for this view and its
      * children. May be overridden to modify how restoreing happens to a view's children; for
      * example, some views may want to not store state for their children.
-     * 
+     *
      * @param container The SparseArray which holds previously saved state.
-     * 
+     *
      * @see #dispatchSaveInstanceState
      * @see #restoreHierarchyState
      * @see #onRestoreInstanceState
@@ -5024,10 +5202,10 @@
      * Hook allowing a view to re-apply a representation of its internal state that had previously
      * been generated by {@link #onSaveInstanceState}. This function will never be called with a
      * null state.
-     * 
+     *
      * @param state The frozen state that had previously been returned by
      *        {@link #onSaveInstanceState}.
-     * 
+     *
      * @see #onSaveInstanceState
      * @see #restoreHierarchyState
      * @see #dispatchRestoreInstanceState
@@ -5038,7 +5216,7 @@
             throw new IllegalArgumentException("Wrong state class -- expecting View State");
         }
     }
-    
+
     /**
      * <p>Return the time at which the drawing of the view hierarchy started.</p>
      *
@@ -5095,7 +5273,7 @@
      *
      * @see #isDrawingCacheEnabled()
      * @see #getDrawingCache()
-     * @see #buildDrawingCache() 
+     * @see #buildDrawingCache()
      */
     public void setDrawingCacheEnabled(boolean enabled) {
         setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED);
@@ -5126,7 +5304,7 @@
      *
      * @see #setDrawingCacheEnabled(boolean)
      * @see #isDrawingCacheEnabled()
-     * @see #buildDrawingCache() 
+     * @see #buildDrawingCache()
      * @see #destroyDrawingCache()
      */
     public Bitmap getDrawingCache() {
@@ -5148,7 +5326,7 @@
      *
      * @see #setDrawingCacheEnabled(boolean)
      * @see #buildDrawingCache()
-     * @see #getDrawingCache()  
+     * @see #getDrawingCache()
      */
     public void destroyDrawingCache() {
         if (mDrawingCache != null) {
@@ -5156,31 +5334,31 @@
             mDrawingCache = null;
         }
     }
-    
+
     /**
      * Setting a solid background color for the drawing cache's bitmaps will improve
      * perfromance and memory usage. Note, though that this should only be used if this
      * view will always be drawn on top of a solid color.
-     * 
+     *
      * @param color The background color to use for the drawing cache's bitmap
-     * 
+     *
      * @see #setDrawingCacheEnabled(boolean)
      * @see #buildDrawingCache()
-     * @see #getDrawingCache()  
+     * @see #getDrawingCache()
      */
     public void setDrawingCacheBackgroundColor(int color) {
         mDrawingCacheBackgroundColor = color;
     }
-    
+
     /**
      * @see #setDrawingCacheBackgroundColor(int)
-     * 
+     *
      * @return The background color to used for the drawing cache's bitmap
      */
     public int getDrawingCacheBackgroundColor() {
         return mDrawingCacheBackgroundColor;
     }
-    
+
     /**
      * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p>
      *
@@ -5204,7 +5382,7 @@
             final int height = mBottom - mTop;
 
             final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
-            final boolean opaque = drawingCacheBackgroundColor != 0 || 
+            final boolean opaque = drawingCacheBackgroundColor != 0 ||
                 (mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE);
 
             if (width <= 0 || height <= 0 ||
@@ -5242,9 +5420,22 @@
                     quality = Bitmap.Config.RGB_565;
                 }
 
-                mDrawingCache = bitmap = Bitmap.createBitmap(width, height, quality);
+                // Try to cleanup memory
+                if (mDrawingCache != null) {
+                    mDrawingCache.recycle();
+                }
 
-                clear = drawingCacheBackgroundColor != 0; 
+                try {
+                    mDrawingCache = bitmap = Bitmap.createBitmap(width, height, quality);
+                } catch (OutOfMemoryError e) {
+                    // If there is not enough memory to create the bitmap cache, just
+                    // ignore the issue as bitmap caches are not required to draw the
+                    // view hierarchy
+                    mDrawingCache = null;
+                    return;
+                }
+
+                clear = drawingCacheBackgroundColor != 0;
             }
 
             Canvas canvas;
@@ -5293,7 +5484,103 @@
             mPrivateFlags |= DRAWING_CACHE_VALID;
         }
     }
-    
+
+    /**
+     * Indicates whether this View is currently in edit mode. A View is usually
+     * in edit mode when displayed within a developer tool. For instance, if
+     * this View is being drawn by a visual user interface builder, this method
+     * should return true.
+     *
+     * Subclasses should check the return value of this method to provide
+     * different behaviors if their normal behavior might interfere with the
+     * host environment. For instance: the class spawns a thread in its
+     * constructor, the drawing code relies on device-specific features, etc.
+     *
+     * This method is usually checked in the drawing code of custom widgets.
+     *
+     * @return True if this View is in edit mode, false otherwise.
+     */
+    public boolean isInEditMode() {
+        return false;
+    }
+
+    /**
+     * If the View draws content inside its padding and enables fading edges,
+     * it needs to support padding offsets. Padding offsets are added to the
+     * fading edges to extend the length of the fade so that it covers pixels
+     * drawn inside the padding.
+     *
+     * Subclasses of this class should override this method if they need
+     * to draw content inside the padding.
+     *
+     * @return True if padding offset must be applied, false otherwise.
+     *
+     * @see #getLeftPaddingOffset()
+     * @see #getRightPaddingOffset()
+     * @see #getTopPaddingOffset()
+     * @see #getBottomPaddingOffset()
+     *
+     * @since CURRENT
+     */
+    protected boolean isPaddingOffsetRequired() {
+        return false;
+    }
+
+    /**
+     * Amount by which to extend the left fading region. Called only when
+     * {@link #isPaddingOffsetRequired()} returns true.
+     *
+     * @return The left padding offset in pixels.
+     *
+     * @see #isPaddingOffsetRequired()
+     *
+     * @since CURRENT
+     */
+    protected int getLeftPaddingOffset() {
+        return 0;
+    }
+
+    /**
+     * Amount by which to extend the right fading region. Called only when
+     * {@link #isPaddingOffsetRequired()} returns true.
+     *
+     * @return The right padding offset in pixels.
+     *
+     * @see #isPaddingOffsetRequired()
+     *
+     * @since CURRENT
+     */
+    protected int getRightPaddingOffset() {
+        return 0;
+    }
+
+    /**
+     * Amount by which to extend the top fading region. Called only when
+     * {@link #isPaddingOffsetRequired()} returns true.
+     *
+     * @return The top padding offset in pixels.
+     *
+     * @see #isPaddingOffsetRequired()
+     *
+     * @since CURRENT
+     */
+    protected int getTopPaddingOffset() {
+        return 0;
+    }
+
+    /**
+     * Amount by which to extend the bottom fading region. Called only when
+     * {@link #isPaddingOffsetRequired()} returns true.
+     *
+     * @return The bottom padding offset in pixels.
+     *
+     * @see #isPaddingOffsetRequired()
+     *
+     * @since CURRENT
+     */
+    protected int getBottomPaddingOffset() {
+        return 0;
+    }
 
     /**
      * Manually render this view (and all of its children) to the given Canvas.
@@ -5379,13 +5666,24 @@
         float rightFadeStrength = 0.0f;
 
         // Step 2, save the canvas' layers
-        final int paddingLeft = mPaddingLeft;
-        final int paddingTop = mPaddingTop;
+        int paddingLeft = mPaddingLeft;
+        int paddingTop = mPaddingTop;
 
-        final int left = mScrollX + paddingLeft;
-        final int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
-        final int top = mScrollY + paddingTop;
-        final int bottom = top + mBottom - mTop - mPaddingBottom - paddingTop;
+        final boolean offsetRequired = isPaddingOffsetRequired();
+        if (offsetRequired) {
+            paddingLeft += getLeftPaddingOffset();
+            paddingTop += getTopPaddingOffset();
+        }
+
+        int left = mScrollX + paddingLeft;
+        int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
+        int top = mScrollY + paddingTop;
+        int bottom = top + mBottom - mTop - mPaddingBottom - paddingTop;
+
+        if (offsetRequired) {
+            right += getRightPaddingOffset();
+            bottom += getBottomPaddingOffset();
+        }
 
         final ScrollabilityCache scrollabilityCache = mScrollCache;
         int length = scrollabilityCache.fadingEdgeLength;
@@ -5416,23 +5714,23 @@
         }
 
         saveCount = canvas.getSaveCount();
-        
+
         int solidColor = getSolidColor();
         if (solidColor == 0) {
             final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
-    
+
             if (drawTop) {
                 canvas.saveLayer(left, top, right, top + length, null, flags);
             }
-    
+
             if (drawBottom) {
                 canvas.saveLayer(left, bottom - length, right, bottom, null, flags);
             }
-    
+
             if (drawLeft) {
                 canvas.saveLayer(left, top, left + length, bottom, null, flags);
             }
-    
+
             if (drawRight) {
                 canvas.saveLayer(right - length, top, right, bottom, null, flags);
             }
@@ -5495,10 +5793,10 @@
      * and needs to draw fading edges. Returning a non-zero color enables the view system to
      * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha
      * should be set to 0xFF.
-     * 
+     *
      * @see #setVerticalFadingEdgeEnabled
      * @see #setHorizontalFadingEdgeEnabled
-     * 
+     *
      * @return The known solid color background for this view, or 0 if the color may vary
      */
     public int getSolidColor() {
@@ -5550,12 +5848,12 @@
     private static String printPrivateFlags(int privateFlags) {
         String output = "";
         int numFlags = 0;
-        
+
         if ((privateFlags & WANTS_FOCUS) == WANTS_FOCUS) {
             output += "WANTS_FOCUS";
             numFlags++;
         }
-        
+
         if ((privateFlags & FOCUSED) == FOCUSED) {
             if (numFlags > 0) {
                 output += " ";
@@ -5563,7 +5861,7 @@
             output += "FOCUSED";
             numFlags++;
         }
-        
+
         if ((privateFlags & SELECTED) == SELECTED) {
             if (numFlags > 0) {
                 output += " ";
@@ -5571,15 +5869,15 @@
             output += "SELECTED";
             numFlags++;
         }
-        
+
         if ((privateFlags & IS_ROOT_NAMESPACE) == IS_ROOT_NAMESPACE) {
             if (numFlags > 0) {
                 output += " ";
             }
             output += "IS_ROOT_NAMESPACE";
             numFlags++;
-        }   
-        
+        }
+
         if ((privateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
             if (numFlags > 0) {
                 output += " ";
@@ -5587,7 +5885,7 @@
             output += "HAS_BOUNDS";
             numFlags++;
         }
-        
+
         if ((privateFlags & DRAWN) == DRAWN) {
             if (numFlags > 0) {
                 output += " ";
@@ -5611,17 +5909,17 @@
     /**
      * Assign a size and position to a view and all of its
      * descendants
-     * 
-     * <p>This is the second phase of the layout mechanism. 
+     *
+     * <p>This is the second phase of the layout mechanism.
      * (The first is measuring). In this phase, each parent calls
      * layout on all of its children to position them.
      * This is typically done using the child measurements
      * that were stored in the measure pass().
-     * 
+     *
      * Derived classes with children should override
      * onLayout. In that method, they should
      * call layout on each of their their children.
-     * 
+     *
      * @param l Left position, relative to parent
      * @param t Top position, relative to parent
      * @param r Right position, relative to parent
@@ -5639,11 +5937,11 @@
         }
         mPrivateFlags &= ~FORCE_LAYOUT;
     }
-    
+
     /**
      * Called from layout when this view should
      * assign a size and position to each of its children.
-     * 
+     *
      * Derived classes with children should override
      * this method and call layout on each of
      * their their children.
@@ -5655,12 +5953,12 @@
      */
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
     }
-    
+
     /**
      * Assign a size and position to this view.
-     * 
+     *
      * This is called from layout.
-     * 
+     *
      * @param left Left position, relative to parent
      * @param top Top position, relative to parent
      * @param right Right position, relative to parent
@@ -5699,7 +5997,7 @@
 
             int newWidth = right - left;
             int newHeight = bottom - top;
-            
+
             if (newWidth != oldWidth || newHeight != oldHeight) {
                 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
             }
@@ -5725,7 +6023,7 @@
     /**
      * Finalize inflating a view from XML.  This is called as the last phase
      * of inflation, after all child views have been added.
-     * 
+     *
      * <p>Even if the subclass overrides onFinishInflate, they should always be
      * sure to call the super method, so that we get called.
      */
@@ -5734,7 +6032,7 @@
 
     /**
      * Returns the resources associated with this view.
-     * 
+     *
      * @return Resources object.
      */
     public Resources getResources() {
@@ -5787,9 +6085,9 @@
      * Unschedule any events associated with the given Drawable.  This can be
      * used when selecting a new Drawable into a view, so that the previous
      * one is completely unscheduled.
-     * 
+     *
      * @param who The Drawable to unschedule.
-     * 
+     *
      * @see #drawableStateChanged
      */
     public void unscheduleDrawable(Drawable who) {
@@ -5803,17 +6101,17 @@
      * override this function and return true for any Drawable it is
      * displaying.  This allows animations for those drawables to be
      * scheduled.
-     * 
+     *
      * <p>Be sure to call through to the super class when overriding this
      * function.
-     * 
+     *
      * @param who The Drawable to verify.  Return true if it is one you are
      *            displaying, else return the result of calling through to the
      *            super class.
-     * 
+     *
      * @return boolean If true than the Drawable is being displayed in the
      *         view; else false and it is not allowed to animate.
-     * 
+     *
      * @see #unscheduleDrawable
      * @see #drawableStateChanged
      */
@@ -5824,7 +6122,7 @@
     /**
      * This function is called whenever the state of the view changes in such
      * a way that it impacts the state of drawables being shown.
-     * 
+     *
      * <p>Be sure to call through to the superclass when overriding this
      * function.
      *
@@ -5836,12 +6134,12 @@
             d.setState(getDrawableState());
         }
     }
-    
+
     /**
      * Call this to force a view to update its drawable state. This will cause
      * drawableStateChanged to be called on this view. Views that are interested
      * in the new state should call getDrawableState.
-     * 
+     *
      * @see #drawableStateChanged
      * @see #getDrawableState
      */
@@ -5858,9 +6156,9 @@
     /**
      * Return an array of resource IDs of the drawable states representing the
      * current state of the view.
-     * 
+     *
      * @return The current drawable state
-     * 
+     *
      * @see Drawable#setState
      * @see #drawableStateChanged
      * @see #onCreateDrawableState
@@ -5880,14 +6178,14 @@
      * this view. This is called by the view
      * system when the cached Drawable state is determined to be invalid.  To
      * retrieve the current state, you should use {@link #getDrawableState}.
-     * 
+     *
      * @param extraSpace if non-zero, this is the number of extra entries you
      * would like in the returned array in which you can place your own
      * states.
-     * 
+     *
      * @return Returns an array holding the current {@link Drawable} state of
      * the view.
-     * 
+     *
      * @see #mergeDrawableStates
      */
     protected int[] onCreateDrawableState(int extraSpace) {
@@ -5897,22 +6195,20 @@
         }
 
         int[] drawableState;
-        
+
         int privateFlags = mPrivateFlags;
 
-        boolean isPressed = (privateFlags & PRESSED) != 0;
-        int viewStateIndex = (isPressed ? 1 : 0);
+        int viewStateIndex = (((privateFlags & PRESSED) != 0) ? 1 : 0);
 
-        boolean isEnabled = (mViewFlags & ENABLED_MASK) == ENABLED;
-        viewStateIndex = (viewStateIndex << 1) + (isEnabled ? 1 : 0);
+        viewStateIndex = (viewStateIndex << 1)
+                + (((mViewFlags & ENABLED_MASK) == ENABLED) ? 1 : 0);
 
-        boolean isFocused = isFocused();
-        viewStateIndex = (viewStateIndex << 1) + (isFocused ? 1 : 0);
-        
-        boolean isSelected = (privateFlags & SELECTED) != 0;
-        viewStateIndex = (viewStateIndex << 1) + (isSelected ? 1 : 0);
-        
-        boolean hasWindowFocus = hasWindowFocus();
+        viewStateIndex = (viewStateIndex << 1) + (isFocused() ? 1 : 0);
+
+        viewStateIndex = (viewStateIndex << 1)
+                + (((privateFlags & SELECTED) != 0) ? 1 : 0);
+
+        final boolean hasWindowFocus = hasWindowFocus();
         viewStateIndex = (viewStateIndex << 1) + (hasWindowFocus ? 1 : 0);
 
         drawableState = VIEW_STATE_SETS[viewStateIndex];
@@ -5920,9 +6216,12 @@
         //noinspection ConstantIfStatement
         if (false) {
             Log.i("View", "drawableStateIndex=" + viewStateIndex);
-            Log.i("View", toString() + " pressed=" + isPressed
-                    + " en=" + isEnabled + " fo=" + isFocused
-                    + " sl=" + isSelected + " wf=" + hasWindowFocus
+            Log.i("View", toString()
+                    + " pressed=" + ((privateFlags & PRESSED) != 0)
+                    + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED)
+                    + " fo=" + hasFocus()
+                    + " sl=" + ((privateFlags & SELECTED) != 0)
+                    + " wf=" + hasWindowFocus
                     + ": " + Arrays.toString(drawableState));
         }
 
@@ -5940,22 +6239,22 @@
 
         return fullState;
     }
-    
+
     /**
      * Merge your own state values in <var>additionalState</var> into the base
      * state values <var>baseState</var> that were returned by
      * {@link #onCreateDrawableState}.
-     * 
+     *
      * @param baseState The base state values returned by
      * {@link #onCreateDrawableState}, which will be modified to also hold your
      * own additional state values.
-     * 
+     *
      * @param additionalState The additional state values you would like
      * added to <var>baseState</var>; this array is not modified.
-     * 
+     *
      * @return As a convenience, the <var>baseState</var> array you originally
      * passed into the function is returned.
-     * 
+     *
      * @see #onCreateDrawableState
      */
     protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) {
@@ -5967,7 +6266,7 @@
         System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length);
         return baseState;
     }
-    
+
     /**
      * Sets the background color for this view.
      * @param color the color of the background
@@ -5975,7 +6274,7 @@
     public void setBackgroundColor(int color) {
         setBackgroundDrawable(new ColorDrawable(color));
     }
-    
+
     /**
      * Set the background to a given resource. The resource should refer to
      * a Drawable object.
@@ -6002,13 +6301,13 @@
      * padding. However, when a background is removed, this View's padding isn't
      * touched. If setting the padding is desired, please use
      * {@link #setPadding(int, int, int, int)}.
-     * 
+     *
      * @param d The Drawable to use as the background, or null to remove the
      *        background
      */
     public void setBackgroundDrawable(Drawable d) {
         boolean requestLayout = false;
-        
+
         mBackgroundResource = 0;
 
         /*
@@ -6021,11 +6320,15 @@
         }
 
         if (d != null) {
-            final Rect padding = mTempRect;
+            Rect padding = sThreadLocal.get();
+            if (padding == null) {
+                padding = new Rect();
+                sThreadLocal.set(padding);
+            }
             if (d.getPadding(padding)) {
                 setPadding(padding.left, padding.top, padding.right, padding.bottom);
             }
-            
+
             // Compare the minimum sizes of the old Drawable and the new.  If there isn't an old or
             // if it has a different minimum size, we should layout again
             if (mBGDrawable == null || mBGDrawable.getMinimumHeight() != d.getMinimumHeight() ||
@@ -6048,7 +6351,7 @@
         } else {
             /* Remove the background */
             mBGDrawable = null;
-            
+
             if ((mPrivateFlags & ONLY_DRAWS_BACKGROUND) != 0) {
                 /*
                  * This view ONLY drew the background before and we're removing
@@ -6065,7 +6368,7 @@
              * padding. This is noted in the Javadocs. Hence, we don't need to
              * requestLayout(), the invalidate() below is sufficient.
              */
-            
+
             // The old background's minimum size could have affected this
             // View's layout, so let's requestLayout
             requestLayout = true;
@@ -6091,7 +6394,7 @@
         // TODO: Deal with RTL languages
         return 0;
     }
-    
+
     /*
      * Returns the pixels occupied by the vertical scrollbar, if not overlaid
      */
@@ -6114,7 +6417,7 @@
     }
 
     /**
-     * Sets the padding. The view may add on the space required to display 
+     * Sets the padding. The view may add on the space required to display
      * the scrollbars, depending on the style and visibility of the scrollbars.
      * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop},
      * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different
@@ -6132,10 +6435,10 @@
      */
     public void setPadding(int left, int top, int right, int bottom) {
         boolean changed = false;
-        
+
         mUserPaddingRight = right;
         mUserPaddingBottom = bottom;
-        
+
         if (mPaddingLeft != left + getScrollBarPaddingLeft()) {
             changed = true;
             mPaddingLeft = left;
@@ -6216,17 +6519,17 @@
             dispatchSetSelected(selected);
         }
     }
-    
+
     /**
      * Dispatch setSelected to all of this View's children.
-     * 
+     *
      * @see #setSelected(boolean)
-     * 
+     *
      * @param selected The new selected state
      */
     protected void dispatchSetSelected(boolean selected) {
     }
-    
+
     /**
      * Indicates the selection state of this view.
      *
@@ -6265,6 +6568,13 @@
      * @return the topmost view containing this view
      */
     public View getRootView() {
+        if (mAttachInfo != null) {
+            final View v = mAttachInfo.mRootView;
+            if (v != null) {
+                return v;
+            }
+        }
+        
         View parent = this;
 
         while (parent.mParent != null && parent.mParent instanceof View) {
@@ -6305,22 +6615,18 @@
         location[0] = mLeft;
         location[1] = mTop;
 
-        if (!(mParent instanceof View)) {
-            return;
+        ViewParent viewParent = mParent;
+        while (viewParent instanceof View) {
+            final View view = (View)viewParent;
+            location[0] += view.mLeft - view.mScrollX;
+            location[1] += view.mTop - view.mScrollY;
+            viewParent = view.mParent;
         }
-
-        View parent = (View) mParent;
-
-        while (parent != null) {
-            location[0] += parent.mLeft - parent.mScrollX;
-            location[1] += parent.mTop - parent.mScrollY;
-
-            final ViewParent viewParent = parent.mParent;
-            if (viewParent != null && viewParent instanceof View) {
-                parent = (View) viewParent;
-            } else {
-                parent = null;
-            }
+        
+        if (viewParent instanceof ViewRoot) {
+            // *cough*
+            final ViewRoot vr = (ViewRoot)viewParent;
+            location[1] -= vr.mCurScrollY;
         }
     }
 
@@ -6380,13 +6686,13 @@
      * Sets the identifier for this view. The identifier does not have to be
      * unique in this view's hierarchy. The identifier should be a positive
      * number.
-     * 
+     *
      * @see #NO_ID
      * @see #getId
      * @see #findViewById
      *
      * @param id a number used to identify the view
-     * 
+     *
      * @attr ref android.R.styleable#View_id
      */
     public void setId(int id) {
@@ -6421,11 +6727,12 @@
      *
      * @return a positive integer used to identify the view or {@link #NO_ID}
      *         if the view has no ID
-     * 
+     *
      * @see #setId
      * @see #findViewById
      * @attr ref android.R.styleable#View_id
      */
+    @ViewDebug.CapturedViewProperty
     public int getId() {
         return mID;
     }
@@ -6433,7 +6740,7 @@
     /**
      * Returns this view's tag.
      *
-     * @return the Object stored in this view as a tag 
+     * @return the Object stored in this view as a tag
      */
     @ViewDebug.ExportedProperty
     public Object getTag() {
@@ -6473,7 +6780,7 @@
      */
     protected void debug(int depth) {
         String output = debugIndent(depth - 1);
-        
+
         output += "+ " + this;
         int id = getId();
         if (id != -1) {
@@ -6484,18 +6791,18 @@
             output += " (tag=" + tag + ")";
         }
         Log.d(VIEW_LOG_TAG, output);
-        
+
         if ((mPrivateFlags & FOCUSED) != 0) {
-            output = debugIndent(depth) + " FOCUSED"; 
+            output = debugIndent(depth) + " FOCUSED";
             Log.d(VIEW_LOG_TAG, output);
         }
-        
+
         output = debugIndent(depth);
         output += "frame={" + mLeft + ", " + mTop + ", " + mRight
                 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY
                 + "} ";
         Log.d(VIEW_LOG_TAG, output);
-        
+
         if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0
                 || mPaddingBottom != 0) {
             output = debugIndent(depth);
@@ -6503,12 +6810,12 @@
                     + ", " + mPaddingRight + ", " + mPaddingBottom + "}";
             Log.d(VIEW_LOG_TAG, output);
         }
-        
+
         output = debugIndent(depth);
         output += "mMeasureWidth=" + mMeasuredWidth +
                 " mMeasureHeight=" + mMeasuredHeight;
         Log.d(VIEW_LOG_TAG, output);
-        
+
         output = debugIndent(depth);
         if (mLayoutParams == null) {
             output += "BAD! no layout params";
@@ -6516,7 +6823,7 @@
             output = mLayoutParams.debug(output);
         }
         Log.d(VIEW_LOG_TAG, output);
-        
+
         output = debugIndent(depth);
         output += "flags={";
         output += View.printFlags(mViewFlags);
@@ -6583,8 +6890,8 @@
      */
     public void forceLayout() {
         mPrivateFlags |= FORCE_LAYOUT;
-    } 
-    
+    }
+
     /**
      * <p>
      * This is called to find out how big a view should be. The parent
@@ -6596,14 +6903,14 @@
      * {@link #onMeasure(int, int)}, called by this method. Therefore, only
      * {@link #onMeasure(int, int)} can and must be overriden by subclasses.
      * </p>
-     * 
-     * 
+     *
+     *
      * @param widthMeasureSpec Horizontal space requirements as imposed by the
      *        parent
      * @param heightMeasureSpec Vertical space requirements as imposed by the
      *        parent
      *
-     * @see #onMeasure(int, int) 
+     * @see #onMeasure(int, int)
      */
     public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
         if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||
@@ -6642,7 +6949,7 @@
      * should be overriden by subclasses to provide accurate and efficient
      * measurement of their contents.
      * </p>
-     * 
+     *
      * <p>
      * <strong>CONTRACT:</strong> When overriding this method, you
      * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the
@@ -6651,35 +6958,35 @@
      * {@link #measure(int, int)}. Calling the superclass'
      * {@link #onMeasure(int, int)} is a valid use.
      * </p>
-     * 
+     *
      * <p>
      * The base class implementation of measure defaults to the background size,
      * unless a larger size is allowed by the MeasureSpec. Subclasses should
      * override {@link #onMeasure(int, int)} to provide better measurements of
      * their content.
      * </p>
-     * 
+     *
      * <p>
      * If this method is overridden, it is the subclass's responsibility to make
      * sure the measured height and width are at least the view's minimum height
      * and width ({@link #getSuggestedMinimumHeight()} and
      * {@link #getSuggestedMinimumWidth()}).
      * </p>
-     * 
+     *
      * @param widthMeasureSpec horizontal space requirements as imposed by the parent.
      *                         The requirements are encoded with
      *                         {@link android.view.View.MeasureSpec}.
      * @param heightMeasureSpec vertical space requirements as imposed by the parent.
      *                         The requirements are encoded with
      *                         {@link android.view.View.MeasureSpec}.
-     * 
+     *
      * @see #getMeasuredWidth()
      * @see #getMeasuredHeight()
      * @see #setMeasuredDimension(int, int)
      * @see #getSuggestedMinimumHeight()
      * @see #getSuggestedMinimumWidth()
      * @see android.view.View.MeasureSpec#getMode(int)
-     * @see android.view.View.MeasureSpec#getSize(int) 
+     * @see android.view.View.MeasureSpec#getSize(int)
      */
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
@@ -6704,7 +7011,7 @@
     /**
      * Utility to reconcile a desired size with constraints imposed by a MeasureSpec.
      * Will take the desired size, unless a different size is imposed by the constraints.
-     *  
+     *
      * @param size How big the view wants to be
      * @param measureSpec Constraints imposed by the parent
      * @return The size this view should be.
@@ -6726,12 +7033,12 @@
         }
         return result;
     }
-    
+
     /**
      * Utility to return a default size. Uses the supplied size if the
      * MeasureSpec imposed no contraints. Will get larger if allowed
      * by the MeasureSpec.
-     * 
+     *
      * @param size Default size for this view
      * @param measureSpec Constraints imposed by the parent
      * @return The size this view should be.
@@ -6740,7 +7047,7 @@
         int result = size;
         int specMode = MeasureSpec.getMode(measureSpec);
         int specSize =  MeasureSpec.getSize(measureSpec);
-        
+
         switch (specMode) {
         case MeasureSpec.UNSPECIFIED:
             result = size;
@@ -6761,19 +7068,19 @@
      * <p>
      * When being used in {@link #onMeasure(int, int)}, the caller should still
      * ensure the returned height is within the requirements of the parent.
-     * 
+     *
      * @return The suggested minimum height of the view.
      */
     protected int getSuggestedMinimumHeight() {
         int suggestedMinHeight = mMinHeight;
-        
+
         if (mBGDrawable != null) {
             final int bgMinHeight = mBGDrawable.getMinimumHeight();
             if (suggestedMinHeight < bgMinHeight) {
                 suggestedMinHeight = bgMinHeight;
             }
         }
-        
+
         return suggestedMinHeight;
     }
 
@@ -6785,19 +7092,19 @@
      * <p>
      * When being used in {@link #onMeasure(int, int)}, the caller should still
      * ensure the returned width is within the requirements of the parent.
-     * 
+     *
      * @return The suggested minimum width of the view.
      */
     protected int getSuggestedMinimumWidth() {
         int suggestedMinWidth = mMinWidth;
-        
+
         if (mBGDrawable != null) {
             final int bgMinWidth = mBGDrawable.getMinimumWidth();
             if (suggestedMinWidth < bgMinWidth) {
                 suggestedMinWidth = bgMinWidth;
             }
         }
-        
+
         return suggestedMinWidth;
     }
 
@@ -6805,7 +7112,7 @@
      * Sets the minimum height of the view. It is not guaranteed the view will
      * be able to achieve this minimum height (for example, if its parent layout
      * constrains it with less available height).
-     * 
+     *
      * @param minHeight The minimum height the view will try to be.
      */
     public void setMinimumHeight(int minHeight) {
@@ -6816,7 +7123,7 @@
      * Sets the minimum width of the view. It is not guaranteed the view will
      * be able to achieve this minimum width (for example, if its parent layout
      * constrains it with less available width).
-     * 
+     *
      * @param minWidth The minimum width the view will try to be.
      */
     public void setMinimumWidth(int minWidth) {
@@ -6832,10 +7139,10 @@
     public Animation getAnimation() {
         return mCurrentAnimation;
     }
-    
+
     /**
      * Start the specified animation now.
-     * 
+     *
      * @param animation the animation to start now
      */
     public void startAnimation(Animation animation) {
@@ -6843,23 +7150,23 @@
         setAnimation(animation);
         invalidate();
     }
-    
+
     /**
      * Cancels any animations for this view.
      */
     public void clearAnimation() {
         mCurrentAnimation = null;
     }
-    
+
     /**
      * Sets the next animation to play for this view.
      * If you want the animation to play immediately, use
      * startAnimation. This method provides allows fine-grained
      * control over the start time and invalidation, but you
      * must make sure that 1) the animation has a start time set, and
-     * 2) the view will be invalidated when the animation is supposed to 
+     * 2) the view will be invalidated when the animation is supposed to
      * start.
-     * 
+     *
      * @param animation The next animation, or null.
      */
     public void setAnimation(Animation animation) {
@@ -6914,25 +7221,26 @@
      * SurfaceView is always considered transparent, but its children are not,
      * therefore all View objects remove themselves from the global transparent
      * region (passed as a parameter to this function).
-     * 
+     *
      * @param region The transparent region for this ViewRoot (window).
-     * 
+     *
      * @return Returns true if the effective visibility of the view at this
      * point is opaque, regardless of the transparent region; returns false
      * if it is possible for underlying windows to be seen behind the view.
-     * 
+     *
      * {@hide}
      */
     public boolean gatherTransparentRegion(Region region) {
-        if (region != null) {
+        final AttachInfo attachInfo = mAttachInfo;
+        if (region != null && attachInfo != null) {
             final int pflags = mPrivateFlags;
             if ((pflags & SKIP_DRAW) == 0) {
                 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to
                 // remove it from the transparent region.
-                getLocationInWindow(mLocation);
-                region.op(mLocation[0], mLocation[1],
-                        mLocation[0] + mRight - mLeft, mLocation[1] + mBottom - mTop,
-                        Region.Op.DIFFERENCE);
+                final int[] location = attachInfo.mTransparentLocation;
+                getLocationInWindow(location);
+                region.op(location[0], location[1], location[0] + mRight - mLeft,
+                        location[1] + mBottom - mTop, Region.Op.DIFFERENCE);
             } else if ((pflags & ONLY_DRAWS_BACKGROUND) != 0 && mBGDrawable != null) {
                 // The ONLY_DRAWS_BACKGROUND flag IS set and the background drawable
                 // exists, so we remove the background drawable's non-transparent
@@ -6952,7 +7260,7 @@
      *
      * The sound effect will only be played if sound effects are enabled by the user, and
      * {@link #isSoundEffectsEnabled()} is true.
-     * 
+     *
      * @param soundConstant One of the constants defined in {@link SoundEffectConstants}
      */
     protected void playSoundEffect(int soundConstant) {
@@ -6967,7 +7275,7 @@
      * update a Region being computed for {@link #gatherTransparentRegion} so
      * that any non-transparent parts of the Drawable are removed from the
      * given transparent region.
-     * 
+     *
      * @param dr The Drawable whose transparency is to be applied to the region.
      * @param region A Region holding the current transparency information,
      * where any parts of the region that are set are considered to be
@@ -6982,7 +7290,8 @@
         }
         final Region r = dr.getTransparentRegion();
         final Rect db = dr.getBounds();
-        if (r != null) {
+        final AttachInfo attachInfo = mAttachInfo;
+        if (r != null && attachInfo != null) {
             final int w = getRight()-getLeft();
             final int h = getBottom()-getTop();
             if (db.left > 0) {
@@ -7001,8 +7310,9 @@
                 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h);
                 r.op(0, db.bottom, w, h, Region.Op.UNION);
             }
-            getLocationInWindow(mLocation);
-            r.translate(mLocation[0], mLocation[1]);
+            final int[] location = attachInfo.mTransparentLocation;
+            getLocationInWindow(location);
+            r.translate(location[0], location[1]);
             region.op(r, Region.Op.INTERSECT);
         } else {
             region.op(db, Region.Op.DIFFERENCE);
@@ -7177,10 +7487,10 @@
     }
 
     class CheckForLongPress implements Runnable {
-        
+
         private int mOriginalWindowAttachCount;
-        
-        public void run() {  
+
+        public void run() {
             if (isPressed() && (mParent != null) && hasWindowFocus()
                     && mOriginalWindowAttachCount == mWindowAttachCount) {
                 if (performLongClick()) {
@@ -7188,7 +7498,7 @@
                 }
             }
         }
-        
+
         public void rememberWindowAttachCount() {
             mOriginalWindowAttachCount = mWindowAttachCount;
         }
@@ -7279,7 +7589,7 @@
         /**
          * Called when the context menu for this view is being built. It is not
          * safe to hold onto the menu after this method returns.
-         * 
+         *
          * @param menu The context menu that is being built
          * @param v The view for which the context menu is being built
          * @param menuInfo Extra information about the item for which the
@@ -7297,12 +7607,12 @@
 
     /**
      * Base class for derived classes that want to save and restore their own
-     * state in {@link #onSaveInstanceState}.
+     * state in {@link android.view.View#onSaveInstanceState()}.
      */
     public static class BaseSavedState extends AbsSavedState {
         /**
          * Constructor used when reading from a parcel. Reads the state of the superclass.
-         * 
+         *
          * @param source
          */
         public BaseSavedState(Parcel source) {
@@ -7311,7 +7621,7 @@
 
         /**
          * Constructor called by derived classes when creating their SavedState objects
-         * 
+         *
          * @param superState The state of the superclass of this view
          */
         public BaseSavedState(Parcelable superState) {
@@ -7340,11 +7650,21 @@
             void playSoundEffect(int effectId);
         }
 
-        IBinder mWindowToken;
+        final IWindowSession mSession;
+
+        final IWindow mWindow;
+
+        final IBinder mWindowToken;
+
+        final SoundEffectPlayer mSoundEffectPlayer;
+
+        /**
+         * The top view of the hierarchy.
+         */
+        View mRootView;
+        
         IBinder mPanelParentWindowToken;
         Surface mSurface;
-        IWindowSession mSession;
-        SoundEffectPlayer mSoundEffectPlayer;
 
         /**
          * Left position of this view's window
@@ -7357,6 +7677,37 @@
         int mWindowTop;
 
         /**
+         * For windows that are full-screen but using insets to layout inside
+         * of the screen decorations, these are the current insets for the
+         * content of the window.
+         */
+        final Rect mContentInsets = new Rect();
+
+        /**
+         * For windows that are full-screen but using insets to layout inside
+         * of the screen decorations, these are the current insets for the
+         * actual visible parts of the window.
+         */
+        final Rect mVisibleInsets = new Rect();
+
+        /**
+         * The internal insets given by this window.  This value is
+         * supplied by the client (through
+         * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will
+         * be given to the window manager when changed to be used in laying
+         * out windows behind it.
+         */
+        final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets
+                = new ViewTreeObserver.InternalInsetsInfo();
+
+        /**
+         * All views in the window's hierarchy that serve as scroll containers,
+         * used to determine if the window can be resized or must be panned
+         * to adjust for a soft input area.
+         */
+        final ArrayList<View> mScrollContainers = new ArrayList<View>();
+
+        /**
          * Indicates whether the view's window currently has the focus.
          */
         boolean mHasWindowFocus;
@@ -7365,7 +7716,7 @@
          * The current visibility of the window.
          */
         int mWindowVisibility;
-        
+
         /**
          * Indicates the time at which drawing started to occur.
          */
@@ -7375,7 +7726,7 @@
          * Indicates whether the view's window is currently in touch mode.
          */
         boolean mInTouchMode;
-        
+
         /**
          * Indicates that ViewRoot should trigger a global layout change
          * the next time it performs a traversal
@@ -7387,12 +7738,29 @@
          * recomputed.
          */
         boolean mAttributesChanged;
-        
+
         /**
          * Set during a traveral if any views want to keep the screen on.
          */
         boolean mKeepScreenOn;
-        
+
+        /**
+         * Set if the visibility of any views has changed.
+         */
+        boolean mViewVisibilityChanged;
+
+        /**
+         * Global to the view hierarchy used as a temporary for dealing with
+         * x/y points in the transparent region computations.
+         */
+        final int[] mTransparentLocation = new int[2];
+
+        /**
+         * Global to the view hierarchy used as a temporary for dealing with
+         * x/y points in the ViewGroup.invalidateChild implementation.
+         */
+        final int[] mInvalidateChildLocation = new int[2];
+
         /**
          * The view tree observer used to dispatch global events like
          * layout, pre-draw, touch mode change, etc.
@@ -7422,17 +7790,23 @@
          */
         static final int INVALIDATE_RECT_MSG = 0x2;
 
-        AttachInfo(Handler handler) {
-            this(handler, null);
-        }
-
+        /**
+         * Temporary for use in computing invalidate rectangles while
+         * calling up the hierarchy.
+         */
+        final Rect mTmpInvalRect = new Rect();
+        
         /**
          * Creates a new set of attachment information with the specified
          * events handler and thread.
          *
          * @param handler the events handler the view must use
          */
-        AttachInfo(Handler handler, SoundEffectPlayer effectPlayer) {
+        AttachInfo(IWindowSession session, IWindow window,
+                Handler handler, SoundEffectPlayer effectPlayer) {
+            mSession = session;
+            mWindow = window;
+            mWindowToken = window.asBinder();
             mHandler = handler;
             mSoundEffectPlayer = effectPlayer;
         }
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 38be806..b7110ce 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -46,6 +46,13 @@
     private static final int LONG_PRESS_TIMEOUT = 500;
     
     /**
+     * Defines the duration in milliseconds a user needs to hold down the
+     * appropriate button to bring up the global actions dialog (power off,
+     * lock screen, etc).
+     */
+    private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 500;
+    
+    /**
      * Defines the duration in milliseconds we will wait to see if a touch event 
      * is a top or a scroll. If the user does not move within this interval, it is
      * considered to be a tap. 
@@ -66,14 +73,6 @@
     private static final int ZOOM_CONTROLS_TIMEOUT = 3000;
 
     /**
-     * Defines the duration in milliseconds a user needs to hold down the
-     * appropriate button to bring up the global actions dialog (power off,
-     * lock screen, etc).
-     */
-    private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 1000;
-    
-    
-    /**
      * Inset in pixels to look for touchable content when the user touches the edge of the screen
      */
     private static final int EDGE_SLOP = 12;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 1bf46b4..883c7bd 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -19,6 +19,7 @@
 import android.util.Log;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.os.Environment;
 
 import java.io.File;
 import java.io.BufferedWriter;
@@ -60,7 +61,19 @@
      * check that this value is set to true as not to affect performance.
      */
     public static final boolean TRACE_RECYCLER = false;
-
+    
+    /**
+     * The system property of dynamic switch for capturing view information
+     * when it is set, we dump interested fields and methods for the view on focus
+     */    
+    static final String SYSTEM_PROPERTY_CAPTURE_VIEW = "debug.captureview";
+        
+    /**
+     * The system property of dynamic switch for capturing event information
+     * when it is set, we log key events, touch/motion and trackball events
+     */    
+    static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent";
+    
     /**
      * This annotation can be used to mark fields and methods to be dumped by
      * the view server. Only non-void methods with no arguments can be annotated
@@ -143,6 +156,29 @@
          */
         String to();
     }
+    
+    /**
+     * This annotation can be used to mark fields and methods to be dumped when
+     * the view is captured. Methods with this annotation must have no arguments
+     * and must return <some type of data>.
+     * 
+     * @hide pending API Council approval
+     */
+    @Target({ ElementType.FIELD, ElementType.METHOD })
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface CapturedViewProperty {
+        /**
+         * When retrieveReturn is true, we need to retrieve second level methods 
+         * e.g., we need myView.getFirstLevelMethod().getSecondLevelMethod()
+         * we will set retrieveReturn = true on the annotation of 
+         * myView.getFirstLevelMethod()
+         * @return true if we need the second level methods 
+         */
+        boolean retrieveReturn() default false;        
+    }
+        
+    private static HashMap<Class<?>, Method[]> mCapturedViewMethodsForClasses = null;
+    private static HashMap<Class<?>, Field[]> mCapturedViewFieldsForClasses = null;
 
     // Maximum delay in ms after which we stop trying to capture a View's drawing
     private static final int CAPTURE_TIMEOUT = 4000;
@@ -154,7 +190,7 @@
 
     private static HashMap<Class<?>, Field[]> sFieldsForClasses;
     private static HashMap<Class<?>, Method[]> sMethodsForClasses;
-
+        
     /**
      * Defines the type of hierarhcy trace to output to the hierarchy traces file.
      */
@@ -250,8 +286,8 @@
 
     /**
      * Starts tracing the view recycler of the specified view. The trace is identified by a prefix,
-     * used to build the traces files names: <code>/tmp/view-recycler/PREFIX.traces</code> and
-     * <code>/tmp/view-recycler/PREFIX.recycler</code>.
+     * used to build the traces files names: <code>/EXTERNAL/view-recycler/PREFIX.traces</code> and
+     * <code>/EXTERNAL/view-recycler/PREFIX.recycler</code>.
      *
      * Only one view recycler can be traced at the same time. After calling this method, any
      * other invocation will result in a <code>IllegalStateException</code> unless
@@ -287,10 +323,10 @@
     /**
      * Stops the current view recycer tracing.
      *
-     * Calling this method creates the file <code>/tmp/view-recycler/PREFIX.traces</code>
+     * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.traces</code>
      * containing all the traces (or method calls) relative to the specified view's recycler.
      *
-     * Calling this method creates the file <code>/tmp/view-recycler/PREFIX.recycler</code>
+     * Calling this method creates the file <code>/EXTERNAL/view-recycler/PREFIX.recycler</code>
      * containing all of the views used by the recycler of the view supplied to
      * {@link #startRecyclerTracing(String, View)}.
      *
@@ -310,7 +346,7 @@
                 " stopRecyclerTracing()!");
         }
 
-        File recyclerDump = new File("/tmp/view-recycler/");
+        File recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/");
         recyclerDump.mkdirs();
 
         recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".recycler");
@@ -329,7 +365,7 @@
             return;
         }
 
-        recyclerDump = new File("/tmp/view-recycler/");
+        recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/");
         recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces");
         try {
             final FileOutputStream file = new FileOutputStream(recyclerDump);
@@ -384,14 +420,14 @@
 
     /**
      * Starts tracing the view hierarchy of the specified view. The trace is identified by a prefix,
-     * used to build the traces files names: <code>/tmp/view-hierarchy/PREFIX.traces</code> and
-     * <code>/tmp/view-hierarchy/PREFIX.tree</code>.
+     * used to build the traces files names: <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code> and
+     * <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code>.
      *
      * Only one view hierarchy can be traced at the same time. After calling this method, any
      * other invocation will result in a <code>IllegalStateException</code> unless
      * {@link #stopHierarchyTracing()} is invoked before.
      *
-     * Calling this method creates the file <code>/tmp/view-hierarchy/PREFIX.traces</code>
+     * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code>
      * containing all the traces (or method calls) relative to the specified view's hierarchy.
      *
      * This method will return immediately if TRACE_HIERARCHY is false.
@@ -413,7 +449,7 @@
                 " a new trace!");
         }
 
-        File hierarchyDump = new File("/tmp/view-hierarchy/");
+        File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/");
         hierarchyDump.mkdirs();
 
         hierarchyDump = new File(hierarchyDump, prefix + ".traces");
@@ -431,10 +467,11 @@
 
     /**
      * Stops the current view hierarchy tracing. This method closes the file
-     * <code>/tmp/view-hierarchy/PREFIX.traces</code>. 
+     * <code>/EXTERNAL/view-hierarchy/PREFIX.traces</code>.
      *
-     * Calling this method creates the file <code>/tmp/view-hierarchy/PREFIX.tree</code> containing
-     * the view hierarchy of the view supplied to {@link #startHierarchyTracing(String, View)}.
+     * Calling this method creates the file <code>/EXTERNAL/view-hierarchy/PREFIX.tree</code>
+     * containing the view hierarchy of the view supplied to
+     * {@link #startHierarchyTracing(String, View)}.
      *
      * This method will return immediately if TRACE_HIERARCHY is false.
      *
@@ -459,7 +496,7 @@
         }
         sHierarchyTraces = null;
 
-        File hierarchyDump = new File("/tmp/view-hierarchy/");
+        File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/");
         hierarchyDump.mkdirs();
         hierarchyDump = new File(hierarchyDump, sHierarchyTracePrefix + ".tree");
 
@@ -484,7 +521,7 @@
 
         sHierarhcyRoot = null;
     }
-
+    
     static void dispatchCommand(View view, String command, String parameters,
             OutputStream clientStream) throws IOException {
 
@@ -714,10 +751,10 @@
 
         final ArrayList<Method> foundMethods = new ArrayList<Method>();
         methods = klass.getDeclaredMethods();
-
+        
         int count = methods.length;
         for (int i = 0; i < count; i++) {
-            final Method method = methods[i];
+            final Method method = methods[i];            
             if (method.getParameterTypes().length == 0 &&
                         method.isAnnotationPresent(ExportedProperty.class) &&
                         method.getReturnType() != Void.class) {
@@ -746,7 +783,7 @@
             klass = klass.getSuperclass();
         } while (klass != Object.class);
     }
-
+    
     private static void exportMethods(Object view, BufferedWriter out, Class<?> klass,
             String prefix) throws IOException {
 
@@ -767,8 +804,12 @@
                         final Resources resources = ((View) view).getContext().getResources();
                         final int id = (Integer) methodValue;
                         if (id >= 0) {
-                            methodValue = resources.getResourceTypeName(id) + '/' +
-                                    resources.getResourceEntryName(id);
+                            try {
+                                methodValue = resources.getResourceTypeName(id) + '/' +
+                                        resources.getResourceEntryName(id);
+                            } catch (Resources.NotFoundException e) {
+                                methodValue = "UNKNOWN";
+                            }
                         } else {
                             methodValue = "NO_ID";
                         }
@@ -839,8 +880,12 @@
                         final Resources resources = ((View) view).getContext().getResources();
                         final int id = field.getInt(view);
                         if (id >= 0) {
-                            fieldValue = resources.getResourceTypeName(id) + '/' +
-                                    resources.getResourceEntryName(id);
+                            try {
+                                fieldValue = resources.getResourceTypeName(id) + '/' +
+                                        resources.getResourceEntryName(id);
+                            } catch (Resources.NotFoundException e) {
+                                fieldValue = "UNKNOWN";
+                            }
                         } else {
                             fieldValue = "NO_ID";
                         }
@@ -924,4 +969,160 @@
         }
         return true;
     }
+
+    private static Field[] capturedViewGetPropertyFields(Class<?> klass) {
+        if (mCapturedViewFieldsForClasses == null) {
+            mCapturedViewFieldsForClasses = new HashMap<Class<?>, Field[]>();
+        }
+        final HashMap<Class<?>, Field[]> map = mCapturedViewFieldsForClasses;
+
+        Field[] fields = map.get(klass);
+        if (fields != null) {
+            return fields;
+        }
+
+        final ArrayList<Field> foundFields = new ArrayList<Field>();
+        fields = klass.getFields();
+
+        int count = fields.length;
+        for (int i = 0; i < count; i++) {
+            final Field field = fields[i];
+            if (field.isAnnotationPresent(CapturedViewProperty.class)) {
+                field.setAccessible(true);
+                foundFields.add(field);
+            }
+        }
+
+        fields = foundFields.toArray(new Field[foundFields.size()]);
+        map.put(klass, fields);
+
+        return fields;
+    }
+
+    private static Method[] capturedViewGetPropertyMethods(Class<?> klass) {
+        if (mCapturedViewMethodsForClasses == null) {
+            mCapturedViewMethodsForClasses = new HashMap<Class<?>, Method[]>();
+        }
+        final HashMap<Class<?>, Method[]> map = mCapturedViewMethodsForClasses;
+
+        Method[] methods = map.get(klass);
+        if (methods != null) {
+            return methods;
+        }
+
+        final ArrayList<Method> foundMethods = new ArrayList<Method>();
+        methods = klass.getMethods();
+        
+        int count = methods.length;
+        for (int i = 0; i < count; i++) {
+            final Method method = methods[i];            
+            if (method.getParameterTypes().length == 0 &&
+                    method.isAnnotationPresent(CapturedViewProperty.class) &&
+                    method.getReturnType() != Void.class) {
+                method.setAccessible(true);
+                foundMethods.add(method);
+            }
+        }
+
+        methods = foundMethods.toArray(new Method[foundMethods.size()]);
+        map.put(klass, methods);
+
+        return methods;
+    }
+              
+    private static String capturedViewExportMethods(Object obj, Class<?> klass, 
+            String prefix) {
+
+        if (obj == null) {
+            return "null";
+        }
+        
+        StringBuilder sb = new StringBuilder();
+        final Method[] methods = capturedViewGetPropertyMethods(klass);
+
+        int count = methods.length;
+        for (int i = 0; i < count; i++) {
+            final Method method = methods[i];
+            try {
+                Object methodValue = method.invoke(obj, (Object[]) null);
+                final Class<?> returnType = method.getReturnType();
+                
+                CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class);
+                if (property.retrieveReturn()) {
+                    //we are interested in the second level data only
+                    sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#"));
+                } else {                    
+                    sb.append(prefix);
+                    sb.append(method.getName());
+                    sb.append("()=");
+                    
+                    if (methodValue != null) {
+                        final String value = methodValue.toString().replace("\n", "\\n");                        
+                        sb.append(value);                        
+                    } else {
+                        sb.append("null");
+                    }
+                    sb.append("; ");
+                }
+              } catch (IllegalAccessException e) {
+                  //Exception IllegalAccess, it is OK here 
+                  //we simply ignore this method
+              } catch (InvocationTargetException e) {
+                  //Exception InvocationTarget, it is OK here 
+                  //we simply ignore this method
+              }              
+        }        
+        return sb.toString();
+    }
+
+    private static String capturedViewExportFields(Object obj, Class<?> klass, String prefix) {
+        
+        if (obj == null) {
+            return "null";
+        }
+        
+        StringBuilder sb = new StringBuilder();
+        final Field[] fields = capturedViewGetPropertyFields(klass);
+
+        int count = fields.length;
+        for (int i = 0; i < count; i++) {
+            final Field field = fields[i];
+            try {
+                Object fieldValue = field.get(obj);
+
+                sb.append(prefix);
+                sb.append(field.getName());
+                sb.append("=");
+
+                if (fieldValue != null) {
+                    final String value = fieldValue.toString().replace("\n", "\\n");
+                    sb.append(value);
+                } else {
+                    sb.append("null");
+                }
+                sb.append(' ');
+            } catch (IllegalAccessException e) {
+                //Exception IllegalAccess, it is OK here 
+                //we simply ignore this field
+            }
+        }
+        return sb.toString();
+    }
+    
+    /**
+     * dump view info for id based instrument test generation 
+     * (and possibly further data analysis). The results are dumped
+     * to the log. 
+     * @param tag for log
+     * @param view for dump
+     * 
+     * @hide pending API Council approval
+     */
+    public static void dumpCapturedView(String tag, Object view) {        
+        Class<?> klass = view.getClass();
+        StringBuilder sb = new StringBuilder(klass.getName() + ": ");
+        sb.append(capturedViewExportFields(view, klass, ""));
+        sb.append(capturedViewExportMethods(view, klass, ""));        
+        Log.d(tag, sb.toString());        
+    }
 }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9063821..e26a19e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -73,7 +73,7 @@
     private View mFocused;
 
     // The current transformation to apply on the child being drawn
-    private final Transformation mChildTransformation = new Transformation();
+    private Transformation mChildTransformation;
 
     // Target of Motion events
     private View mMotionTarget;
@@ -148,9 +148,6 @@
      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
      * set this flags in {@link #mGroupFlags}.
      * 
-     * This flag needs to be removed until we can add a setter for it.  People
-     * can't be directly stuffing values in to mGroupFlags!!!
-     * 
      * {@hide}
      */
     protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
@@ -466,27 +463,7 @@
     }
 
     /**
-     * Called when a child of this group wants a particular rectangle to be
-     * positioned onto the screen.  {@link ViewGroup}s overriding this can trust
-     * that:
-     * <ul>
-     *   <li>child will be a direct child of this group</li>
-     *   <li>rectangle will be in the child's coordinates</li>
-     * </ul>
-     *
-     * <p>{@link ViewGroup}s overriding this should uphold the contract:</p>
-     * <ul>
-     *   <li>nothing will change if the rectangle is already visible</li>
-     *   <li>the view port will be scrolled only just enough to make the
-     *       rectangle visible</li>
-     * <ul>
-     *
-     * @param child The direct child making the request.
-     * @param rectangle The rectangle in the child's coordinates the child
-     *        wishes to be on the screen.
-     * @param immediate True to forbid animated or delayed scrolling,
-     *        false otherwise
-     * @return Whether the group scrolled to handle the operation
+     * {@inheritDoc}
      */
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
         return false;
@@ -727,6 +704,19 @@
      * {@inheritDoc}
      */
     @Override
+    public boolean dispatchKeyEventPreIme(KeyEvent event) {
+        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
+            return super.dispatchKeyEventPreIme(event);
+        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
+            return mFocused.dispatchKeyEventPreIme(event);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
             return super.dispatchKeyEvent(event);
@@ -740,6 +730,19 @@
      * {@inheritDoc}
      */
     @Override
+    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
+            return super.dispatchKeyShortcutEvent(event);
+        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
+            return mFocused.dispatchKeyShortcutEvent(event);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public boolean dispatchTrackballEvent(MotionEvent event) {
         if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
             return super.dispatchTrackballEvent(event);
@@ -1314,7 +1317,9 @@
         final int flags = mGroupFlags;
 
         if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
-            mChildTransformation.clear();
+            if (mChildTransformation != null) {
+                mChildTransformation.clear();
+            }
             mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;
         }
 
@@ -1328,6 +1333,9 @@
                 child.onAnimationStart();
             }
 
+            if (mChildTransformation == null) {
+                mChildTransformation = new Transformation();
+            }
             more = a.getTransformation(drawingTime, mChildTransformation);
             transformToApply = mChildTransformation;
 
@@ -1347,6 +1355,9 @@
             }
         } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
                 FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
+            if (mChildTransformation == null) {
+                mChildTransformation = new Transformation();
+            }
             final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation);
             if (hasTransform) {
                 final int transformType = mChildTransformation.getTransformationType();
@@ -1507,7 +1518,27 @@
     }
 
     /**
+     * When this property is set to true, this ViewGroup supports static transformations on
+     * children; this causes
+     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
+     * invoked when a child is drawn.
+     *
+     * Any subclass overriding
+     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
+     * set this property to true.
+     *
+     * @param enabled True to enable static transformations on children, false otherwise.
+     *
+     * @see #FLAG_SUPPORT_STATIC_TRANSFORMATIONS
+     */
+    protected void setStaticTransformationsEnabled(boolean enabled) {
+        setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
+    }
+
+    /**
      * {@inheritDoc}
+     *
+     * @see #setStaticTransformationsEnabled(boolean) 
      */
     protected boolean getChildStaticTransformation(View child, Transformation t) {
         return false;
@@ -1969,7 +2000,7 @@
 
         if (view.getAnimation() != null) {
             addDisappearingView(view);
-        } else if (mAttachInfo != null) {
+        } else if (view.mAttachInfo != null) {
            view.dispatchDetachedFromWindow();
         }
 
@@ -2107,7 +2138,7 @@
         
         if (animate && child.getAnimation() != null) {
             addDisappearingView(child);
-        } else if (mAttachInfo != null) {
+        } else if (child.mAttachInfo != null) {
             child.dispatchDetachedFromWindow();
         }
 
@@ -2205,7 +2236,7 @@
     }
 
     /**
-     * Detaches all views from theparent. Detaching a view should be temporary and followed
+     * Detaches all views from the parent. Detaching a view should be temporary and followed
      * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
      * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
      * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
@@ -2242,13 +2273,16 @@
 
         ViewParent parent = this;
 
-        final int[] location = mLocation;
-        location[CHILD_LEFT_INDEX] = child.mLeft;
-        location[CHILD_TOP_INDEX] = child.mTop;
-
-        do {
-            parent = parent.invalidateChildInParent(location, dirty);
-        } while (parent != null);
+        final AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo != null) {
+            final int[] location = attachInfo.mInvalidateChildLocation;
+            location[CHILD_LEFT_INDEX] = child.mLeft;
+            location[CHILD_TOP_INDEX] = child.mTop;
+    
+            do {
+                parent = parent.invalidateChildInParent(location, dirty);
+            } while (parent != null);
+        }
     }
 
     /**
@@ -2917,7 +2951,7 @@
             if (disappearingChildren.contains(view)) {
                 disappearingChildren.remove(view);
 
-                if (mAttachInfo != null) {
+                if (view.mAttachInfo != null) {
                     view.dispatchDetachedFromWindow();
                 }
 
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 1a5d495..b456c5d 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -182,4 +182,30 @@
      *            intercept touch events.
      */
     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept);
+    
+    /**
+     * Called when a child of this group wants a particular rectangle to be
+     * positioned onto the screen.  {@link ViewGroup}s overriding this can trust
+     * that:
+     * <ul>
+     *   <li>child will be a direct child of this group</li>
+     *   <li>rectangle will be in the child's coordinates</li>
+     * </ul>
+     *
+     * <p>{@link ViewGroup}s overriding this should uphold the contract:</p>
+     * <ul>
+     *   <li>nothing will change if the rectangle is already visible</li>
+     *   <li>the view port will be scrolled only just enough to make the
+     *       rectangle visible</li>
+     * <ul>
+     *
+     * @param child The direct child making the request.
+     * @param rectangle The rectangle in the child's coordinates the child
+     *        wishes to be on the screen.
+     * @param immediate True to forbid animated or delayed scrolling,
+     *        false otherwise
+     * @return Whether the group scrolled to handle the operation
+     */
+    public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
+            boolean immediate);
 }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index ca67404..db0b368 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -16,18 +16,26 @@
 
 package android.view;
 
+import com.android.internal.view.IInputMethodCallback;
+import com.android.internal.view.IInputMethodSession;
+
 import android.graphics.Canvas;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.*;
 import android.os.Process;
+import android.os.SystemProperties;
 import android.util.AndroidRuntimeException;
 import android.util.Config;
 import android.util.Log;
 import android.util.EventLog;
+import android.util.SparseArray;
 import android.view.View.MeasureSpec;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Scroller;
 import android.content.pm.PackageManager;
 import android.content.Context;
 import android.app.ActivityManagerNative;
@@ -51,15 +59,19 @@
  * {@hide}
  */
 @SuppressWarnings({"EmptyCatchBlock"})
-final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.SoundEffectPlayer {
+public final class ViewRoot extends Handler implements ViewParent,
+        View.AttachInfo.SoundEffectPlayer {
     private static final String TAG = "ViewRoot";
     private static final boolean DBG = false;
     @SuppressWarnings({"ConstantConditionalExpression"})
     private static final boolean LOCAL_LOGV = false ? Config.LOGD : Config.LOGV;
     /** @noinspection PointlessBooleanExpression*/
     private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
+    private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
+    private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
     private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
-    private static final boolean DEBUG_TRACKBALL = LOCAL_LOGV;
+    private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
+    private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
     private static final boolean WATCH_POINTER = false;
 
     static final boolean PROFILE_DRAWING = false;
@@ -75,85 +87,103 @@
      */
     static final int MAX_TRACKBALL_DELAY = 250;
 
-    private static long sInstanceCount = 0;
+    static long sInstanceCount = 0;
 
-    private static IWindowSession sWindowSession;
+    static IWindowSession sWindowSession;
 
-    private static final Object mStaticInit = new Object();
-    private static boolean mInitialized = false;
+    static final Object mStaticInit = new Object();
+    static boolean mInitialized = false;
 
     static final ThreadLocal<Handler> sUiThreads = new ThreadLocal<Handler>();
     static final RunQueue sRunQueue = new RunQueue();
 
-    private long mLastTrackballTime = 0;
-    private final TrackballAxis mTrackballAxisX = new TrackballAxis();
-    private final TrackballAxis mTrackballAxisY = new TrackballAxis();
+    long mLastTrackballTime = 0;
+    final TrackballAxis mTrackballAxisX = new TrackballAxis();
+    final TrackballAxis mTrackballAxisY = new TrackballAxis();
 
-    private final Thread mThread;
+    final int[] mTmpLocation = new int[2];
+    
+    final InputMethodCallback mInputMethodCallback;
+    final SparseArray<Object> mPendingEvents = new SparseArray<Object>();
+    int mPendingEventSeq = 0;
+    
+    final Thread mThread;
 
-    private final WindowLeaked mLocation;
+    final WindowLeaked mLocation;
 
-    private final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
+    final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
 
     final W mWindow;
 
-    private View mView;
-    private View mFocusedView;
-    private int mViewVisibility;
-    private boolean mAppVisible = true;
+    View mView;
+    View mFocusedView;
+    int mViewVisibility;
+    boolean mAppVisible = true;
 
-    private final Region mTransparentRegion;
-    private final Region mPreviousTransparentRegion;
+    final Region mTransparentRegion;
+    final Region mPreviousTransparentRegion;
 
-    private int mWidth;
-    private int mHeight;
-    private Rect mDirty; // will be a graphics.Region soon
+    int mWidth;
+    int mHeight;
+    Rect mDirty; // will be a graphics.Region soon
 
-    private final View.AttachInfo mAttachInfo;
+    final View.AttachInfo mAttachInfo;
 
-    private final Rect mTempRect; // used in the transaction to not thrash the heap.
+    final Rect mTempRect; // used in the transaction to not thrash the heap.
+    final Rect mVisRect; // used to retrieve visible rect of focused view.
+    final Point mVisPoint; // used to retrieve global offset of focused view.
 
-    private boolean mTraversalScheduled;
-    private boolean mWillDrawSoon;
-    private boolean mLayoutRequested;
-    private boolean mFirst;
-    private boolean mReportNextDraw;
-    private boolean mFullRedrawNeeded;
-    private boolean mNewSurfaceNeeded;
+    boolean mTraversalScheduled;
+    boolean mWillDrawSoon;
+    boolean mLayoutRequested;
+    boolean mFirst;
+    boolean mReportNextDraw;
+    boolean mFullRedrawNeeded;
+    boolean mNewSurfaceNeeded;
+    boolean mHasHadWindowFocus;
 
-    private boolean mWindowAttributesChanged = false;
+    boolean mWindowAttributesChanged = false;
 
     // These can be accessed by any thread, must be protected with a lock.
-    private Surface mSurface;
+    Surface mSurface;
 
-    private boolean mAdded;
-    private boolean mAddedTouchMode;
+    boolean mAdded;
+    boolean mAddedTouchMode;
 
     /*package*/ int mAddNesting;
 
     // These are accessed by multiple threads.
-    private final Rect mWinFrame; // frame given by window manager.
+    final Rect mWinFrame; // frame given by window manager.
 
-    private final Rect mCoveredInsets = new Rect();
-    private final Rect mNewCoveredInsets = new Rect();
+    final Rect mPendingVisibleInsets = new Rect();
+    final Rect mPendingContentInsets = new Rect();
+    final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
+            = new ViewTreeObserver.InternalInsetsInfo();
 
-    private EGL10 mEgl;
-    private EGLDisplay mEglDisplay;
-    private EGLContext mEglContext;
-    private EGLSurface mEglSurface;
-    private GL11 mGL;
-    private Canvas mGlCanvas;
-    private boolean mUseGL;
-    private boolean mGlWanted;
+    boolean mScrollMayChange;
+    int mSoftInputMode;
+    View mLastScrolledFocus;
+    int mScrollY;
+    int mCurScrollY;
+    Scroller mScroller;
+    
+    EGL10 mEgl;
+    EGLDisplay mEglDisplay;
+    EGLContext mEglContext;
+    EGLSurface mEglSurface;
+    GL11 mGL;
+    Canvas mGlCanvas;
+    boolean mUseGL;
+    boolean mGlWanted;
 
     /**
      * see {@link #playSoundEffect(int)}
      */
-    private AudioManager mAudioManager;
+    AudioManager mAudioManager;
 
 
 
-    public ViewRoot() {
+    public ViewRoot(Context context) {
         super();
 
         ++sInstanceCount;
@@ -164,9 +194,10 @@
         synchronized (mStaticInit) {
             if (!mInitialized) {
                 try {
+                    InputMethodManager imm = InputMethodManager.getInstance(context);
                     sWindowSession = IWindowManager.Stub.asInterface(
                             ServiceManager.getService("window"))
-                            .openSession(new Binder());
+                            .openSession(imm.getClient(), imm.getInputContext());
                     mInitialized = true;
                 } catch (RemoteException e) {
                 }
@@ -180,8 +211,11 @@
         mHeight = -1;
         mDirty = new Rect();
         mTempRect = new Rect();
+        mVisRect = new Rect();
+        mVisPoint = new Point();
         mWinFrame = new Rect();
         mWindow = new W(this);
+        mInputMethodCallback = new InputMethodCallback(this);
         mViewVisibility = View.GONE;
         mTransparentRegion = new Region();
         mPreviousTransparentRegion = new Region();
@@ -194,7 +228,7 @@
             handler = new RootHandler();
             sUiThreads.set(handler);
         }
-        mAttachInfo = new View.AttachInfo(handler, this);
+        mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, handler, this);
     }
 
     @Override
@@ -350,8 +384,10 @@
         synchronized (this) {
             if (mView == null) {
                 mWindowAttributes.copyFrom(attrs);
+                mSoftInputMode = attrs.softInputMode;
                 mWindowAttributesChanged = true;
                 mView = view;
+                mAttachInfo.mRootView = view;
                 if (panelParentView != null) {
                     mAttachInfo.mPanelParentWindowToken
                             = panelParentView.getApplicationWindowToken();
@@ -366,16 +402,20 @@
                 
                 try {
                     res = sWindowSession.add(mWindow, attrs,
-                            getHostVisibility(), mCoveredInsets);
+                            getHostVisibility(), mAttachInfo.mContentInsets);
                 } catch (RemoteException e) {
                     mAdded = false;
                     mView = null;
+                    mAttachInfo.mRootView = null;
                     unscheduleTraversals();
                     throw new RuntimeException("Adding window failed", e);
                 }
+                mPendingContentInsets.set(mAttachInfo.mContentInsets);
+                mPendingVisibleInsets.set(0, 0, 0, 0);
                 if (Config.LOGV) Log.v("ViewRoot", "Added window " + mWindow);
                 if (res < WindowManagerImpl.ADD_OKAY) {
                     mView = null;
+                    mAttachInfo.mRootView = null;
                     mAdded = false;
                     unscheduleTraversals();
                     switch (res) {
@@ -427,9 +467,13 @@
         return mLocation;
     }
 
-    public void setLayoutParams(WindowManager.LayoutParams attrs) {
+    void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
         synchronized (this) {
             mWindowAttributes.copyFrom(attrs);
+            if (newView) {
+                mSoftInputMode = attrs.softInputMode;
+                requestLayout();
+            }
             mWindowAttributesChanged = true;
             scheduleTraversals();
         }
@@ -467,6 +511,11 @@
     public void invalidateChild(View child, Rect dirty) {
         checkThread();
         if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
+        if (mCurScrollY != 0) {
+            mTempRect.set(dirty);
+            mTempRect.offset(0, -mCurScrollY);
+            dirty = mTempRect;
+        }
         mDirty.union(dirty);
         if (!mWillDrawSoon) {
             scheduleTraversals();
@@ -486,6 +535,8 @@
         if (child != mView) {
             throw new RuntimeException("child is not mine, honest!");
         }
+        // Note: don't apply scroll offset, because we want to know its
+        // visibility in the virtual canvas being given to the view hierarchy.
         return r.intersect(0, 0, mWidth, mHeight);
     }
 
@@ -528,7 +579,7 @@
         boolean windowResizesToFitContent = false;
         boolean fullRedrawNeeded = mFullRedrawNeeded;
         boolean newSurface = false;
-        WindowManager.LayoutParams lp = (WindowManager.LayoutParams) host.getLayoutParams();
+        WindowManager.LayoutParams lp = mWindowAttributes;
 
         int desiredWindowWidth;
         int desiredWindowHeight;
@@ -544,7 +595,7 @@
         WindowManager.LayoutParams params = null;
         if (mWindowAttributesChanged) {
             mWindowAttributesChanged = false;
-            params = mWindowAttributes;
+            params = lp;
         }
 
         if (mFirst) {
@@ -559,9 +610,7 @@
             // is attached to the window.  Note that at this point the surface
             // object is not initialized to its backing store, but soon it
             // will be (assuming the window is visible).
-            attachInfo.mWindowToken = mWindow.asBinder();
             attachInfo.mSurface = mSurface;
-            attachInfo.mSession = sWindowSession;
             attachInfo.mHasWindowFocus = false;
             attachInfo.mWindowVisibility = viewVisibility;
             attachInfo.mRecomputeGlobalAttributes = false;
@@ -590,16 +639,35 @@
                     destroyGL();
                 }
             }
+            if (viewVisibility == View.GONE) {
+                // After making a window gone, we will count it as being
+                // shown for the first time the next time it gets focus.
+                mHasHadWindowFocus = false;
+            }
         }
 
+        boolean insetsChanged = false;
+        
         if (mLayoutRequested) {
             if (mFirst) {
-                host.fitSystemWindows(mCoveredInsets);
+                host.fitSystemWindows(mAttachInfo.mContentInsets);
                 // make sure touch mode code executes by setting cached value
                 // to opposite of the added touch mode.
                 mAttachInfo.mInTouchMode = !mAddedTouchMode;
                 ensureTouchModeLocally(mAddedTouchMode);
             } else {
+                if (!mAttachInfo.mContentInsets.equals(mPendingContentInsets)) {
+                    mAttachInfo.mContentInsets.set(mPendingContentInsets);
+                    host.fitSystemWindows(mAttachInfo.mContentInsets);
+                    insetsChanged = true;
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
+                            + mAttachInfo.mContentInsets);
+                }
+                if (!mAttachInfo.mVisibleInsets.equals(mPendingVisibleInsets)) {
+                    mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
+                            + mAttachInfo.mVisibleInsets);
+                }
                 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
                     windowResizesToFitContent = true;
@@ -614,7 +682,7 @@
             childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
 
             // Ask host how big it wants to be
-            if (DEBUG_ORIENTATION) Log.v("ViewRoot",
+            if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v("ViewRoot",
                     "Measuring " + host + " in display " + desiredWindowWidth
                     + "x" + desiredWindowHeight + "...");
             host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
@@ -633,11 +701,37 @@
             attachInfo.mKeepScreenOn = false;
             host.dispatchCollectViewAttributes(0);
             if (attachInfo.mKeepScreenOn != oldVal) {
-                params = mWindowAttributes;
+                params = lp;
                 //Log.i(TAG, "Keep screen on changed: " + attachInfo.mKeepScreenOn);
             }
         }
 
+        if (mFirst || attachInfo.mViewVisibilityChanged) {
+            attachInfo.mViewVisibilityChanged = false;
+            int resizeMode = mSoftInputMode &
+                    WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+            // If we are in auto resize mode, then we need to determine
+            // what mode to use now.
+            if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
+                final int N = attachInfo.mScrollContainers.size();
+                for (int i=0; i<N; i++) {
+                    if (attachInfo.mScrollContainers.get(i).isShown()) {
+                        resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+                    }
+                }
+                if (resizeMode == 0) {
+                    resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
+                }
+                if ((lp.softInputMode &
+                        WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
+                    lp.softInputMode = (lp.softInputMode &
+                            ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
+                            resizeMode;
+                    params = lp;
+                }
+            }
+        }
+        
         if (params != null && (host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
             if (!PixelFormat.formatHasAlpha(params.format)) {
                 params.format = PixelFormat.TRANSLUCENT;
@@ -647,10 +741,26 @@
         boolean windowShouldResize = mLayoutRequested && windowResizesToFitContent
             && (mWidth != host.mMeasuredWidth || mHeight != host.mMeasuredHeight);
 
+        final boolean computesInternalInsets =
+                attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
+        boolean insetsPending = false;
         int relayoutResult = 0;
-        if (mFirst || windowShouldResize || viewVisibilityChanged || params != null) {
+        if (mFirst || windowShouldResize || insetsChanged
+                || viewVisibilityChanged || params != null) {
 
             if (viewVisibility == View.VISIBLE) {
+                // If this window is giving internal insets to the window
+                // manager, and it is being added or changing its visibility,
+                // then we want to first give the window manager "fake"
+                // insets to cause it to effectively ignore the content of
+                // the window during layout.  This avoids it briefly causing
+                // other windows to resize/move based on the raw frame of the
+                // window, waiting until we can finish laying out this window
+                // and get back to the window manager with the ultimately
+                // computed insets.
+                insetsPending = computesInternalInsets
+                        && (mFirst || viewVisibilityChanged);
+                
                 if (mWindowAttributes.memoryType == WindowManager.LayoutParams.MEMORY_TYPE_GPU) {
                     if (params == null) {
                         params = mWindowAttributes;
@@ -661,7 +771,8 @@
 
             final Rect frame = mWinFrame;
             boolean initialized = false;
-            boolean coveredInsetsChanged = false;
+            boolean contentInsetsChanged = false;
+            boolean visibleInsetsChanged = false;
             try {
                 boolean hadSurface = mSurface.isValid();
                 int fl = 0;
@@ -673,31 +784,57 @@
                 }
                 relayoutResult = sWindowSession.relayout(
                     mWindow, params, host.mMeasuredWidth, host.mMeasuredHeight,
-                    viewVisibility, frame, mNewCoveredInsets, mSurface);
+                    viewVisibility, insetsPending, frame,
+                    mPendingContentInsets, mPendingVisibleInsets, mSurface);
                 if (params != null) {
                     params.flags = fl;
                 }
 
-                coveredInsetsChanged = !mNewCoveredInsets.equals(mCoveredInsets);
-                if (coveredInsetsChanged) {
-                    mCoveredInsets.set(mNewCoveredInsets);
-                    host.fitSystemWindows(mCoveredInsets);
+                if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
+                        + " content=" + mPendingContentInsets.toShortString()
+                        + " visible=" + mPendingVisibleInsets.toShortString()
+                        + " surface=" + mSurface);
+                
+                contentInsetsChanged = !mPendingContentInsets.equals(
+                        mAttachInfo.mContentInsets);
+                visibleInsetsChanged = !mPendingVisibleInsets.equals(
+                        mAttachInfo.mVisibleInsets);
+                if (contentInsetsChanged) {
+                    mAttachInfo.mContentInsets.set(mPendingContentInsets);
+                    host.fitSystemWindows(mAttachInfo.mContentInsets);
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
+                            + mAttachInfo.mContentInsets);
+                }
+                if (visibleInsetsChanged) {
+                    mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
+                            + mAttachInfo.mVisibleInsets);
                 }
 
-                if (!hadSurface && mSurface.isValid()) {
-                    // If we are creating a new surface, then we need to
-                    // completely redraw it.  Also, when we get to the
-                    // point of drawing it we will hold off and schedule
-                    // a new traversal instead.  This is so we can tell the
-                    // window manager about all of the windows being displayed
-                    // before actually drawing them, so it can display then
-                    // all at once.
-                    newSurface = true;
-                    fullRedrawNeeded = true;
-
-                    if (mGlWanted && !mUseGL) {
-                        initializeGL();
-                        initialized = mGlCanvas != null;
+                if (!hadSurface) {
+                    if (mSurface.isValid()) {
+                        // If we are creating a new surface, then we need to
+                        // completely redraw it.  Also, when we get to the
+                        // point of drawing it we will hold off and schedule
+                        // a new traversal instead.  This is so we can tell the
+                        // window manager about all of the windows being displayed
+                        // before actually drawing them, so it can display then
+                        // all at once.
+                        newSurface = true;
+                        fullRedrawNeeded = true;
+    
+                        if (mGlWanted && !mUseGL) {
+                            initializeGL();
+                            initialized = mGlCanvas != null;
+                        }
+                    }
+                } else if (!mSurface.isValid()) {
+                    // If the surface has been removed, then reset the scroll
+                    // positions.
+                    mLastScrolledFocus = null;
+                    mScrollY = mCurScrollY = 0;
+                    if (mScroller != null) {
+                        mScroller.abortAnimation();
                     }
                 }
             } catch (RemoteException e) {
@@ -721,10 +858,16 @@
             boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                     (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
             if (focusChangedDueToTouchMode || mWidth != host.mMeasuredWidth
-                    || mHeight != host.mMeasuredHeight || coveredInsetsChanged) {
+                    || mHeight != host.mMeasuredHeight || contentInsetsChanged) {
                 childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
                 childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
 
+                if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
+                        + mWidth + " measuredWidth=" + host.mMeasuredWidth
+                        + " mHeight=" + mHeight
+                        + " measuredHeight" + host.mMeasuredHeight
+                        + " coveredInsetsChanged=" + contentInsetsChanged);
+                
                  // Ask host how big it wants to be
                 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
 
@@ -749,6 +892,9 @@
                 }
 
                 if (measureAgain) {
+                    if (DEBUG_LAYOUT) Log.v(TAG,
+                            "And hey let's measure once more: width=" + width
+                            + " height=" + height);
                     host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
                 }
 
@@ -756,12 +902,14 @@
             }
         }
 
-        boolean triggerGlobalLayoutListener = mLayoutRequested
+        final boolean didLayout = mLayoutRequested;
+        boolean triggerGlobalLayoutListener = didLayout
                 || attachInfo.mRecomputeGlobalAttributes;
-        if (mLayoutRequested) {
+        if (didLayout) {
             mLayoutRequested = false;
-            if (DEBUG_ORIENTATION) Log.v(
-                "ViewRoot", "Setting frame " + host + " to (" +
+            mScrollMayChange = true;
+            if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
+                "ViewRoot", "Laying out " + host + " to (" +
                 host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
             long startTime;
             if (PROFILE_LAYOUT) {
@@ -780,10 +928,10 @@
             if ((host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
                 // start out transparent
                 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
-                host.getLocationInWindow(host.mLocation);
-                mTransparentRegion.set(host.mLocation[0], host.mLocation[1],
-                        host.mLocation[0] + host.mRight - host.mLeft,
-                        host.mLocation[1] + host.mBottom - host.mTop);
+                host.getLocationInWindow(mTmpLocation);
+                mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
+                        mTmpLocation[0] + host.mRight - host.mLeft,
+                        mTmpLocation[1] + host.mBottom - host.mTop);
 
                 host.gatherTransparentRegion(mTransparentRegion);
                 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
@@ -809,6 +957,24 @@
             attachInfo.mTreeObserver.dispatchOnGlobalLayout();
         }
 
+        if (computesInternalInsets) {
+            ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
+            final Rect givenContent = attachInfo.mGivenInternalInsets.contentInsets;
+            final Rect givenVisible = attachInfo.mGivenInternalInsets.visibleInsets;
+            givenContent.left = givenContent.top = givenContent.right
+                    = givenContent.bottom = givenVisible.left = givenVisible.top
+                    = givenVisible.right = givenVisible.bottom = 0;
+            attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
+            if (insetsPending || !mLastGivenInsets.equals(insets)) {
+                mLastGivenInsets.set(insets);
+                try {
+                    sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
+                            insets.contentInsets, insets.visibleInsets);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+            
         if (mFirst) {
             // handle first focus request
             if (mView != null && !mView.hasFocus()) {
@@ -841,7 +1007,7 @@
             }
         } else {
             // We were supposed to report when we are done drawing. Since we canceled the
-            // draw, rememeber it here.
+            // draw, remember it here.
             if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
                 mReportNextDraw = true;
             }
@@ -903,6 +1069,21 @@
             return;
         }
 
+        scrollToRectOrFocus(null, false);
+        
+        int yoff;
+        final boolean scrolling = mScroller != null
+                && mScroller.computeScrollOffset(); 
+        if (scrolling) {
+            yoff = mScroller.getCurrY();
+        } else {
+            yoff = mScrollY;
+        }
+        if (mCurScrollY != yoff) {
+            mCurScrollY = yoff;
+            fullRedrawNeeded = true;
+        }
+        
         Rect dirty = mDirty;
         if (mUseGL) {
             if (!dirty.isEmpty()) {
@@ -914,7 +1095,9 @@
                     mGL.glEnable(GL_SCISSOR_TEST);
 
                     mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
+                    canvas.translate(0, -yoff);
                     mView.draw(canvas);
+                    canvas.translate(0, yoff);
 
                     mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
                     checkEglErrors();
@@ -928,6 +1111,10 @@
                     }
                 }
             }
+            if (scrolling) {
+                mFullRedrawNeeded = true;
+                scheduleTraversals();
+            }
             return;
         }
 
@@ -973,11 +1160,18 @@
                 // background. This automatically respects the clip/dirty region
                 if (!canvas.isOpaque()) {
                     canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+                } else if (yoff != 0) {
+                    // If we are applying an offset, we need to clear the area
+                    // where the offset doesn't appear to avoid having garbage
+                    // left in the blank areas.
+                    canvas.drawColor(0, PorterDuff.Mode.CLEAR);
                 }
 
                 dirty.setEmpty();
                 mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
+                canvas.translate(0, -yoff);
                 mView.draw(canvas);
+                canvas.translate(0, yoff);
 
                 if (SHOW_FPS) {
                     int now = (int)SystemClock.elapsedRealtime();
@@ -999,12 +1193,125 @@
                 Log.v("ViewRoot", "Surface " + surface + " unlockCanvasAndPost");
             }
         }
+        
+        if (scrolling) {
+            mFullRedrawNeeded = true;
+            scheduleTraversals();
+        }
     }
 
+    boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
+        final View.AttachInfo attachInfo = mAttachInfo;
+        final Rect ci = attachInfo.mContentInsets;
+        final Rect vi = attachInfo.mVisibleInsets;
+        int scrollY = 0;
+        boolean handled = false;
+        
+        if (vi.left > ci.left || vi.top > ci.top
+                || vi.right > ci.right || vi.bottom > ci.bottom) {
+            // We'll assume that we aren't going to change the scroll
+            // offset, since we want to avoid that unless it is actually
+            // going to make the focus visible...  otherwise we scroll
+            // all over the place.
+            scrollY = mScrollY;
+            // We can be called for two different situations: during a draw,
+            // to update the scroll position if the focus has changed (in which
+            // case 'rectangle' is null), or in response to a
+            // requestChildRectangleOnScreen() call (in which case 'rectangle'
+            // is non-null and we just want to scroll to whatever that
+            // rectangle is).
+            View focus = mFocusedView;
+            if (focus != mLastScrolledFocus) {
+                // If the focus has changed, then ignore any requests to scroll
+                // to a rectangle; first we want to make sure the entire focus
+                // view is visible.
+                rectangle = null;
+            }
+            if (focus == mLastScrolledFocus && !mScrollMayChange
+                    && rectangle == null) {
+                // Optimization: if the focus hasn't changed since last
+                // time, and no layout has happened, then just leave things
+                // as they are.
+                if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
+                        + mScrollY + " vi=" + vi.toShortString());
+            } else if (focus != null) {
+                // We need to determine if the currently focused view is
+                // within the visible part of the window and, if not, apply
+                // a pan so it can be seen.
+                mLastScrolledFocus = focus;
+                mScrollMayChange = false;
+                // Try to find the rectangle from the focus view.
+                if (focus.getGlobalVisibleRect(mVisRect, null)) {
+                    if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
+                            + mView.getWidth() + " h=" + mView.getHeight()
+                            + " ci=" + ci.toShortString()
+                            + " vi=" + vi.toShortString());
+                    if (rectangle == null) {
+                        focus.getFocusedRect(mTempRect);
+                        if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
+                                + ": focusRect=" + mTempRect.toShortString());
+                        ((ViewGroup) mView).offsetDescendantRectToMyCoords(
+                                focus, mTempRect);
+                        if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                                "Focus in window: focusRect="
+                                + mTempRect.toShortString()
+                                + " visRect=" + mVisRect.toShortString());
+                    } else {
+                        mTempRect.set(rectangle);
+                        if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                                "Request scroll to rect: "
+                                + mTempRect.toShortString()
+                                + " visRect=" + mVisRect.toShortString());
+                    }
+                    if (mTempRect.intersect(mVisRect)) {
+                        if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                                "Focus window visible rect: "
+                                + mTempRect.toShortString());
+                        if (mTempRect.height() >
+                                (mView.getHeight()-vi.top-vi.bottom)) {
+                            // If the focus simply is not going to fit, then
+                            // best is probably just to leave things as-is.
+                            if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                                    "Too tall; leaving scrollY=" + scrollY);
+                        } else if ((mTempRect.top-scrollY) < vi.top) {
+                            scrollY -= vi.top - (mTempRect.top-scrollY);
+                            if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                                    "Top covered; scrollY=" + scrollY);
+                        } else if ((mTempRect.bottom-scrollY)
+                                > (mView.getHeight()-vi.bottom)) {
+                            scrollY += (mTempRect.bottom-scrollY)
+                                    - (mView.getHeight()-vi.bottom);
+                            if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                                    "Bottom covered; scrollY=" + scrollY);
+                        }
+                        handled = true;
+                    }
+                }
+            }
+        }
+        
+        if (scrollY != mScrollY) {
+            if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
+                    + mScrollY + " , new=" + scrollY);
+            if (!immediate) {
+                if (mScroller == null) {
+                    mScroller = new Scroller(mView.getContext());
+                }
+                mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
+            } else if (mScroller != null) {
+                mScroller.abortAnimation();
+            }
+            mScrollY = scrollY;
+        }
+        
+        return handled;
+    }
+    
     public void requestChildFocus(View child, View focused) {
         checkThread();
         if (mFocusedView != focused) {
             mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
+            scheduleTraversals();
         }
         mFocusedView = focused;
     }
@@ -1063,6 +1370,7 @@
             mView.dispatchDetachedFromWindow();
         }
         mView = null;
+        mAttachInfo.mRootView = null;
         if (mUseGL) {
             destroyGL();
         }
@@ -1081,16 +1389,17 @@
     }
 
 
-    private final static int DO_TRAVERSAL = 1000;
-    private final static int DIE = 1001;
-    private final static int RESIZED = 1002;
-    private final static int RESIZED_REPORT = 1003;
-    private final static int WINDOW_FOCUS_CHANGED = 1004;
-    private final static int DISPATCH_KEY = 1005;
-    private final static int DISPATCH_POINTER = 1006;
-    private final static int DISPATCH_TRACKBALL = 1007;
-    private final static int DISPATCH_APP_VISIBILITY = 1008;
-    private final static int DISPATCH_GET_NEW_SURFACE = 1009;
+    public final static int DO_TRAVERSAL = 1000;
+    public final static int DIE = 1001;
+    public final static int RESIZED = 1002;
+    public final static int RESIZED_REPORT = 1003;
+    public final static int WINDOW_FOCUS_CHANGED = 1004;
+    public final static int DISPATCH_KEY = 1005;
+    public final static int DISPATCH_POINTER = 1006;
+    public final static int DISPATCH_TRACKBALL = 1007;
+    public final static int DISPATCH_APP_VISIBILITY = 1008;
+    public final static int DISPATCH_GET_NEW_SURFACE = 1009;
+    public final static int FINISHED_EVENT = 1010;
 
     @Override
     public void handleMessage(Message msg) {
@@ -1107,6 +1416,9 @@
                 mProfile = false;
             }
             break;
+        case FINISHED_EVENT:
+            handleFinishedEvent(msg.arg1, msg.arg2 != 0);
+            break;
         case DISPATCH_KEY:
             if (LOCAL_LOGV) Log.v(
                 "ViewRoot", "Dispatching key "
@@ -1124,7 +1436,7 @@
                 }
                 didFinish = true;
             } else {
-                didFinish = false;
+                didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
             }
 
             try {
@@ -1136,7 +1448,10 @@
                     if (isDown) {
                         ensureTouchMode(true);
                     }
-
+                    if(Config.LOGV) {
+                        captureMotionLog("captureDispatchPointer", event);
+                    }
+                    event.offsetLocation(0, mCurScrollY);
                     handled = mView.dispatchTouchEvent(event);
                     if (!handled && isDown) {
                         int edgeSlop = ViewConfiguration.getEdgeSlop();
@@ -1207,7 +1522,11 @@
             handleGetNewSurface();
             break;
         case RESIZED:
-            if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2) {
+            Rect coveredInsets = ((Rect[])msg.obj)[0];
+            Rect visibleInsets = ((Rect[])msg.obj)[1];
+            if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
+                    && mPendingContentInsets.equals(coveredInsets)
+                    && mPendingVisibleInsets.equals(visibleInsets)) {
                 break;
             }
             // fall through...
@@ -1217,6 +1536,8 @@
                 mWinFrame.right = msg.arg1;
                 mWinFrame.top = 0;
                 mWinFrame.bottom = msg.arg2;
+                mPendingContentInsets.set(((Rect[])msg.obj)[0]);
+                mPendingVisibleInsets.set(((Rect[])msg.obj)[1]);
                 if (msg.what == RESIZED_REPORT) {
                     mReportNextDraw = true;
                 }
@@ -1245,6 +1566,18 @@
                 if (mView != null) {
                     mView.dispatchWindowFocusChanged(hasWindowFocus);
                 }
+                
+                // Note: must be done after the focus change callbacks,
+                // so all of the view state is set up correctly.
+                if (hasWindowFocus) {
+                    InputMethodManager imm = InputMethodManager.peekInstance();
+                    if (imm != null) {
+                        imm.onWindowFocus(mView.findFocus(),
+                                mWindowAttributes.softInputMode, !mHasHadWindowFocus,
+                                mWindowAttributes.flags);
+                    }
+                    mHasHadWindowFocus = true;
+                }
             }
         } break;
         case DIE:
@@ -1387,7 +1720,7 @@
             didFinish = false;
         }
 
-        //Log.i("foo", "Motion event:" + event);
+        if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
 
         boolean handled = false;
         try {
@@ -1397,7 +1730,7 @@
                 handled = mView.dispatchTrackballEvent(event);
                 if (!handled) {
                     // we could do something here, like changing the focus
-                    // or someting?
+                    // or something?
                 }
             }
         } finally {
@@ -1456,8 +1789,8 @@
                     + " / Y=" + y.position + " step="
                     + y.step + " dir=" + y.dir + " acc=" + y.acceleration
                     + " move=" + event.getY());
-            final float xOff = x.collect(event.getX(), "X");
-            final float yOff = y.collect(event.getY(), "Y");
+            final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
+            final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
 
             // Generate DPAD events based on the trackball movement.
             // We pick the axis that has moved the most as the direction of
@@ -1489,9 +1822,9 @@
             if (keycode != 0) {
                 if (movement < 0) movement = -movement;
                 int accelMovement = (int)(movement * accel);
-                //Log.i(TAG, "Move: movement=" + movement
-                //        + " accelMovement=" + accelMovement
-                //        + " accel=" + accel);
+                if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
+                        + " accelMovement=" + accelMovement
+                        + " accel=" + accel);
                 if (accelMovement > movement) {
                     if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
                             + keycode);
@@ -1602,8 +1935,116 @@
         return false;
     }
 
+    /**
+     * log motion events 
+     */
+    private static void captureMotionLog(String subTag, MotionEvent ev) {
+        //check dynamic switch        
+        if (ev == null ||
+                SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) {
+            return;
+        } 
+        
+        StringBuilder sb = new StringBuilder(subTag + ": ");        
+        sb.append(ev.getDownTime()).append(',');        
+        sb.append(ev.getEventTime()).append(',');        
+        sb.append(ev.getAction()).append(',');        
+        sb.append(ev.getX()).append(',');        
+        sb.append(ev.getY()).append(',');        
+        sb.append(ev.getPressure()).append(',');        
+        sb.append(ev.getSize()).append(',');        
+        sb.append(ev.getMetaState()).append(',');        
+        sb.append(ev.getXPrecision()).append(',');        
+        sb.append(ev.getYPrecision()).append(',');        
+        sb.append(ev.getDeviceId()).append(',');        
+        sb.append(ev.getEdgeFlags());
+        Log.d(TAG, sb.toString());        
+    }
+    /**
+     * log motion events 
+     */
+    private static void captureKeyLog(String subTag, KeyEvent ev) {
+        //check dynamic switch                
+        if (ev == null || 
+                SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) {
+            return;
+        }
+        StringBuilder sb = new StringBuilder(subTag + ": ");        
+        sb.append(ev.getDownTime()).append(',');
+        sb.append(ev.getEventTime()).append(',');
+        sb.append(ev.getAction()).append(',');
+        sb.append(ev.getKeyCode()).append(',');        
+        sb.append(ev.getRepeatCount()).append(',');
+        sb.append(ev.getMetaState()).append(',');
+        sb.append(ev.getDeviceId()).append(',');
+        sb.append(ev.getScanCode());
+        Log.d(TAG, sb.toString());        
+    }    
 
+    int enqueuePendingEvent(Object event, boolean sendDone) {
+        int seq = mPendingEventSeq+1;
+        if (seq < 0) seq = 0;
+        mPendingEventSeq = seq;
+        mPendingEvents.put(seq, event);
+        return sendDone ? seq : -seq;
+    }
+
+    Object retrievePendingEvent(int seq) {
+        if (seq < 0) seq = -seq;
+        Object event = mPendingEvents.get(seq);
+        if (event != null) {
+            mPendingEvents.remove(seq);
+        }
+        return event;
+    }
+    
     private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
+        boolean handled = false;
+        handled = mView.dispatchKeyEventPreIme(event);
+        if (handled) {
+            if (sendDone) {
+                if (LOCAL_LOGV) Log.v(
+                    "ViewRoot", "Telling window manager key is finished");
+                try {
+                    sWindowSession.finishKey(mWindow);
+                } catch (RemoteException e) {
+                }
+            }
+            return;
+        }
+        InputMethodManager imm = InputMethodManager.peekInstance();
+        if (imm != null && mView != null && imm.isActive()) {
+            int seq = enqueuePendingEvent(event, sendDone);
+            if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
+                    + seq + " event=" + event);
+            imm.dispatchKeyEvent(mView.getContext(), seq, event,
+                    mInputMethodCallback);
+            return;
+        }
+        deliverKeyEventToViewHierarchy(event, sendDone);
+    }
+
+    void handleFinishedEvent(int seq, boolean handled) {
+        final KeyEvent event = (KeyEvent)retrievePendingEvent(seq);
+        if (DEBUG_IMF) Log.v(TAG, "IME finished event: seq=" + seq
+                + " handled=" + handled + " event=" + event);
+        if (event != null) {
+            final boolean sendDone = seq >= 0;
+            if (!handled) {
+                deliverKeyEventToViewHierarchy(event, sendDone);
+                return;
+            } else if (sendDone) {
+                if (LOCAL_LOGV) Log.v(
+                        "ViewRoot", "Telling window manager key is finished");
+                try {
+                    sWindowSession.finishKey(mWindow);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+    }
+    
+    private void deliverKeyEventToViewHierarchy(KeyEvent event, boolean sendDone) {
         try {
             if (mView != null && mAdded) {
                 final int action = event.getAction();
@@ -1611,8 +2052,11 @@
 
                 if (checkForLeavingTouchModeAndConsume(event)) {
                     return;
+                }                
+                
+                if (Config.LOGV) {
+                    captureKeyLog("captureDispatchKeyEvent", event);
                 }
-
                 boolean keyHandled = mView.dispatchKeyEvent(event);
 
                 if ((!keyHandled && isDown) || (action == KeyEvent.ACTION_MULTIPLE)) {
@@ -1740,10 +2184,11 @@
                     // animation info.
                     try {
                         if ((sWindowSession.relayout(
-                            mWindow, mWindowAttributes,
-                            mView.mMeasuredWidth, mView.mMeasuredHeight,
-                            viewVisibility, mWinFrame, mCoveredInsets, mSurface)
-                            &WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+                                    mWindow, mWindowAttributes,
+                                    mView.mMeasuredWidth, mView.mMeasuredHeight,
+                                    viewVisibility, false, mWinFrame, mPendingContentInsets,
+                                    mPendingVisibleInsets, mSurface)
+                                &WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
                             sWindowSession.finishDrawing(mWindow);
                         }
                     } catch (RemoteException e) {
@@ -1767,12 +2212,23 @@
         }
     }
 
-    public void dispatchResized(int w, int h, boolean reportDraw) {
-        if (DEBUG_DRAW) Log.v(TAG, "Resized " + this + ": w=" + w
-                + " h=" + h + " reportDraw=" + reportDraw);
-        Message msg = obtainMessage(reportDraw ? RESIZED_REPORT : RESIZED);
+    public void dispatchFinishedEvent(int seq, boolean handled) {
+        Message msg = obtainMessage(FINISHED_EVENT);
+        msg.arg1 = seq;
+        msg.arg2 = handled ? 1 : 0;
+        sendMessage(msg);
+    }
+    
+    public void dispatchResized(int w, int h, Rect coveredInsets,
+            Rect visibleInsets, boolean reportDraw) {
+        if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w
+                + " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
+                + " visibleInsets=" + visibleInsets.toShortString()
+                + " reportDraw=" + reportDraw);
+        Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
         msg.arg1 = w;
         msg.arg2 = h;
+        msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
         sendMessage(msg);
     }
 
@@ -1855,6 +2311,30 @@
         // ViewRoot never intercepts touch event, so this can be a no-op
     }
 
+    public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
+            boolean immediate) {
+        return scrollToRectOrFocus(rectangle, immediate);
+    }
+    
+    static class InputMethodCallback extends IInputMethodCallback.Stub {
+        private WeakReference<ViewRoot> mViewRoot;
+
+        public InputMethodCallback(ViewRoot viewRoot) {
+            mViewRoot = new WeakReference<ViewRoot>(viewRoot);
+        }
+        
+        public void finishedEvent(int seq, boolean handled) {
+            final ViewRoot viewRoot = mViewRoot.get();
+            if (viewRoot != null) {
+                viewRoot.dispatchFinishedEvent(seq, handled);
+            }
+        }
+
+        public void sessionCreated(IInputMethodSession session) throws RemoteException {
+            // Stub -- not for use in the client.
+        }
+    }
+    
     static class W extends IWindow.Stub {
         private WeakReference<ViewRoot> mViewRoot;
 
@@ -1862,10 +2342,12 @@
             mViewRoot = new WeakReference<ViewRoot>(viewRoot);
         }
 
-        public void resized(int w, int h, boolean reportDraw) {
+        public void resized(int w, int h, Rect coveredInsets,
+                Rect visibleInsets, boolean reportDraw) {
             final ViewRoot viewRoot = mViewRoot.get();
             if (viewRoot != null) {
-                viewRoot.dispatchResized(w, h, reportDraw);
+                viewRoot.dispatchResized(w, h, coveredInsets,
+                        visibleInsets, reportDraw);
             }
         }
 
@@ -1961,9 +2443,30 @@
      * discrete (DPAD) movements based on raw trackball motion.
      */
     static final class TrackballAxis {
+        /**
+         * The maximum amount of acceleration we will apply.
+         */
+        static final float MAX_ACCELERATION = 20;
+        
+        /**
+         * The maximum amount of time (in milliseconds) between events in order
+         * for us to consider the user to be doing fast trackball movements,
+         * and thus apply an acceleration.
+         */
+        static final long FAST_MOVE_TIME = 100;
+        
+        /**
+         * Scaling factor to the time (in milliseconds) between events to how
+         * much to multiple/divide the current acceleration.  When movement
+         * is < FAST_MOVE_TIME this multiplies the acceleration; when >
+         * FAST_MOVE_TIME it divides it.
+         */
+        static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/50);
+        
         float position;
         float absPosition;
         float acceleration = 1;
+        long lastMoveTime = 0;
         int step;
         int dir;
         int nonAccelMovement;
@@ -1971,6 +2474,7 @@
         void reset(int _step) {
             position = 0;
             acceleration = 1;
+            lastMoveTime = 0;
             step = _step;
             dir = 0;
         }
@@ -1985,23 +2489,56 @@
          * @return Returns the absolute value of the amount of movement
          * collected so far.
          */
-        float collect(float off, String axis) {
+        float collect(float off, long time, String axis) {
+            long normTime;
             if (off > 0) {
+                normTime = (long)(off * FAST_MOVE_TIME);
                 if (dir < 0) {
                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
                     position = 0;
                     step = 0;
                     acceleration = 1;
+                    lastMoveTime = 0;
                 }
                 dir = 1;
             } else if (off < 0) {
+                normTime = (long)((-off) * FAST_MOVE_TIME);
                 if (dir > 0) {
                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
                     position = 0;
                     step = 0;
                     acceleration = 1;
+                    lastMoveTime = 0;
                 }
                 dir = -1;
+            } else {
+                normTime = 0;
+            }
+            
+            // The number of milliseconds between each movement that is
+            // considered "normal" and will not result in any acceleration
+            // or deceleration, scaled by the offset we have here.
+            if (normTime > 0) {
+                long delta = time - lastMoveTime;
+                lastMoveTime = time;
+                float acc = acceleration;
+                if (delta < normTime) {
+                    // The user is scrolling rapidly, so increase acceleration.
+                    float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
+                    if (scale > 1) acc *= scale;
+                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
+                            + off + " normTime=" + normTime + " delta=" + delta
+                            + " scale=" + scale + " acc=" + acc);
+                    acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
+                } else {
+                    // The user is scrolling slowly, so decrease acceleration.
+                    float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
+                    if (scale > 1) acc /= scale;
+                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
+                            + off + " normTime=" + normTime + " delta=" + delta
+                            + " scale=" + scale + " acc=" + acc);
+                    acceleration = acc > 1 ? acc : 1;
+                }
             }
             position += off;
             return (absPosition = Math.abs(position));
@@ -2050,12 +2587,11 @@
                         break;
                     // After the first two, we generate discrete movements
                     // consistently with the trackball, applying an acceleration
-                    // if the trackball is moving quickly.  The acceleration is
-                    // currently very simple, just reducing the amount of
-                    // trackball motion required as more discrete movements are
-                    // generated.  This should probably be changed to take time
-                    // more into account, so that quick trackball movements will
-                    // have increased acceleration.
+                    // if the trackball is moving quickly.  This is a simple
+                    // acceleration on top of what we already compute based
+                    // on how quickly the wheel is being turned, to apply
+                    // a longer increasing acceleration to continuous movement
+                    // in one direction.
                     default:
                         if (absPosition < 1) {
                             return movement;
@@ -2065,7 +2601,7 @@
                         absPosition = Math.abs(position);
                         float acc = acceleration;
                         acc *= 1.1f;
-                        acceleration = acc < 20 ? acc : acceleration;
+                        acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
                         break;
                 }
             } while (true);
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 2e1e01a..05f5fa2 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.graphics.Rect;
+
 import java.util.ArrayList;
 
 /**
@@ -32,6 +34,7 @@
     private ArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
     private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
     private ArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
+    private ArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
 
     private boolean mAlive = true;
 
@@ -96,6 +99,108 @@
     }
 
     /**
+     * Parameters used with OnComputeInternalInsetsListener.
+     * {@hide pending API Council approval}
+     */
+    public final static class InternalInsetsInfo {
+        /**
+         * Offsets from the frame of the window at which the content of
+         * windows behind it should be placed.
+         */
+        public final Rect contentInsets = new Rect();
+        
+        /**
+         * Offsets from the fram of the window at which windows behind it
+         * are visible.
+         */
+        public final Rect visibleInsets = new Rect();
+        
+        /**
+         * Option for {@link #setTouchableInsets(int)}: the entire window frame
+         * can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_FRAME = 0;
+        
+        /**
+         * Option for {@link #setTouchableInsets(int)}: the area inside of
+         * the content insets can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_CONTENT = 1;
+        
+        /**
+         * Option for {@link #setTouchableInsets(int)}: the area inside of
+         * the visible insets can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_VISIBLE = 2;
+        
+        /**
+         * Set which parts of the window can be touched: either
+         * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
+         * or {@link #TOUCHABLE_INSETS_VISIBLE}. 
+         */
+        public void setTouchableInsets(int val) {
+            mTouchableInsets = val;
+        }
+        
+        public int getTouchableInsets() {
+            return mTouchableInsets;
+        }
+        
+        int mTouchableInsets;
+        
+        void reset() {
+            final Rect givenContent = contentInsets;
+            final Rect givenVisible = visibleInsets;
+            givenContent.left = givenContent.top = givenContent.right
+                    = givenContent.bottom = givenVisible.left = givenVisible.top
+                    = givenVisible.right = givenVisible.bottom = 0;
+            mTouchableInsets = TOUCHABLE_INSETS_FRAME;
+        }
+        
+        @Override public boolean equals(Object o) {
+            try {
+                if (o == null) {
+                    return false;
+                }
+                InternalInsetsInfo other = (InternalInsetsInfo)o;
+                if (!contentInsets.equals(other.contentInsets)) {
+                    return false;
+                }
+                if (!visibleInsets.equals(other.visibleInsets)) {
+                    return false;
+                }
+                return mTouchableInsets == other.mTouchableInsets;
+            } catch (ClassCastException e) {
+                return false;
+            }
+        }
+        
+        void set(InternalInsetsInfo other) {
+            contentInsets.set(other.contentInsets);
+            visibleInsets.set(other.visibleInsets);
+            mTouchableInsets = other.mTouchableInsets;
+        }
+    }
+    
+    /**
+     * Interface definition for a callback to be invoked when layout has
+     * completed and the client can compute its interior insets.
+     * {@hide pending API Council approval}
+     */
+    public interface OnComputeInternalInsetsListener {
+        /**
+         * Callback method to be invoked when layout has completed and the
+         * client can compute its interior insets.
+         *
+         * @param inoutInfo Should be filled in by the implementation with
+         * the information about the insets of the window.  This is called
+         * with whatever values the previous OnComputeInternalInsetsListener
+         * returned, if there are multiple such listeners in the window.
+         */
+        public void onComputeInternalInsets(InternalInsetsInfo inoutInfo);
+    }
+
+    /**
      * Creates a new ViewTreeObserver. This constructor should not be called
      */
     ViewTreeObserver() {
@@ -141,6 +246,14 @@
             }
         }
 
+        if (observer.mOnComputeInternalInsetsListeners != null) {
+            if (mOnComputeInternalInsetsListeners != null) {
+                mOnComputeInternalInsetsListeners.addAll(observer.mOnComputeInternalInsetsListeners);
+            } else {
+                mOnComputeInternalInsetsListeners = observer.mOnComputeInternalInsetsListeners;
+            }
+        }
+
         observer.kill();
     }
 
@@ -281,6 +394,43 @@
         mOnTouchModeChangeListeners.remove(victim);
     }
 
+    /**
+     * Register a callback to be invoked when the invoked when it is time to
+     * compute the window's internal insets.
+     *
+     * @param listener The callback to add
+     *
+     * @throws IllegalStateException If {@link #isAlive()} returns false
+     * {@hide pending API Council approval}
+     */
+    public void addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener listener) {
+        checkIsAlive();
+
+        if (mOnComputeInternalInsetsListeners == null) {
+            mOnComputeInternalInsetsListeners = new ArrayList<OnComputeInternalInsetsListener>();
+        }
+
+        mOnComputeInternalInsetsListeners.add(listener);
+    }
+
+    /**
+     * Remove a previously installed internal insets computation callback
+     *
+     * @param victim The callback to remove
+     *
+     * @throws IllegalStateException If {@link #isAlive()} returns false
+     *
+     * @see #addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener)
+     * {@hide pending API Council approval}
+     */
+    public void removeOnComputeInternalInsetsListener(OnComputeInternalInsetsListener victim) {
+        checkIsAlive();
+        if (mOnComputeInternalInsetsListeners == null) {
+            return;
+        }
+        mOnComputeInternalInsetsListeners.remove(victim);
+    }
+
     private void checkIsAlive() {
         if (!mAlive) {
             throw new IllegalStateException("This ViewTreeObserver is not alive, call "
@@ -373,4 +523,25 @@
             }
         }
     }
+
+    /**
+     * Returns whether there are listeners for computing internal insets.
+     */
+    final boolean hasComputeInternalInsetsListeners() {
+        final ArrayList<OnComputeInternalInsetsListener> listeners = mOnComputeInternalInsetsListeners;
+        return (listeners != null && listeners.size() > 0);
+    }
+    
+    /**
+     * Calls all listeners to compute the current insets.
+     */
+    final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) {
+        final ArrayList<OnComputeInternalInsetsListener> listeners = mOnComputeInternalInsetsListeners;
+        if (listeners != null) {
+            final int count = listeners.size();
+            for (int i = count - 1; i >= 0; i--) {
+                listeners.get(i).onComputeInternalInsets(inoutInfo);
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 24f4853..f4d0fde 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -19,10 +19,15 @@
 import android.media.ToneGenerator;
 import android.media.AudioManager;
 import android.media.AudioService;
+import android.media.AudioSystem;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Vibrator;
+import android.text.TextUtils;
 import android.util.Config;
 import android.util.Log;
 import android.widget.ImageView;
@@ -69,46 +74,47 @@
     private static final int MSG_STOP_SOUNDS = 3;
     private static final int MSG_VIBRATE = 4;
     
-    private final String RINGTONE_VOLUME_TEXT;
-    private final String MUSIC_VOLUME_TEXT;
-    private final String INCALL_VOLUME_TEXT;
-    private final String ALARM_VOLUME_TEXT;
-    private final String UNKNOWN_VOLUME_TEXT;
+    private static final int RINGTONE_VOLUME_TEXT = com.android.internal.R.string.volume_ringtone;
+    private static final int MUSIC_VOLUME_TEXT = com.android.internal.R.string.volume_music;
+    private static final int INCALL_VOLUME_TEXT = com.android.internal.R.string.volume_call;
+    private static final int ALARM_VOLUME_TEXT = com.android.internal.R.string.volume_alarm;
+    private static final int UNKNOWN_VOLUME_TEXT = com.android.internal.R.string.volume_unknown;
+    private static final int NOTIFICATION_VOLUME_TEXT =
+            com.android.internal.R.string.volume_notification; 
     
     protected Context mContext;
+    private AudioManager mAudioManager;
     protected AudioService mAudioService;
     
-    private Toast mToast;
-    private View mView;
-    private TextView mMessage;
-    private ImageView mOtherStreamIcon;
-    private ImageView mRingerStreamIcon;
-    private ProgressBar mLevel;
+    private final Toast mToast;
+    private final View mView;
+    private final TextView mMessage;
+    private final TextView mAdditionalMessage;
+    private final ImageView mSmallStreamIcon;
+    private final ImageView mLargeStreamIcon;
+    private final ProgressBar mLevel;
 
     // Synchronize when accessing this
     private ToneGenerator mToneGenerators[];
     private Vibrator mVibrator;
-    
+
     public VolumePanel(Context context, AudioService volumeService) {
         mContext = context;
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mAudioService = volumeService;
         mToast = new Toast(context);
-    
-        RINGTONE_VOLUME_TEXT = context.getString(com.android.internal.R.string.volume_ringtone);
-        MUSIC_VOLUME_TEXT = context.getString(com.android.internal.R.string.volume_music);
-        INCALL_VOLUME_TEXT = context.getString(com.android.internal.R.string.volume_call);
-        ALARM_VOLUME_TEXT = context.getString(com.android.internal.R.string.volume_alarm);
-        UNKNOWN_VOLUME_TEXT = context.getString(com.android.internal.R.string.volume_unknown);
-        
+
         LayoutInflater inflater = (LayoutInflater) context
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View view = mView = inflater.inflate(com.android.internal.R.layout.volume_adjust, null);
         mMessage = (TextView) view.findViewById(com.android.internal.R.id.message);
-        mOtherStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.other_stream_icon);
-        mRingerStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.ringer_stream_icon);
+        mAdditionalMessage =
+                (TextView) view.findViewById(com.android.internal.R.id.additional_message);
+        mSmallStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.other_stream_icon);
+        mLargeStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.ringer_stream_icon);
         mLevel = (ProgressBar) view.findViewById(com.android.internal.R.id.level);
 
-        mToneGenerators = new ToneGenerator[AudioManager.NUM_STREAMS];
+        mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
         mVibrator = new Vibrator();
     }
     
@@ -148,13 +154,17 @@
 
     protected void onShowVolumeChanged(int streamType, int flags) {
         int index = mAudioService.getStreamVolume(streamType);
-        String message = UNKNOWN_VOLUME_TEXT;
+        int message = UNKNOWN_VOLUME_TEXT;
+        int additionalMessage = 0;
         
         if (LOGD) {
             Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
                     + ", flags: " + flags + "), index: " + index);
         }
 
+        // get max volume for progress bar
+        int max = mAudioService.getStreamMaxVolume(streamType);
+
         switch (streamType) {
             
             case AudioManager.STREAM_RING: {
@@ -165,32 +175,60 @@
                 
             case AudioManager.STREAM_MUSIC: {
                 message = MUSIC_VOLUME_TEXT;
-                setOtherIcon(index);
+                if (mAudioManager.isBluetoothA2dpOn()) {
+                    additionalMessage =
+                        com.android.internal.R.string.volume_music_hint_playing_through_bluetooth;
+                    setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_ad2p);
+                } else {
+                    setSmallIcon(index);
+                }
                 break;
             }
                 
             case AudioManager.STREAM_VOICE_CALL: {
-                message = INCALL_VOLUME_TEXT;
                 /*
-                 * For in-call voice call volume, there is no inaudible volume
-                 * level, so never show the mute icon
+                 * For in-call voice call volume, there is no inaudible volume.
+                 * Rescale the UI control so the progress bar doesn't go all
+                 * the way to zero and don't show the mute icon.
                  */
-                setOtherIcon(index == 0 ? 1 : index);
+                index++;
+                max++;
+                message = INCALL_VOLUME_TEXT;
+                if (mAudioManager.isBluetoothScoOn()) {
+                    additionalMessage =
+                        com.android.internal.R.string.volume_call_hint_playing_through_bluetooth;
+                    setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_in_call);
+                } else {
+                    setSmallIcon(index);
+                }
                 break;
             }
 
             case AudioManager.STREAM_ALARM: {
                 message = ALARM_VOLUME_TEXT;
-                setOtherIcon(index);
+                setSmallIcon(index);
+                break;
+            }
+            
+            case AudioManager.STREAM_NOTIFICATION: {
+                message = NOTIFICATION_VOLUME_TEXT;
+                setSmallIcon(index);
                 break;
             }
         }
 
-        if (!mMessage.getText().equals(message)) {
-            mMessage.setText(message);
+        String messageString = Resources.getSystem().getString(message);
+        if (!mMessage.getText().equals(messageString)) {
+            mMessage.setText(messageString);
         }
 
-        int max = mAudioService.getStreamMaxVolume(streamType);
+        if (additionalMessage == 0) {
+            mAdditionalMessage.setVisibility(View.GONE);
+        } else {
+            mAdditionalMessage.setVisibility(View.VISIBLE);
+            mAdditionalMessage.setText(Resources.getSystem().getString(additionalMessage));
+        }
+        
         if (max != mLevel.getMax()) {
             mLevel.setMax(max);
         }
@@ -230,7 +268,8 @@
     protected void onStopSounds() {
         
         synchronized (this) {
-            for (int i = AudioManager.NUM_STREAMS - 1; i >= 0; i--) {
+            int numStreamTypes = AudioSystem.getNumStreamTypes();
+            for (int i = numStreamTypes - 1; i >= 0; i--) {
                 ToneGenerator toneGen = mToneGenerators[i];
                 if (toneGen != null) {
                     toneGen.stopTone();
@@ -261,19 +300,41 @@
             }
         }
     }
-    
-    private void setOtherIcon(int index) {
-        mRingerStreamIcon.setVisibility(View.GONE);
-        mOtherStreamIcon.setVisibility(View.VISIBLE);
+
+    /**
+     * Makes the small icon visible, and hides the large icon.
+     * 
+     * @param index The volume index, where 0 means muted.
+     */
+    private void setSmallIcon(int index) {
+        mLargeStreamIcon.setVisibility(View.GONE);
+        mSmallStreamIcon.setVisibility(View.VISIBLE);
         
-        mOtherStreamIcon.setImageResource(index == 0
+        mSmallStreamIcon.setImageResource(index == 0
                 ? com.android.internal.R.drawable.ic_volume_off_small
                 : com.android.internal.R.drawable.ic_volume_small);
     }
 
+    /**
+     * Makes the large image view visible with the given icon.
+     * 
+     * @param resId The icon to display.
+     */
+    private void setLargeIcon(int resId) {
+        mSmallStreamIcon.setVisibility(View.GONE);
+        mLargeStreamIcon.setVisibility(View.VISIBLE);
+        mLargeStreamIcon.setImageResource(resId);
+    }
+
+    /**
+     * Makes the ringer icon visible with an icon that is chosen
+     * based on the current ringer mode.
+     * 
+     * @param index
+     */
     private void setRingerIcon(int index) {
-        mOtherStreamIcon.setVisibility(View.GONE);
-        mRingerStreamIcon.setVisibility(View.VISIBLE);
+        mSmallStreamIcon.setVisibility(View.GONE);
+        mLargeStreamIcon.setVisibility(View.VISIBLE);
 
         int ringerMode = mAudioService.getRingerMode();
         int icon;
@@ -287,14 +348,14 @@
         } else {
             icon = com.android.internal.R.drawable.ic_volume;
         }
-        mRingerStreamIcon.setImageResource(icon);
+        mLargeStreamIcon.setImageResource(icon);
     }
     
     protected void onFreeResources() {
         // We'll keep the views, just ditch the cached drawable and hence
         // bitmaps
-        mOtherStreamIcon.setImageDrawable(null);
-        mRingerStreamIcon.setImageDrawable(null);
+        mSmallStreamIcon.setImageDrawable(null);
+        mLargeStreamIcon.setImageDrawable(null);
         
         synchronized (this) {
             for (int i = mToneGenerators.length - 1; i >= 0; i--) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 4aeab2d..a68436b 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -24,6 +24,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.util.Log;
 
 /**
  * Abstract base class for a top-level window look and behavior policy.  An
@@ -106,6 +107,8 @@
     private boolean mHaveWindowFormat = false;
     private int mDefaultWindowFormat = PixelFormat.OPAQUE;
 
+    private boolean mHasSoftInputMode = false;
+    
     // The current window attributes.
     private final WindowManager.LayoutParams mWindowAttributes =
         new WindowManager.LayoutParams();
@@ -382,11 +385,7 @@
                         && mAppName != null) {
                     wp.setTitle(mAppName);
                 }
-                if (wp.windowAnimations == 0) {
-                    wp.windowAnimations = getWindowStyle().getResourceId(
-                            com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
-                }
-            }
+           }
             if (wp.packageName == null) {
                 wp.packageName = mContext.getPackageName();
             }
@@ -526,6 +525,26 @@
     }
 
     /**
+     * Specify an explicit soft input mode to use for the window, as per
+     * {@link WindowManager.LayoutParams#softInputMode
+     * WindowManager.LayoutParams.softInputMode}.  Providing anything besides
+     * "unspecified" here will override the input mode the window would
+     * normally retrieve from its theme.
+     */
+    public void setSoftInputMode(int mode) {
+        final WindowManager.LayoutParams attrs = getAttributes();
+        if (mode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
+            attrs.softInputMode = mode;
+            mHasSoftInputMode = true;
+        } else {
+            mHasSoftInputMode = false;
+        }
+        if (mCallback != null) {
+            mCallback.onWindowAttributesChanged(attrs);
+        }
+    }
+    
+    /**
      * Convenience function to set the flag bits as specified in flags, as
      * per {@link #setFlags}.
      * @param flags The flag bits to be set.
@@ -572,14 +591,17 @@
     }
 
     /**
-     * Specify custom window attributes.
+     * Specify custom window attributes.  <strong>PLEASE NOTE:</strong> the
+     * layout params you give here should generally be from values previously
+     * retrieved with {@link #getAttributes()}; you probably do not want to
+     * blindly create and apply your own, since this will blow away any values
+     * set by the framework that you are not interested in.
      *
      * @param a The new window attributes, which will completely override any
      *          current values.
      */
     public void setAttributes(WindowManager.LayoutParams a) {
         mWindowAttributes.copyFrom(a);
-        mForcedWindowFlags = 0xffffffff;
         if (mCallback != null) {
             mCallback.onWindowAttributesChanged(mWindowAttributes);
         }
@@ -604,6 +626,13 @@
     }
     
     /**
+     * Has the app specified their own soft input mode?
+     */
+    protected final boolean hasSoftInputMode() {
+        return mHasSoftInputMode;
+    }
+    
+    /**
      * Enable extended screen features.  This must be called before
      * setContentView().  May be called as many times as desired as long as it
      * is before setContentView().  If not called, no extended features
@@ -926,8 +955,7 @@
      * @see #setFormat
      * @see PixelFormat
      */
-    protected void setDefaultWindowFormat(int format)
-    {
+    protected void setDefaultWindowFormat(int format) {
         mDefaultWindowFormat = format;
         if (!mHaveWindowFormat) {
             final WindowManager.LayoutParams attrs = getAttributes();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 4c1dec5..7d202aa 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -125,6 +125,9 @@
          * @see #TYPE_APPLICATION_PANEL
          * @see #TYPE_APPLICATION_MEDIA
          * @see #TYPE_APPLICATION_SUB_PANEL
+         * @see #TYPE_APPLICATION_ATTACHED_DIALOG
+         * @see #TYPE_INPUT_METHOD
+         * @see #TYPE_INPUT_METHOD_DIALOG
          * @see #TYPE_STATUS_BAR
          * @see #TYPE_SEARCH_BAR
          * @see #TYPE_PHONE
@@ -133,6 +136,12 @@
          * @see #TYPE_TOAST
          * @see #TYPE_SYSTEM_OVERLAY
          * @see #TYPE_PRIORITY_PHONE
+         * @see #TYPE_STATUS_BAR_PANEL
+         * @see #TYPE_SYSTEM_DIALOG
+         * @see #TYPE_KEYGUARD_DIALOG
+         * @see #TYPE_SYSTEM_ERROR
+         * @see #TYPE_INPUT_METHOD
+         * @see #TYPE_INPUT_METHOD_DIALOG
          */
         public int type;
     
@@ -193,12 +202,18 @@
          * {@link #TYPE_APPLICATION_PANEL} panels.
          */
         public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2;
-    
+
+        /** Window type: like {@link #TYPE_APPLICATION_PANEL}, but layout
+         * of the window happens as that of a top-level window, <em>not</em>
+         * as a child of its container.
+         */
+        public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3;
+        
         /**
          * End of types of sub-windows.
          */
         public static final int LAST_SUB_WINDOW         = 1999;
-    
+        
         /**
          * Start of system-specific window types.  These are not normally
          * created by applications.
@@ -278,10 +293,23 @@
         public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;
         
         /**
+         * Window type: internal input methods windows, which appear above
+         * the normal UI.  Application windows may be resized or panned to keep
+         * the input focus visible while this window is displayed.
+         */
+        public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;
+
+        /**
+         * Window type: internal input methods dialog windows, which appear above
+         * the current input method window.
+         */
+        public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
-    
+        
         /**
          * Specifies what type of memory buffers should be used by this window.
          * Default is normal.
@@ -330,7 +358,19 @@
         /** Window flag: blur everything behind this window. */
         public static final int FLAG_BLUR_BEHIND        = 0x00000004;
         
-        /** Window flag: this window won't ever get focus. */
+        /** Window flag: this window won't ever get key input focus, so the
+         * user can not send key or other button events to it.  Those will
+         * instead go to whatever focusable window is behind it.  This flag
+         * will also enable {@link #FLAG_NOT_TOUCH_MODAL} whether or not that
+         * is explicitly set.
+         * 
+         * <p>Setting this flag also implies that the window will not need to
+         * interact with
+         * a soft input method, so it will be Z-ordered and positioned 
+         * independently of any active input method (typically this means it
+         * gets Z-ordered on top of the input method, so it can use the full
+         * screen for its content and cover the input method if needed.  You
+         * can use {@link #FLAG_ALT_FOCUSABLE_IM} to modify this behavior. */
         public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;
         
         /** Window flag: this window can never receive touch events. */
@@ -405,6 +445,33 @@
          * set for you by Window as described in {@link Window#setFlags}.*/
         public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;
         
+        /** Window flag: invert the state of {@link #FLAG_NOT_FOCUSABLE} with
+         * respect to how this window interacts with the current method.  That
+         * is, if FLAG_NOT_FOCUSABLE is set and this flag is set, then the
+         * window will behave as if it needs to interact with the input method
+         * and thus be placed behind/away from it; if FLAG_NOT_FOCUSABLE is
+         * not set and this flag is set, then the window will behave as if it
+         * doesn't need to interact with the input method and can be placed
+         * to use more space and cover the input method.
+         */
+        public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;
+        
+        /** Window flag: if you have set {@link #FLAG_NOT_TOUCH_MODAL}, you
+         * can set this flag to receive a single special MotionEvent with
+         * the action
+         * {@link MotionEvent#ACTION_OUTSIDE MotionEvent.ACTION_OUTSIDE} for
+         * touches that occur outside of your window.  Note that you will not
+         * receive the full down/move/up gesture, only the location of the
+         * first down as an ACTION_OUTSIDE.
+         */
+        public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;
+        
+        /** Window flag: set when this window was created from the restored
+         * state of a previous window, indicating this is not the first time
+         * the user has navigated to it.
+         */
+        public static final int FLAG_RESTORED_STATE = 0x00080000;
+        
         /** Window flag: a special option intended for system dialogs.  When
          * this flag is set, the window will demand focus unconditionally when
          * it is created.
@@ -412,6 +479,90 @@
         public static final int FLAG_SYSTEM_ERROR = 0x40000000;
 
         /**
+         * Mask for {@link #softInputMode} of the bits that determine the
+         * desired visibility state of the soft input area for this window.
+         */
+        public static final int SOFT_INPUT_MASK_STATE = 0x0f;
+        
+        /**
+         * Visibility state for {@link #softInputMode}: no state has been specified.
+         */
+        public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
+        
+        /**
+         * Visibility state for {@link #softInputMode}: please don't change the state of
+         * the soft input area.
+         */
+        public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
+        
+        /**
+         * Visibility state for {@link #softInputMode}: please hide any soft input
+         * area.
+         */
+        public static final int SOFT_INPUT_STATE_HIDDEN = 2;
+        
+        /**
+         * Visibility state for {@link #softInputMode}: please show the soft input area
+         * the first time the window is shown.
+         */
+        public static final int SOFT_INPUT_STATE_FIRST_VISIBLE = 3;
+        
+        /**
+         * Visibility state for {@link #softInputMode}: please always show the soft
+         * input area.
+         */
+        public static final int SOFT_INPUT_STATE_VISIBLE = 4;
+        
+        /**
+         * Mask for {@link #softInputMode} of the bits that determine the
+         * way that the window should be adjusted to accomodate the soft
+         * input window.
+         */
+        public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
+        
+        /** Adjustment option for {@link #softInputMode}: nothing specified.
+         * The system will try to pick one or
+         * the other depending on the contents of the window.
+         */
+        public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
+        
+        /** Adjustment option for {@link #softInputMode}: set to allow the
+         * window to be resized when an input
+         * method is shown, so that its contents are not covered by the input
+         * method.  This can <em>not<em> be combined with
+         * {@link #SOFT_INPUT_ADJUST_PAN}; if
+         * neither of these are set, then the system will try to pick one or
+         * the other depending on the contents of the window.
+         */
+        public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
+        
+        /** Adjustment option for {@link #softInputMode}: set to have a window
+         * pan when an input method is
+         * shown, so it doesn't need to deal with resizing but just panned
+         * by the framework to ensure the current input focus is visible.  This
+         * can <em>not<em> be combined with {@link #SOFT_INPUT_ADJUST_RESIZE}; if
+         * neither of these are set, then the system will try to pick one or
+         * the other depending on the contents of the window.
+         */
+        public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
+        
+        /**
+         * Desired operating mode for any soft input area.  May any combination
+         * of:
+         * 
+         * <ul>
+         * <li> One of the visibility states
+         * {@link #SOFT_INPUT_STATE_UNSPECIFIED}, {@link #SOFT_INPUT_STATE_UNCHANGED},
+         * {@link #SOFT_INPUT_STATE_HIDDEN}, {@link #SOFT_INPUT_STATE_FIRST_VISIBLE}, or
+         * {@link #SOFT_INPUT_STATE_VISIBLE}.
+         * <li> One of the adjustment options
+         * {@link #SOFT_INPUT_ADJUST_UNSPECIFIED},
+         * {@link #SOFT_INPUT_ADJUST_RESIZE}, or
+         * {@link #SOFT_INPUT_ADJUST_PAN}.
+         */
+        public int softInputMode;
+        
+        /**
          * Placement of window within the screen as per {@link Gravity}
          *
          * @see Gravity
@@ -533,6 +684,7 @@
             out.writeInt(type);
             out.writeInt(memoryType);
             out.writeInt(flags);
+            out.writeInt(softInputMode);
             out.writeInt(gravity);
             out.writeFloat(horizontalMargin);
             out.writeFloat(verticalMargin);
@@ -565,6 +717,7 @@
             type = in.readInt();
             memoryType = in.readInt();
             flags = in.readInt();
+            softInputMode = in.readInt();
             gravity = in.readInt();
             horizontalMargin = in.readFloat();
             verticalMargin = in.readFloat();
@@ -586,6 +739,7 @@
         public static final int TITLE_CHANGED = 1<<6;
         public static final int ALPHA_CHANGED = 1<<7;
         public static final int MEMORY_TYPE_CHANGED = 1<<8;
+        public static final int SOFT_INPUT_MODE_CHANGED = 1<<9;
     
         public final int copyFrom(LayoutParams o) {
             int changes = 0;
@@ -606,6 +760,22 @@
                 y = o.y;
                 changes |= LAYOUT_CHANGED;
             }
+            if (horizontalWeight != o.horizontalWeight) {
+                horizontalWeight = o.horizontalWeight;
+                changes |= LAYOUT_CHANGED;
+            }
+            if (verticalWeight != o.verticalWeight) {
+                verticalWeight = o.verticalWeight;
+                changes |= LAYOUT_CHANGED;
+            }
+            if (horizontalMargin != o.horizontalMargin) {
+                horizontalMargin = o.horizontalMargin;
+                changes |= LAYOUT_CHANGED;
+            }
+            if (verticalMargin != o.verticalMargin) {
+                verticalMargin = o.verticalMargin;
+                changes |= LAYOUT_CHANGED;
+            }
             if (type != o.type) {
                 type = o.type;
                 changes |= TYPE_CHANGED;
@@ -618,6 +788,10 @@
                 flags = o.flags;
                 changes |= FLAGS_CHANGED;
             }
+            if (softInputMode != o.softInputMode) {
+                softInputMode = o.softInputMode;
+                changes |= SOFT_INPUT_MODE_CHANGED;
+            }
             if (gravity != o.gravity) {
                 gravity = o.gravity;
                 changes |= LAYOUT_CHANGED;
@@ -677,15 +851,37 @@
     
         @Override
         public String toString() {
-            return "WM.LayoutParams{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " (" + x + "," + y + ")("
-                + (width==FILL_PARENT?"fill_parent":(width==WRAP_CONTENT?"wrap_content":width))
-                + "x"
-                + (height==FILL_PARENT?"fill_parent":(height==WRAP_CONTENT?"wrap_content":height))
-                + ") gr=#" + Integer.toHexString(gravity)
-                + " ty=" + type + " fl=#" + Integer.toHexString(flags)
-                + " fmt=" + format + "}";
+            StringBuilder sb = new StringBuilder(256);
+            sb.append("WM.LayoutParams{");
+            sb.append("(");
+            sb.append(x);
+            sb.append(',');
+            sb.append(y);
+            sb.append(")(");
+            sb.append((width==FILL_PARENT?"fill":(width==WRAP_CONTENT?"wrap":width)));
+            sb.append('x');
+            sb.append((height==FILL_PARENT?"fill":(height==WRAP_CONTENT?"wrap":height)));
+            sb.append(")");
+            if (softInputMode != 0) {
+                sb.append(" sim=#");
+                sb.append(Integer.toHexString(softInputMode));
+            }
+            if (gravity != 0) {
+                sb.append(" gr=#");
+                sb.append(Integer.toHexString(gravity));
+            }
+            sb.append(" ty=");
+            sb.append(type);
+            sb.append(" fl=#");
+            sb.append(Integer.toHexString(flags));
+            sb.append(" fmt=");
+            sb.append(format);
+            if (windowAnimations != 0) {
+                sb.append(" wanim=0x");
+                sb.append(Integer.toHexString(windowAnimations));
+            }
+            sb.append('}');
+            return sb.toString();
         }
     
         private CharSequence mTitle = "";
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index fbecf46..755d7b8 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -22,6 +22,7 @@
 import android.util.Config;
 import android.util.Log;
 import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
 
 final class WindowLeaked extends AndroidRuntimeException {
     public WindowLeaked(String msg) {
@@ -128,7 +129,7 @@
                 root.mAddNesting++;
                 // Update layout parameters.
                 view.setLayoutParams(wparams);
-                root.setLayoutParams(wparams);
+                root.setLayoutParams(wparams, true);
                 return;
             }
             
@@ -144,7 +145,7 @@
                 }
             }
             
-            root = new ViewRoot();
+            root = new ViewRoot(view.getContext());
             root.mAddNesting = 1;
 
             view.setLayoutParams(wparams);
@@ -191,7 +192,7 @@
             int index = findViewLocked(view, true);
             ViewRoot root = mRoots[index];
             mParams[index] = wparams;
-            root.setLayoutParams(wparams);
+            root.setLayoutParams(wparams, false);
         }
     }
 
@@ -236,6 +237,10 @@
             return view;
         }
 
+        InputMethodManager imm = InputMethodManager.getInstance(view.getContext());
+        if (imm != null) {
+            imm.windowDismissed(mViews[index].getWindowToken());
+        }
         root.die(false);
         finishRemoveViewLocked(view, index);
         return view;
@@ -294,6 +299,26 @@
         }
     }
     
+    public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
+        ViewParent vp = view.getParent();
+        while (vp != null && !(vp instanceof ViewRoot)) {
+            vp = vp.getParent();
+        }
+        
+        if (vp == null) return null;
+        
+        ViewRoot vr = (ViewRoot)vp;
+        
+        int N = mRoots.length;
+        for (int i = 0; i < N; ++i) {
+            if (mRoots[i] == vr) {
+                return mParams[i];
+            }
+        }
+        
+        return null;
+    }
+    
     public void closeAll() {
         closeAll(null, null, null);
     }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 93e1a0b..a6def51 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -109,37 +109,23 @@
          * getFrame() if so desired.  Must be called with the window manager
          * lock held.
          * 
-         * @param parentLeft The left edge of the parent container this window
-         * is in, used for computing its position.
-         * @param parentTop The top edge of the parent container this window
-         * is in, used for computing its position.
-         * @param parentRight The right edge of the parent container this window
-         * is in, used for computing its position.
-         * @param parentBottom The bottom edge of the parent container this window
-         * is in, used for computing its position.
-         * @param displayLeft The left edge of the available display, used
-         * for constraining the overall dimensions of the window.
-         * @param displayTop The left edge of the available display, used
-         * for constraining the overall dimensions of the window.
-         * @param displayRight The right edge of the available display, used
-         * for constraining the overall dimensions of the window.
-         * @param displayBottom The bottom edge of the available display, used
-         * for constraining the overall dimensions of the window.
+         * @param parentFrame The frame of the parent container this window
+         * is in, used for computing its basic position.
+         * @param displayFrame The frame of the overall display in which this
+         * window can appear, used for constraining the overall dimensions
+         * of the window.
+         * @param contentFrame The frame within the display in which we would
+         * like active content to appear.  This will cause windows behind to
+         * be resized to match the given content frame.
+         * @param visibleFrame The frame within the display that the window
+         * is actually visible, used for computing its visible insets to be
+         * given to windows behind.
+         * This can be used as a hint for scrolling (avoiding resizing)
+         * the window to make certain that parts of its content
+         * are visible.
          */
-        public void computeFrameLw(int parentLeft, int parentRight, int parentBottom,
-                int parentHeight, int displayLeft, int displayTop,
-                int displayRight, int displayBottom);
-
-        /**
-         * Set the window's frame to an exact value.  Must be called with the
-         * window manager lock held.
-         * 
-         * @param left Left edge of the window.
-         * @param top Top edge of the window.
-         * @param right Right edge (exclusive) of the window.
-         * @param bottom Bottom edge (exclusive) of the window.
-         */
-        public void setFrameLw(int left, int top, int right, int bottom);
+        public void computeFrameLw(Rect parentFrame, Rect displayFrame,
+                Rect contentFrame, Rect visibleFrame);
 
         /**
          * Retrieve the current frame of the window.  Must be called with the
@@ -150,6 +136,66 @@
         public Rect getFrameLw();
 
         /**
+         * Retrieve the frame of the display that this window was last
+         * laid out in.  Must be called with the
+         * window manager lock held.
+         * 
+         * @return Rect The rectangle holding the display frame.
+         */
+        public Rect getDisplayFrameLw();
+
+        /**
+         * Retrieve the frame of the content area that this window was last
+         * laid out in.  This is the area in which the content of the window
+         * should be placed.  It will be smaller than the display frame to
+         * account for screen decorations such as a status bar or soft
+         * keyboard.  Must be called with the
+         * window manager lock held.
+         * 
+         * @return Rect The rectangle holding the content frame.
+         */
+        public Rect getContentFrameLw();
+
+        /**
+         * Retrieve the frame of the visible area that this window was last
+         * laid out in.  This is the area of the screen in which the window
+         * will actually be fully visible.  It will be smaller than the
+         * content frame to account for transient UI elements blocking it
+         * such as an input method's candidates UI.  Must be called with the
+         * window manager lock held.
+         * 
+         * @return Rect The rectangle holding the visible frame.
+         */
+        public Rect getVisibleFrameLw();
+
+        /**
+         * Returns true if this window is waiting to receive its given
+         * internal insets from the client app, and so should not impact the
+         * layout of other windows.
+         */
+        public boolean getGivenInsetsPendingLw();
+        
+        /**
+         * Retrieve the insets given by this window's client for the content
+         * area of windows behind it.  Must be called with the
+         * window manager lock held.
+         * 
+         * @return Rect The left, top, right, and bottom insets, relative
+         * to the window's frame, of the actual contents.
+         */
+        public Rect getGivenContentInsetsLw();
+
+        /**
+         * Retrieve the insets given by this window's client for the visible
+         * area of windows behind it.  Must be called with the
+         * window manager lock held.
+         * 
+         * @return Rect The left, top, right, and bottom insets, relative
+         * to the window's frame, of the actual visible area.
+         */
+        public Rect getGivenVisibleInsetsLw();
+
+        /**
          * Retrieve the current LayoutParams of the window.
          * 
          * @return WindowManager.LayoutParams The window's internal LayoutParams
@@ -158,6 +204,11 @@
         public WindowManager.LayoutParams getAttrs();
 
         /**
+         * Get the layer at which this window's surface will be Z-ordered.
+         */
+        public int getSurfaceLayer();
+        
+        /**
          * Return the token for the application (actually activity) that owns 
          * this window.  May return null for system windows. 
          * 
@@ -240,18 +291,6 @@
          * lock held.
          */
         public void showLw();
-
-        /**
-         * Sets insets on the window that represent the area within the window that is covered
-         * by system windows (e.g. status bar).  Must be called with the window
-         * manager lock held.
-         * 
-         * @param l
-         * @param t
-         * @param r
-         * @param b
-         */
-        public void setCoveredInsetsLw(int l, int t, int r, int b);
     }
 
     /** No transition happening. */
@@ -506,14 +545,15 @@
 
     
     /**
-     * Return the insets for the areas covered by system windows. These values are computed on the
-     * mose recent layout, so they are not guaranteed to be correct.
+     * Return the insets for the areas covered by system windows. These values
+     * are computed on the most recent layout, so they are not guaranteed to
+     * be correct.
      * 
      * @param attrs The LayoutParams of the window.
-     * @param coveredInset The areas covered by system windows, expressed as positive insets
+     * @param contentInset The areas covered by system windows, expressed as positive insets
      * 
      */
-    public void getCoveredInsetHintLw(WindowManager.LayoutParams attrs, Rect coveredInset);
+    public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset);
     
     /**
      * Called when layout of the windows is finished.  After this function has
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 39fe561..9f3650b 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -582,6 +582,16 @@
     }
 
     /**
+     * Compute a hint at how long the entire animation may last, in milliseconds.
+     * Animations can be written to cause themselves to run for a different
+     * duration than what is computed here, but generally this should be
+     * accurate.
+     */
+    public long computeDurationHint() {
+        return (getStartOffset() + getDuration()) * (getRepeatCount() + 1);
+    }
+    
+    /**
      * Gets the transformation to apply at a specified point in time. Implementations of this
      * method should always replace the specified Transformation or document they are doing
      * otherwise.
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 3c5920f..688da70 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -224,6 +224,23 @@
     }
 
     /**
+     * The duration hint of an animation set is the maximum of the duration
+     * hints of all of its component animations.
+     * 
+     * @see android.view.animation.Animation#computeDurationHint
+     */
+    public long computeDurationHint() {
+        long duration = 0;
+        final int count = mAnimations.size();
+        final ArrayList<Animation> animations = mAnimations;
+        for (int i = count - 1; i >= 0; --i) {
+            final long d = animations.get(i).computeDurationHint();
+            if (d > duration) duration = d;
+        }
+        return duration;
+    }
+    
+    /**
      * The transformation of an animation set is the concatenation of all of its
      * component animations.
      * 
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index c7a0cc8..f9e85bf 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -134,6 +134,14 @@
     
     @Override
     public String toString() {
-        return "Transformation{alpha=" + mAlpha + " matrix=" + mMatrix + "}";
+        return "Transformation{alpha=" + mAlpha + " matrix="
+                + mMatrix.toShortString() + "}";
+    }
+    
+    /**
+     * Return a string representation of the transformation in a compact form.
+     */
+    public String toShortString() {
+        return "{alpha=" + mAlpha + " matrix=" + mMatrix.toShortString() + "}";
     }
 }
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
new file mode 100644
index 0000000..4416ee5
--- /dev/null
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewRoot;
+
+/**
+ * Base class for implementors of the InputConnection interface, taking care
+ * of implementing common system-oriented parts of the functionality.
+ */
+public abstract class BaseInputConnection implements InputConnection {
+    final InputMethodManager mIMM;
+    final Handler mH;
+    final View mTargetView;
+    
+    BaseInputConnection(InputMethodManager mgr) {
+        mIMM = mgr;
+        mTargetView = null;
+        mH = null;
+    }
+    
+    public BaseInputConnection(View targetView) {
+        mIMM = (InputMethodManager)targetView.getContext().getSystemService(
+                Context.INPUT_METHOD_SERVICE);
+        mH = targetView.getHandler();
+        mTargetView = targetView;
+    }
+    
+    /**
+     * Provides standard implementation for sending a key event to the window
+     * attached to the input connection's view.
+     */
+    public boolean sendKeyEvent(KeyEvent event) {
+        synchronized (mIMM.mH) {
+            Handler h = mH;
+            if (h == null) {
+                if (mIMM.mServedView != null) {
+                    h = mIMM.mServedView.getHandler();
+                }
+            }
+            if (h != null && mTargetView != null) {
+                h.post(new DispatchKey(event, mTargetView.getRootView()));
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Provides standard implementation for hiding the status icon associated
+     * with the current input method.
+     */
+    public boolean hideStatusIcon() {
+        mIMM.updateStatusIcon(0, null);
+        return true;
+    }
+    
+    /**
+     * Provides standard implementation for showing the status icon associated
+     * with the current input method.
+     */
+    public boolean showStatusIcon(String packageName, int resId) {
+        mIMM.updateStatusIcon(resId, packageName);
+        return true;
+    }
+    
+    static class DispatchKey implements Runnable {
+        KeyEvent mEvent;
+        View mView;
+        
+        DispatchKey(KeyEvent event, View v) {
+            mEvent = event;
+            mView = v;
+        }
+        
+        public void run() {
+            mView.dispatchKeyEvent(mEvent);
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/view/inputmethod/CompletionInfo.aidl b/core/java/android/view/inputmethod/CompletionInfo.aidl
new file mode 100644
index 0000000..e601054
--- /dev/null
+++ b/core/java/android/view/inputmethod/CompletionInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+parcelable CompletionInfo;
diff --git a/core/java/android/view/inputmethod/CompletionInfo.java b/core/java/android/view/inputmethod/CompletionInfo.java
new file mode 100644
index 0000000..3a8fe72
--- /dev/null
+++ b/core/java/android/view/inputmethod/CompletionInfo.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * Information about a single text completion that an editor has reported to
+ * an input method.
+ */
+public final class CompletionInfo implements Parcelable {
+    static final String TAG = "CompletionInfo";
+    
+    final long mId;
+    final int mPosition;
+    final CharSequence mText;
+    final CharSequence mLabel;
+    
+    /**
+     * Create a simple completion with just text, no label.
+     */
+    public CompletionInfo(long id, int index, CharSequence text) {
+        mId = id;
+        mPosition = index;
+        mText = text;
+        mLabel = null;
+    }
+
+    /**
+     * Create a full completion with both text and label.
+     */
+    public CompletionInfo(long id, int index, CharSequence text, CharSequence label) {
+        mId = id;
+        mPosition = index;
+        mText = text;
+        mLabel = label;
+    }
+
+    CompletionInfo(Parcel source) {
+        mId = source.readLong();
+        mPosition = source.readInt();
+        mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+        mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+    }
+    
+    /**
+     * Return the abstract identifier for this completion, typically
+     * corresponding to the id associated with it in the original adapter.
+     */
+    public long getId() {
+        return mId;
+    }
+    
+    /**
+     * Return the original position of this completion, typically
+     * corresponding to its position in the original adapter.
+     */
+    public int getPosition() {
+        return mPosition;
+    }
+    
+    /**
+     * Return the actual text associated with this completion.  This is the
+     * real text that will be inserted into the editor if the user selects it.
+     */
+    public CharSequence getText() {
+        return mText;
+    }
+    
+    /**
+     * Return the user-visible label for the completion, or null if the plain
+     * text should be shown.  If non-null, this will be what the user sees as
+     * the completion option instead of the actual text.
+     */
+    public CharSequence getLabel() {
+        return mLabel;
+    }
+    
+    @Override
+    public String toString() {
+        return "CompletionInfo{#" + mPosition + " \"" + mText
+                + "\" id=" + mId + " label=" + mLabel + "}";
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     * 
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mId);
+        dest.writeInt(mPosition);
+        TextUtils.writeToParcel(mText, dest, flags);
+        TextUtils.writeToParcel(mLabel, dest, flags);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<CompletionInfo> CREATOR
+            = new Parcelable.Creator<CompletionInfo>() {
+        public CompletionInfo createFromParcel(Parcel source) {
+            return new CompletionInfo(source);
+        }
+
+        public CompletionInfo[] newArray(int size) {
+            return new CompletionInfo[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/inputmethod/DefaultInputMethod.java b/core/java/android/view/inputmethod/DefaultInputMethod.java
new file mode 100644
index 0000000..da5cab5
--- /dev/null
+++ b/core/java/android/view/inputmethod/DefaultInputMethod.java
@@ -0,0 +1,239 @@
+package android.view.inputmethod;
+
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethod;
+import com.android.internal.view.IInputMethodCallback;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.InputConnectionWrapper;
+
+/**
+ * This is the default input method that runs in the same context of the
+ * application that requests text input. It does nothing but returns false for
+ * any key events, so that all key events will be processed by the key listener
+ * of the focused text box.
+ * {@hide}
+ */
+public class DefaultInputMethod implements InputMethod, InputMethodSession {
+    private static IInputMethod sInstance = new SimpleInputMethod(
+            new DefaultInputMethod());
+
+    private static InputMethodInfo sProperty = new InputMethodInfo(
+            "android.text.inputmethod", DefaultInputMethod.class.getName(),
+            "Default", "android.text.inputmethod.defaultImeSettings");
+
+    private InputConnection mInputConnection;
+
+    public static IInputMethod getInstance() {
+        return sInstance;
+    }
+
+    public static InputMethodInfo getMetaInfo() {
+        return sProperty;
+    }
+
+    public void bindInput(InputBinding binding) {
+        mInputConnection = binding.getConnection();
+    }
+
+    public void unbindInput() {
+    }
+
+    public void createSession(SessionCallback callback) {
+        callback.sessionCreated(this);
+    }
+
+    public void setSessionEnabled(InputMethodSession session, boolean enabled) {
+    }
+
+    public void revokeSession(InputMethodSession session) {
+    }
+
+    public void finishInput() {
+        mInputConnection.hideStatusIcon();
+    }
+
+    public void displayCompletions(CompletionInfo[] completions) {
+    }
+    
+    public void updateExtractedText(int token, ExtractedText text) {
+    }
+    
+    public void updateSelection(int oldSelStart, int oldSelEnd,
+            int newSelStart, int newSelEnd) {
+    }
+
+    public void updateCursor(Rect newCursor) {
+    }
+
+    public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) {
+        callback.finishedEvent(seq, false);
+    }
+
+    public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback) {
+        callback.finishedEvent(seq, false);
+    }
+
+    public void restartInput(EditorInfo attribute) {
+    }
+
+    public void attachToken(IBinder token) {
+    }
+
+    public void startInput(EditorInfo attribute) {
+        mInputConnection
+                .showStatusIcon("android", com.android.internal.R.drawable.ime_qwerty);
+    }
+
+    public void appPrivateCommand(String action, Bundle data) {
+    }
+    
+    public void hideSoftInput() {
+    }
+
+    public void showSoftInput() {
+    }
+}
+
+// ----------------------------------------------------------------------
+
+class SimpleInputMethod extends IInputMethod.Stub {
+    final InputMethod mInputMethod;
+
+    static class Session extends IInputMethodSession.Stub {
+        final InputMethodSession mSession;
+        
+        Session(InputMethodSession session) {
+            mSession = session;
+        }
+        
+        public void finishInput() {
+            mSession.finishInput();
+        }
+        
+        public void updateSelection(int oldSelStart, int oldSelEnd,
+                int newSelStart, int newSelEnd) {
+            mSession.updateSelection(oldSelStart, oldSelEnd,
+                    newSelStart, newSelEnd);
+        }
+
+        public void updateCursor(Rect newCursor) {
+            mSession.updateCursor(newCursor);
+        }
+
+        static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback {
+            final IInputMethodCallback mCb;
+            InputMethodEventCallbackWrapper(IInputMethodCallback cb) {
+                mCb = cb;
+            }
+            public void finishedEvent(int seq, boolean handled) {
+                try {
+                    mCb.finishedEvent(seq, handled);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        
+        public void dispatchKeyEvent(int seq, KeyEvent event, IInputMethodCallback callback) {
+            mSession.dispatchKeyEvent(seq, event,
+                    new InputMethodEventCallbackWrapper(callback));
+        }
+
+        public void dispatchTrackballEvent(int seq, MotionEvent event, IInputMethodCallback callback) {
+            mSession.dispatchTrackballEvent(seq, event,
+                    new InputMethodEventCallbackWrapper(callback));
+        }
+        
+        public void displayCompletions(CompletionInfo[] completions) {
+            mSession.displayCompletions(completions);
+        }
+        
+        public void updateExtractedText(int token, ExtractedText text) {
+            mSession.updateExtractedText(token, text);
+        }
+        
+        public void appPrivateCommand(String action, Bundle data) {
+            mSession.appPrivateCommand(action, data);
+        }
+    }
+    
+    public SimpleInputMethod(InputMethod inputMethod) {
+        mInputMethod = inputMethod;
+    }
+
+    public InputMethod getInternalInputMethod() {
+        return mInputMethod;
+    }
+
+    public void attachToken(IBinder token) {
+        mInputMethod.attachToken(token);
+    }
+    
+    public void bindInput(InputBinding binding) {
+        InputConnectionWrapper ic = new InputConnectionWrapper(
+                IInputContext.Stub.asInterface(binding.getConnectionToken()));
+        InputBinding nu = new InputBinding(ic, binding);
+        mInputMethod.bindInput(nu);
+    }
+
+    public void unbindInput() {
+        mInputMethod.unbindInput();
+    }
+
+    public void restartInput(EditorInfo attribute) {
+        mInputMethod.restartInput(attribute);
+    }
+
+    public void startInput(EditorInfo attribute) {
+        mInputMethod.startInput(attribute);
+    }
+
+    static class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {
+        final IInputMethodCallback mCb;
+        InputMethodSessionCallbackWrapper(IInputMethodCallback cb) {
+            mCb = cb;
+        }
+        
+        public void sessionCreated(InputMethodSession session) {
+            try {
+                mCb.sessionCreated(new Session(session));
+            } catch (RemoteException e) {
+            }
+        }
+    }
+    
+    public void createSession(IInputMethodCallback callback) throws RemoteException {
+        mInputMethod.createSession(new InputMethodSessionCallbackWrapper(callback));
+    }
+
+    public void setSessionEnabled(IInputMethodSession session, boolean enabled) throws RemoteException {
+        try {
+            InputMethodSession ls = ((Session)session).mSession;
+            mInputMethod.setSessionEnabled(ls, enabled);
+        } catch (ClassCastException e) {
+            Log.w("SimpleInputMethod", "Incoming session not of correct type: " + session, e);
+        }
+    }
+
+    public void revokeSession(IInputMethodSession session) throws RemoteException {
+        try {
+            InputMethodSession ls = ((Session)session).mSession;
+            mInputMethod.revokeSession(ls);
+        } catch (ClassCastException e) {
+            Log.w("SimpleInputMethod", "Incoming session not of correct type: " + session, e);
+        }
+    }
+
+    public void showSoftInput() {
+    }
+    
+    public void hideSoftInput() {
+    }
+}
diff --git a/core/java/android/view/inputmethod/EditorInfo.aidl b/core/java/android/view/inputmethod/EditorInfo.aidl
new file mode 100644
index 0000000..48068f0
--- /dev/null
+++ b/core/java/android/view/inputmethod/EditorInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+parcelable EditorInfo;
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
new file mode 100644
index 0000000..c050691
--- /dev/null
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -0,0 +1,126 @@
+package android.view.inputmethod;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.InputType;
+import android.text.TextUtils;
+
+/**
+ * An EditorInfo describes several attributes of a text editing object
+ * that an input method is communicating with (typically an EditText), most
+ * importantly the type of text content it contains.
+ */
+public class EditorInfo implements InputType, Parcelable {
+    /**
+     * The content type of the text box, whose bits are defined by
+     * {@link InputType}.
+     * 
+     * @see InputType
+     * @see #TYPE_MASK_CLASS
+     * @see #TYPE_MASK_VARIATION
+     * @see #TYPE_MASK_FLAGS
+     */
+    public int inputType = TYPE_CLASS_TEXT;
+
+    /**
+     * A string supplying additional information about the content type that
+     * is private to a particular IME implementation.  The string must be
+     * scoped to a package owned by the implementation, to ensure there are
+     * no conflicts between implementations, but other than that you can put
+     * whatever you want in it to communicate with the IME.  For example,
+     * you could have a string that supplies an argument like
+     * <code>"com.example.myapp.SpecialMode=3"</code>.  This field is can be
+     * filled in from the {@link android.R.attr#editorPrivateContentType}
+     * attribute of a TextView.
+     */
+    public String privateContentType = null;
+    
+    /**
+     * The text offset of the start of the selection at the time editing
+     * began; -1 if not known.
+     */
+    public int initialSelStart = -1;
+    
+    /**
+     * The text offset of the end of the selection at the time editing
+     * began; -1 if not known.
+     */
+    public int initialSelEnd = -1;
+    
+    /**
+     * The capitalization mode of the first character being edited in the
+     * text.  Values may be any combination of
+     * {@link TextUtils#CAP_MODE_CHARACTERS TextUtils.CAP_MODE_CHARACTERS},
+     * {@link TextUtils#CAP_MODE_WORDS TextUtils.CAP_MODE_WORDS}, and
+     * {@link TextUtils#CAP_MODE_SENTENCES TextUtils.CAP_MODE_SENTENCES}, though
+     * you should generally just take a non-zero value to mean start out in
+     * caps mode.
+     */
+    public int initialCapsMode = 0;
+    
+    /**
+     * The "hint" text of the text view, typically shown in-line when the
+     * text is empty to tell the user what to enter.
+     */
+    public CharSequence hintText;
+    
+    /**
+     * A label to show to the user describing the text they are writing.
+     */
+    public CharSequence label;
+    
+    /**
+     * Any extra data to supply to the input method.  This is for extended
+     * communication with specific input methods; the name fields in the
+     * bundle should be scoped (such as "com.mydomain.im.SOME_FIELD") so
+     * that they don't conflict with others.  This field is can be
+     * filled in from the {@link android.R.attr#editorExtras}
+     * attribute of a TextView.
+     */
+    public Bundle extras;
+    
+    /**
+     * Used to package this object into a {@link Parcel}.
+     * 
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(inputType);
+        dest.writeString(privateContentType);
+        dest.writeInt(initialSelStart);
+        dest.writeInt(initialSelEnd);
+        dest.writeInt(initialCapsMode);
+        TextUtils.writeToParcel(hintText, dest, flags);
+        TextUtils.writeToParcel(label, dest, flags);
+        dest.writeBundle(extras);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<EditorInfo> CREATOR = new Parcelable.Creator<EditorInfo>() {
+        public EditorInfo createFromParcel(Parcel source) {
+            EditorInfo res = new EditorInfo();
+            res.inputType = source.readInt();
+            res.privateContentType = source.readString();
+            res.initialSelStart = source.readInt();
+            res.initialSelEnd = source.readInt();
+            res.initialCapsMode = source.readInt();
+            res.hintText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+            res.label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+            res.extras = source.readBundle();
+            return res;
+        }
+
+        public EditorInfo[] newArray(int size) {
+            return new EditorInfo[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+
+}
diff --git a/core/java/android/view/inputmethod/ExtractedText.aidl b/core/java/android/view/inputmethod/ExtractedText.aidl
new file mode 100644
index 0000000..95e56d7
--- /dev/null
+++ b/core/java/android/view/inputmethod/ExtractedText.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+parcelable ExtractedText;
diff --git a/core/java/android/view/inputmethod/ExtractedText.java b/core/java/android/view/inputmethod/ExtractedText.java
new file mode 100644
index 0000000..0ca3c79
--- /dev/null
+++ b/core/java/android/view/inputmethod/ExtractedText.java
@@ -0,0 +1,82 @@
+package android.view.inputmethod;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * Information about text that has been extracted for use by an input method.
+ */
+public class ExtractedText implements Parcelable {
+    /**
+     * The text that has been extracted.
+     */
+    public CharSequence text;
+
+    /**
+     * The offset in the overall text at which the extracted text starts.
+     */
+    public int startOffset;
+    
+    /**
+     * The offset where the selection currently starts within the extracted
+     * text.  The real selection start position is at
+     * <var>startOffset</var>+<var>selectionStart</var>.
+     */
+    public int selectionStart;
+    
+    /**
+     * The offset where the selection currently ends within the extracted
+     * text.  The real selection end position is at
+     * <var>startOffset</var>+<var>selectionEnd</var>.
+     */
+    public int selectionEnd;
+    
+    /**
+     * Bit for {@link #flags}: set if the text being edited can only be on
+     * a single line.
+     */
+    public static final int FLAG_SINGLE_LINE = 0x0001;
+    
+    /**
+     * Additional bit flags of information about the edited text.
+     */
+    public int flags;
+    
+    /**
+     * Used to package this object into a {@link Parcel}.
+     * 
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        TextUtils.writeToParcel(text, dest, flags);
+        dest.writeInt(startOffset);
+        dest.writeInt(selectionStart);
+        dest.writeInt(selectionEnd);
+        dest.writeInt(flags);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<ExtractedText> CREATOR = new Parcelable.Creator<ExtractedText>() {
+        public ExtractedText createFromParcel(Parcel source) {
+            ExtractedText res = new ExtractedText();
+            res.text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+            res.startOffset = source.readInt();
+            res.selectionStart = source.readInt();
+            res.selectionEnd = source.readInt();
+            res.flags = source.readInt();
+            return res;
+        }
+
+        public ExtractedText[] newArray(int size) {
+            return new ExtractedText[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/inputmethod/ExtractedTextRequest.aidl b/core/java/android/view/inputmethod/ExtractedTextRequest.aidl
new file mode 100644
index 0000000..c69acc7
--- /dev/null
+++ b/core/java/android/view/inputmethod/ExtractedTextRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+parcelable ExtractedTextRequest;
diff --git a/core/java/android/view/inputmethod/ExtractedTextRequest.java b/core/java/android/view/inputmethod/ExtractedTextRequest.java
new file mode 100644
index 0000000..d962329
--- /dev/null
+++ b/core/java/android/view/inputmethod/ExtractedTextRequest.java
@@ -0,0 +1,61 @@
+package android.view.inputmethod;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * Description of what an input method would like from an application when
+ * extract text from its input editor.
+ */
+public class ExtractedTextRequest implements Parcelable {
+    /**
+     * Arbitrary integer that can be supplied in the request, which will be
+     * delivered back when reporting updates.
+     */
+    public int token;
+    
+    /**
+     * Hint for the maximum number of lines to return.
+     */
+    public int hintMaxLines;
+    
+    /**
+     * Hint for the maximum number of characters to return.
+     */
+    public int hintMaxChars;
+    
+    /**
+     * Used to package this object into a {@link Parcel}.
+     * 
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(token);
+        dest.writeInt(hintMaxLines);
+        dest.writeInt(hintMaxChars);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<ExtractedTextRequest> CREATOR
+            = new Parcelable.Creator<ExtractedTextRequest>() {
+        public ExtractedTextRequest createFromParcel(Parcel source) {
+            ExtractedTextRequest res = new ExtractedTextRequest();
+            res.token = source.readInt();
+            res.hintMaxLines = source.readInt();
+            res.hintMaxChars = source.readInt();
+            return res;
+        }
+
+        public ExtractedTextRequest[] newArray(int size) {
+            return new ExtractedTextRequest[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/inputmethod/InputBinding.aidl b/core/java/android/view/inputmethod/InputBinding.aidl
new file mode 100644
index 0000000..ea09d8b
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputBinding.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+parcelable InputBinding;
diff --git a/core/java/android/view/inputmethod/InputBinding.java b/core/java/android/view/inputmethod/InputBinding.java
new file mode 100644
index 0000000..f4209ef
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputBinding.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * Information given to an {@link InputMethod} about a client connecting
+ * to it.
+ */
+public final class InputBinding implements Parcelable {
+    static final String TAG = "InputBinding";
+    
+    /**
+     * The connection back to the client.
+     */
+    final InputConnection mConnection;
+    
+    /**
+     * A remotable token for the connection back to the client.
+     */
+    final IBinder mConnectionToken;
+    
+    /**
+     * The UID where this binding came from.
+     */
+    final int mUid;
+    
+    /**
+     * The PID where this binding came from.
+     */
+    final int mPid;
+    
+    /**
+     * Constructor.
+     * 
+     * @param conn The interface for communicating back with the application.
+     * @param connToken A remoteable token for communicating across processes.
+     * @param uid The user id of the client of this binding.
+     * @param pid The process id of where the binding came from.
+     */
+    public InputBinding(InputConnection conn, IBinder connToken,
+            int uid, int pid) {
+        mConnection = conn;
+        mConnectionToken = connToken;
+        mUid = uid;
+        mPid = pid;
+    }
+
+    /**
+     * Constructor from an existing InputBinding taking a new local input
+     * connection interface.
+     * 
+     * @param conn The new connection interface.
+     * @param binding Existing binding to copy.
+     */
+    public InputBinding(InputConnection conn, InputBinding binding) {
+        mConnection = conn;
+        mConnectionToken = binding.getConnectionToken();
+        mUid = binding.getUid();
+        mPid = binding.getPid();
+    }
+
+    InputBinding(Parcel source) {
+        mConnection = null;
+        mConnectionToken = source.readStrongBinder();
+        mUid = source.readInt();
+        mPid = source.readInt();
+    }
+    
+    /**
+     * Return the connection for interacting back with the application.
+     */
+    public InputConnection getConnection() {
+        return mConnection;
+    }
+    
+    /**
+     * Return the token for the connection back to the application.  You can
+     * not use this directly, it must be converted to a {@link InputConnection}
+     * for you.
+     */
+    public IBinder getConnectionToken() {
+        return mConnectionToken;
+    }
+    
+    /**
+     * Return the user id of the client associated with this binding.
+     */
+    public int getUid() {
+        return mUid;
+    }
+    
+    /**
+     * Return the process id where this binding came from.
+     */
+    public int getPid() {
+        return mPid;
+    }
+    
+    @Override
+    public String toString() {
+        return "InputBinding{" + mConnectionToken
+                + " / uid " + mUid + " / pid " + mPid + "}";
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     * 
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mConnectionToken);
+        dest.writeInt(mUid);
+        dest.writeInt(mPid);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<InputBinding> CREATOR = new Parcelable.Creator<InputBinding>() {
+        public InputBinding createFromParcel(Parcel source) {
+            return new InputBinding(source);
+        }
+
+        public InputBinding[] newArray(int size) {
+            return new InputBinding[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
new file mode 100644
index 0000000..5f8ba1f
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.os.Bundle;
+import android.text.Spanned;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+
+/**
+ * The InputConnection interface is the communication channel from an
+ * {@link InputMethod} back to the application that is receiving its input. It
+ * is used to perform such things as reading text around the cursor,
+ * committing text to the text box, and sending raw key events to the application.
+ */
+public interface InputConnection {
+    /**
+     * Get <var>n</var> characters of text before the current cursor position.
+     * 
+     * <p>This method may fail either if the input connection has become invalid
+     * (such as its process crashing) or the client is taking too long to
+     * respond with the text (it is given a couple seconds to return).
+     * In either case, a null is returned.
+     * 
+     * @param n The expected length of the text.
+     * 
+     * @return Returns the text before the cursor position; the length of the
+     * returned text might be less than <var>n</var>.
+     */
+    public CharSequence getTextBeforeCursor(int n);
+
+    /**
+     * Get <var>n</var> characters of text after the current cursor position.
+     * 
+     * <p>This method may fail either if the input connection has become invalid
+     * (such as its process crashing) or the client is taking too long to
+     * respond with the text (it is given a couple seconds to return).
+     * In either case, a null is returned.
+     * 
+     * @param n The expected length of the text.
+     * 
+     * @return Returns the text after the cursor position; the length of the
+     * returned text might be less than <var>n</var>.
+     */
+    public CharSequence getTextAfterCursor(int n);
+
+    /**
+     * Retrieve the current capitalization mode in effect at the current
+     * cursor position in the text.  See
+     * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode} for
+     * more information.
+     * 
+     * <p>This method may fail either if the input connection has become invalid
+     * (such as its process crashing) or the client is taking too long to
+     * respond with the text (it is given a couple seconds to return).
+     * In either case, a 0 is returned.
+     * 
+     * @param reqModes The desired modes to retrieve, as defined by
+     * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}.  These
+     * constants are defined so that you can simply pass the current
+     * {@link EditorInfo#inputType TextBoxAttribute.contentType} value
+     * directly in to here.
+     * 
+     * @return Returns the caps mode flags that are in effect.
+     */
+    public int getCursorCapsMode(int reqModes);
+    
+    public static final int EXTRACTED_TEXT_MONITOR = 0x0001;
+    
+    /**
+     * Retrieve the current text in the input connection's editor, and monitor
+     * for any changes to it.  This function returns with the current text,
+     * and optionally the input connection can send updates to the
+     * input method when its text changes.
+     * 
+     * <p>This method may fail either if the input connection has become invalid
+     * (such as its process crashing) or the client is taking too long to
+     * respond with the text (it is given a couple seconds to return).
+     * In either case, a null is returned.
+     * 
+     * @param request Description of how the text should be returned.
+     * @param flags Additional options to control the client, either 0 or
+     * {@link #EXTRACTED_TEXT_MONITOR}.
+     * 
+     * @return Returns an ExtractedText object describing the state of the
+     * text view and containing the extracted text itself.
+     */
+    public ExtractedText getExtractedText(ExtractedTextRequest request,
+            int flags);
+
+    /**
+     * Delete <var>leftLength</var> characters of text before the current cursor
+     * position, and delete <var>rightLength</var> characters of text after the
+     * current cursor position, excluding composing text.
+     * 
+     * @param leftLength The number of characters to be deleted before the
+     *        current cursor position.
+     * @param rightLength The number of characters to be deleted after the
+     *        current cursor position.
+     *        
+     * @return Returns true on success, false if the input connection is no longer
+     * valid.
+     */
+    boolean deleteSurroundingText(int leftLength, int rightLength);
+
+    /**
+     * Set composing text around the current cursor position with the given text,
+     * and set the new cursor position.  Any composing text set previously will
+     * be removed automatically.
+     * 
+     * @param text The composing text with styles if necessary. If no style
+     *        object attached to the text, the default style for composing text
+     *        is used. See {#link android.text.Spanned} for how to attach style
+     *        object to the text. {#link android.text.SpannableString} and
+     *        {#link android.text.SpannableStringBuilder} are two
+     *        implementations of the interface {#link android.text.Spanned}.
+     * @param newCursorPosition The new cursor position within the
+     *        <var>text</var>.
+     * 
+     * @return Returns true on success, false if the input connection is no longer
+     * valid.
+     */
+    public boolean setComposingText(CharSequence text, int newCursorPosition);
+
+    /**
+     * Commit text to the text box and set the new cursor position.
+     * Any composing text set previously will be removed
+     * automatically.
+     * 
+     * @param text The committed text.
+     * @param newCursorPosition The new cursor position within the
+     *        <var>text</var>.
+     * 
+     *        
+     * @return Returns true on success, false if the input connection is no longer
+     * valid.
+     */
+    public boolean commitText(CharSequence text, int newCursorPosition);
+
+    /**
+     * Commit a completion the user has selected from the possible ones
+     * previously reported to {@link InputMethodSession#displayCompletions
+     * InputMethodSession.displayCompletions()}.  This will result in the
+     * same behavior as if the user had selected the completion from the
+     * actual UI.
+     * 
+     * @param text The committed completion.
+     *        
+     * @return Returns true on success, false if the input connection is no longer
+     * valid.
+     */
+    public boolean commitCompletion(CompletionInfo text);
+
+    /**
+     * Send a key event to the process that is currently attached through
+     * this input connection.  The event will be dispatched like a normal
+     * key event, to the currently focused; this generally is the view that
+     * is providing this InputConnection, but due to the asynchronous nature
+     * of this protocol that can not be guaranteed and the focus may have
+     * changed by the time the event is received.
+     * 
+     * <p>
+     * This method can be used to send key events to the application. For
+     * example, an on-screen keyboard may use this method to simulate a hardware
+     * keyboard. There are three types of standard keyboards, numeric (12-key),
+     * predictive (20-key) and ALPHA (QWERTY). You can specify the keyboard type
+     * by specify the device id of the key event.
+     * 
+     * <p>
+     * You will usually want to set the flag
+     * {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD} on all
+     * key event objects you give to this API; the flag will not be set
+     * for you.
+     * 
+     * @param event The key event.
+     *        
+     * @return Returns true on success, false if the input connection is no longer
+     * valid.
+     * 
+     * @see KeyEvent
+     * @see KeyCharacterMap#NUMERIC
+     * @see KeyCharacterMap#PREDICTIVE
+     * @see KeyCharacterMap#ALPHA
+     */
+    public boolean sendKeyEvent(KeyEvent event);
+
+    /**
+     * Clear the given meta key pressed states in the given input connection.
+     * 
+     * @param states The states to be cleared, may be one or more bits as
+     * per {@link KeyEvent#getMetaState() KeyEvent.getMetaState()}.
+     * 
+     * @return Returns true on success, false if the input connection is no longer
+     * valid.
+     */
+    public boolean clearMetaKeyStates(int states);
+    
+    /**
+     * API to send private commands from an input method to its connected
+     * editor.  This can be used to provide domain-specific features that are
+     * only known between certain input methods and their clients.  Note that
+     * because the InputConnection protocol is asynchronous, you have no way
+     * to get a result back or know if the client understood the command; you
+     * can use the information in {@link EditorInfo} to determine if
+     * a client supports a particular command.
+     * 
+     * @param action Name of the command to be performed.  This <em>must</em>
+     * be a scoped name, i.e. prefixed with a package name you own, so that
+     * different developers will not create conflicting commands.
+     * @param data Any data to include with the command.
+     * @return Returns true if the command was sent (whether or not the
+     * associated editor understood it), false if the input connection is no longer
+     * valid.
+     */
+    public boolean performPrivateCommand(String action, Bundle data);
+    
+    /**
+     * Show an icon in the status bar.
+     * 
+     * @param packageName The package holding the icon resource to be shown.
+     * @param resId The resource id of the icon to show.
+     *        
+     * @return Returns true on success, false if the input connection is no longer
+     * valid.
+     */
+    public boolean showStatusIcon(String packageName, int resId);
+    
+    /**
+     * Hide the icon shown in the status bar.
+     *        
+     * @return Returns true on success, false if the input connection is no longer
+     * valid.
+     */
+    public boolean hideStatusIcon();
+}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
new file mode 100644
index 0000000..f150ad6
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.os.Bundle;
+import android.view.KeyEvent;
+
+/**
+ * Wrapper around InputConnection interface, calling through to another
+ * implementation of it.
+ */
+public class InputConnectionWrapper implements InputConnection {
+    InputConnection mBase;
+    
+    /**
+     * Create a new wrapper around an existing InputConnection implementation.
+     */
+    public InputConnectionWrapper(InputConnection base) {
+        mBase = base;
+    }
+    
+    /**
+     * Return the base InputConnection that this class is wrapping.
+     */
+    InputConnection getBase() {
+        return mBase;
+    }
+    
+    public CharSequence getTextBeforeCursor(int n) {
+        return mBase.getTextBeforeCursor(n);
+    }
+
+    public CharSequence getTextAfterCursor(int n) {
+        return mBase.getTextAfterCursor(n);
+    }
+
+    public int getCursorCapsMode(int reqModes) {
+        return mBase.getCursorCapsMode(reqModes);
+    }
+    
+    public ExtractedText getExtractedText(ExtractedTextRequest request,
+            int flags) {
+        return mBase.getExtractedText(request, flags);
+    }
+
+    public boolean deleteSurroundingText(int leftLength, int rightLength) {
+        return mBase.deleteSurroundingText(leftLength, rightLength);
+    }
+
+    public boolean setComposingText(CharSequence text, int newCursorPosition) {
+        return mBase.setComposingText(text, newCursorPosition);
+    }
+
+    public boolean commitText(CharSequence text, int newCursorPosition) {
+        return mBase.commitText(text, newCursorPosition);
+    }
+
+    public boolean commitCompletion(CompletionInfo text) {
+        return mBase.commitCompletion(text);
+    }
+    
+    public boolean sendKeyEvent(KeyEvent event) {
+        return mBase.sendKeyEvent(event);
+    }
+
+    public boolean clearMetaKeyStates(int states) {
+        return mBase.clearMetaKeyStates(states);
+    }
+    
+    public boolean performPrivateCommand(String action, Bundle data) {
+        return mBase.performPrivateCommand(action, data);
+    }
+    
+    public boolean showStatusIcon(String packageName, int resId) {
+        return mBase.showStatusIcon(packageName, resId);
+    }
+    
+    public boolean hideStatusIcon() {
+        return mBase.hideStatusIcon();
+    }
+}
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
new file mode 100644
index 0000000..259e759
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.graphics.Rect;
+import android.inputmethodservice.InputMethodService;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+/**
+ * The InputMethod interface represents an input method which can generate key
+ * events and text, such as digital, email addresses, CJK characters, other
+ * language characters, and etc., while handling various input events, and send
+ * the text back to the application that requests text input.
+ * 
+ * <p>Applications will not normally use this interface themselves, instead
+ * relying on the standard interaction provided by
+ * {@link android.widget.TextView} and {@link android.widget.EditText}.
+ * 
+ * <p>Those implementing input methods should normally do so by deriving from
+ * {@link InputMethodService} or one of its subclasses.  When implementing
+ * an input method, the service component containing it must also supply
+ * a {@link #SERVICE_META_DATA} meta-data field, referencing an XML resource
+ * providing details about the input method.  All input methods also must
+ * require that clients hold the
+ * {@link android.Manifest.permission#BIND_INPUT_METHOD} in order to interact
+ * with the service; if this is not required, the system will not use that
+ * input method, because it can not trust that it is not compromised.
+ */
+public interface InputMethod {
+    /**
+     * This is the interface name that a service implementing an input
+     * method should say that it supports -- that is, this is the action it
+     * uses for its intent filter.  (Note: this name is used because this
+     * interface should be moved to the view package.)
+     */
+    public static final String SERVICE_INTERFACE = "android.view.InputMethod";
+    
+    /**
+     * Name under which an InputMethod service component publishes information
+     * about itself.  This meta-data must reference an XML resource containing
+     * an
+     * <code>&lt;{@link android.R.styleable#InputMethod input-method}&gt;</code>
+     * tag.
+     */
+    public static final String SERVICE_META_DATA = "android.view.im";
+    
+    public interface SessionCallback {
+        public void sessionCreated(InputMethodSession session);
+    }
+    
+    /**
+     * Called first thing after an input method is created, this supplies a
+     * unique token for the session it has with the system service.  It is
+     * needed to identify itself with the service to validate its operations.
+     * This token <strong>must not</strong> be passed to applications, since
+     * it grants special priviledges that should not be given to applications.
+     * 
+     * <p>Note: to protect yourself from malicious clients, you should only
+     * accept the first token given to you.  Any after that may come from the
+     * client.
+     */
+    public void attachToken(IBinder token);
+    
+    /**
+     * Bind a new application environment in to the input method, so that it
+     * can later start and stop input processing.
+     * Typically this method is called when this input method is enabled in an
+     * application for the first time.
+     * 
+     * @param binding Information about the application window that is binding
+     * to the input method.
+     * 
+     * @see InputBinding
+     * @see #unbindInput()
+     */
+    public void bindInput(InputBinding binding);
+
+    /**
+     * Unbind an application environment, called when the information previously
+     * set by {@link #bindInput} is no longer valid for this input method.
+     * 
+     * <p>
+     * Typically this method is called when the application changes to be
+     * non-foreground.
+     */
+    public void unbindInput();
+
+    /**
+     * This method is called when the application starts to receive text and it
+     * is ready for this input method to process received events and send result
+     * text back to the application.
+     * 
+     * @param attribute The attribute of the text box (typically, a EditText)
+     *        that requests input.
+     * 
+     * @see EditorInfo
+     */
+    public void startInput(EditorInfo attribute);
+
+    /**
+     * This method is called when the state of this input method needs to be
+     * reset.
+     * 
+     * <p>
+     * Typically, this method is called when the input focus is moved from one
+     * text box to another.
+     * 
+     * @param attribute The attribute of the text box (typically, a EditText)
+     *        that requests input.
+     * 
+     * @see EditorInfo
+     */
+    public void restartInput(EditorInfo attribute);
+
+    /**
+     * Create a new {@link InputMethodSession} that can be handed to client
+     * applications for interacting with the input method.  You can later
+     * use {@link #revokeSession(InputMethodSession)} to destroy the session
+     * so that it can no longer be used by any clients.
+     * 
+     * @param callback Interface that is called with the newly created session.
+     */
+    public void createSession(SessionCallback callback);
+    
+    /**
+     * Control whether a particular input method session is active.
+     * 
+     * @param session The {@link InputMethodSession} previously provided through
+     * SessionCallback.sessionCreated() that is to be changed.
+     */
+    public void setSessionEnabled(InputMethodSession session, boolean enabled);
+    
+    /**
+     * Disable and destroy a session that was previously created with
+     * {@link #createSession(android.view.inputmethod.InputMethod.SessionCallback)}.
+     * After this call, the given session interface is no longer active and
+     * calls on it will fail.
+     * 
+     * @param session The {@link InputMethodSession} previously provided through
+     * SessionCallback.sessionCreated() that is to be revoked.
+     */
+    public void revokeSession(InputMethodSession session);
+    
+    /**
+     * Request that any soft input part of the input method be shown to the user.
+     */
+    public void showSoftInput();
+    
+    /**
+     * Request that any soft input part of the input method be hidden from the user.
+     */
+    public void hideSoftInput();
+}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.aidl b/core/java/android/view/inputmethod/InputMethodInfo.aidl
new file mode 100644
index 0000000..5f4d6b6
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputMethodInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+parcelable InputMethodInfo;
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
new file mode 100644
index 0000000..e8f4b54
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Printer;
+import android.util.Xml;
+
+import java.io.IOException;
+
+/**
+ * This class is used to specify meta information of an input method.
+ */
+public final class InputMethodInfo implements Parcelable {
+    static final String TAG = "InputMethodMetaInfo";
+    
+    /**
+     * The Service that implements this input method component.
+     */
+    final ResolveInfo mService;
+    
+    /**
+     * The unique string Id to identify the input method.  This is generated
+     * from the input method component.
+     */
+    final String mId;
+
+    /**
+     * The input method setting activity's name, used by the system settings to
+     * launch the setting activity of this input method.
+     */
+    final String mSettingsActivityName;
+
+    /**
+     * The resource in the input method's .apk that holds a boolean indicating
+     * whether it should be considered the default input method for this
+     * system.  This is a resource ID instead of the final value so that it
+     * can change based on the configuration (in particular locale).
+     */
+    final int mIsDefaultResId;
+    
+    /**
+     * Constructor.
+     * 
+     * @param context The Context in which we are parsing the input method.
+     * @param service The ResolveInfo returned from the package manager about
+     * this input method's component.
+     */
+    public InputMethodInfo(Context context, ResolveInfo service)
+            throws XmlPullParserException, IOException {
+        mService = service;
+        ServiceInfo si = service.serviceInfo;
+        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+        
+        PackageManager pm = context.getPackageManager();
+        String settingsActivityComponent = null;
+        int isDefaultResId = 0;
+        
+        XmlResourceParser parser = null;
+        try {
+            parser = si.loadXmlMetaData(pm, InputMethod.SERVICE_META_DATA);
+            if (parser == null) {
+                throw new XmlPullParserException("No "
+                        + InputMethod.SERVICE_META_DATA + " meta-data");
+            }
+        
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+            
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+            }
+            
+            String nodeName = parser.getName();
+            if (!"input-method".equals(nodeName)) {
+                throw new XmlPullParserException(
+                        "Meta-data does not start with input-method tag");
+            }
+            
+            TypedArray sa = context.getResources().obtainAttributes(attrs,
+                    com.android.internal.R.styleable.InputMethod);
+            settingsActivityComponent = sa.getString(
+                    com.android.internal.R.styleable.InputMethod_settingsActivity);
+            isDefaultResId = sa.getResourceId(
+                    com.android.internal.R.styleable.InputMethod_isDefault, 0);
+            sa.recycle();
+        } finally {
+            if (parser != null) parser.close();
+        }
+        
+        mSettingsActivityName = settingsActivityComponent;
+        mIsDefaultResId = isDefaultResId;
+    }
+
+    InputMethodInfo(Parcel source) {
+        mId = source.readString();
+        mSettingsActivityName = source.readString();
+        mIsDefaultResId = source.readInt();
+        mService = ResolveInfo.CREATOR.createFromParcel(source);
+    }
+    
+    /**
+     * Temporary API for creating a built-in input method.
+     */
+    public InputMethodInfo(String packageName, String className,
+            CharSequence label, String settingsActivity) {
+        ResolveInfo ri = new ResolveInfo();
+        ServiceInfo si = new ServiceInfo();
+        ApplicationInfo ai = new ApplicationInfo();
+        ai.packageName = packageName;
+        ai.enabled = true;
+        si.applicationInfo = ai;
+        si.enabled = true;
+        si.packageName = packageName;
+        si.name = className;
+        si.exported = true;
+        si.nonLocalizedLabel = label;
+        ri.serviceInfo = si;
+        mService = ri;
+        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+        mSettingsActivityName = settingsActivity;
+        mIsDefaultResId = 0;
+    }
+    
+    /**
+     * Return a unique ID for this input method.  The ID is generated from
+     * the package and class name implementing the method.
+     */
+    public String getId() {
+        return mId;
+    }
+    
+    /**
+     * Return the .apk package that implements this input method.
+     */
+    public String getPackageName() {
+        return mService.serviceInfo.packageName;
+    }
+    
+    /**
+     * Return the class name of the service component that implements
+     * this input method.
+     */
+    public String getServiceName() {
+        return mService.serviceInfo.name;
+    }
+
+    /**
+     * Return the component of the service that implements this input
+     * method.
+     */
+    public ComponentName getComponent() {
+        return new ComponentName(mService.serviceInfo.packageName,
+                mService.serviceInfo.name);
+    }
+    
+    /**
+     * Load the user-displayed label for this input method.
+     * 
+     * @param pm Supply a PackageManager used to load the input method's
+     * resources.
+     */
+    public CharSequence loadLabel(PackageManager pm) {
+        return mService.loadLabel(pm);
+    }
+    
+    /**
+     * Load the user-displayed icon for this input method.
+     * 
+     * @param pm Supply a PackageManager used to load the input method's
+     * resources.
+     */
+    public Drawable loadIcon(PackageManager pm) {
+        return mService.loadIcon(pm);
+    }
+    
+    /**
+     * Return the class name of an activity that provides a settings UI for
+     * the input method.  You can launch this activity be starting it with
+     * an {@link android.content.Intent} whose action is MAIN and with an
+     * explicit {@link android.content.ComponentName}
+     * composed of {@link #getPackageName} and the class name returned here.
+     * 
+     * <p>A null will be returned if there is no settings activity associated
+     * with the input method.
+     */
+    public String getSettingsActivity() {
+        return mSettingsActivityName;
+    }
+    
+    /**
+     * Return the resource identifier of a resource inside of this input
+     * method's .apk that determines whether it should be considered a
+     * default input method for the system.
+     */
+    public int getIsDefaultResourceId() {
+        return mIsDefaultResId;
+    }
+    
+    /**
+     * Returns true if this input method is one of the components that is
+     * built in to the system.
+     */
+    public boolean isBuiltin() {
+        return mService.serviceInfo.packageName.equals(
+                InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE);
+    }
+    
+    public void dump(Printer pw, String prefix) {
+        pw.println(prefix + "mId=" + mId
+                + " mSettingsActivityName=" + mSettingsActivityName);
+        pw.println(prefix + "mIsDefaultResId=0x"
+                + Integer.toHexString(mIsDefaultResId));
+        pw.println(prefix + "Service:");
+        mService.dump(pw, prefix + "  ");
+    }
+    
+    @Override
+    public String toString() {
+        return "InputMethodMetaInfo{" + mId
+                + ", settings: "
+                + mSettingsActivityName + "}";
+    }
+
+    /**
+     * Used to test whether the given parameter object is an
+     * {@link InputMethodInfo} and its Id is the same to this one.
+     * 
+     * @return true if the given parameter object is an
+     *         {@link InputMethodInfo} and its Id is the same to this one.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) return true;
+        if (o == null) return false;
+
+        if (!(o instanceof InputMethodInfo)) return false;
+
+        InputMethodInfo obj = (InputMethodInfo) o;
+        return mId.equals(obj.mId);
+    }
+    
+    /**
+     * Used to package this object into a {@link Parcel}.
+     * 
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mId);
+        dest.writeString(mSettingsActivityName);
+        dest.writeInt(mIsDefaultResId);
+        mService.writeToParcel(dest, flags);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<InputMethodInfo> CREATOR = new Parcelable.Creator<InputMethodInfo>() {
+        public InputMethodInfo createFromParcel(Parcel source) {
+            return new InputMethodInfo(source);
+        }
+
+        public InputMethodInfo[] newArray(int size) {
+            return new InputMethodInfo[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
new file mode 100644
index 0000000..da82593
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -0,0 +1,900 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.internal.view.IInputConnectionWrapper;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodCallback;
+import com.android.internal.view.IInputMethodClient;
+import com.android.internal.view.IInputMethodManager;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.InputBindResult;
+
+import java.util.List;
+
+/**
+ * Public interface to the global input method manager.  You can retrieve
+ * an instance of this interface with
+ * {@link Context#getSystemService(String) Context.getSystemService()}.
+ */
+public final class InputMethodManager {
+    static final boolean DEBUG = false;
+    static final String TAG = "InputMethodManager";
+
+    /**
+     * The package name of the build-in input method.
+     * {@hide}
+     */
+    public static final String BUILDIN_INPUTMETHOD_PACKAGE = "android.text.inputmethod";
+
+    static final Object mInstanceSync = new Object();
+    static InputMethodManager mInstance;
+    
+    final IInputMethodManager mService;
+    final Looper mMainLooper;
+    
+    // For scheduling work on the main thread.  This also serves as our
+    // global lock.
+    final H mH;
+    
+    // The currently active input connection.
+    final MutableInputConnectionWrapper mInputConnectionWrapper;
+    final IInputContext mIInputContext;
+
+    /**
+     * True if this input method client is active, initially false.
+     */
+    boolean mActive = false;
+    
+    /**
+     * The current base input connection, used when mActive is true.
+     */
+    InputConnection mCurrentInputConnection;
+
+    // -----------------------------------------------------------
+    
+    /**
+     * This is the view that should currently be served by an input method,
+     * regardless of the state of setting that up.
+     */
+    View mServedView;
+    /**
+     * For evaluating the state after a focus change, this is the view that
+     * had focus.
+     */
+    View mLastServedView;
+    /**
+     * This is set when we are in the process of connecting, to determine
+     * when we have actually finished.
+     */
+    boolean mServedConnecting;
+    /**
+     * This is non-null when we have connected the served view; it holds
+     * the attributes that were last retrieved from the served view and given
+     * to the input connection.
+     */
+    EditorInfo mCurrentTextBoxAttribute;
+    /**
+     * The InputConnection that was last retrieved from the served view.
+     */
+    InputConnection mServedInputConnection;
+    /**
+     * The completions that were last provided by the served view.
+     */
+    CompletionInfo[] mCompletions;
+    
+    // Cursor position on the screen.
+    Rect mTmpCursorRect = new Rect();
+    Rect mCursorRect = new Rect();
+    int mCursorSelStart;
+    int mCursorSelEnd;
+
+    // -----------------------------------------------------------
+    
+    /**
+     * Sequence number of this binding, as returned by the server.
+     */
+    int mBindSequence = -1;
+    /**
+     * ID of the method we are bound to.
+     */
+    String mCurId;
+    /**
+     * The actual instance of the method to make calls on it.
+     */
+    IInputMethodSession mCurMethod;
+
+    // -----------------------------------------------------------
+    
+    static final int MSG_CHECK_FOCUS = 1;
+    
+    class H extends Handler {
+        H(Looper looper) {
+            super(looper);
+        }
+        
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_CHECK_FOCUS:
+                    checkFocus();
+                    return;
+            }
+        }
+    }
+    
+    static class NoOpInputConnection implements InputConnection {
+
+        public boolean clearMetaKeyStates(int states) {
+            return false;
+        }
+
+        public boolean commitCompletion(CompletionInfo text) {
+            return false;
+        }
+
+        public boolean commitText(CharSequence text, int newCursorPosition) {
+            return false;
+        }
+
+        public boolean deleteSurroundingText(int leftLength, int rightLength) {
+            return false;
+        }
+
+        public int getCursorCapsMode(int reqModes) {
+            return 0;
+        }
+
+        public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
+            return null;
+        }
+
+        public CharSequence getTextAfterCursor(int n) {
+            return null;
+        }
+
+        public CharSequence getTextBeforeCursor(int n) {
+            return null;
+        }
+
+        public boolean hideStatusIcon() {
+            return false;
+        }
+
+        public boolean performPrivateCommand(String action, Bundle data) {
+            return false;
+        }
+
+        public boolean sendKeyEvent(KeyEvent event) {
+            return false;
+        }
+
+        public boolean setComposingText(CharSequence text, int newCursorPosition) {
+            return false;
+        }
+
+        public boolean showStatusIcon(String packageName, int resId) {
+            return false;
+        }
+    }
+    
+    final NoOpInputConnection mNoOpInputConnection = new NoOpInputConnection();
+
+    final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
+        public void setUsingInputMethod(boolean state) {
+            
+        }
+        
+        public void onBindMethod(InputBindResult res) {
+            synchronized (mH) {
+                if (mBindSequence < 0 || mBindSequence != res.sequence) {
+                    Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
+                            + ", given seq=" + res.sequence);
+                    return;
+                }
+                
+                mCurMethod = res.method;
+                mCurId = res.id;
+                mBindSequence = res.sequence;
+            }
+            startInputInner();
+        }
+        
+        public void onUnbindMethod(int sequence) {
+            synchronized (mH) {
+                if (mBindSequence == sequence) {
+                    if (false) {
+                        // XXX the server has already unbound!
+                        if (mCurMethod != null && mCurrentTextBoxAttribute != null) {
+                            try {
+                                mCurMethod.finishInput();
+                            } catch (RemoteException e) {
+                                Log.w(TAG, "IME died: " + mCurId, e);
+                            }
+                        }
+                    }
+                    clearBindingLocked();
+                    
+                    // If we were actively using the last input method, then
+                    // we would like to re-connect to the next input method.
+                    if (mServedView != null && mServedView.isFocused()) {
+                        mServedConnecting = true;
+                    }
+                }
+                startInputInner();
+            }
+        }
+        
+        public void setActive(boolean active) {
+            mActive = active;
+            mInputConnectionWrapper.setBaseInputConnection(active
+                    ? mCurrentInputConnection : mNoOpInputConnection);
+        }
+    };    
+    
+    final InputConnection mDummyInputConnection = new BaseInputConnection(this) {
+        public boolean commitText(CharSequence text, int newCursorPosition) {
+            return false;
+        }
+        public boolean commitCompletion(CompletionInfo text) {
+            return false;
+        }
+        public boolean deleteSurroundingText(int leftLength, int rightLength) {
+            return false;
+        }
+        public ExtractedText getExtractedText(ExtractedTextRequest request,
+                int flags) {
+            return null;
+        }
+        public CharSequence getTextAfterCursor(int n) {
+            return null;
+        }
+        public CharSequence getTextBeforeCursor(int n) {
+            return null;
+        }
+        public int getCursorCapsMode(int reqModes) {
+            return 0;
+        }
+        public boolean clearMetaKeyStates(int states) {
+            return false;
+        }
+        public boolean performPrivateCommand(String action, Bundle data) {
+            return false;
+        }
+        public boolean setComposingText(CharSequence text, int newCursorPosition) {
+            return false;
+        }
+    };
+    
+    InputMethodManager(IInputMethodManager service, Looper looper) {
+        mService = service;
+        mMainLooper = looper;
+        mH = new H(looper);
+        mInputConnectionWrapper = new MutableInputConnectionWrapper(mNoOpInputConnection);
+        mIInputContext = new IInputConnectionWrapper(looper,
+                mInputConnectionWrapper);
+        setCurrentInputConnection(mDummyInputConnection);
+        
+        if (mInstance == null) {
+            mInstance = this;
+        }
+    }
+
+    /**
+     * Retrieve the global InputMethodManager instance, creating it if it
+     * doesn't already exist.
+     * @hide
+     */
+    static public InputMethodManager getInstance(Context context) {
+        synchronized (mInstanceSync) {
+            if (mInstance != null) {
+                return mInstance;
+            }
+            IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
+            IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
+            mInstance = new InputMethodManager(service, context.getMainLooper());
+        }
+        return mInstance;
+    }
+    
+    /**
+     * Private optimization: retrieve the global InputMethodManager instance,
+     * if it exists.
+     * @hide
+     */
+    static public InputMethodManager peekInstance() {
+        return mInstance;
+    }
+    
+    /** @hide */
+    public IInputMethodClient getClient() {
+        return mClient;
+    }
+    
+    /** @hide */
+    public IInputContext getInputContext() {
+        return mIInputContext;
+    }
+    
+    public List<InputMethodInfo> getInputMethodList() {
+        try {
+            return mService.getInputMethodList();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public List<InputMethodInfo> getEnabledInputMethodList() {
+        try {
+            return mService.getEnabledInputMethodList();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void updateStatusIcon(int iconId, String iconPackage) {
+        try {
+            mService.updateStatusIcon(iconId, iconPackage);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Return true if the given view is the currently active view for the
+     * input method.
+     */
+    public boolean isActive(View view) {
+        synchronized (mH) {
+            return mServedView == view && mCurrentTextBoxAttribute != null;
+        }
+    }
+    
+    /**
+     * Return true if any view is currently active in the input method.
+     */
+    public boolean isActive() {
+        synchronized (mH) {
+            return mServedView != null && mCurrentTextBoxAttribute != null;
+        }
+    }
+    
+    /**
+     * Return true if the currently served view is accepting full text edits.
+     * If false, it has no input connection, so can only handle raw key events.
+     */
+    public boolean isAcceptingText() {
+        return mServedInputConnection != null;
+    }
+
+    /**
+     * Reset all of the state associated with being bound to an input method.
+     */
+    void clearBindingLocked() {
+        clearConnectionLocked();
+        mBindSequence = -1;
+        mCurId = null;
+        mCurMethod = null;
+    }
+    
+    /**
+     * Record the desired input connection, but only set it if mActive is true.
+     */
+    void setCurrentInputConnection(InputConnection connection) {
+        mCurrentInputConnection = connection;
+        mInputConnectionWrapper.setBaseInputConnection(mActive
+                ? connection : mNoOpInputConnection);
+    }
+    
+    /**
+     * Reset all of the state associated with a served view being connected
+     * to an input method
+     */
+    void clearConnectionLocked() {
+        mCurrentTextBoxAttribute = null;
+        mServedInputConnection = null;
+        setCurrentInputConnection(mDummyInputConnection);
+    }
+    
+    /**
+     * Disconnect any existing input connection, clearing the served view.
+     */
+    void finishInputLocked() {
+        synchronized (mH) {
+            if (mServedView != null) {
+                if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView);
+                updateStatusIcon(0, null);
+                
+                if (mCurrentTextBoxAttribute != null) {
+                    try {
+                        mService.finishInput(mClient);
+                    } catch (RemoteException e) {
+                    }
+                }
+                
+                mServedView = null;
+                mCompletions = null;
+                mServedConnecting = false;
+                clearConnectionLocked();
+            }
+        }
+    }
+    
+    public void displayCompletions(View view, CompletionInfo[] completions) {
+        synchronized (mH) {
+            if (mServedView != view) {
+                return;
+            }
+            
+            mCompletions = completions;
+            if (mCurMethod != null) {
+                try {
+                    mCurMethod.displayCompletions(mCompletions);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+    }
+    
+    public void updateExtractedText(View view, int token, ExtractedText text) {
+        synchronized (mH) {
+            if (mServedView != view) {
+                return;
+            }
+            
+            if (mCurMethod != null) {
+                try {
+                    mCurMethod.updateExtractedText(token, text);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+    }
+    
+    /**
+     * Explicitly request that the current input method's soft input area be
+     * shown to the user, if needed.  Call this if the user interacts with
+     * your view in such a way that they have expressed they would like to
+     * start performing input into it.
+     * 
+     * @param view The currently focused view, which would like to receive
+     * soft keyboard input.
+     */
+    public void showSoftInput(View view) {
+        synchronized (mH) {
+            if (mServedView != view) {
+                return;
+            }
+
+            try {
+                mService.showSoftInput(mClient);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+    
+    /**
+     * Request to hide the soft input window from the context of the window
+     * that is currently accepting input.  This should be called as a result
+     * of the user doing some actually than fairly explicitly requests to
+     * have the input window hidden.
+     * 
+     * @param windowToken The token of the window that is making the request,
+     * as returned by {@link View#getWindowToken() View.getWindowToken()}.
+     */
+    public void hideSoftInputFromWindow(IBinder windowToken) {
+        synchronized (mH) {
+            if (mServedView == null || mServedView.getWindowToken() != windowToken) {
+                return;
+            }
+
+            try {
+                mService.hideSoftInput(mClient);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+    
+    /**
+     * If the input method is currently connected to the given view,
+     * restart it with its new contents.  You should call this when the text
+     * within your view changes outside of the normal input method or key
+     * input flow, such as when an application calls TextView.setText().
+     * 
+     * @param view The view whose text has changed.
+     */
+    public void restartInput(View view) {
+        synchronized (mH) {
+            if (mServedView != view) {
+                return;
+            }
+            
+            mServedConnecting = true;
+        }
+        
+        startInputInner();
+    }
+    
+    void startInputInner() {
+        final View view;
+        synchronized (mH) {
+            view = mServedView;
+            
+            // Make sure we have a window token for the served view.
+            if (DEBUG) Log.v(TAG, "Starting input: view=" + view);
+            if (view == null) {
+                if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
+                return;
+            }
+        }
+        
+        // Now we need to get an input connection from the served view.
+        // This is complicated in a couple ways: we can't be holding our lock
+        // when calling out to the view, and we need to make sure we call into
+        // the view on the same thread that is driving its view hierarchy.
+        Handler vh = view.getHandler();
+        if (vh == null) {
+            // If the view doesn't have a handler, something has changed out
+            // from under us, so just bail.
+            if (DEBUG) Log.v(TAG, "ABORT input: no handler for view!");
+            return;
+        }
+        if (vh.getLooper() != Looper.myLooper()) {
+            // The view is running on a different thread than our own, so
+            // we need to reschedule our work for over there.
+            if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
+            vh.post(new Runnable() {
+                public void run() {
+                    startInputInner();
+                }
+            });
+        }
+        
+        // Okay we are now ready to call into the served view and have it
+        // do its stuff.
+        // Life is good: let's hook everything up!
+        EditorInfo tba = new EditorInfo();
+        InputConnection ic = view.createInputConnection(tba);
+        if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
+        
+        synchronized (mH) {
+            // Now that we are locked again, validate that our state hasn't
+            // changed.
+            if (mServedView != view || !mServedConnecting) {
+                // Something else happened, so abort.
+                if (DEBUG) Log.v(TAG, 
+                        "Starting input: finished by someone else (view="
+                        + mServedView + " conn=" + mServedConnecting + ")");
+                return;
+            }
+            
+            // If we already have a text box, then this view is already
+            // connected so we want to restart it.
+            final boolean initial = mCurrentTextBoxAttribute == null;
+            
+            // Hook 'em up and let 'er rip.
+            mCurrentTextBoxAttribute = tba;
+            mServedConnecting = false;
+            mServedInputConnection = ic;
+            if (ic != null) {
+                mCursorSelStart = tba.initialSelStart;
+                mCursorSelEnd = tba.initialSelEnd;
+                mCursorRect.setEmpty();
+                setCurrentInputConnection(ic);
+            } else {
+                setCurrentInputConnection(mDummyInputConnection);
+            }
+            
+            try {
+                if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
+                        + ic + " tba=" + tba);
+                InputBindResult res = mService.startInput(mClient, tba, initial,
+                        mCurMethod == null);
+                if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
+                if (res != null) {
+                    if (res.id != null) {
+                        mBindSequence = res.sequence;
+                        mCurMethod = res.method;
+                    } else {
+                        // This means there is no input method available.
+                        if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
+                        return;
+                    }
+                }
+                if (mCurMethod != null && mCompletions != null) {
+                    try {
+                        mCurMethod.displayCompletions(mCompletions);
+                    } catch (RemoteException e) {
+                    }
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "IME died: " + mCurId, e);
+            }
+        }
+    }
+
+    /**
+     * When the focused window is dismissed, this method is called to finish the
+     * input method started before.
+     * @hide
+     */
+    public void windowDismissed(IBinder appWindowToken) {
+        synchronized (mH) {
+            if (mServedView != null &&
+                    mServedView.getWindowToken() == appWindowToken) {
+                finishInputLocked();
+            }
+        }
+    }
+
+    /**
+     * Call this when a view receives focus.
+     * @hide
+     */
+    public void focusIn(View view) {
+        synchronized (mH) {
+            if (DEBUG) Log.v(TAG, "focusIn: " + view);
+            // Okay we have a new view that is being served.
+            mServedView = view;
+            mCompletions = null;
+            mServedConnecting = true;
+        }
+        
+        startInputInner();
+    }
+
+    /**
+     * Call this when a view loses focus.
+     * @hide
+     */
+    public void focusOut(View view) {
+        synchronized (mH) {
+            if (DEBUG) Log.v(TAG, "focusOut: " + view
+                    + " mServedView=" + mServedView
+                    + " winFocus=" + view.hasWindowFocus());
+            if (mServedView == view && view.hasWindowFocus()) {
+                mLastServedView = view;
+                mH.removeMessages(MSG_CHECK_FOCUS);
+                mH.sendEmptyMessage(MSG_CHECK_FOCUS);
+            }
+        }
+    }
+
+    void checkFocus() {
+        synchronized (mH) {
+            if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
+                    + " last=" + mLastServedView);
+            if (mServedView == mLastServedView) {
+                finishInputLocked();
+                // In this case, we used to have a focused view on the window,
+                // but no longer do.  We should make sure the input method is
+                // no longer shown, since it serves no purpose.
+                closeCurrentInput();
+            }
+            mLastServedView = null;
+        }
+    }
+    
+    void closeCurrentInput() {
+        try {
+            mService.hideSoftInput(mClient);
+        } catch (RemoteException e) {
+        }
+    }
+    
+    /**
+     * Called by ViewRoot the first time it gets window focus.
+     */
+    public void onWindowFocus(View focusedView, int softInputMode,
+            boolean first, int windowFlags) {
+        synchronized (mH) {
+            if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
+                    + " softInputMode=" + softInputMode
+                    + " first=" + first + " flags=#"
+                    + Integer.toHexString(windowFlags));
+            try {
+                mService.windowGainedFocus(mClient, focusedView != null,
+                        softInputMode, first, windowFlags);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+    
+    /**
+     * Report the current selection range.
+     */
+    public void updateSelection(View view, int selStart, int selEnd) {
+        synchronized (mH) {
+            if (mServedView != view || mCurrentTextBoxAttribute == null
+                    || mCurMethod == null) {
+                return;
+            }
+            
+            if (mCursorSelStart != selStart || mCursorSelEnd != selEnd) {
+                if (DEBUG) Log.d(TAG, "updateSelection");
+
+                try {
+                    if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
+                    mCurMethod.updateSelection(mCursorSelStart, mCursorSelEnd,
+                            selStart, selEnd);
+                    mCursorSelStart = selStart;
+                    mCursorSelEnd = selEnd;
+                } catch (RemoteException e) {
+                    Log.w(TAG, "IME died: " + mCurId, e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns true if the current input method wants to watch the location
+     * of the input editor's cursor in its window.
+     */
+    public boolean isWatchingCursor(View view) {
+        return false;
+    }
+    
+    /**
+     * Report the current cursor location in its window.
+     */
+    public void updateCursor(View view, int left, int top, int right, int bottom) {
+        synchronized (mH) {
+            if (mServedView != view || mCurrentTextBoxAttribute == null
+                    || mCurMethod == null) {
+                return;
+            }
+            
+            mTmpCursorRect.set(left, top, right, bottom);
+            if (!mCursorRect.equals(mTmpCursorRect)) {
+                if (DEBUG) Log.d(TAG, "updateCursor");
+
+                try {
+                    if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
+                    mCurMethod.updateCursor(mTmpCursorRect);
+                    mCursorRect.set(mTmpCursorRect);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "IME died: " + mCurId, e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Force switch to a new input method component.  This can only be called
+     * from the currently active input method, as validated by the given token.
+     * @param token Supplies the identifying token given to an input method
+     * when it was started, which allows it to perform this operation on
+     * itself.
+     * @param id The unique identifier for the new input method to be switched to.
+     */
+    public void setInputMethod(IBinder token, String id) {
+        try {
+            mService.setInputMethod(token, id);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    /**
+     * Close/hide the input method's soft input area, so the user no longer
+     * sees it or can interact with it.  This can only be called
+     * from the currently active input method, as validated by the given token.
+     * @param token Supplies the identifying token given to an input method
+     * when it was started, which allows it to perform this operation on
+     * itself.
+     */
+    public void hideSoftInputFromInputMethod(IBinder token) {
+        try {
+            mService.hideMySoftInput(token);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    /**
+     * @hide
+     */
+    public void dispatchKeyEvent(Context context, int seq, KeyEvent key,
+            IInputMethodCallback callback) {
+        synchronized (mH) {
+            if (DEBUG) Log.d(TAG, "dispatchKeyEvent");
+    
+            if (mCurMethod == null || mCurrentTextBoxAttribute == null) {
+                try {
+                    callback.finishedEvent(seq, false);
+                } catch (RemoteException e) {
+                }
+                return;
+            }
+    
+            if (key.getAction() == KeyEvent.ACTION_DOWN
+                    && key.getKeyCode() == KeyEvent.KEYCODE_SYM) {
+                showInputMethodPicker();
+                try {
+                    callback.finishedEvent(seq, true);
+                } catch (RemoteException e) {
+                }
+                return;
+            }
+            try {
+                if (DEBUG) Log.v(TAG, "DISPATCH KEY: " + mCurMethod);
+                mCurMethod.dispatchKeyEvent(seq, key, callback);
+            } catch (RemoteException e) {
+                Log.w(TAG, "IME died: " + mCurId + " dropping: " + key, e);
+                try {
+                    callback.finishedEvent(seq, false);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    void dispatchTrackballEvent(Context context, int seq, MotionEvent motion,
+            IInputMethodCallback callback) {
+        synchronized (mH) {
+            if (DEBUG) Log.d(TAG, "dispatchTrackballEvent");
+    
+            if (mCurMethod == null || mCurrentTextBoxAttribute == null) {
+                try {
+                    callback.finishedEvent(seq, false);
+                } catch (RemoteException e) {
+                }
+                return;
+            }
+    
+            try {
+                if (DEBUG) Log.v(TAG, "DISPATCH TRACKBALL: " + mCurMethod);
+                mCurMethod.dispatchTrackballEvent(seq, motion, callback);
+            } catch (RemoteException e) {
+                Log.w(TAG, "IME died: " + mCurId + " dropping trackball: " + motion, e);
+                try {
+                    callback.finishedEvent(seq, false);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+    
+    public void showInputMethodPicker() {
+        synchronized (mH) {
+            try {
+                mService.showInputMethodPickerFromClient(mClient);
+            } catch (RemoteException e) {
+                Log.w(TAG, "IME died: " + mCurId, e);
+            }
+        }
+    }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
new file mode 100644
index 0000000..603da13
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+/**
+ * The InputMethodSession interface provides the per-client functionality
+ * of {@link InputMethod} that is safe to expose to applications.
+ * 
+ * <p>Applications will not normally use this interface themselves, instead
+ * relying on the standard interaction provided by
+ * {@link android.widget.TextView} and {@link android.widget.EditText}.
+ */
+public interface InputMethodSession {
+    
+    public interface EventCallback {
+        void finishedEvent(int seq, boolean handled);
+    }
+    
+    /**
+     * This method is called when the application would like to stop
+     * receiving text input.
+     */
+    public void finishInput();
+
+    /**
+     * This method is called when the selection or cursor in the current
+     * target input field has changed.
+     * 
+     * @param oldSelStart The previous text offset of the cursor selection
+     * start position.
+     * @param oldSelEnd The previous text offset of the cursor selection
+     * end position.
+     * @param newSelStart The new text offset of the cursor selection
+     * start position.
+     * @param newSelEnd The new text offset of the cursor selection
+     * end position.
+     */
+    public void updateSelection(int oldSelStart, int oldSelEnd,
+            int newSelStart, int newSelEnd);
+
+    /**
+     * This method is called when cursor location of the target input field
+     * has changed within its window.  This is not normally called, but will
+     * only be reported if requested by the input method.
+     * 
+     * @param newCursor The rectangle of the cursor currently being shown in
+     * the input field's window coordinates.
+     */
+    public void updateCursor(Rect newCursor);
+    
+    /**
+     * Called by a text editor that performs auto completion, to tell the
+     * input method about the completions it has available.  This can be used
+     * by the input method to display them to the user to select the text to
+     * be inserted.
+     * 
+     * @param completions Array of text completions that are available, starting with
+     * the best.  If this array is null, any existing completions will be
+     * removed.
+     */
+    public void displayCompletions(CompletionInfo[] completions);
+    
+    /**
+     * Called by a text editor to report its new extracted text when its
+     * contents change.  This will only be called if the input method
+     * calls {@link InputConnection#getExtractedText(ExtractedTextRequest, int)
+     * InputConnection.getExtractedText()} with the option to report updates.
+     * 
+     * @param token The input method supplied token for identifying its request.
+     * @param text The new extracted text.
+     */
+    public void updateExtractedText(int token, ExtractedText text);
+    
+    /**
+     * This method is called when a key is pressed.  When done with the event,
+     * the implementation must call back on <var>callback</var> with its
+     * result.
+     * 
+     * <p>
+     * If the input method wants to handle this event, return true, otherwise
+     * return false and the caller (i.e. the application) will handle the event.
+     * 
+     * @param event The key event.
+     * 
+     * @return Whether the input method wants to handle this event.
+     * 
+     * @see #dispatchKeyUp
+     * @see android.view.KeyEvent
+     */
+    public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback);
+
+    /**
+     * This method is called when there is a track ball event.
+     * 
+     * <p>
+     * If the input method wants to handle this event, return true, otherwise
+     * return false and the caller (i.e. the application) will handle the event.
+     * 
+     * @param event The motion event.
+     * 
+     * @return Whether the input method wants to handle this event.
+     * 
+     * @see android.view.MotionEvent
+     */
+    public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback);
+
+    /**
+     * Process a private command sent from the application to the input method.
+     * This can be used to provide domain-specific features that are
+     * only known between certain input methods and their clients.
+     * 
+     * @param action Name of the command to be performed.  This <em>must</em>
+     * be a scoped name, i.e. prefixed with a package name you own, so that
+     * different developers will not create conflicting commands.
+     * @param data Any data to include with the command.
+     */
+    public void appPrivateCommand(String action, Bundle data);
+}
diff --git a/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java b/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java
new file mode 100644
index 0000000..025a059
--- /dev/null
+++ b/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+
+/**
+ * Special version of {@link InputConnectionWrapper} that allows the base
+ * input connection to be modified after it is initially set.
+ */
+public class MutableInputConnectionWrapper extends InputConnectionWrapper {
+    public MutableInputConnectionWrapper(InputConnection base) {
+        super(base);
+    }
+
+    /**
+     * Change the base InputConnection for this wrapper. All calls will then be
+     * delegated to the base input connection.
+     * 
+     * @param base The new base InputConnection for this wrapper.
+     */
+    public void setBaseInputConnection(InputConnection base) {
+        mBase = base;
+    }
+}
diff --git a/core/java/android/view/inputmethod/package.html b/core/java/android/view/inputmethod/package.html
new file mode 100644
index 0000000..348aba6
--- /dev/null
+++ b/core/java/android/view/inputmethod/package.html
@@ -0,0 +1,11 @@
+<html>
+<body>
+Framework classes for interaction between views and input methods (such
+as soft keyboards).  In most cases the main classes here are not needed for
+most applications, since they are dealt with for you by
+{@link android.widget.TextView}.  When implementing a custom text editor,
+however, you will need to implement the
+{@link android.view.inputmethod.InputConnection} class to allow the current
+input method to interact with your view.
+</body>
+</html>
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index e99c444..1dd37be 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -26,10 +26,10 @@
 import android.os.Message;
 import android.util.Config;
 import android.util.Log;
+import android.util.TypedValue;
 
 import junit.framework.Assert;
 
-import java.net.URLDecoder;
 import java.net.URLEncoder;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -52,9 +52,7 @@
     private final WebViewDatabase mDatabase;
     private final WebViewCore mWebViewCore;
     private boolean mLoadInitFromJava;
-    private String mCurrentUrl;
     private int mLoadType;
-    private String mCompletedUrl;
     private boolean mFirstLayoutDone = true;
     private boolean mCommitted = true;
 
@@ -114,9 +112,7 @@
             CookieSyncManager.createInstance(context);
         }
         AssetManager am = context.getAssets();
-        nativeCreateFrame(am, proxy.getBackForwardList());
-        // Create a native FrameView and attach it to the native frame.
-        nativeCreateView(w);
+        nativeCreateFrame(w, am, proxy.getBackForwardList());
 
         mSettings = settings;
         mContext = context;
@@ -142,11 +138,7 @@
             stringByEvaluatingJavaScriptFromString(
                     url.substring("javascript:".length()));
         } else {
-            if (!nativeLoadUrl(url)) {
-                reportError(android.net.http.EventHandler.ERROR_BAD_URL,
-                        mContext.getString(com.android.internal.R.string.httpErrorBadUrl),
-                        url);
-            }
+            nativeLoadUrl(url);
         }
         mLoadInitFromJava = false;
     }
@@ -186,6 +178,17 @@
     }
 
     /**
+     * Go back or forward the number of steps given.
+     * @param steps A negative or positive number indicating the direction
+     *              and number of steps to move.
+     */
+    public void goBackOrForward(int steps) {
+        mLoadInitFromJava = true;
+        nativeGoBackOrForward(steps);
+        mLoadInitFromJava = false;
+    }
+
+    /**
      * native callback
      * Report an error to an activity.
      * @param errorCode The HTTP error code.
@@ -216,34 +219,12 @@
         return mLoadType;
     }
 
-    /* package */String currentUrl() {
-        return mCurrentUrl;
-    }
-
-    /* package */void didFirstLayout(String url) {
-        // this is common case
-        if (url.equals(mCurrentUrl)) {
-            if (!mFirstLayoutDone) {
-                mFirstLayoutDone = true;
-                // ensure {@link WebViewCore#webkitDraw} is called as we were
-                // blocking the update in {@link #loadStarted}
-                mWebViewCore.contentInvalidate();
-            }
-        } else if (url.equals(mCompletedUrl)) {
-            /*
-             * FIXME: when loading http://www.google.com/m, 
-             * mCurrentUrl will be http://www.google.com/m, 
-             * mCompletedUrl will be http://www.google.com/m#search 
-             * and url will be http://www.google.com/m#search. 
-             * This is probably a bug in WebKit. If url matches mCompletedUrl, 
-             * also set mFirstLayoutDone to be true and update.
-             */
-            if (!mFirstLayoutDone) {
-                mFirstLayoutDone = true;
-                // ensure {@link WebViewCore#webkitDraw} is called as we were
-                // blocking the update in {@link #loadStarted}
-                mWebViewCore.contentInvalidate();
-            }
+    /* package */void didFirstLayout() {
+        if (!mFirstLayoutDone) {
+            mFirstLayoutDone = true;
+            // ensure {@link WebViewCore#webkitDraw} is called as we were
+            // blocking the update in {@link #loadStarted}
+            mWebViewCore.contentDraw();
         }
         mWebViewCore.mEndScaleZoom = true;
     }
@@ -258,8 +239,6 @@
         mIsMainFrame = isMainFrame;
 
         if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
-            mCurrentUrl = url;
-            mCompletedUrl = null;
             mLoadType = loadType;
 
             if (isMainFrame) {
@@ -310,7 +289,6 @@
         // mIsMainFrame and isMainFrame are better be equal!!!
 
         if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
-            mCompletedUrl = url;
             if (isMainFrame) {
                 mCallbackProxy.switchOutDrawHistory();
                 mCallbackProxy.onPageFinished(url);
@@ -355,8 +333,8 @@
                     WebAddress uri = new WebAddress(
                             mCallbackProxy.getBackForwardList().getCurrentItem()
                             .getUrl());
-                    String host = uri.mHost;
-                    String[] up = mDatabase.getUsernamePassword(host);
+                    String schemePlusHost = uri.mScheme + uri.mHost;
+                    String[] up = mDatabase.getUsernamePassword(schemePlusHost);
                     if (up != null && up[0] != null) {
                         setUsernamePassword(up[0], up[1]);
                     }
@@ -441,7 +419,13 @@
         if (mLoadInitFromJava == true) {
             return false;
         }
-        return mCallbackProxy.shouldOverrideUrlLoading(url);
+        if (mCallbackProxy.shouldOverrideUrlLoading(url)) {
+            // if the url is hijacked, reset the state of the BrowserFrame
+            didFirstLayout();
+            return true;
+        } else {
+            return false;
+        }
     }
 
     public void addJavascriptInterface(Object obj, String interfaceName) {
@@ -462,7 +446,7 @@
      * @param method The http method.
      * @param headers The http headers.
      * @param postData If the method is "POST" postData is sent as the request
-     *                 body.
+     *                 body. Is null when empty.
      * @param cacheMode The cache mode to use when loading this resource.
      * @param isHighPriority True if this resource needs to be put at the front
      *                       of the network queue.
@@ -473,7 +457,7 @@
                                               String url,
                                               String method,
                                               HashMap headers,
-                                              String postData,
+                                              byte[] postData,
                                               int cacheMode,
                                               boolean isHighPriority,
                                               boolean synchronous) {
@@ -497,41 +481,47 @@
                     }
                     WebAddress uri = new WebAddress(mCallbackProxy
                             .getBackForwardList().getCurrentItem().getUrl());
-                    String host = uri.mHost;
+                    String schemePlusHost = uri.mScheme + uri.mHost;
                     String[] ret = getUsernamePassword();
-                    if (ret != null && postData != null && ret[0].length() > 0
-                            && ret[1].length() > 0
-                            && postData.contains(URLEncoder.encode(ret[0]))
-                            && postData.contains(URLEncoder.encode(ret[1]))) {
-                        String[] saved = mDatabase.getUsernamePassword(host);
-                        if (saved != null) {
-                            // null username implies that user has chosen not to
-                            // save password
-                            if (saved[0] != null) {
-                                // non-null username implies that user has
-                                // chosen to save password, so update the 
-                                // recorded password
-                                mDatabase.setUsernamePassword(host, ret[0],
-                                        ret[1]);
+                    // Has the user entered a username/password pair and is
+                    // there some POST data
+                    if (ret != null && postData != null && 
+                            ret[0].length() > 0 && ret[1].length() > 0) {
+                        // Check to see if the username & password appear in
+                        // the post data (there could be another form on the
+                        // page and that was posted instead.
+                        String postString = new String(postData);
+                        if (postString.contains(URLEncoder.encode(ret[0])) &&
+                                postString.contains(URLEncoder.encode(ret[1]))) {
+                            String[] saved = mDatabase.getUsernamePassword(
+                                    schemePlusHost);
+                            if (saved != null) {
+                                // null username implies that user has chosen not to
+                                // save password
+                                if (saved[0] != null) {
+                                    // non-null username implies that user has
+                                    // chosen to save password, so update the 
+                                    // recorded password
+                                    mDatabase.setUsernamePassword(
+                                            schemePlusHost, ret[0], ret[1]);
+                                }
+                            } else {
+                                // CallbackProxy will handle creating the resume
+                                // message
+                                mCallbackProxy.onSavePassword(schemePlusHost, ret[0], 
+                                        ret[1], null);
                             }
-                        } else {
-                            // CallbackProxy will handle creating the resume
-                            // message
-                            mCallbackProxy.onSavePassword(host, ret[0], ret[1],
-                                    null);
                         }
                     }
                 } catch (ParseException ex) {
                     // if it is bad uri, don't save its password
                 }
-            }
-            if (postData == null) {
-                postData = "";
+                
             }
         }
 
         // is this resource the main-frame top-level page?
-        boolean isMainFramePage = mIsMainFrame && url.equals(mCurrentUrl);
+        boolean isMainFramePage = mIsMainFrame;
 
         if (Config.LOGV) {
             Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method="
@@ -561,8 +551,8 @@
             CacheManager.endCacheTransaction();
         }
 
-        FrameLoader loader = new FrameLoader(loadListener,
-                mSettings.getUserAgentString(), method, isHighPriority);
+        FrameLoader loader = new FrameLoader(loadListener, mSettings,
+                method, isHighPriority);
         loader.setHeaders(headers);
         loader.setPostData(postData);
         loader.setCacheMode(cacheMode); // Set the load mode to the mode used
@@ -666,36 +656,51 @@
         return mSettings.getUserAgentString();
     }
 
+    // these ids need to be in sync with enum RAW_RES_ID in WebFrame
+    private static final int NODOMAIN = 1;
+    private static final int LOADERROR = 2;
+
+    String getRawResFilename(int id) {
+        int resid;
+        switch (id) {
+            case NODOMAIN:
+                resid = com.android.internal.R.raw.nodomain;
+                break;
+
+            case LOADERROR:
+                resid = com.android.internal.R.raw.loaderror;
+                break;
+
+            default:
+                Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
+                return new String();
+        }
+        TypedValue value = new TypedValue();
+        mContext.getResources().getValue(resid, value, true);
+        return value.string.toString();
+    }
+
     //==========================================================================
     // native functions
     //==========================================================================
 
     /**
-     * Create a new native frame.
+     * Create a new native frame for a given WebView
+     * @param w     A WebView that the frame draws into.
      * @param am    AssetManager to use to get assets.
      * @param list  The native side will add and remove items from this list as
      *              the native list changes.
      */
-    private native void nativeCreateFrame(AssetManager am,
+    private native void nativeCreateFrame(WebViewCore w, AssetManager am,
             WebBackForwardList list);
 
     /**
-     * Create a native view attached to a WebView.
-     * @param w A WebView that the frame draws into.
-     */
-    private native void nativeCreateView(WebViewCore w);
-
-    private native void nativeCallPolicyFunction(int policyFunction,
-            int decision);
-    /**
      * Destroy the native frame.
      */
     public native void nativeDestroyFrame();
 
-    /**
-     * Detach the view from the frame.
-     */
-    private native void nativeDetachView();
+    private native void nativeCallPolicyFunction(int policyFunction,
+            int decision);
 
     /**
      * Reload the current main frame.
@@ -707,7 +712,7 @@
      * @param steps A negative or positive number indicating the direction
      *              and number of steps to move.
      */
-    public native void goBackOrForward(int steps);
+    private native void nativeGoBackOrForward(int steps);
 
     /**
      * stringByEvaluatingJavaScriptFromString will execute the
@@ -738,7 +743,7 @@
     /**
      * Returns false if the url is bad.
      */
-    private native boolean nativeLoadUrl(String url);
+    private native void nativeLoadUrl(String url);
 
     private native void nativeLoadData(String baseUrl, String data,
             String mimeType, String encoding, String failUrl);
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index f5a09b8..d12940d 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -62,8 +62,18 @@
     // Reference count the enable/disable transaction
     private static int mRefCount;
 
+    // trimCacheIfNeeded() is called when a page is fully loaded. But JavaScript
+    // can load the content, e.g. in a slideshow, continuously, so we need to
+    // trim the cache on a timer base too. endCacheTransaction() is called on a 
+    // timer base. We share the same timer with less frequent update.
+    private static int mTrimCacheCount = 0;
+    private static final int TRIM_CACHE_INTERVAL = 5;
+
     private static WebViewDatabase mDataBase;
     private static File mBaseDir;
+    
+    // Flag to clear the cache when the CacheManager is initialized
+    private static boolean mClearCacheOnInit = false;
 
     public static class CacheResult {
         // these fields are saved to the database
@@ -145,16 +155,37 @@
     static void init(Context context) {
         mDataBase = WebViewDatabase.getInstance(context);
         mBaseDir = new File(context.getCacheDir(), "webviewCache");
+        if (createCacheDirectory() && mClearCacheOnInit) {
+            removeAllCacheFiles();
+            mClearCacheOnInit = false;
+        }
+    }
+    
+    /**
+     * Create the cache directory if it does not already exist.
+     * 
+     * @return true if the cache directory didn't exist and was created.
+     */
+    static private boolean createCacheDirectory() {
         if (!mBaseDir.exists()) {
             if(!mBaseDir.mkdirs()) {
                 Log.w(LOGTAG, "Unable to create webviewCache directory");
-                return;
+                return false;
             }
             FileUtils.setPermissions(
                     mBaseDir.toString(),
                     FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
                     -1, -1);
+            // If we did create the directory, we need to flush 
+            // the cache database. The directory could be recreated
+            // because the system flushed all the data/cache directories
+            // to free up disk space.
+            WebViewCore.endCacheTransaction();
+            mDataBase.clearCache();
+            WebViewCore.startCacheTransaction();
+            return true;
         }
+        return false;
     }
 
     /**
@@ -224,7 +255,12 @@
     // only called from WebCore thread
     // make sure to call startCacheTransaction/endCacheTransaction in pair
     public static boolean endCacheTransaction() {
-        return mDataBase.endCacheTransaction();
+        boolean ret = mDataBase.endCacheTransaction();
+        if (++mTrimCacheCount >= TRIM_CACHE_INTERVAL) {
+            mTrimCacheCount = 0;
+            trimCacheIfNeeded();
+        }
+        return ret;
     }
 
     /**
@@ -319,7 +355,20 @@
             try {
                 ret.outStream = new FileOutputStream(ret.outFile);
             } catch (FileNotFoundException e) {
-                return null;
+                // This can happen with the system did a purge and our
+                // subdirectory has gone, so lets try to create it again
+                if (createCacheDirectory()) {
+                    try {
+                        ret.outStream = new FileOutputStream(ret.outFile);
+                    } catch  (FileNotFoundException e2) {
+                        // We failed to create the file again, so there
+                        // is something else wrong. Return null.
+                        return null;
+                    }
+                } else {
+                    // Failed to create cache directory
+                    return null;
+                }
             }
             ret.mimeType = mimeType;
         }
@@ -371,14 +420,25 @@
      */
     // only called from WebCore thread
     static boolean removeAllCacheFiles() {
+        // Note, this is called before init() when the database is
+        // created or upgraded.
+        if (mBaseDir == null) {
+            // Init() has not been called yet, so just flag that
+            // we need to clear the cache when init() is called.
+            mClearCacheOnInit = true;
+            return true;
+        }
         // delete cache in a separate thread to not block UI.
         final Runnable clearCache = new Runnable() {
             public void run() {
                 // delete all cache files
                 try {
                     String[] files = mBaseDir.list();
-                    for (int i = 0; i < files.length; i++) {
-                        new File(mBaseDir, files[i]).delete();
+                    // if mBaseDir doesn't exist, files can be null.
+                    if (files != null) {
+                        for (int i = 0; i < files.length; i++) {
+                            new File(mBaseDir, files[i]).delete();
+                        }
                     }
                 } catch (SecurityException e) {
                     // Ignore SecurityExceptions.
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 7c296cc..cae94c9 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -354,12 +354,12 @@
 
             case SAVE_PASSWORD:
                 Bundle bundle = msg.getData();
-                String host = bundle.getString("host");
+                String schemePlusHost = bundle.getString("host");
                 String username = bundle.getString("username");
                 String password = bundle.getString("password");
                 // If the client returned false it means that the notify message
                 // will not be sent and we should notify WebCore ourselves.
-                if (!mWebView.onSavePassword(host, username, password,
+                if (!mWebView.onSavePassword(schemePlusHost, username, password,
                             (Message) msg.obj)) {
                     synchronized (this) {
                         notify();
@@ -700,8 +700,8 @@
     // functions just need to operate within the UI thread.
     //--------------------------------------------------------------------------
 
-    public boolean onSavePassword(String host, String username, String password,
-            Message resumeMsg) {
+    public boolean onSavePassword(String schemePlusHost, String username,
+            String password, Message resumeMsg) {
         // resumeMsg should be null at this point because we want to create it
         // within the CallbackProxy.
         if (Config.DEBUG) {
@@ -711,7 +711,7 @@
 
         Message msg = obtainMessage(SAVE_PASSWORD, resumeMsg);
         Bundle bundle = msg.getData();
-        bundle.putString("host", host);
+        bundle.putString("host", schemePlusHost);
         bundle.putString("username", username);
         bundle.putString("password", password);
         synchronized (this) {
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 176471f..00b17d2 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -151,13 +151,34 @@
         }
 
         boolean domainMatch(String urlHost) {
-            return urlHost.equals(domain) ||
-                    (domain.startsWith(".") &&
-                     urlHost.endsWith(domain.substring(1)));
+            if (domain.startsWith(".")) {
+                if (urlHost.endsWith(domain.substring(1))) {
+                    int len = domain.length();
+                    int urlLen = urlHost.length();
+                    if (urlLen > len - 1) {
+                        // make sure bar.com doesn't match .ar.com
+                        return urlHost.charAt(urlLen - len) == PERIOD;
+                    }
+                    return true;
+                }
+                return false;
+            } else {
+                // exact match if domain is not leading w/ dot
+                return urlHost.equals(domain);
+            }
         }
 
         boolean pathMatch(String urlPath) {
-            return urlPath.startsWith (path);
+            if (urlPath.startsWith(path)) {
+                int len = path.length();
+                int urlLen = urlPath.length();
+                if (urlLen > len) {
+                    // make sure /wee doesn't match /we
+                    return urlPath.charAt(len) == PATH_DELIM;
+                }
+                return true;
+            }
+            return false;
         }
 
         public String toString() {
@@ -232,7 +253,7 @@
      * a system private class.
      */
     public synchronized void setCookie(WebAddress uri, String value) {
-        if (value != null && value.length() > 4096) {
+        if (value != null && value.length() > MAX_COOKIE_LENGTH) {
             return;
         }
         if (!mAcceptCookie || uri == null) {
@@ -246,25 +267,19 @@
         if (hostAndPath == null) {
             return;
         }
+        
+        // For default path, when setting a cookie, the spec says:
+        //Path:   Defaults to the path of the request URL that generated the
+        // Set-Cookie response, up to, but not including, the
+        // right-most /.
+        if (hostAndPath[1].length() > 1) {
+            int index = hostAndPath[1].lastIndexOf(PATH_DELIM);
+            hostAndPath[1] = hostAndPath[1].substring(0, 
+                    index > 0 ? index : index + 1);
+        }
 
         ArrayList<Cookie> cookies = null;
         try {
-            /* Google is setting cookies like the following to detect whether 
-             * a browser supports cookie. We need to skip the leading "www" for 
-             * the default host. Otherwise the second cookie will make the first
-             * cookie expired.
-             *  
-             * url: https://www.google.com/accounts/ServiceLoginAuth 
-             * value: LSID=xxxxxxxxxxxxx;Path=/accounts;
-             * Expires=Tue, 13-Mar-2018 01:41:39 GMT
-             * 
-             * url: https://www.google.com/accounts/ServiceLoginAuth 
-             * value:LSID=EXPIRED;Domain=www.google.com;Path=/accounts;
-             * Expires=Mon, 01-Jan-1990 00:00:00 GMT 
-             */  
-            if (hostAndPath[0].startsWith("www.")) {
-                hostAndPath[0] = hostAndPath[0].substring(3);
-            }
             cookies = parseCookie(hostAndPath[0], hostAndPath[1], value);
         } catch (RuntimeException ex) {
             Log.e(LOGTAG, "parse cookie failed for: " + value);
@@ -622,26 +637,17 @@
 
             /*
              * find cookie path, e.g. for http://www.google.com, the path is "/"
-             * for http://www.google.com/lab/, the path is "/lab/"
-             * for http://www.google.com/lab/foo, the path is "/lab/"
-             * for http://www.google.com/lab?hl=en, the path is "/lab/"
-             * for http://www.google.com/lab.asp?hl=en, the path is "/"
+             * for http://www.google.com/lab/, the path is "/lab"
+             * for http://www.google.com/lab/foo, the path is "/lab/foo"
+             * for http://www.google.com/lab?hl=en, the path is "/lab"
+             * for http://www.google.com/lab.asp?hl=en, the path is "/lab.asp"
              * Note: the path from URI has at least one "/"
+             * See:
+             * http://www.unix.com.ua/rfc/rfc2109.html
              */
             index = ret[1].indexOf(QUESTION_MARK);
             if (index != -1) {
                 ret[1] = ret[1].substring(0, index);
-                if (ret[1].charAt(ret[1].length() - 1) != PATH_DELIM) {
-                    index = ret[1].lastIndexOf(PATH_DELIM);
-                    if (ret[1].lastIndexOf('.') > index) {
-                        ret[1] = ret[1].substring(0, index + 1);
-                    } else {
-                        ret[1] += PATH_DELIM;
-                    }
-                }
-            } else if (ret[1].charAt(ret[1].length() - 1) != PATH_DELIM) {
-                ret[1] = ret[1].substring(0,
-                        ret[1].lastIndexOf(PATH_DELIM) + 1);
             }
             return ret;
         } else
@@ -687,10 +693,6 @@
             String cookieString) {
         ArrayList<Cookie> ret = new ArrayList<Cookie>();
 
-        // domain needs at least two PERIOD,
-        if (host.indexOf(PERIOD) == host.lastIndexOf(PERIOD)) {
-            host = PERIOD + host;
-        }
         int index = 0;
         int length = cookieString.length();
         while (true) {
@@ -841,15 +843,14 @@
                                     "illegal format for max-age: " + value);
                         }
                     } else if (name.equals(PATH)) {
-                        // make sure path ends with PATH_DELIM
-                        if (value.length() > 1 &&
-                                value.charAt(value.length() - 1) != PATH_DELIM) {
-                            cookie.path = value + PATH_DELIM;
-                        } else {
-                            cookie.path = value;
-                        }
+                        cookie.path = value;
                     } else if (name.equals(DOMAIN)) {
                         int lastPeriod = value.lastIndexOf(PERIOD);
+                        if (lastPeriod == 0) {
+                            // disallow cookies set for TLDs like [.com]
+                            cookie.domain = null;
+                            continue;
+                        }
                         try {
                             Integer.parseInt(value.substring(lastPeriod + 1));
                             // no wildcard for ip address match
@@ -862,15 +863,22 @@
                             // ignore the exception, value is a host name
                         }
                         value = value.toLowerCase();
-                        if (value.endsWith(host) || host.endsWith(value)) {
-                            // domain needs at least two PERIOD
-                            if (value.indexOf(PERIOD) == lastPeriod) {
-                                value = PERIOD + value;
+                        if (value.charAt(0) != PERIOD) {
+                            // pre-pended dot to make it as a domain cookie
+                            value = PERIOD + value;
+                            lastPeriod++;
+                        }
+                        if (host.endsWith(value.substring(1))) {
+                            int len = value.length();
+                            int hostLen = host.length();
+                            if (hostLen > (len - 1)
+                                    && host.charAt(hostLen - len) != PERIOD) {
+                                // make sure the bar.com doesn't match .ar.com
+                                cookie.domain = null;
+                                continue;
                             }
                             // disallow cookies set on ccTLDs like [.co.uk]
-                            int len = value.length();
-                            if ((value.charAt(0) == PERIOD)
-                                    && (len == lastPeriod + 3)
+                            if ((len == lastPeriod + 3)
                                     && (len >= 6 && len <= 8)) {
                                 String s = value.substring(1, lastPeriod);
                                 if (Arrays.binarySearch(BAD_COUNTRY_2LDS, s) >= 0) {
@@ -880,7 +888,7 @@
                             }
                             cookie.domain = value;
                         } else {
-                            // no cross-site cookie
+                            // no cross-site or more specific sub-domain cookie
                             cookie.domain = null;
                         }
                     }
diff --git a/core/java/android/webkit/DateSorter.java b/core/java/android/webkit/DateSorter.java
index 3dc15c1..750403b 100644
--- a/core/java/android/webkit/DateSorter.java
+++ b/core/java/android/webkit/DateSorter.java
@@ -17,7 +17,7 @@
 package android.webkit;
 
 import android.content.Context;
-import android.util.Log;
+import android.content.res.Resources;
 
 import java.util.Calendar;
 import java.util.Date;
@@ -40,6 +40,8 @@
 
     private long [] mBins = new long[DAY_COUNT];
     private String [] mLabels = new String[DAY_COUNT];
+    
+    private static final int NUM_DAYS_AGO = 5;
 
     Date mDate = new Date();
     Calendar mCal = Calendar.getInstance();
@@ -48,6 +50,7 @@
      * @param context Application context
      */
     public DateSorter(Context context) {
+        Resources resources = context.getResources();
 
         Calendar c = Calendar.getInstance();
         beginningOfDay(c);
@@ -56,9 +59,9 @@
         mBins[0] = c.getTimeInMillis(); // Today
         c.roll(Calendar.DAY_OF_YEAR, -1);
         mBins[1] = c.getTimeInMillis();  // Yesterday
-        c.roll(Calendar.DAY_OF_YEAR, -4);
+        c.roll(Calendar.DAY_OF_YEAR, -(NUM_DAYS_AGO - 1));
         mBins[2] = c.getTimeInMillis();  // Five days ago
-        c.roll(Calendar.DAY_OF_YEAR, 5); // move back to today
+        c.roll(Calendar.DAY_OF_YEAR, NUM_DAYS_AGO); // move back to today
         c.roll(Calendar.MONTH, -1);
         mBins[3] = c.getTimeInMillis();  // One month ago
         c.roll(Calendar.MONTH, -1);
@@ -67,14 +70,14 @@
         // build labels
         mLabels[0] = context.getText(com.android.internal.R.string.today).toString();
         mLabels[1] = context.getText(com.android.internal.R.string.yesterday).toString();
-        mLabels[2] = context.getString(com.android.internal.R.string.daysDurationPastPlural, 5);
-        mLabels[3] = context.getText(com.android.internal.R.string.oneMonthDurationPast).toString();
-        StringBuilder sb = new StringBuilder();
-        sb.append(context.getText(com.android.internal.R.string.before)).append(" ");
-        sb.append(context.getText(com.android.internal.R.string.oneMonthDurationPast));
-        mLabels[4] = sb.toString();
-                
 
+        int resId = com.android.internal.R.plurals.num_days_ago;
+        String format = resources.getQuantityString(resId, NUM_DAYS_AGO);
+        mLabels[2] = String.format(format, NUM_DAYS_AGO);
+
+        mLabels[3] = context.getText(com.android.internal.R.string.oneMonthDurationPast).toString();
+        mLabels[4] = context.getText(com.android.internal.R.string.beforeOneMonthDurationPast)
+                .toString();
     }
 
     /**
diff --git a/core/java/android/webkit/FileLoader.java b/core/java/android/webkit/FileLoader.java
index 6696bae..10343b2 100644
--- a/core/java/android/webkit/FileLoader.java
+++ b/core/java/android/webkit/FileLoader.java
@@ -16,6 +16,8 @@
 
 package android.webkit;
 
+import com.android.internal.R;
+
 import android.content.Context;
 import android.content.res.AssetManager;
 import android.net.http.EventHandler;
@@ -35,6 +37,7 @@
     private String mPath;  // Full path to the file to load
     private Context mContext;  // Application context, used for asset loads
     private boolean mIsAsset;  // Indicates if the load is an asset or not
+    private boolean mAllowFileAccess; // Allow/block file system access
 
     /**
      * Construct a FileLoader with the file URL specified as the content
@@ -44,12 +47,15 @@
      * @param loadListener LoadListener to pass the content to
      * @param context Context to use to access the asset.
      * @param asset true if url points to an asset.
+     * @param allowFileAccess true if this WebView is allowed to access files
+     *                        on the file system.
      */
     FileLoader(String url, LoadListener loadListener, Context context,
-            boolean asset) {
+            boolean asset, boolean allowFileAccess) {
         super(loadListener);
         mIsAsset = asset;
         mContext = context;
+        mAllowFileAccess = allowFileAccess;
 
         // clean the Url
         int index = url.indexOf('?');
@@ -73,35 +79,27 @@
                 mDataStream = mContext.getAssets().open(mPath,
                         AssetManager.ACCESS_STREAMING);
             } else {
-                mHandler.error(EventHandler.FILE_ERROR,
-                        mContext.getString(
-                                com.android.internal.R.string.httpErrorFileNotFound));
-                return false;
-/*
-                if (!mPath.startsWith(
-                        Environment.getExternalStorageDirectory().getPath())) {
+                if (!mAllowFileAccess) {
                     mHandler.error(EventHandler.FILE_ERROR,
-                            mContext.getString(
-                                    com.android.internal.R.string.httpErrorFileNotFound));
+                            mContext.getString(R.string.httpErrorFileNotFound));
                     return false;
                 }
+
                 mDataStream = new FileInputStream(mPath);
                 mContentLength = (new File(mPath)).length();
-*/
             }
             mHandler.status(1, 1, 0, "OK");
 
         } catch (java.io.FileNotFoundException ex) {
             mHandler.error(
                     EventHandler.FILE_NOT_FOUND_ERROR,
-                    mContext.getString(com.android.internal.R.string.httpErrorFileNotFound) +
+                    mContext.getString(R.string.httpErrorFileNotFound) +
                     " " + ex.getMessage());
             return false;
 
         } catch (java.io.IOException ex) {
             mHandler.error(EventHandler.FILE_ERROR,
-                           mContext.getString(
-                                   com.android.internal.R.string.httpErrorFileNotFound) +
+                           mContext.getString(R.string.httpErrorFileNotFound) +
                            " " + ex.getMessage());
             return false;
         }
@@ -121,10 +119,13 @@
      * @param loadListener LoadListener to pass the content to
      * @param context Context to use to access the asset.
      * @param asset true if url points to an asset.
+     * @param allowFileAccess true if this FileLoader can load files from the
+     *                        file system.
      */
     public static void requestUrl(String url, LoadListener loadListener,
-            Context context, boolean asset) {
-        FileLoader loader = new FileLoader(url, loadListener, context, asset);
+            Context context, boolean asset, boolean allowFileAccess) {
+        FileLoader loader = new FileLoader(url, loadListener, context, asset,
+                allowFileAccess);
         loader.load();
     }
 
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index ebfebd0..7a3bbe6 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -28,16 +28,16 @@
 
 class FrameLoader {
 
-    protected LoadListener mListener;
-    protected Map<String, String> mHeaders;
-    protected String mMethod;
-    protected String mPostData;
-    protected boolean mIsHighPriority;
-    protected Network mNetwork;
-    protected int mCacheMode;
-    protected String mReferrer;
-    protected String mUserAgent;
-    protected String mContentType;
+    private final LoadListener mListener;
+    private final String mMethod;
+    private final boolean mIsHighPriority;
+    private final WebSettings mSettings;
+    private Map<String, String> mHeaders;
+    private byte[] mPostData;
+    private Network mNetwork;
+    private int mCacheMode;
+    private String mReferrer;
+    private String mContentType;
 
     private static final int URI_PROTOCOL = 0x100;
 
@@ -53,43 +53,14 @@
 
     private static final String LOGTAG = "webkit";
     
-    /*
-     * Construct the Accept_Language once. If the user changes language, then
-     * the phone will be rebooted.
-     */
-    private static String ACCEPT_LANGUAGE;
-    static {
-        // Set the accept-language to the current locale plus US if we are in a
-        // different locale than US.
-        java.util.Locale l = java.util.Locale.getDefault();
-        ACCEPT_LANGUAGE = "";
-        if (l.getLanguage() != null) {
-            ACCEPT_LANGUAGE += l.getLanguage();
-            if (l.getCountry() != null) {
-                ACCEPT_LANGUAGE += "-" + l.getCountry();
-            }
-        }
-        if (!l.equals(java.util.Locale.US)) {
-            ACCEPT_LANGUAGE += ", ";
-            java.util.Locale us = java.util.Locale.US;
-            if (us.getLanguage() != null) {
-                ACCEPT_LANGUAGE += us.getLanguage();
-                if (us.getCountry() != null) {
-                    ACCEPT_LANGUAGE += "-" + us.getCountry();
-                }
-            }
-        }
-    }
-
-
-    FrameLoader(LoadListener listener, String userAgent,
+    FrameLoader(LoadListener listener, WebSettings settings,
             String method, boolean highPriority) {
         mListener = listener;
         mHeaders = null;
         mMethod = method;
         mIsHighPriority = highPriority;
         mCacheMode = WebSettings.LOAD_NORMAL;
-        mUserAgent = userAgent;
+        mSettings = settings;
     }
 
     public void setReferrer(String ref) {
@@ -97,7 +68,7 @@
         if (URLUtil.isNetworkUrl(ref)) mReferrer = ref;
     }
 
-    public void setPostData(String postData) {
+    public void setPostData(byte[] postData) {
         mPostData = postData;
     }
 
@@ -140,12 +111,15 @@
         }
 
         if (URLUtil.isNetworkUrl(url)){
+            if (mSettings.getBlockNetworkLoads()) {
+                mListener.error(EventHandler.ERROR_BAD_URL,
+                        mListener.getContext().getString(
+                                com.android.internal.R.string.httpErrorBadUrl));
+                return false;
+            }
             mNetwork = Network.getInstance(mListener.getContext());
-            return handleHTTPLoad(false);
-        } else if (URLUtil.isCookielessProxyUrl(url)) {
-            mNetwork = Network.getInstance(mListener.getContext());
-            return handleHTTPLoad(true);
-        } else if (handleLocalFile(url, mListener)) {
+            return handleHTTPLoad();
+        } else if (handleLocalFile(url, mListener, mSettings)) {
             return true;
         }
         if (Config.LOGV) {
@@ -160,14 +134,15 @@
     }
 
     /* package */
-    static boolean handleLocalFile(String url, LoadListener loadListener) {
+    static boolean handleLocalFile(String url, LoadListener loadListener,
+            WebSettings settings) {
         if (URLUtil.isAssetUrl(url)) {
             FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
-                    true);
+                    true, settings.getAllowFileAccess());
             return true;
         } else if (URLUtil.isFileUrl(url)) {
             FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
-                    false);
+                    false, settings.getAllowFileAccess());
             return true;
         } else if (URLUtil.isContentUrl(url)) {
             // Send the raw url to the ContentLoader because it will do a
@@ -186,21 +161,12 @@
         return false;
     }
     
-    protected boolean handleHTTPLoad(boolean proxyUrl) {
+    private boolean handleHTTPLoad() {
         if (mHeaders == null) {
             mHeaders = new HashMap<String, String>();
         }
         populateStaticHeaders();
-
-        if (!proxyUrl) {
-            // Don't add private information if this is a proxy load, ie don't
-            // add cookies and authentication
-            populateHeaders();
-        } else {
-            // If this is a proxy URL, fix it to be a network load
-            mListener.setUrl("http://"
-                    + mListener.url().substring(URLUtil.PROXY_BASE.length()));
-        }
+        populateHeaders();
 
         // response was handled by UrlIntercept, don't issue HTTP request
         if (handleUrlIntercept()) return true;
@@ -246,7 +212,7 @@
      * This function is used by handleUrlInterecpt and handleCache to
      * setup a load from the byte stream in a CacheResult.
      */
-    protected void startCacheLoad(CacheResult result) {
+    private void startCacheLoad(CacheResult result) {
         if (Config.LOGV) {
             Log.v(LOGTAG, "FrameLoader: loading from cache: "
                   + mListener.url());
@@ -264,7 +230,7 @@
      *
      * Returns true if the response was handled by UrlIntercept.
      */
-    protected boolean handleUrlIntercept() {
+    private boolean handleUrlIntercept() {
         // Check if the URL can be served from UrlIntercept. If
         // successful, return the data just like a cache hit.
         CacheResult result = UrlInterceptRegistry.getSurrogate(
@@ -284,7 +250,7 @@
      * correctly.
      * Returns true if the response was handled from the cache
      */
-    protected boolean handleCache() {
+    private boolean handleCache() {
         switch (mCacheMode) {
             // This mode is normally used for a reload, it instructs the http
             // loader to not use the cached content.
@@ -357,11 +323,12 @@
         }
         mHeaders.put("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7");
 
-        if (ACCEPT_LANGUAGE.length() > 0) {
-            mHeaders.put("Accept-Language", ACCEPT_LANGUAGE);
+        String acceptLanguage = mSettings.getAcceptLanguage();
+        if (acceptLanguage.length() > 0) {
+            mHeaders.put("Accept-Language", acceptLanguage);
         }
-
-        mHeaders.put("User-Agent", mUserAgent);
+        
+        mHeaders.put("User-Agent", mSettings.getUserAgentString());
     }
 
     /**
diff --git a/core/java/android/webkit/HttpDateTime.java b/core/java/android/webkit/HttpDateTime.java
index b22f2ba..c6ec2d2 100644
--- a/core/java/android/webkit/HttpDateTime.java
+++ b/core/java/android/webkit/HttpDateTime.java
@@ -16,7 +16,7 @@
 
 package android.webkit;
 
-import android.pim.Time;
+import android.text.format.Time;
 
 import java.util.Calendar;
 import java.util.regex.Matcher;
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index 1cfea99..a0049ac 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -191,4 +191,5 @@
     private native void nativeFinalize();
     private native void sharedTimerFired();
     private native void setDeferringTimers(boolean defer);
+    public native void setNetworkOnLine(boolean online);
 }
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 86947a2..c45ab29 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -99,7 +99,7 @@
     // cache. It is needed if the cache returns a redirect
     private String mMethod;
     private Map<String, String> mRequestHeaders;
-    private String mPostData;
+    private byte[] mPostData;
     private boolean mIsHighPriority;
     // Flag to indicate that this load is synchronous.
     private boolean mSynchronous;
@@ -220,7 +220,8 @@
                  */
                 Message contMsg = obtainMessage(MSG_LOCATION_CHANGED);
                 Message stopMsg = obtainMessage(MSG_CONTENT_FINISHED);
-                //TODO, need to call mCallbackProxy and request UI.
+                mBrowserFrame.getCallbackProxy().onFormResubmission(
+                        stopMsg, contMsg);
                 break;
 
         }
@@ -286,15 +287,16 @@
                 if (newMimeType != null) {
                     mMimeType = newMimeType;
                 }
-            } else if (mMimeType.equalsIgnoreCase("text/vnd.wap.wml") || 
-                    mMimeType.
-                    equalsIgnoreCase("application/vnd.wap.xhtml+xml")) {
+            } else if (mMimeType.equalsIgnoreCase("text/vnd.wap.wml")) {
                 // As we don't support wml, render it as plain text
                 mMimeType = "text/plain";
             } else {
                 // XXX: Until the servers send us either correct xhtml or
                 // text/html, treat application/xhtml+xml as text/html.
-                if (mMimeType.equalsIgnoreCase("application/xhtml+xml")) {
+                // It seems that xhtml+xml and vnd.wap.xhtml+xml mime
+                // subtypes are used interchangeably. So treat them the same.
+                if (mMimeType.equalsIgnoreCase("application/xhtml+xml") ||
+                        mMimeType.equals("application/vnd.wap.xhtml+xml")) {
                     mMimeType = "text/html";
                 }
             }
@@ -527,23 +529,21 @@
                 } else {
                     sendMessageInternal(obtainMessage(MSG_LOCATION_CHANGED));
                 }
-
-                break;
+                return;
 
             case HTTP_AUTH:
             case HTTP_PROXY_AUTH:
+                // According to rfc2616, the response for HTTP_AUTH must include
+                // WWW-Authenticate header field and the response for 
+                // HTTP_PROXY_AUTH must include Proxy-Authenticate header field.
                 if (mAuthHeader != null &&
                         (Network.getInstance(mContext).isValidProxySet() ||
                          !mAuthHeader.isProxy())) {
                     Network.getInstance(mContext).handleAuthRequest(this);
-                } else {
-                    final int stringId =
-                            com.android.internal.R.string.httpErrorUnsupportedAuthScheme;
-                    error(EventHandler.ERROR_UNSUPPORTED_AUTH_SCHEME,
-                            getContext().getText(stringId).toString());
+                    return;
                 }
-                break;
-                
+                break;  // use default
+
             case HTTP_NOT_MODIFIED:
                 // Server could send back NOT_MODIFIED even if we didn't
                 // ask for it, so make sure we have a valid CacheLoader
@@ -554,16 +554,18 @@
                     if (Config.LOGV) {
                         Log.v(LOGTAG, "LoadListener cache load url=" + url());
                     }
-                    break;
-                } // Fall through to default if there is no CacheLoader
+                    return;
+                }
+                break;  // use default
 
             case HTTP_NOT_FOUND:
                 // Not an error, the server can send back content.
             default:
-                sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED));
-                detachRequestHandle();
                 break;
         }
+
+        sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED));
+        detachRequestHandle();
     }
 
     /**
@@ -725,7 +727,7 @@
      * @param isHighPriority
      */
     void setRequestData(String method, Map<String, String> headers, 
-            String postData, boolean isHighPriority) {
+            byte[] postData, boolean isHighPriority) {
         mMethod = method;
         mRequestHeaders = headers;
         mPostData = postData;
@@ -878,37 +880,16 @@
         int statusCode = mStatusCode == HTTP_NOT_MODIFIED
                 ? HTTP_OK : mStatusCode;
         // pass content-type content-length and content-encoding
-        int nativeResponse = nativeCreateResponse(mUrl, statusCode, mStatusText,
+        final int nativeResponse = nativeCreateResponse(
+                mUrl, statusCode, mStatusText,
                 mMimeType, mContentLength, mEncoding,
                 mCacheResult == null ? 0 : mCacheResult.expires / 1000);
         if (mHeaders != null) {
-            // "content-disposition",
-            String value = mHeaders.getContentDisposition();
-            if (value != null) {
-                nativeSetResponseHeader(nativeResponse, 
-                        Headers.CONTENT_DISPOSITION, value);
-            }
-            
-            // location            
-            value = mHeaders.getLocation();
-            if (value != null) {
-                nativeSetResponseHeader(nativeResponse,
-                        Headers.LOCATION, value);
-            }
-            
-            // refresh (paypal.com are using this)
-            value = mHeaders.getRefresh();
-            if (value != null) {
-                nativeSetResponseHeader(nativeResponse,
-                        Headers.REFRESH, value);
-            }
-
-            // Content-Type
-            value = mHeaders.getContentType();
-            if (value != null) {
-                nativeSetResponseHeader(nativeResponse,
-                        Headers.CONTENT_TYPE, value);
-            }
+            mHeaders.getHeaders(new Headers.HeaderCallback() {
+                    public void header(String name, String value) {
+                        nativeSetResponseHeader(nativeResponse, name, value);
+                    }
+                });
         }
         return nativeResponse;
     }
@@ -1048,7 +1029,6 @@
                 cancel();
                 return;
             } else if (!URLUtil.isNetworkUrl(redirectTo)) {
-                cancel();
                 final String text = mContext
                         .getString(com.android.internal.R.string.open_permission_deny)
                         + "\n" + redirectTo;
@@ -1250,7 +1230,12 @@
      */
     void setUrl(String url) {
         if (url != null) {
-            mUrl = URLUtil.stripAnchor(url);
+            if (URLUtil.isDataUrl(url)) {
+             // Don't strip anchor as that is a valid part of the URL
+                mUrl = url;
+            } else {
+                mUrl = URLUtil.stripAnchor(url);
+            }
             mUri = null;
             if (URLUtil.isNetworkUrl(mUrl)) {
                 try {
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index 2700aa5..85cb8c0 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -65,7 +65,7 @@
             // if the filename contains special characters, we don't
             // consider it valid for our matching purposes:
             if (filename.length() > 0 &&
-                Pattern.matches("[a-zA-Z_0-9\\.\\-]+", filename)) {
+                Pattern.matches("[a-zA-Z_0-9\\.\\-\\(\\)]+", filename)) {
                 int dotPos = filename.lastIndexOf('.');
                 if (0 <= dotPos) {
                     return filename.substring(dotPos + 1);
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index ea42e58..74622b3 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -155,7 +155,7 @@
      */
     public boolean requestURL(String method,
                               Map<String, String> headers,
-                              String postData,
+                              byte [] postData,
                               LoadListener loader,
                               boolean isHighPriority) {
 
@@ -178,9 +178,8 @@
         InputStream bodyProvider = null;
         int bodyLength = 0;
         if (postData != null) {
-            byte[] data = postData.getBytes();
-            bodyLength = data.length;
-            bodyProvider = new ByteArrayInputStream(data);
+            bodyLength = postData.length;
+            bodyProvider = new ByteArrayInputStream(postData);
         }
 
         RequestQueue q = mRequestQueue;
diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java
index 95209c7..4e9370c 100644
--- a/core/java/android/webkit/TextDialog.java
+++ b/core/java/android/webkit/TextDialog.java
@@ -124,6 +124,10 @@
         int flags = paint.getFlags() | Paint.SUBPIXEL_TEXT_FLAG |
                 Paint.ANTI_ALIAS_FLAG & ~Paint.DEV_KERN_TEXT_FLAG;
         paint.setFlags(flags);
+        // Set the text color to black, regardless of the theme.  This ensures
+        // that other applications that use embedded WebViews will properly
+        // display the text in textfields.
+        setTextColor(Color.BLACK);
     }
 
     @Override
@@ -395,6 +399,7 @@
      * focus to the host.
      */
     /* package */ void remove() {
+        mHandler.removeMessages(LONGPRESS);
         mWebView.removeView(this);
         mWebView.requestFocus();
     }
@@ -532,6 +537,7 @@
         mPreChange = text.toString();
         Editable edit = (Editable) getText();
         edit.replace(0, edit.length(), text);
+        updateCachedTextfield();
     }
     
     /**
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index 43666c1..0e8144e 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -145,6 +145,7 @@
     /**
      * @return True iff the url is an proxy url to allow cookieless network 
      * requests from a file url.
+     * @deprecated Cookieless proxy is no longer supported.
      */
     public static boolean isCookielessProxyUrl(String url) {
         return (null != url) && url.startsWith(PROXY_BASE);
diff --git a/core/java/android/webkit/WebBackForwardList.java b/core/java/android/webkit/WebBackForwardList.java
index c86b21d..9dea5ec 100644
--- a/core/java/android/webkit/WebBackForwardList.java
+++ b/core/java/android/webkit/WebBackForwardList.java
@@ -133,7 +133,7 @@
     }
 
     /* Remove the item at the given index. Called by JNI only. */
-    private void removeHistoryItem(int index) {
+    private synchronized void removeHistoryItem(int index) {
         // XXX: This is a special case. Since the callback is only triggered
         // when removing the first item, we can assert that the index is 0.
         // This lets us change the current index without having to query the
diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java
index 5570af8..a408e06 100644
--- a/core/java/android/webkit/WebHistoryItem.java
+++ b/core/java/android/webkit/WebHistoryItem.java
@@ -33,6 +33,8 @@
     private String mTitle;
     // The base url of this item.
     private String mUrl;
+    // The original requested url of this item.
+    private String mOriginalUrl;
     // The favicon for this item.
     private Bitmap mFavicon;
     // The pre-flattened data used for saving the state.
@@ -95,6 +97,18 @@
     }
 
     /**
+     * Return the original url of this history item. This was the requested
+     * url, the final url may be different as there might have been 
+     * redirects while loading the site.
+     * @return The original url of this history item.
+     * 
+     * @hide pending API Council approval
+     */
+    public String getOriginalUrl() {
+        return mOriginalUrl;
+    }
+    
+    /**
      * Return the document title of this history item.
      * @return The document title of this history item.
      * Note: The VM ensures 32-bit atomic read/write operations so we don't have
@@ -154,8 +168,10 @@
     private native void inflate(int nativeFrame, byte[] data);
 
     /* Called by jni when the item is updated */
-    private void update(String url, String title, Bitmap favicon, byte[] data) {
+    private void update(String url, String originalUrl, String title, 
+            Bitmap favicon, byte[] data) {
         mUrl = url;
+        mOriginalUrl = originalUrl;
         mTitle = title;
         mFavicon = favicon;
         mFlattenedData = data;
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index de64b30..1a7c4ff 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -20,6 +20,8 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
+import java.lang.SecurityException;
+import android.content.pm.PackageManager;
 
 import java.util.Locale;
 
@@ -111,6 +113,7 @@
     // retrieve the values. After setXXX, postSync() needs to be called.
     // XXX: The default values need to match those in WebSettings.cpp
     private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
+    private Context         mContext;
     private TextSize        mTextSize = TextSize.NORMAL;
     private String          mStandardFontFamily = "sans-serif";
     private String          mFixedFontFamily = "monospace";
@@ -119,7 +122,9 @@
     private String          mCursiveFontFamily = "cursive";
     private String          mFantasyFontFamily = "fantasy";
     private String          mDefaultTextEncoding = "Latin-1";
-    private String          mUserAgent = ANDROID_USERAGENT;
+    private String          mUserAgent;
+    private boolean         mUseDefaultUserAgent;
+    private String          mAcceptLanguage;
     private String          mPluginsPath = "";
     private int             mMinimumFontSize = 8;
     private int             mMinimumLogicalFontSize = 8;
@@ -127,12 +132,14 @@
     private int             mDefaultFixedFontSize = 13;
     private boolean         mLoadsImagesAutomatically = true;
     private boolean         mBlockNetworkImage = false;
+    private boolean         mBlockNetworkLoads = false;
     private boolean         mJavaScriptEnabled = false;
     private boolean         mPluginsEnabled = false;
     private boolean         mJavaScriptCanOpenWindowsAutomatically = false;
     private boolean         mUseDoubleTree = false;
     private boolean         mUseWideViewport = false;
     private boolean         mSupportMultipleWindows = false;
+    private boolean         mShrinksStandaloneImagesToFit = false;
     // Don't need to synchronize the get/set methods as they
     // are basic types, also none of these values are used in
     // native WebCore code.
@@ -144,6 +151,7 @@
     private boolean         mNeedInitialFocus = true;
     private boolean         mNavDump = false;
     private boolean         mSupportZoom = true;
+    private boolean         mAllowFileAccess = true;
 
     // Class to handle messages before WebCore is ready.
     private class EventHandler {
@@ -212,58 +220,113 @@
 
     // User agent strings.
     private static final String DESKTOP_USERAGENT =
-            "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/522+ " +
-            "(KHTML, like Gecko) Safari/419.3";
-    private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " +
-            "CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) " +
-            "Version/3.0 Mobile/1A543 Safari/419.3";
-    private static String ANDROID_USERAGENT;
-
+            "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en)"
+            + " AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2"
+            + " Safari/525.20.1";
+    private static final String IPHONE_USERAGENT = 
+            "Mozilla/5.0 (iPhone; U; CPU iPhone 2_1 like Mac OS X; en)"
+            + " AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2"
+            + " Mobile/5F136 Safari/525.20.1";
+    private static Locale sLocale;
+    private static Object sLockForLocaleSettings;
+    
     /**
      * Package constructor to prevent clients from creating a new settings
      * instance.
      */
-    WebSettings(Context context) {
-        if (ANDROID_USERAGENT == null) {
-            StringBuffer arg = new StringBuffer();
-            // Add version
-            final String version = Build.VERSION.RELEASE;
-            if (version.length() > 0) {
-                arg.append(version);
-            } else {
-                // default to "1.0"
-                arg.append("1.0");
-            }
-            arg.append("; ");
-            // Initialize the mobile user agent with the default locale.
-            final Locale l = Locale.getDefault();
-            final String language = l.getLanguage();
-            if (language != null) {
-                arg.append(language.toLowerCase());
-                final String country = l.getCountry();
-                if (country != null) {
-                    arg.append("-");
-                    arg.append(country.toLowerCase());
-                }
-            } else {
-                // default to "en"
-                arg.append("en");
-            }
-            // Add device name
-            final String device = Build.DEVICE;
-            if (device.length() > 0) {
-                arg.append("; ");
-                arg.append(device);
-            }
-            final String base = context.getResources().getText(
-                    com.android.internal.R.string.web_user_agent).toString();
-            ANDROID_USERAGENT = String.format(base, arg);
-            mUserAgent = ANDROID_USERAGENT;
-        }
+    WebSettings(Context context) {   
         mEventHandler = new EventHandler();
+        mContext = context;
+
+        if (sLockForLocaleSettings == null) {
+            sLockForLocaleSettings = new Object();
+            sLocale = Locale.getDefault();
+        }
+        mAcceptLanguage = getCurrentAcceptLanguage();
+        mUserAgent = getCurrentUserAgent();
+        mUseDefaultUserAgent = true;
+
+        verifyNetworkAccess();
     }
 
     /**
+     * Looks at sLocale and returns current AcceptLanguage String.
+     * @return Current AcceptLanguage String.
+     */
+    private String getCurrentAcceptLanguage() {
+        Locale locale;
+        synchronized(sLockForLocaleSettings) {
+            locale = sLocale;
+        }
+        StringBuffer buffer = new StringBuffer();
+        final String language = locale.getLanguage();
+        if (language != null) {
+            buffer.append(language);
+            final String country = locale.getCountry();
+            if (country != null) {
+                buffer.append("-");
+                buffer.append(country);
+            }
+        }
+        if (!locale.equals(Locale.US)) {
+            buffer.append(", ");
+            java.util.Locale us = Locale.US;
+            if (us.getLanguage() != null) {
+                buffer.append(us.getLanguage());
+                final String country = us.getCountry();
+                if (country != null) {
+                    buffer.append("-");
+                    buffer.append(country);
+                }
+            }
+        }
+
+        return buffer.toString();
+    }
+    
+    /**
+     * Looks at sLocale and mContext and returns current UserAgent String.
+     * @return Current UserAgent String.
+     */
+    private synchronized String getCurrentUserAgent() {
+        Locale locale;
+        synchronized(sLockForLocaleSettings) {
+            locale = sLocale;
+        }
+        StringBuffer buffer = new StringBuffer();
+        // Add version
+        final String version = Build.VERSION.RELEASE;
+        if (version.length() > 0) {
+            buffer.append(version);
+        } else {
+            // default to "1.0"
+            buffer.append("1.0");
+        }  
+        buffer.append("; ");
+        final String language = locale.getLanguage();
+        if (language != null) {
+            buffer.append(language.toLowerCase());
+            final String country = locale.getCountry();
+            if (country != null) {
+                buffer.append("-");
+                buffer.append(country.toLowerCase());
+            }
+        } else {
+            // default to "en"
+            buffer.append("en");
+        }
+        
+        final String device = Build.DEVICE;
+        if (device.length() > 0) {
+            buffer.append("; ");
+            buffer.append(device);
+        }
+        final String base = mContext.getResources().getText(
+                com.android.internal.R.string.web_user_agent).toString();
+        return String.format(base, buffer);
+    }
+    
+    /**
      * Enables dumping the pages navigation cache to a text file.
      */
     public void setNavDump(boolean enabled) {
@@ -292,6 +355,21 @@
     }
 
     /**
+     * Enable or disable file access within WebView. File access is enabled by
+     * default.
+     */
+    public void setAllowFileAccess(boolean allow) {
+        mAllowFileAccess = allow;
+    }
+
+    /**
+     * Returns true if this WebView supports file access.
+     */
+    public boolean getAllowFileAccess() {
+        return mAllowFileAccess;
+    }
+
+    /**
      * Store whether the WebView is saving form data.
      */
     public void setSaveFormData(boolean save) {
@@ -377,34 +455,48 @@
      * Tell the WebView about user-agent string.
      * @param ua 0 if the WebView should use an Android user-agent string,
      *           1 if the WebView should use a desktop user-agent string.
-     *           2 if the WebView should use an iPhone user-agent string.
+     *
+     * @deprecated Please use setUserAgentString instead.
      */
+    @Deprecated
     public synchronized void setUserAgent(int ua) {
-        if (ua == 0 && !ANDROID_USERAGENT.equals(mUserAgent)) {
-            mUserAgent = ANDROID_USERAGENT;
-            postSync();
-        } else if (ua == 1 && !DESKTOP_USERAGENT.equals(mUserAgent)) {
-            mUserAgent = DESKTOP_USERAGENT;
-            postSync();
-        } else if (ua == 2 && !IPHONE_USERAGENT.equals(mUserAgent)) {
-            mUserAgent = IPHONE_USERAGENT;
-            postSync();
+        String uaString = null;
+        if (ua == 1) {
+            if (DESKTOP_USERAGENT.equals(mUserAgent)) {
+                return; // do nothing
+            } else {
+                uaString = DESKTOP_USERAGENT;
+            }
+        } else if (ua == 2) {
+            if (IPHONE_USERAGENT.equals(mUserAgent)) {
+                return; // do nothing
+            } else {
+                uaString = IPHONE_USERAGENT;
+            }
+        } else if (ua != 0) {
+            return; // do nothing
         }
+        setUserAgentString(uaString);
     }
 
     /**
      * Return user-agent as int
      * @return int  0 if the WebView is using an Android user-agent string.
      *              1 if the WebView is using a desktop user-agent string.
-     *              2 if the WebView is using an iPhone user-agent string.
+     *             -1 if the WebView is using user defined user-agent string.
+     *
+     * @deprecated Please use getUserAgentString instead.
      */
+    @Deprecated
     public synchronized int getUserAgent() {
         if (DESKTOP_USERAGENT.equals(mUserAgent)) {
             return 1;
         } else if (IPHONE_USERAGENT.equals(mUserAgent)) {
             return 2;
+        } else if (mUseDefaultUserAgent) {
+            return 0;
         }
-        return 0;
+        return -1;
     }
 
     /**
@@ -706,6 +798,40 @@
     public synchronized boolean getBlockNetworkImage() {
         return mBlockNetworkImage;
     }
+    
+    /**
+     * @hide
+     * Tell the WebView to block all network load requests. 
+     * @param flag True if the WebView should block all network loads
+     */
+    public synchronized void setBlockNetworkLoads(boolean flag) {
+        if (mBlockNetworkLoads != flag) {
+            mBlockNetworkLoads = flag;
+            verifyNetworkAccess();
+        }
+    }
+
+    /**
+     * @hide
+     * Return true if the WebView will block all network loads.
+     * @return True if the WebView blocks all network loads.
+     */
+    public synchronized boolean getBlockNetworkLoads() {
+        return mBlockNetworkLoads;
+    }
+    
+    
+    private void verifyNetworkAccess() {
+        if (!mBlockNetworkLoads) {
+            if (mContext.checkPermission("android.permission.INTERNET", 
+                    android.os.Process.myPid(), 0) != 
+                        PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException
+                        ("Permission denied - " +
+                                "application missing INTERNET permission");
+            }
+        }
+    }
 
     /**
      * Tell the WebView to enable javascript execution.
@@ -806,11 +932,69 @@
         return mDefaultTextEncoding;
     }
 
-    /* Package api to grab the user agent string. */
-    /*package*/ synchronized String getUserAgentString() {
+    /**
+     * Set the WebView's user-agent string. If the string "ua" is null or empty,
+     * it will use the system default user-agent string.
+     */
+    public synchronized void setUserAgentString(String ua) {
+        if (ua == null || ua.length() == 0) {
+            synchronized(sLockForLocaleSettings) {
+                Locale currentLocale = Locale.getDefault(); 
+                if (!sLocale.equals(currentLocale)) {
+                    sLocale = currentLocale;
+                    mAcceptLanguage = getCurrentAcceptLanguage();
+                }
+            }
+            ua = getCurrentUserAgent();
+            mUseDefaultUserAgent = true;
+        } else  {
+            mUseDefaultUserAgent = false;
+        }
+
+        if (!ua.equals(mUserAgent)) {
+            mUserAgent = ua;
+            postSync();
+        }
+    }
+
+    /**
+     * Return the WebView's user-agent string.
+     */
+    public synchronized String getUserAgentString() {
+        if (DESKTOP_USERAGENT.equals(mUserAgent) ||
+                IPHONE_USERAGENT.equals(mUserAgent) ||
+                !mUseDefaultUserAgent) {
+            return mUserAgent;
+        }
+
+        boolean doPostSync = false;
+        synchronized(sLockForLocaleSettings) {
+            Locale currentLocale = Locale.getDefault();
+            if (!sLocale.equals(currentLocale)) {
+                sLocale = currentLocale;
+                mUserAgent = getCurrentUserAgent();
+                mAcceptLanguage = getCurrentAcceptLanguage();
+                doPostSync = true;
+            }
+        }
+        if (doPostSync) {
+            postSync();
+        }
         return mUserAgent;
     }
 
+    /* package api to grab the Accept Language string. */
+    /*package*/ synchronized String getAcceptLanguage() {
+        synchronized(sLockForLocaleSettings) {
+            Locale currentLocale = Locale.getDefault();
+            if (!sLocale.equals(currentLocale)) {
+                sLocale = currentLocale;
+                mAcceptLanguage = getCurrentAcceptLanguage();
+            }
+        }
+        return mAcceptLanguage;
+    }
+    
     /**
      * Tell the WebView whether it needs to set a node to have focus when
      * {@link WebView#requestFocus(int, android.graphics.Rect)} is called.
@@ -863,6 +1047,20 @@
     public int getCacheMode() {
         return mOverrideCacheMode;
     }
+    
+    /**
+     * If set, webkit alternately shrinks and expands images viewed outside
+     * of an HTML page to fit the screen. This conflicts with attempts by
+     * the UI to zoom in and out of an image, so it is set false by default.
+     * @param shrink Set true to let webkit shrink the standalone image to fit.
+     * {@hide}
+     */
+    public void setShrinksStandaloneImagesToFit(boolean shrink) {
+        if (mShrinksStandaloneImagesToFit != shrink) {
+            mShrinksStandaloneImagesToFit = shrink;
+            postSync();
+        }
+     }
 
     /**
      * Transfer messages from the queue to the new WebCoreThread. Called from
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6623257..7467b83 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -56,6 +56,7 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.ViewTreeObserver;
+import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebViewCore.EventHub;
 import android.widget.AbsoluteLayout;
 import android.widget.AdapterView;
@@ -94,6 +95,12 @@
         implements ViewTreeObserver.OnGlobalFocusChangeListener,
         ViewGroup.OnHierarchyChangeListener {
 
+    // if AUTO_REDRAW_HACK is true, then the CALL key will toggle redrawing
+    // the screen all-the-time. Good for profiling our drawing code
+    static private final boolean AUTO_REDRAW_HACK = false;
+    // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
+    private boolean mAutoRedraw;
+
     // keep debugging parameters near the top of the file
     static final String LOGTAG = "webview";
     static final boolean DEBUG = false;
@@ -112,7 +119,8 @@
                     (com.android.internal.R.id.zoomMagnify);
         }
         
-        public void show(boolean canZoomOut) {
+        public void show(boolean showZoom, boolean canZoomOut) {
+            mZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE);
             mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE);
             fade(View.VISIBLE, 0.0f, 1.0f);
         }
@@ -211,6 +219,17 @@
     private long mLastTouchTime;
 
     /**
+     * Time of the last time sending touch event to WebViewCore
+     */
+    private long mLastSentTouchTime;
+
+    /**
+     * The minimum elapsed time before sending another ACTION_MOVE event to
+     * WebViewCore
+     */
+    private static final int TOUCH_SENT_INTERVAL = 100;
+
+    /**
      * Helper class to get velocity for fling
      */
     VelocityTracker mVelocityTracker;
@@ -226,6 +245,7 @@
     private static final int TOUCH_SHORTPRESS_MODE = 5;
     private static final int TOUCH_DOUBLECLICK_MODE = 6;
     private static final int TOUCH_DONE_MODE = 7;
+    private static final int TOUCH_SELECT_MODE = 8;
     // touch mode values specific to scale+scroll
     private static final int FIRST_SCROLL_ZOOM = 9;
     private static final int SCROLL_ZOOM_ANIMATION_IN = 9;
@@ -234,6 +254,9 @@
     private static final int LAST_SCROLL_ZOOM = 11;
     // end of touch mode values specific to scale+scroll
 
+    // Whether to forward the touch events to WebCore
+    private boolean mForwardTouchEvents = false;
+
     // If updateTextEntry gets called while we are out of focus, use this 
     // variable to remember to do it next time we gain focus.
     private boolean mNeedsUpdateTextEntry = false;
@@ -337,7 +360,9 @@
     static final int NOTIFY_FOCUS_SET_MSG_ID        = 20;
     static final int MARK_NODE_INVALID_ID           = 21;
     static final int UPDATE_CLIPBOARD               = 22;
-    static final int LONG_PRESS_TRACKBALL           = 24;
+    static final int LONG_PRESS_ENTER               = 23;
+    static final int PREVENT_TOUCH_ID               = 24;
+    static final int WEBCORE_NEED_TOUCH_EVENTS      = 25;
 
     // width which view is considered to be fully zoomed out
     static final int ZOOM_OUT_WIDTH = 1024;
@@ -524,23 +549,23 @@
         setVerticalScrollBarEnabled(true);
     }
 
-    /* package */ boolean onSavePassword(String host, String username,
+    /* package */ boolean onSavePassword(String schemePlusHost, String username,
             String password, final Message resumeMsg) {
        boolean rVal = false;
        if (resumeMsg == null) {
            // null resumeMsg implies saving password silently
-           mDatabase.setUsernamePassword(host, username, password);
+           mDatabase.setUsernamePassword(schemePlusHost, username, password);
        } else {
             final Message remember = mPrivateHandler.obtainMessage(
                     REMEMBER_PASSWORD);
-            remember.getData().putString("host", host);
+            remember.getData().putString("host", schemePlusHost);
             remember.getData().putString("username", username);
             remember.getData().putString("password", password);
             remember.obj = resumeMsg;
 
             final Message neverRemember = mPrivateHandler.obtainMessage(
                     NEVER_REMEMBER_PASSWORD);
-            neverRemember.getData().putString("host", host);
+            neverRemember.getData().putString("host", schemePlusHost);
             neverRemember.getData().putString("username", username);
             neverRemember.getData().putString("password", password);
             neverRemember.obj = resumeMsg;
@@ -749,14 +774,36 @@
     public static void disablePlatformNotifications() {
         Network.disablePlatformNotifications();
     }
+    
+    /**
+     * Inform WebView of the network state. This is used to set
+     * the javascript property window.navigator.isOnline and
+     * generates the online/offline event as specified in HTML5, sec. 5.7.7
+     * @param networkUp boolean indicating if network is available
+     * 
+     * @hide pending API Council approval
+     */
+    public void setNetworkAvailable(boolean networkUp) {
+        BrowserFrame.sJavaBridge.setNetworkOnLine(networkUp);
+    }
 
     /**
-     * Save the state of this WebView used in Activity.onSaveInstanceState.
+     * Save the state of this WebView used in 
+     * {@link android.app.Activity#onSaveInstanceState}. Please note that this
+     * method no longer stores the display data for this WebView. The previous
+     * behavior could potentially leak files if {@link #restoreState} was never
+     * called. See {@link #savePicture} and {@link #restorePicture} for saving
+     * and restoring the display data.
      * @param outState The Bundle to store the WebView state.
      * @return The same copy of the back/forward list used to save the state. If
      *         saveState fails, the returned list will be null.
+     * @see #savePicture
+     * @see #restorePicture
      */
     public WebBackForwardList saveState(Bundle outState) {
+        if (outState == null) {
+            return null;
+        }
         // We grab a copy of the back/forward list because a client of WebView
         // may have invalidated the history list by calling clearHistory.
         WebBackForwardList list = copyBackForwardList();
@@ -782,29 +829,6 @@
                 return null;
             }
             history.add(data);
-            if (i == currentIndex) {
-                Picture p = capturePicture();
-                String path = mContext.getDir("thumbnails", 0).getPath()
-                        + File.separatorChar + hashCode() + "_pic.save";
-                File f = new File(path);
-                try {
-                    final FileOutputStream out = new FileOutputStream(f);
-                    p.writeToStream(out);
-                    out.close();
-                } catch (FileNotFoundException e){
-                    e.printStackTrace();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                } catch (RuntimeException e) {
-                    e.printStackTrace();
-                }
-                if (f.length() > 0) {
-                    outState.putString("picture", path);
-                    outState.putInt("scrollX", mScrollX);
-                    outState.putInt("scrollY", mScrollY);
-                    outState.putFloat("scale", mActualScale);
-                }
-            }
         }
         outState.putSerializable("history", history);
         if (mCertificate != null) {
@@ -815,16 +839,103 @@
     }
 
     /**
+     * Save the current display data to the Bundle given. Used in conjunction
+     * with {@link #saveState}.
+     * @param b A Bundle to store the display data.
+     * @param dest The file to store the serialized picture data. Will be
+     *             overwritten with this WebView's picture data.
+     * @return True if the picture was successfully saved.
+     */
+    public boolean savePicture(Bundle b, File dest) {
+        if (dest == null || b == null) {
+            return false;
+        }
+        final Picture p = capturePicture();
+        try {
+            final FileOutputStream out = new FileOutputStream(dest);
+            p.writeToStream(out);
+            out.close();
+        } catch (FileNotFoundException e){
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (RuntimeException e) {
+            e.printStackTrace();
+        }
+        if (dest.length() > 0) {
+            b.putInt("scrollX", mScrollX);
+            b.putInt("scrollY", mScrollY);
+            b.putFloat("scale", mActualScale);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Restore the display data that was save in {@link #savePicture}. Used in
+     * conjunction with {@link #restoreState}.
+     * @param b A Bundle containing the saved display data.
+     * @param src The file where the picture data was stored.
+     * @return True if the picture was successfully restored.
+     */
+    public boolean restorePicture(Bundle b, File src) {
+        if (src == null || b == null) {
+            return false;
+        }
+        if (src.exists()) {
+            Picture p = null;
+            try {
+                final FileInputStream in = new FileInputStream(src);
+                p = Picture.createFromStream(in);
+                in.close();
+            } catch (FileNotFoundException e){
+                e.printStackTrace();
+            } catch (RuntimeException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            if (p != null) {
+                int sx = b.getInt("scrollX", 0);
+                int sy = b.getInt("scrollY", 0);
+                float scale = b.getFloat("scale", 1.0f);
+                mDrawHistory = true;
+                mHistoryPicture = p;
+                mScrollX = sx;
+                mScrollY = sy;
+                mHistoryWidth = Math.round(p.getWidth() * scale);
+                mHistoryHeight = Math.round(p.getHeight() * scale);
+                // as getWidth() / getHeight() of the view are not
+                // available yet, set up mActualScale, so that when
+                // onSizeChanged() is called, the rest will be set
+                // correctly
+                mActualScale = scale;
+                invalidate();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Restore the state of this WebView from the given map used in
-     * Activity.onThaw. This method should be called to restore the state of
-     * the WebView before using the object. If it is called after the WebView
-     * has had a chance to build state (load pages, create a back/forward list,
-     * etc.) there may be undesirable side-effects.
+     * {@link android.app.Activity#onRestoreInstanceState}. This method should 
+     * be called to restore the state of the WebView before using the object. If 
+     * it is called after the WebView has had a chance to build state (load 
+     * pages, create a back/forward list, etc.) there may be undesirable 
+     * side-effects. Please note that this method no longer restores the
+     * display data for this WebView. See {@link #savePicture} and {@link
+     * #restorePicture} for saving and restoring the display data.
      * @param inState The incoming Bundle of state.
      * @return The restored back/forward list or null if restoreState failed.
+     * @see #savePicture
+     * @see #restorePicture
      */
     public WebBackForwardList restoreState(Bundle inState) {
         WebBackForwardList returnList = null;
+        if (inState == null) {
+            return returnList;
+        }
         if (inState.containsKey("index") && inState.containsKey("history")) {
             mCertificate = SslCertificate.restoreState(
                 inState.getBundle("certificate"));
@@ -853,42 +964,6 @@
                     WebHistoryItem item = new WebHistoryItem(data);
                     list.addHistoryItem(item);
                 }
-                if (inState.containsKey("picture")) {
-                    String path = inState.getString("picture");
-                    File f = new File(path);
-                    if (f.exists()) {
-                        Picture p = null;
-                        try {
-                            final FileInputStream in = new FileInputStream(f);
-                            p = Picture.createFromStream(in);
-                            in.close();
-                            f.delete();
-                        } catch (FileNotFoundException e){
-                            e.printStackTrace();
-                        } catch (RuntimeException e) {
-                            e.printStackTrace();
-                        } catch (IOException e) {
-                            e.printStackTrace();
-                        }
-                        if (p != null) {
-                            int sx = inState.getInt("scrollX", 0);
-                            int sy = inState.getInt("scrollY", 0);
-                            float scale = inState.getFloat("scale", 1.0f);
-                            mDrawHistory = true;
-                            mHistoryPicture = p;
-                            mScrollX = sx;
-                            mScrollY = sy;
-                            mHistoryWidth = Math.round(p.getWidth() * scale);
-                            mHistoryHeight = Math.round(p.getHeight() * scale);
-                            // as getWidth() / getHeight() of the view are not
-                            // available yet, set up mActualScale, so that when
-                            // onSizeChanged() is called, the rest will be set
-                            // correctly
-                            mActualScale = scale;
-                            invalidate();
-                        }
-                    }
-                }
                 // Grab the most recent copy to return to the caller.
                 returnList = copyBackForwardList();
                 // Update the copy to have the correct index.
@@ -929,14 +1004,22 @@
      * Load the given data into the WebView, use the provided URL as the base
      * URL for the content. The base URL is the URL that represents the page
      * that is loaded through this interface. As such, it is used for the
-     * history entry and to resolve any relative URLs.
-     * The failUrl is used if browser fails to load the data provided. If it 
-     * is empty or null, and the load fails, then no history entry is created.
+     * history entry and to resolve any relative URLs. The failUrl is used if
+     * browser fails to load the data provided. If it is empty or null, and the
+     * load fails, then no history entry is created.
+     * <p>
+     * Note for post 1.0. Due to the change in the WebKit, the access to asset
+     * files through "file:///android_asset/" for the sub resources is more
+     * restricted. If you provide null or empty string as baseUrl, you won't be
+     * able to access asset files. If the baseUrl is anything other than
+     * http(s)/ftp(s)/about/javascript as scheme, you can access asset files for
+     * sub resources.
+     * 
      * @param baseUrl Url to resolve relative paths with, if null defaults to
-     *        "about:blank"
+     *            "about:blank"
      * @param data A String of data in the given encoding.
      * @param mimeType The MIMEType of the data. i.e. text/html. If null,
-     *        defaults to "text/html"
+     *            defaults to "text/html"
      * @param encoding The encoding of the data. i.e. utf-8, us-ascii
      * @param failUrl URL to use if the content fails to load or null.
      */
@@ -1133,7 +1216,7 @@
     public void clearView() {
         mContentWidth = 0;
         mContentHeight = 0;
-        mWebViewCore.clearContentPicture();
+        mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
     }
     
     /**
@@ -1197,7 +1280,7 @@
         clearTextEntry();
         ExtendedZoomControls zoomControls = (ExtendedZoomControls) 
                 getZoomControls();
-        zoomControls.show(canZoomScrollOut());
+        zoomControls.show(true, canZoomScrollOut());
         zoomControls.requestFocus();
         mPrivateHandler.removeCallbacks(mZoomControlRunnable);
         mPrivateHandler.postDelayed(mZoomControlRunnable,
@@ -1206,11 +1289,15 @@
 
     /**
      * Return a HitTestResult based on the current focus node. If a HTML::a tag
-     * is found, the HitTestResult type is set to ANCHOR_TYPE and the url has to
-     * be retrieved through {@link #requestFocusNodeHref} asynchronously. If a
-     * HTML::img tag is found, the HitTestResult type is set to IMAGE_TYPE and
-     * the url has to be retrieved through {@link #requestFocusNodeHref}
-     * asynchronously. If a phone number is found, the HitTestResult type is set
+     * is found and the anchor has a non-javascript url, the HitTestResult type
+     * is set to SRC_ANCHOR_TYPE and the url is set in the "extra" field. If the
+     * anchor does not have a url or if it is a javascript url, the type will
+     * be UNKNOWN_TYPE and the url has to be retrieved through
+     * {@link #requestFocusNodeHref} asynchronously. If a HTML::img tag is
+     * found, the HitTestResult type is set to IMAGE_TYPE and the url is set in
+     * the "extra" field. A type of
+     * SRC_IMAGE_ANCHOR_TYPE indicates an anchor with a url that has an image as
+     * a child node. If a phone number is found, the HitTestResult type is set
      * to PHONE_TYPE and the phone number is set in the "extra" field of
      * HitTestResult. If a map address is found, the HitTestResult type is set
      * to GEO_TYPE and the address is set in the "extra" field of HitTestResult.
@@ -1227,42 +1314,38 @@
 
         if (nativeUpdateFocusNode()) {
             FocusNode node = mFocusNode;
-            if (node.mIsAnchor && node.mText == null) {
-                result.setType(HitTestResult.ANCHOR_TYPE);
-            } else if (node.mIsTextField || node.mIsTextArea) {
+            if (node.mIsTextField || node.mIsTextArea) {
                 result.setType(HitTestResult.EDIT_TEXT_TYPE);
-            } else {
+            } else if (node.mText != null) {
                 String text = node.mText;
-                if (text != null) {
-                    if (text.startsWith(SCHEME_TEL)) {
-                        result.setType(HitTestResult.PHONE_TYPE);
-                        result.setExtra(text.substring(SCHEME_TEL.length()));
-                    } else if (text.startsWith(SCHEME_MAILTO)) {
-                        result.setType(HitTestResult.EMAIL_TYPE);
-                        result.setExtra(text.substring(SCHEME_MAILTO.length()));
-                    } else if (text.startsWith(SCHEME_GEO)) {
-                        result.setType(HitTestResult.GEO_TYPE);
-                        result.setExtra(URLDecoder.decode(text
-                                .substring(SCHEME_GEO.length())));
-                    }
+                if (text.startsWith(SCHEME_TEL)) {
+                    result.setType(HitTestResult.PHONE_TYPE);
+                    result.setExtra(text.substring(SCHEME_TEL.length()));
+                } else if (text.startsWith(SCHEME_MAILTO)) {
+                    result.setType(HitTestResult.EMAIL_TYPE);
+                    result.setExtra(text.substring(SCHEME_MAILTO.length()));
+                } else if (text.startsWith(SCHEME_GEO)) {
+                    result.setType(HitTestResult.GEO_TYPE);
+                    result.setExtra(URLDecoder.decode(text
+                            .substring(SCHEME_GEO.length())));
+                } else if (node.mIsAnchor) {
+                    result.setType(HitTestResult.SRC_ANCHOR_TYPE);
+                    result.setExtra(text);
                 }
             }
         }
         int type = result.getType();
         if (type == HitTestResult.UNKNOWN_TYPE
-                || type == HitTestResult.ANCHOR_TYPE) {
+                || type == HitTestResult.SRC_ANCHOR_TYPE) {
             // Now check to see if it is an image.
             int contentX = viewToContent((int) mLastTouchX + mScrollX);
             int contentY = viewToContent((int) mLastTouchY + mScrollY);
-            if (nativeIsImage(contentX, contentY)) {
+            String text = nativeImageURI(contentX, contentY);
+            if (text != null) {
                 result.setType(type == HitTestResult.UNKNOWN_TYPE ? 
                         HitTestResult.IMAGE_TYPE : 
-                        HitTestResult.IMAGE_ANCHOR_TYPE);
-            }
-            if (nativeHasSrcUrl()) {
-                result.setType(result.getType() == HitTestResult.ANCHOR_TYPE ? 
-                        HitTestResult.SRC_ANCHOR_TYPE : 
                         HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
+                result.setExtra(text);
             }
         }
         return result;
@@ -1284,12 +1367,15 @@
         if (nativeUpdateFocusNode()) {
             FocusNode node = mFocusNode;
             if (node.mIsAnchor) {
+                // NOTE: We may already have the url of the anchor stored in
+                // node.mText but it may be out of date or the caller may want
+                // to know about javascript urls.
                 mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF,
                         node.mFramePointer, node.mNodePointer, hrefMsg);
             }
         }
     }
-
+    
     /**
      * Request the url of the image last touched by the user. msg will be sent
      * to its target with a String representing the url as its object.
@@ -1298,13 +1384,13 @@
      *            as the data member with "url" as key. The result can be null.
      */
     public void requestImageRef(Message msg) {
-        if (msg == null || mNativeClass == 0) {
-            return;
-        }
         int contentX = viewToContent((int) mLastTouchX + mScrollX);
         int contentY = viewToContent((int) mLastTouchY + mScrollY);
-        mWebViewCore.sendMessage(EventHub.REQUEST_IMAGE_HREF, contentX,
-                contentY, msg);
+        String ref = nativeImageURI(contentX, contentY);
+        Bundle data = msg.getData();
+        data.putString("url", ref);
+        msg.setData(data);
+        msg.sendToTarget();
     }
 
     private static int pinLoc(int x, int viewMax, int docMax) {
@@ -1340,6 +1426,25 @@
         return Math.round(x * mActualScale);
     }
 
+    // Called by JNI to invalidate the View, given rectangle coordinates in
+    // content space
+    private void viewInvalidate(int l, int t, int r, int b) {
+        invalidate(contentToView(l), contentToView(t), contentToView(r),
+                contentToView(b));
+    }
+
+    // Called by JNI to invalidate the View after a delay, given rectangle
+    // coordinates in content space
+    private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) {
+        postInvalidateDelayed(delay, contentToView(l), contentToView(t),
+                contentToView(r), contentToView(b));
+    }
+
+    private Rect contentToView(Rect x) {
+        return new Rect(contentToView(x.left), contentToView(x.top)
+                , contentToView(x.right), contentToView(x.bottom));
+    }
+
     /* call from webcoreview.draw(), so we're still executing in the UI thread
     */
     private void recordNewContentSize(int w, int h, boolean updateLayout) {
@@ -1420,15 +1525,29 @@
 
     // Used to avoid sending many visible rect messages.
     private Rect mLastVisibleRectSent;
+    private Rect mLastGlobalRect;
 
     private Rect sendOurVisibleRect() {
         Rect rect = new Rect();
         calcOurContentVisibleRect(rect);
+        if (mFindIsUp) {
+            rect.bottom -= viewToContent(FIND_HEIGHT);
+        }
         // Rect.equals() checks for null input.
         if (!rect.equals(mLastVisibleRectSent)) {
-            mWebViewCore.sendMessage(EventHub.SET_VISIBLE_RECT, rect);
+            mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
+                                     rect.left, rect.top);
             mLastVisibleRectSent = rect;
         }
+        Rect globalRect = new Rect();
+        if (getGlobalVisibleRect(globalRect)
+                && !globalRect.equals(mLastGlobalRect)) {
+            // TODO: the global offset is only used by windowRect()
+            // in ChromeClientAndroid ; other clients such as touch
+            // and mouse events could return view + screen relative points.
+            mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, globalRect);
+            mLastGlobalRect = globalRect;
+        }
         return rect;
     }
 
@@ -1488,12 +1607,19 @@
         }
     }
 
+    // Make sure this stays in sync with the actual height of the FindDialog.
+    private static final int FIND_HEIGHT = 79;
+
     @Override
     protected int computeVerticalScrollRange() {
         if (mDrawHistory) {
             return mHistoryHeight;
         } else {
-            return contentToView(mContentHeight);
+            int height = contentToView(mContentHeight);
+            if (mFindIsUp) {
+                height += FIND_HEIGHT;
+            }
+            return height;
         }
     }
 
@@ -1507,6 +1633,21 @@
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getUrl() : null;
     }
+    
+    /**
+     * Get the original url for the current page. This is not always the same 
+     * as the url passed to WebViewClient.onPageStarted because although the 
+     * load for that url has begun, the current page may not have changed.
+     * Also, there may have been redirects resulting in a different url to that
+     * originally requested.
+     * @return The url that was originally requested for the current page.
+     * 
+     * @hide pending API Council approval
+     */
+    public String getOriginalUrl() {
+        WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
+        return h != null ? h.getOriginalUrl() : null;
+    }
 
     /**
      * Get the title for the current page. This is the title of the current page
@@ -1612,82 +1753,35 @@
     }
 
     /*
-     * Making the find methods private since we are disabling for 1.0
+     * Highlight and scroll to the next occurance of String in findAll.
+     * Wraps the page infinitely, and scrolls.  Must be called after 
+     * calling findAll.
      *
-     * Find and highlight the next occurance of the String find, beginning with
-     * the current selection. Wraps the page infinitely, and scrolls. When
-     * WebCore determines whether it has found it, the response message is sent
-     * to its target with true(1) or false(0) as arg1 depending on whether the
-     * text was found.
-     * @param find String to find.
-     * @param response A Message object that will be dispatched with the result
-     *                 as the arg1 member. A result of 1 means the search
-     *                 succeeded.
+     * @param forward Direction to search.
      */
-    private void findNext(String find, Message response) {
-        if (response == null) {
-            return;
-        }
-        Message m = Message.obtain(null, EventHub.FIND, 1, 0, response);
-        m.getData().putString("find", find);
-        mWebViewCore.sendMessage(m);
+    public void findNext(boolean forward) {
+        nativeFindNext(forward);
     }
 
     /*
-     * Making the find methods private since we are disabling for 1.0
-     *
-     * Find and highlight the previous occurance of the String find, beginning
-     * with the current selection.
-     * @param find String to find.
-     * @param response A Message object that will be dispatched with the result
-     *                 as the arg1 member. A result of 1 means the search
-     *                 succeeded.
-     */
-    private void findPrevious(String find, Message response) {
-        if (response == null) {
-            return;
-        }
-        Message m = Message.obtain(null, EventHub.FIND, -1, 0, response);
-        m.getData().putString("find", find);
-        mWebViewCore.sendMessage(m);
-    }
-
-    /*
-     * Making the find methods private since we are disabling for 1.0
-     *
-     * Find and highlight the first occurance of find, beginning with the start
-     * of the page.
-     * @param find String to find.
-     * @param response A Message object that will be dispatched with the result
-     *                 as the arg1 member. A result of 1 means the search
-     *                 succeeded.
-     */
-    private void findFirst(String find, Message response) {
-        if (response == null) {
-            return;
-        }
-        Message m = Message.obtain(null, EventHub.FIND, 0, 0, response);
-        m.getData().putString("find", find);
-        mWebViewCore.sendMessage(m);
-    }
-
-    /*
-     * Making the find methods private since we are disabling for 1.0
-     *
      * Find all instances of find on the page and highlight them.
      * @param find  String to find.
-     * @param response A Message object that will be dispatched with the result
-     *                 as the arg1 member.  The result will be the number of
-     *                 matches to the String find.
+     * @return int  The number of occurances of the String "find"
+     *              that were found.
      */
-    private void findAll(String find, Message response) {
-        if (response == null) {
-            return;
-        }
-        Message m = Message.obtain(null, EventHub.FIND_ALL, 0, 0, response);
-        m.getData().putString("find", find);
-        mWebViewCore.sendMessage(m);
+    public int findAll(String find) {
+        mFindIsUp = true;
+        int result = nativeFindAll(find.toLowerCase(), find.toUpperCase());
+        invalidate();
+        return result;
     }
+
+    // Used to know whether the find dialog is open.  Affects whether
+    // or not we draw the highlights for matches.
+    private boolean mFindIsUp;
+
+    private native int nativeFindAll(String findLower, String findUpper);
+    private native void nativeFindNext(boolean forward);
     
     /**
      * Return the first substring consisting of the address of a physical 
@@ -1714,12 +1808,15 @@
     }
 
     /*
-     * Making the find methods private since we are disabling for 1.0
-     *
      * Clear the highlighting surrounding text matches created by findAll.
      */
-    private void clearMatches() {
-        mWebViewCore.sendMessage(EventHub.CLEAR_MATCHES);
+    public void clearMatches() {
+        mFindIsUp = false;
+        nativeSetFindIsDown();
+        // Now that the dialog has been removed, ensure that we scroll to a
+        // location that is not beyond the end of the page.
+        pinScrollTo(mScrollX, mScrollY, false);
+        invalidate();
     }
 
     /**
@@ -2023,10 +2120,21 @@
             nativeRecomputeFocus();
             // Update the buttons in the picture, so when we draw the picture
             // to the screen, they are in the correct state.
-            nativeRecordButtons();
+            // Tell the native side if user is a) touching the screen,
+            // b) pressing the trackball down, or c) pressing the enter key
+            // If the focus is a button, we need to draw it in the pressed
+            // state.
+            // If mNativeClass is 0, we should not reach here, so we do not
+            // need to check it again.
+            nativeRecordButtons(mTouchMode == TOUCH_SHORTPRESS_START_MODE
+                    || mTrackballDown || mGotEnterDown, false);
             drawCoreAndFocusRing(canvas, mBackgroundColor, mDrawFocusRing);
         }
         canvas.restoreToCount(sc);
+        
+        if (AUTO_REDRAW_HACK && mAutoRedraw) {
+            invalidate();
+        }
     }
 
     @Override
@@ -2097,7 +2205,12 @@
 
         if (mNativeClass == 0) return;
         if (mShiftIsPressed) {
-            nativeDrawSelection(canvas, mSelectX, mSelectY, mExtendSelection);
+            if (mTouchSelection) {
+                nativeDrawSelectionRegion(canvas);
+            } else {
+                nativeDrawSelection(canvas, mSelectX, mSelectY, 
+                        mExtendSelection);
+            }
         } else if (drawFocus) {
             if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
                 mTouchMode = TOUCH_SHORTPRESS_MODE;
@@ -2111,7 +2224,14 @@
             }
             nativeDrawFocusRing(canvas);
         }
+        // When the FindDialog is up, only draw the matches if we are not in
+        // the process of scrolling them into view.
+        if (mFindIsUp && !animateScroll) {
+            nativeDrawMatches(canvas);
+        }
     }
+
+    private native void nativeDrawMatches(Canvas canvas);
     
     private float scrollZoomGridScale(float invScale) {
         float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID) 
@@ -2163,19 +2283,40 @@
         Rect scrollFrame = new Rect();
         scrollFrame.set(mZoomScrollX, mZoomScrollY, 
                 mZoomScrollX + width, mZoomScrollY + height);
-        if (mContentWidth == width) {
-            float offsetX = (width * halfScale - width) / 2;
+        if (mContentWidth * mZoomScrollLimit < width) {
+            float scale = zoomFrameScaleX(width, halfScale, 1.0f);
+            float offsetX = (width * scale - width) * 0.5f;
             scrollFrame.left -= offsetX;
             scrollFrame.right += offsetX;
         }
-        if (mContentHeight == height) {
-            float offsetY = (height * halfScale - height) / 2;
+        if (mContentHeight * mZoomScrollLimit < height) {
+            float scale = zoomFrameScaleY(height, halfScale, 1.0f);
+            float offsetY = (height * scale - height) * 0.5f;
             scrollFrame.top -= offsetY;
             scrollFrame.bottom += offsetY;
         }
         return scrollFrame;
     }
     
+    private float zoomFrameScaleX(int width, float halfScale, float noScale) {
+        // mContentWidth > width > mContentWidth * mZoomScrollLimit
+        if (mContentWidth <= width) {
+            return halfScale;
+        }
+        float part = (width - mContentWidth * mZoomScrollLimit)  
+                / (width * (1 - mZoomScrollLimit));
+        return halfScale * part + noScale * (1.0f - part);
+    }
+    
+    private float zoomFrameScaleY(int height, float halfScale, float noScale) {
+        if (mContentHeight <= height) {
+            return halfScale;
+        }
+        float part = (height - mContentHeight * mZoomScrollLimit)  
+                / (height * (1 - mZoomScrollLimit));
+        return halfScale * part + noScale * (1.0f - part);
+    }
+    
     private float scrollZoomMagScale(float invScale) {
         return (invScale * 2 + mInvActualScale) / 3;
     }
@@ -2252,8 +2393,14 @@
         }
         int sc = canvas.save();
         canvas.clipRect(scrollFrame);
-        float halfX = maxX > 0 ? (float) mZoomScrollX / maxX : 0.5f;
-        float halfY = maxY > 0 ? (float) mZoomScrollY / maxY : 0.5f;
+        float halfX = (float) mZoomScrollX / maxX;
+        if (mContentWidth * mZoomScrollLimit < width) {
+            halfX = zoomFrameScaleX(width, 0.5f, halfX);
+        }
+        float halfY = (float) mZoomScrollY / maxY;
+        if (mContentHeight * mZoomScrollLimit < height) {
+            halfY = zoomFrameScaleY(height, 0.5f, halfY);
+        }
         canvas.scale(halfScale, halfScale, mZoomScrollX + width * halfX
                 , mZoomScrollY + height * halfY);
         if (LOGV_ENABLED) {
@@ -2350,7 +2497,10 @@
     }
     
     private void zoomScrollOut() {
-        if (canZoomScrollOut() == false) return;
+        if (canZoomScrollOut() == false) {
+            mTouchMode = TOUCH_DONE_MODE;
+            return;
+        }
         startZoomScrollOut();
         mTouchMode = SCROLL_ZOOM_ANIMATION_OUT;
         invalidate();
@@ -2377,8 +2527,8 @@
                         + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x); 
             }
             x += maxScreenX * mLastScrollX / maxZoomX - mLastTouchX;
-            x = Math.max(0, Math.min(maxScreenX, x));
-            mZoomScrollX = (int) (x * maxZoomX / maxScreenX);
+            x *= Math.max(maxZoomX / maxScreenX, mZoomScrollInvLimit);
+            mZoomScrollX = Math.max(0, Math.min(maxZoomX, (int) x));
         }
         int maxZoomY = mContentHeight - height;
         if (maxZoomY > 0) {
@@ -2390,8 +2540,8 @@
                         + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y); 
             }
             y += maxScreenY * mLastScrollY / maxZoomY - mLastTouchY;
-            y = Math.max(0, Math.min(maxScreenY, y));
-            mZoomScrollY = (int) (y * maxZoomY / maxScreenY);
+            y *= Math.max(maxZoomY / maxScreenY, mZoomScrollInvLimit);
+            mZoomScrollY = Math.max(0, Math.min(maxZoomY, (int) y));
         }
         if (oldX != mZoomScrollX || oldY != mZoomScrollY) {
             invalidate();
@@ -2540,6 +2690,13 @@
                 new WebViewCore.FocusData(mFocusData));
     }
 
+    // Called by JNI when a touch event puts a textfield into focus.
+    private void displaySoftKeyboard() {
+        InputMethodManager imm = (InputMethodManager)
+                getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.showSoftInput(mTextEntry);
+    }
+
     // Used to register the global focus change listener one time to avoid
     // multiple references to WebView
     private boolean mGlobalFocusChangeListenerAdded;
@@ -2663,7 +2820,8 @@
             ArrayList<String> pastEntries = mDatabase.getFormData(mUrl, mName);
             if (pastEntries.size() > 0) {
                 ArrayAdapter<String> adapter = new ArrayAdapter<String>(
-                        mContext, com.android.internal.R.layout.simple_list_item_1,
+                        mContext, com.android.internal.R.layout
+                        .search_dropdown_item_1line,
                         pastEntries);
                 ((HashMap) mUpdateMessage.obj).put("adapter", adapter);
                 mUpdateMessage.sendToTarget();
@@ -2679,152 +2837,166 @@
         mTextEntry.setRect(x, y, width, height);
     }
 
-    // These variables are used to determine long press with the enter key, or
+    // This is used to determine long press with the enter key, or
     // a center key.  Does not affect long press with the trackball/touch.
-    private long mDownTime = 0;
-    private boolean mGotDown = false;
+    private boolean mGotEnterDown = false;
 
     // Enable copy/paste with trackball here.
     // This should be left disabled until the framework can guarantee
     // delivering matching key-up and key-down events for the shift key
-    private static final boolean ENABLE_COPY_PASTE = false;
+    private static final boolean ENABLE_COPY_PASTE = true;
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
+        if (LOGV_ENABLED) {
+            Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis()
+                    + ", " + event);
+        }
+
+        if (mNativeClass == 0) {
             return false;
         }
-        if (keyCode != KeyEvent.KEYCODE_DPAD_CENTER && 
-                keyCode != KeyEvent.KEYCODE_ENTER) {
-            mGotDown = false;
+
+        // do this hack up front, so it always works, regardless of touch-mode
+        if (AUTO_REDRAW_HACK && (keyCode == KeyEvent.KEYCODE_CALL)) {
+            mAutoRedraw = !mAutoRedraw;
+            if (mAutoRedraw) {
+                invalidate();
+            }
+            return true;
         }
-        if (mAltIsPressed == false && (keyCode == KeyEvent.KEYCODE_ALT_LEFT 
-                || keyCode == KeyEvent.KEYCODE_ALT_RIGHT)) {
-            mAltIsPressed = true;
+
+        // Bubble up the key event if
+        // 1. it is a system key; or
+        // 2. the host application wants to handle it; or
+        // 3. webview is in scroll-zoom state;
+        if (event.isSystem()
+                || mCallbackProxy.uiOverrideKeyEvent(event)
+                || (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM)) {
+            return false;
         }
+
         if (ENABLE_COPY_PASTE && mShiftIsPressed == false 
                 && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT 
                 || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) {
             mExtendSelection = false;
             mShiftIsPressed = true;
-            if (mNativeClass != 0 && nativeUpdateFocusNode()) {
+            if (nativeUpdateFocusNode()) {
                 FocusNode node = mFocusNode;
-                mSelectX = node.mBounds.left;
-                mSelectY = node.mBounds.top;
+                mSelectX = contentToView(node.mBounds.left);
+                mSelectY = contentToView(node.mBounds.top);
             } else {
-                mSelectX = mScrollX + SELECT_CURSOR_OFFSET;
-                mSelectY = mScrollY + SELECT_CURSOR_OFFSET;
+                mSelectX = mScrollX + (int) mLastTouchX;
+                mSelectY = mScrollY + (int) mLastTouchY;
             }
        }
-       if (keyCode == KeyEvent.KEYCODE_CALL) {
-            if (mNativeClass != 0 && nativeUpdateFocusNode()) {
-                FocusNode node = mFocusNode;
-                String text = node.mText;
-                if (!node.mIsTextField && !node.mIsTextArea && text != null &&
-                        text.startsWith(SCHEME_TEL)) {
-                    Intent intent = new Intent(Intent.ACTION_DIAL,
-                            Uri.parse(text));
-                    getContext().startActivity(intent);
-                    return true;
-                }
+
+        if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
+                && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
+            // always handle the navigation keys in the UI thread
+            switchOutDrawHistory();
+            if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
+                playSoundEffect(keyCodeToSoundsEffect(keyCode));
+                return true;
             }
+            // Bubble up the key event as WebView doesn't handle it
             return false;
         }
 
-        if (event.isSystem() || mCallbackProxy.uiOverrideKeyEvent(event)) {
+        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+                || keyCode == KeyEvent.KEYCODE_ENTER) {
+            switchOutDrawHistory();
+            if (event.getRepeatCount() == 0) {
+                mGotEnterDown = true;
+                mPrivateHandler.sendMessageDelayed(mPrivateHandler
+                        .obtainMessage(LONG_PRESS_ENTER), LONG_PRESS_TIMEOUT);
+                nativeRecordButtons(true, true);
+                // FIXME, currently in webcore keydown it doesn't do anything.
+                // In keyup, it calls both keydown and keyup, we should fix it.
+                mWebViewCore.sendMessage(EventHub.KEY_DOWN, keyCode,
+                        EventHub.KEYEVENT_UNHANDLED_TYPE, event);
+                return true;
+            }
+            // Bubble up the key event as WebView doesn't handle it
             return false;
         }
-        if (LOGV_ENABLED) {
-            Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis()
-                    + ", " + event);
-        }
-        boolean isArrowKey = keyCode == KeyEvent.KEYCODE_DPAD_UP ||
-                keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
-                keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
-                keyCode == KeyEvent.KEYCODE_DPAD_RIGHT;
-        if (isArrowKey && event.getEventTime() - mTrackballLastTime 
-                <= TRACKBALL_KEY_TIMEOUT) {
-            if (LOGV_ENABLED) Log.v(LOGTAG, "ignore arrow");
-            return false;
-        }
-        boolean weHandledTheKey = false;
 
-        if (event.getMetaState() == 0) {
+        if (getSettings().getNavDump()) {
             switch (keyCode) {
-                case KeyEvent.KEYCODE_DPAD_UP:
-                case KeyEvent.KEYCODE_DPAD_DOWN:
-                case KeyEvent.KEYCODE_DPAD_RIGHT:
-                case KeyEvent.KEYCODE_DPAD_LEFT:
-                    // TODO: alternatively we can do panning as touch does
-                    switchOutDrawHistory();
-                    weHandledTheKey = navHandledKey(keyCode, 1, false
-                            , event.getEventTime());
-                    if (weHandledTheKey) {
-                        playSoundEffect(keyCodeToSoundsEffect(keyCode));
-                    }
+                case KeyEvent.KEYCODE_4:
+                    // "/data/data/com.android.browser/displayTree.txt"
+                    nativeDumpDisplayTree(getUrl());
                     break;
-                case KeyEvent.KEYCODE_DPAD_CENTER:
-                case KeyEvent.KEYCODE_ENTER:
-                    if (event.getRepeatCount() == 0) {
-                        switchOutDrawHistory();
-                        mDownTime = event.getEventTime();
-                        mGotDown = true;
-                        return true;
-                    } 
-                    if (mGotDown && event.getEventTime() - mDownTime > 
-                            ViewConfiguration.getLongPressTimeout()) {
-                        performLongClick();
-                        mGotDown = false;
-                        return true;
-                    }
+                case KeyEvent.KEYCODE_5:
+                case KeyEvent.KEYCODE_6:
+                    // 5: dump the dom tree to the file
+                    // "/data/data/com.android.browser/domTree.txt"
+                    // 6: dump the dom tree to the adb log
+                    mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE,
+                            (keyCode == KeyEvent.KEYCODE_5) ? 1 : 0, 0);
+                    break;
+                case KeyEvent.KEYCODE_7:
+                case KeyEvent.KEYCODE_8:
+                    // 7: dump the render tree to the file
+                    // "/data/data/com.android.browser/renderTree.txt"
+                    // 8: dump the render tree to the adb log
+                    mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE,
+                            (keyCode == KeyEvent.KEYCODE_7) ? 1 : 0, 0);
                     break;
                 case KeyEvent.KEYCODE_9:
-                    if (mNativeClass != 0 && getSettings().getNavDump()) {
-                        debugDump();
-                    }
-                    break;
-                default:
+                    debugDump();
                     break;
             }
         }
 
-        // suppress sending arrow keys to webkit
-        if (!weHandledTheKey && !isArrowKey) {
-            mWebViewCore.sendMessage(EventHub.KEY_DOWN, keyCode, 0, event);
+        if (nativeFocusNodeWantsKeyEvents()) {
+            mWebViewCore.sendMessage(EventHub.KEY_DOWN, keyCode,
+                                 EventHub.KEYEVENT_FOCUS_NODE_TYPE, event);
+            // return true as DOM handles the key
+            return true;
+        } else if (false) { // reserved to check the meta tag
+            // pass the key to DOM
+            mWebViewCore.sendMessage(EventHub.KEY_DOWN, keyCode,
+                                 EventHub.KEYEVENT_UNHANDLED_TYPE, event);
+            // return true as DOM handles the key
+            return true;
         }
 
-        return weHandledTheKey;
+        // Bubble up the key event as WebView doesn't handle it
+        return false;
     }
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT 
-                || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
-            if (mExtendSelection) {
-                // copy region so core operates on copy without touching orig.
-                Region selection = new Region(nativeGetSelection());
-                if (selection.isEmpty() == false) {
-                    Toast.makeText(mContext
-                            , com.android.internal.R.string.text_copied
-                            , Toast.LENGTH_SHORT).show();
-                    mWebViewCore.sendMessage(EventHub.GET_SELECTION, selection);
-                }
-            }
-            mShiftIsPressed = false;
-            return true;
-        }
         if (LOGV_ENABLED) {
-            Log.v(LOGTAG, "MT keyUp at" + System.currentTimeMillis()
+            Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis()
                     + ", " + event);
         }
-        if (keyCode == KeyEvent.KEYCODE_ALT_LEFT 
-                || keyCode == KeyEvent.KEYCODE_ALT_RIGHT) {
-            mAltIsPressed = false;
+
+        if (mNativeClass == 0) {
+            return false;
         }
+
+        // special CALL handling when focus node's href is "tel:XXX"
+        if (keyCode == KeyEvent.KEYCODE_CALL && nativeUpdateFocusNode()) {
+            FocusNode node = mFocusNode;
+            String text = node.mText;
+            if (!node.mIsTextField && !node.mIsTextArea && text != null
+                    && text.startsWith(SCHEME_TEL)) {
+                Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text));
+                getContext().startActivity(intent);
+                return true;
+            }
+        }
+
+        // Bubble up the key event if
+        // 1. it is a system key; or
+        // 2. the host application wants to handle it;
         if (event.isSystem() || mCallbackProxy.uiOverrideKeyEvent(event)) {
             return false;
         }
 
+        // special handling in scroll_zoom state
         if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
             if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode
                     && mTouchMode != SCROLL_ZOOM_ANIMATION_IN) {
@@ -2835,64 +3007,112 @@
             }
             return false;
         }
-        Rect visibleRect = sendOurVisibleRect();
-        // Note that sendOurVisibleRect calls viewToContent, so the coordinates
-        // should be in content coordinates.
-        boolean nodeOnScreen = false;
-        boolean isTextField = false;
-        boolean isTextArea = false;
-        FocusNode node = null;
-        if (mNativeClass != 0 && nativeUpdateFocusNode()) {
-            node = mFocusNode;
-            isTextField = node.mIsTextField;
-            isTextArea = node.mIsTextArea;
-            nodeOnScreen = Rect.intersects(node.mBounds, visibleRect);
+
+        if (ENABLE_COPY_PASTE && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT 
+                || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) {
+            if (commitCopy()) {
+                return true;
+            }
         }
 
-        if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
-            if (mShiftIsPressed) {
-                return false;
-            }
-            if (getSettings().supportZoom()) {
-                if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
-                    zoomScrollOut();
-                } else {
-                    if (LOGV_ENABLED) Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE");
-                    mPrivateHandler.sendMessageDelayed(mPrivateHandler
-                            .obtainMessage(SWITCH_TO_ENTER), TAP_TIMEOUT);
-                    mTouchMode = TOUCH_DOUBLECLICK_MODE;
-                }
-                return true;
-            } else {
-                keyCode = KeyEvent.KEYCODE_ENTER;
-            }
-        }
-        if (KeyEvent.KEYCODE_ENTER == keyCode) {
-            if (LOGV_ENABLED) Log.v(LOGTAG, "KEYCODE_ENTER == keyCode");
-            if (!nodeOnScreen) {
-                return false;
-            }
-            if (node != null && !isTextField && !isTextArea) {
-                nativeSetFollowedLink(true);
-                mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS, 
-                        EventHub.BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP, 0,
-                        new WebViewCore.FocusData(mFocusData));
-                if (mCallbackProxy.uiOverrideUrlLoading(node.mText)) {
-                    return true;
-                }
-                playSoundEffect(SoundEffectConstants.CLICK);
-            }
-        }
-        if (!nodeOnScreen) {
-            // FIXME: Want to give Callback a chance to handle it, and
-            // possibly pass down to javascript.
+        if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
+                && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
+            // always handle the navigation keys in the UI thread
+            // Bubble up the key event as WebView doesn't handle it
             return false;
         }
-        if (LOGV_ENABLED) Log.v(LOGTAG, "onKeyUp send EventHub.KEY_UP");
-        mWebViewCore.sendMessage(EventHub.KEY_UP, keyCode, 0, event);
-        return true;
+
+        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+                || keyCode == KeyEvent.KEYCODE_ENTER) {
+            // remove the long press message first
+            mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
+            mGotEnterDown = false;
+
+            if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
+                if (mShiftIsPressed) {
+                    return false;
+                }
+                if (getSettings().supportZoom()) {
+                    if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
+                        zoomScrollOut();
+                    } else {
+                        if (LOGV_ENABLED) {
+                            Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE");
+                        }
+                        mPrivateHandler.sendMessageDelayed(mPrivateHandler
+                                .obtainMessage(SWITCH_TO_ENTER), TAP_TIMEOUT);
+                        mTouchMode = TOUCH_DOUBLECLICK_MODE;
+                    }
+                    return true;
+                }
+            }
+
+            Rect visibleRect = sendOurVisibleRect();
+            // Note that sendOurVisibleRect calls viewToContent, so the
+            // coordinates should be in content coordinates.
+            boolean nodeOnScreen = false;
+            boolean isTextField = false;
+            boolean isTextArea = false;
+            FocusNode node = null;
+            if (nativeUpdateFocusNode()) {
+                node = mFocusNode;
+                isTextField = node.mIsTextField;
+                isTextArea = node.mIsTextArea;
+                nodeOnScreen = Rect.intersects(node.mBounds, visibleRect);
+            }
+            if (nodeOnScreen && !isTextField && !isTextArea) {
+                nativeSetFollowedLink(true);
+                mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS,
+                        EventHub.BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP, 0,
+                        new WebViewCore.FocusData(mFocusData));
+                playSoundEffect(SoundEffectConstants.CLICK);
+                if (!mCallbackProxy.uiOverrideUrlLoading(node.mText)) {
+                    mWebViewCore.sendMessage(EventHub.KEY_UP, keyCode,
+                            EventHub.KEYEVENT_UNHANDLED_TYPE, event);
+                }
+                return true;
+            }
+            // Bubble up the key event as WebView doesn't handle it
+            return false;
+        }
+
+        if (nativeFocusNodeWantsKeyEvents()) {
+            mWebViewCore.sendMessage(EventHub.KEY_UP, keyCode,
+                    EventHub.KEYEVENT_FOCUS_NODE_TYPE, event);
+            // return true as DOM handles the key
+            return true;
+        } else if (false) { // reserved to check the meta tag
+            // pass the key to DOM
+            mWebViewCore.sendMessage(EventHub.KEY_UP, keyCode,
+                    EventHub.KEYEVENT_UNHANDLED_TYPE, event);
+            // return true as DOM handles the key
+            return true;
+        }
+
+        // Bubble up the key event as WebView doesn't handle it
+        return false;
     }
-    
+
+    private boolean commitCopy() {
+        boolean copiedSomething = false;
+        if (mExtendSelection) {
+            // copy region so core operates on copy without touching orig.
+            Region selection = new Region(nativeGetSelection());
+            if (selection.isEmpty() == false) {
+                Toast.makeText(mContext
+                        , com.android.internal.R.string.text_copied
+                        , Toast.LENGTH_SHORT).show();
+                mWebViewCore.sendMessage(EventHub.GET_SELECTION, selection);
+                copiedSomething = true;
+            }
+        }
+        mShiftIsPressed = false;
+        if (mTouchMode == TOUCH_SELECT_MODE) {
+            mTouchMode = TOUCH_INIT_MODE;
+        }
+        return copiedSomething;
+    }
+
     // Set this as a hierarchy change listener so we can know when this view
     // is removed and still have access to our parent.
     @Override
@@ -2962,6 +3182,7 @@
             // we regain focus.
             mDrawFocusRing = false;
             mGotKeyDown = false;
+            mShiftIsPressed = false;
             if (inEditingMode()) {
                 clearTextEntry();
                 mNeedsUpdateTextEntry = true;
@@ -3055,8 +3276,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (mNativeClass == 0 || !isClickable() || !isLongClickable() || 
-                !hasFocus()) {
+        if (mNativeClass == 0 || !isClickable() || !isLongClickable()) {
             return false;
         }
 
@@ -3069,6 +3289,32 @@
         float x = ev.getX();
         float y = ev.getY();
         long eventTime = ev.getEventTime();
+
+        // Due to the touch screen edge effect, a touch closer to the edge
+        // always snapped to the edge. As getViewWidth() can be different from
+        // getWidth() due to the scrollbar, adjusting the point to match
+        // getViewWidth(). Same applied to the height.
+        if (x > getViewWidth() - 1) {
+            x = getViewWidth() - 1;
+        }
+        if (y > getViewHeight() - 1) {
+            y = getViewHeight() - 1;
+        }
+
+        // pass the touch events from UI thread to WebCore thread
+        if (mForwardTouchEvents && mTouchMode != SCROLL_ZOOM_OUT
+                && mTouchMode != SCROLL_ZOOM_ANIMATION_IN
+                && mTouchMode != SCROLL_ZOOM_ANIMATION_OUT
+                && (action != MotionEvent.ACTION_MOVE || 
+                        eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) {
+            WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
+            ted.mAction = action;
+            ted.mX = viewToContent((int) x + mScrollX);
+            ted.mY = viewToContent((int) y + mScrollY);;
+            mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
+            mLastSentTouchTime = eventTime;
+        }
+
         switch (action) {
             case MotionEvent.ACTION_DOWN: {
                 if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN
@@ -3083,6 +3329,16 @@
                     mScroller.abortAnimation();
                     mTouchMode = TOUCH_DRAG_START_MODE;
                     mPrivateHandler.removeMessages(RESUME_WEBCORE_UPDATE);
+                } else if (mShiftIsPressed) {
+                    mSelectX = mScrollX + (int) x;
+                    mSelectY = mScrollY + (int) y;
+                    mTouchMode = TOUCH_SELECT_MODE;
+                    if (LOGV_ENABLED) {
+                        Log.v(LOGTAG, "select=" + mSelectX + "," + mSelectY);
+                    }
+                    nativeMoveSelection(viewToContent(mSelectX)
+                            , viewToContent(mSelectY), false);
+                    mTouchSelection = mExtendSelection = true;
                 } else {
                     mTouchMode = TOUCH_INIT_MODE;
                 }
@@ -3116,6 +3372,17 @@
                 int deltaY = (int) (mLastTouchY - y);
 
                 if (mTouchMode != TOUCH_DRAG_MODE) {
+                    if (mTouchMode == TOUCH_SELECT_MODE) {
+                        mSelectX = mScrollX + (int) x;
+                        mSelectY = mScrollY + (int) y;
+                        if (LOGV_ENABLED) {
+                            Log.v(LOGTAG, "xtend=" + mSelectX + "," + mSelectY);
+                        }
+                        nativeMoveSelection(viewToContent(mSelectX)
+                                , viewToContent(mSelectY), true);
+                        invalidate();
+                        break;
+                    }
                     if ((deltaX * deltaX + deltaY * deltaY)
                             < TOUCH_SLOP_SQUARE) {
                         break;
@@ -3214,11 +3481,13 @@
                     mUserScroll = true;
                 }
 
-                if (mZoomControls != null && mMinZoomScale < mMaxZoomScale) {
+                boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
+                boolean showMagnify = canZoomScrollOut();
+                if (mZoomControls != null && (showPlusMinus || showMagnify)) {
                     if (mZoomControls.getVisibility() == View.VISIBLE) {
                         mPrivateHandler.removeCallbacks(mZoomControlRunnable);
                     } else {
-                        mZoomControls.show(canZoomScrollOut());
+                        mZoomControls.show(showPlusMinus, showMagnify);
                     }
                     mPrivateHandler.postDelayed(mZoomControlRunnable,
                             ZOOM_CONTROLS_TIMEOUT);
@@ -3244,6 +3513,10 @@
                             doShortPress();
                         }
                         break;
+                    case TOUCH_SELECT_MODE:
+                        commitCopy();
+                        mTouchSelection = mExtendSelection = false;
+                        break;
                     case SCROLL_ZOOM_ANIMATION_IN:
                     case SCROLL_ZOOM_ANIMATION_OUT:
                         // no action during scroll animation
@@ -3349,6 +3622,7 @@
     private int mTrackballXMove = 0;
     private int mTrackballYMove = 0;
     private boolean mExtendSelection = false;
+    private boolean mTouchSelection = false;
     private static final int TRACKBALL_KEY_TIMEOUT = 1000;
     private static final int TRACKBALL_TIMEOUT = 200;
     private static final int TRACKBALL_WAIT = 100;
@@ -3359,7 +3633,6 @@
     private int mSelectX = 0;
     private int mSelectY = 0;
     private boolean mShiftIsPressed = false;
-    private boolean mAltIsPressed = false;
     private boolean mTrackballDown = false;
     private long mTrackballUpTime = 0;
     private long mLastFocusTime = 0;
@@ -3386,17 +3659,18 @@
     @Override
     public boolean onTrackballEvent(MotionEvent ev) {
         long time = ev.getEventTime();
-        if (mAltIsPressed) {
+        if ((ev.getMetaState() & KeyEvent.META_ALT_ON) != 0) {
             if (ev.getY() > 0) pageDown(true);
             if (ev.getY() < 0) pageUp(true);
             return true;
         }
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             mPrivateHandler.removeMessages(SWITCH_TO_ENTER);
-            mPrivateHandler.sendMessageDelayed(
-                    mPrivateHandler.obtainMessage(LONG_PRESS_TRACKBALL), 1000);
             mTrackTrackball = true;
             mTrackballDown = true;
+            if (mNativeClass != 0) {
+                nativeRecordButtons(true, true);
+            }
             if (time - mLastFocusTime <= TRACKBALL_TIMEOUT
                     && !mLastFocusBounds.equals(nativeGetFocusRingBounds())) {
                 nativeSelectBestAt(mLastFocusBounds);
@@ -3408,7 +3682,8 @@
             }
             return false; // let common code in onKeyDown at it
         } else if (mTrackTrackball) {
-            mPrivateHandler.removeMessages(LONG_PRESS_TRACKBALL);
+            // LONG_PRESS_ENTER is set in common onKeyDown
+            mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
             mTrackTrackball = false;
         } 
         if (ev.getAction() == MotionEvent.ACTION_UP) {
@@ -3823,13 +4098,7 @@
             return;
         }
         switchOutDrawHistory();
-        // mLastTouchX and mLastTouchY are the point in the current viewport
-        int contentX = viewToContent((int) mLastTouchX + mScrollX);
-        int contentY = viewToContent((int) mLastTouchY + mScrollY);
-        int contentSize = ViewConfiguration.getTouchSlop();
-        nativeMotionUp(contentX, contentY, contentSize, true);
-
-        // call uiOverride next to check whether it is a special node,
+        // call uiOverride to check whether it is a special node,
         // phone/email/address, which are not handled by WebKit
         if (nativeUpdateFocusNode()) {
             FocusNode node = mFocusNode;
@@ -3840,6 +4109,11 @@
             }
             playSoundEffect(SoundEffectConstants.CLICK);
         }
+        // mLastTouchX and mLastTouchY are the point in the current viewport
+        int contentX = viewToContent((int) mLastTouchX + mScrollX);
+        int contentY = viewToContent((int) mLastTouchY + mScrollY);
+        int contentSize = ViewConfiguration.getTouchSlop();
+        nativeMotionUp(contentX, contentY, contentSize, true);
     }
 
     @Override
@@ -3907,6 +4181,8 @@
                     mHeightCanMeasure = false;
                 }
             }
+        } else {
+            mHeightCanMeasure = false;
         }
         if (mNativeClass != 0) {
             nativeSetHeightCanMeasure(mHeightCanMeasure);
@@ -3915,6 +4191,8 @@
         if (widthMode == MeasureSpec.UNSPECIFIED) {
             mWidthCanMeasure = true;
             measuredWidth = contentWidth;
+        } else {
+            mWidthCanMeasure = false;
         }
 
         synchronized (this) {
@@ -4076,10 +4354,14 @@
                     break;
                 case NEW_PICTURE_MSG_ID:
                     // called for new content
-                    final Point viewSize = (Point) msg.obj;
+                    final WebViewCore.DrawData draw = 
+                            (WebViewCore.DrawData) msg.obj;
+                    final Point viewSize = draw.mViewPoint;
                     if (mZoomScale > 0) {
-                        if (Math.abs(mZoomScale * viewSize.x -
-                                getViewWidth()) < 1) {
+                        // use the same logic in sendViewSizeZoom() to make sure
+                        // the mZoomScale has matched the viewSize so that we
+                        // can clear mZoomScale
+                        if (Math.round(getViewWidth() / mZoomScale) == viewSize.x) {
                             mZoomScale = 0;
                             mWebViewCore.sendMessage(EventHub.SET_SNAP_ANCHOR,
                                     0, 0);
@@ -4091,8 +4373,14 @@
                     // received in the fixed dimension.
                     final boolean updateLayout = viewSize.x == mLastWidthSent
                             && viewSize.y == mLastHeightSent;
-                    recordNewContentSize(msg.arg1, msg.arg2, updateLayout);
-                    invalidate();
+                    recordNewContentSize(draw.mWidthHeight.x, 
+                            draw.mWidthHeight.y, updateLayout);
+                    if (LOGV_ENABLED) {
+                        Rect b = draw.mInvalRegion.getBounds();
+                        Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
+                                b.left+","+b.top+","+b.right+","+b.bottom+"}");
+                    }
+                    invalidate(contentToView(draw.mInvalRegion.getBounds()));
                     if (mPictureListener != null) {
                         mPictureListener.onNewPicture(WebView.this, capturePicture());
                     }
@@ -4156,6 +4444,7 @@
                     }
                     int initialScale = msg.arg1;
                     int viewportWidth = msg.arg2;
+                    // by default starting a new page with 100% zoom scale.
                     float scale = 1.0f;
                     if (mInitialScale > 0) {
                         scale = mInitialScale / 100.0f;
@@ -4165,10 +4454,15 @@
                             // to 0
                             mLastWidthSent = 0;
                         }
-                        // by default starting a new page with 100% zoom scale.
-                        scale = initialScale == 0 ? (viewportWidth > 0 ? 
-                                ((float) width / viewportWidth) : 1.0f)
-                                : initialScale / 100.0f;
+                        if (initialScale == 0) {
+                            // if viewportWidth is defined and it is smaller
+                            // than the view width, zoom in to fill the view
+                            if (viewportWidth > 0 && viewportWidth < width) {
+                                scale = (float) width / viewportWidth;
+                            }
+                        } else {
+                            scale = initialScale / 100.0f;
+                        }
                     }
                     setNewZoomScale(scale, false);
                     break;
@@ -4213,10 +4507,32 @@
                     WebViewCore.resumeUpdate(mWebViewCore);
                     break;
 
-                case LONG_PRESS_TRACKBALL:
+                case LONG_PRESS_ENTER:
+                    // as this is shared by keydown and trackballdown, reset all
+                    // the states
+                    mGotEnterDown = false;
                     mTrackTrackball = false;
                     mTrackballDown = false;
-                    performLongClick();
+                    // LONG_PRESS_ENTER is sent as a delayed message. If we
+                    // switch to windows overview, the WebView will be
+                    // temporarily removed from the view system. In that case,
+                    // do nothing.
+                    if (getParent() != null) {
+                        performLongClick();
+                    }
+                    break;
+
+                case WEBCORE_NEED_TOUCH_EVENTS:
+                    mForwardTouchEvents = (msg.arg1 != 0);
+                    break;
+
+                case PREVENT_TOUCH_ID:
+                // update may have already been paused by touch; restore since
+                // this effectively aborts touch and skips logic in touch up
+                    if (mTouchMode == TOUCH_DRAG_MODE) {
+                        WebViewCore.resumeUpdate(mWebViewCore);
+                    }
+                    mTouchMode = TOUCH_DONE_MODE;
                     break;
 
                 default:
@@ -4514,10 +4830,7 @@
         }
         Rect contentFocus = nativeGetFocusRingBounds();
         if (contentFocus.isEmpty()) return keyHandled;
-        Rect viewFocus = new Rect(contentToView(contentFocus.left)
-                , contentToView(contentFocus.top)
-                , contentToView(contentFocus.right)
-                , contentToView(contentFocus.bottom));
+        Rect viewFocus = contentToView(contentFocus);
         Rect visRect = new Rect();
         calcOurVisibleRect(visRect);
         Rect outset = new Rect(visRect);
@@ -4559,7 +4872,7 @@
 
     public void debugDump() {
         nativeDebugDump();
-        mWebViewCore.sendMessage(EventHub.DUMP_WEBKIT);
+        mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
     }
     
     /**
@@ -4583,6 +4896,7 @@
     private native void     nativeDrawFocusRing(Canvas content);
     private native void     nativeDrawSelection(Canvas content
             , int x, int y, boolean extendSelection);
+    private native void     nativeDrawSelectionRegion(Canvas content);
     private native boolean  nativeUpdateFocusNode();
     private native Rect     nativeGetFocusRingBounds();
     private native Rect     nativeGetNavBounds();
@@ -4593,17 +4907,27 @@
             boolean noScroll);
     private native void     nativeNotifyFocusSet(boolean inEditingMode);
     private native void     nativeRecomputeFocus();
-    private native void     nativeRecordButtons();
+    // Like many other of our native methods, you must make sure that
+    // mNativeClass is not null before calling this method.
+    private native void     nativeRecordButtons(boolean pressed,
+            boolean invalidate);
     private native void     nativeResetFocus();
     private native void     nativeResetNavClipBounds();
     private native void     nativeSelectBestAt(Rect rect);
+    private native void     nativeSetFindIsDown();
     private native void     nativeSetFollowedLink(boolean followed);
     private native void     nativeSetHeightCanMeasure(boolean measure);
     private native void     nativeSetNavBounds(Rect rect);
     private native void     nativeSetNavClipBounds(Rect rect);
-    private native boolean  nativeHasSrcUrl();
-    private native boolean  nativeIsImage(int x, int y);
+    private native String   nativeImageURI(int x, int y);
+    /**
+     * Returns true if the native focus nodes says it wants to handle key events
+     * (ala plugins). This can only be called if mNativeClass is non-zero!
+     */
+    private native boolean  nativeFocusNodeWantsKeyEvents();
     private native void     nativeMoveSelection(int x, int y
             , boolean extendSelection);
     private native Region   nativeGetSelection();
+
+    private native void nativeDumpDisplayTree(String urlOrNull);
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 263346e..9e413f9 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -70,13 +70,6 @@
     // The BrowserFrame is an interface to the native Frame component.
     private BrowserFrame mBrowserFrame;
 
-
-    /*  This is a ring of pictures for content. After B is built, it is swapped
-        with A.
-    */
-    private Picture mContentPictureA = new Picture();   // draw()
-    private Picture mContentPictureB = new Picture();   // nativeDraw()
-
     /*
      * range is from 200 to 10,000. 0 is a special value means device-width. -1
      * means undefined.
@@ -196,7 +189,8 @@
         sWebCoreHandler.removeMessages(WebCoreThread.INITIALIZE, this);
     }
 
-    /* Get the BrowserFrame component. This is used for subwindow creation. */
+    /* Get the BrowserFrame component. This is used for subwindow creation and
+     * is called only from BrowserFrame in the WebCore thread. */
     /* package */ BrowserFrame getBrowserFrame() {
         return mBrowserFrame;
     }
@@ -278,30 +272,40 @@
     static native String nativeFindAddress(String addr);
 
     /**
-     * Find and highlight an occurance of text matching find
-     * @param find The text to find.
-     * @param forward If true, search forward.  Else, search backwards.
-     * @param fromSelection Whether to start from the current selection or from
-     *                      the beginning of the viewable page.
-     * @return boolean Whether the text was found.
+     * Empty the picture set.
      */
-    private native boolean nativeFind(String find,
-                                      boolean forward,
-                                      boolean fromSelection);
-
-    /**
-     * Find all occurances of text matching find and highlight them.
-     * @param find The text to find.
-     * @return int The number of occurances of find found.
-     */
-    private native int nativeFindAll(String find);
+    private native void nativeClearContent();
     
     /**
-     * Clear highlights on text created by nativeFindAll.
+     * Create a flat picture from the set of pictures.
      */
-    private native void nativeClearMatches();
+    private native void nativeCopyContentToPicture(Picture picture);
+   
+    /**
+     * Draw the picture set with a background color. Returns true
+     * if some individual picture took too long to draw and can be 
+     * split into parts. Called from the UI thread.
+     */
+    private native boolean nativeDrawContent(Canvas canvas, int color);
+    
+    /**
+     * Redraw a portion of the picture set. The Point wh returns the
+     * width and height of the overall picture.
+     */
+    private native boolean nativeRecordContent(Region invalRegion, Point wh);
+    
+    /**
+     * Splits slow parts of the picture set. Called from the webkit
+     * thread after nativeDrawContent returns true.
+     */
+    private native void nativeSplitContent();
 
-    private native void nativeDraw(Picture content);
+    // these must be kept lock-step with the KeyState enum in WebViewCore.h
+    static private final int KEY_ACTION_DOWN = 0;
+    static private final int KEY_ACTION_UP = 1;
+
+    private native boolean nativeSendKeyToFocusNode(int keyCode, int unichar,
+                int repeatCount, boolean isShift, boolean isAlt, int keyAction);
 
     private native boolean nativeKeyUp(int keycode, int keyvalue);
 
@@ -343,21 +347,12 @@
 
     private native String nativeRetrieveHref(int framePtr, int nodePtr);
     
-    /**
-     *  Return the url of the image located at (x,y) in content coordinates, or
-     *  null if there is no image at that point.
-     *
-     *  @param x    x content ordinate
-     *  @param y    y content ordinate
-     *  @return String  url of the image located at (x,y), or null if there is
-     *                  no image there.
-     */
-    private native String nativeRetrieveImageRef(int x, int y);
-
     private native void nativeTouchUp(int touchGeneration, 
             int buildGeneration, int framePtr, int nodePtr, int x, int y, 
             int size, boolean isClick, boolean retry);
 
+    private native boolean nativeHandleTouchEvent(int action, int x, int y);
+
     private native void nativeUnblockFocus();
     
     private native void nativeUpdateFrameCache();
@@ -368,7 +363,11 @@
     
     private native void nativeSetBackgroundColor(int color);
     
-    private native void nativeDump();
+    private native void nativeDumpDomTree(boolean useFile);
+
+    private native void nativeDumpRenderTree(boolean useFile);
+
+    private native void nativeDumpNavTree();
 
     private native void nativeRefreshPlugins(boolean reloadOpenPages);
     
@@ -393,6 +392,10 @@
 
     private native String nativeGetSelection(Region sel);
     
+    // Register a scheme to be treated as local scheme so that it can access
+    // local asset files for resources
+    private native void nativeRegisterURLSchemeAsLocal(String scheme);
+
     // EventHub for processing messages
     private final EventHub mEventHub;
     // WebCore thread handler
@@ -421,10 +424,7 @@
                         switch (msg.what) {
                             case INITIALIZE:
                                 WebViewCore core = (WebViewCore) msg.obj;
-                                synchronized (core) {
-                                    core.initialize();
-                                    core.notify();
-                                }
+                                core.initialize();
                                 break;
 
                             case REDUCE_PRIORITY:
@@ -501,6 +501,12 @@
         boolean mRetry;
     }
 
+    static class TouchEventData {
+        int mAction;    // MotionEvent.getAction()
+        int mX;
+        int mY;
+    }
+
     class EventHub {
         // Message Ids
         static final int LOAD_URL = 100;
@@ -510,7 +516,7 @@
         static final int KEY_UP = 104;
         static final int VIEW_SIZE_CHANGED = 105;
         static final int GO_BACK_FORWARD = 106;
-        static final int SET_VISIBLE_RECT = 107;
+        static final int SET_SCROLL_OFFSET = 107;
         static final int RESTORE_STATE = 108;
         static final int PAUSE_TIMERS = 109;
         static final int RESUME_TIMERS = 110;
@@ -519,16 +525,13 @@
         static final int SET_SELECTION = 113;
         static final int REPLACE_TEXT = 114;
         static final int PASS_TO_JS = 115;
-        static final int FIND = 116;
+        static final int SET_GLOBAL_BOUNDS = 116;
         static final int UPDATE_CACHE_AND_TEXT_ENTRY = 117;
-        static final int FIND_ALL = 118;
-        static final int CLEAR_MATCHES = 119;
         static final int DOC_HAS_IMAGES = 120;
         static final int SET_SNAP_ANCHOR = 121;
         static final int DELETE_SELECTION = 122;
         static final int LISTBOX_CHOICES = 123;
         static final int SINGLE_LISTBOX_CHOICE = 124;
-        static final int DUMP_WEBKIT = 125;
         static final int SET_BACKGROUND_COLOR = 126;
         static final int UNBLOCK_FOCUS = 127;
         static final int SAVE_DOCUMENT_STATE = 128;
@@ -536,9 +539,10 @@
         static final int WEBKIT_DRAW = 130;
         static final int SYNC_SCROLL = 131;
         static final int REFRESH_PLUGINS = 132;
-
+        static final int SPLIT_PICTURE_SET = 133;
+        static final int CLEAR_CONTENT = 134;
+        
         // UI nav messages
-        static final int REQUEST_IMAGE_HREF = 134;
         static final int SET_FINAL_FOCUS = 135;
         static final int SET_KIT_FOCUS = 136;
         static final int REQUEST_FOCUS_HREF = 137;
@@ -547,6 +551,8 @@
 
         // motion
         static final int TOUCH_UP = 140;
+        // message used to pass UI touch events to WebCore
+        static final int TOUCH_EVENT = 141;
 
         // Network-based messaging
         static final int CLEAR_SSL_PREF_TABLE = 150;
@@ -554,6 +560,12 @@
         // Test harness messages
         static final int REQUEST_EXT_REPRESENTATION = 160;
         static final int REQUEST_DOC_AS_TEXT = 161;
+
+        // debugging
+        static final int DUMP_DOMTREE = 170;
+        static final int DUMP_RENDERTREE = 171;
+        static final int DUMP_NAVTREE = 172;
+
         // private message ids
         private static final int DESTROY =     200;
         
@@ -561,6 +573,19 @@
         static final int NO_FOCUS_CHANGE_BLOCK = 0;
         static final int BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP = 1;
 
+        /*  The KEY_DOWN and KEY_UP messages pass the keyCode in arg1, and a
+            "type" in arg2. These are the types, and they describe what the
+            circumstances were that prompted the UI thread to send the keyevent
+            to webkit.
+         
+            FOCUS_NODE - the currently focused node says it wants key events
+                         (e.g. plugins)
+            UNHANDLED - the UI side did not handle the key, so we give webkit
+                        a shot at it.
+         */
+        static final int KEYEVENT_FOCUS_NODE_TYPE = 0;
+        static final int KEYEVENT_UNHANDLED_TYPE = 1;
+
         // Private handler for WebCore messages.
         private Handler mHandler;
         // Message queue for containing messages before the WebCore thread is
@@ -607,8 +632,30 @@
 
                         case LOAD_DATA:
                             HashMap loadParams = (HashMap) msg.obj;
-                            mBrowserFrame.loadData(
-                                    (String) loadParams.get("baseUrl"),
+                            String baseUrl = (String) loadParams.get("baseUrl");
+                            if (baseUrl != null) {
+                                int i = baseUrl.indexOf(':');
+                                if (i > 0) {
+                                    /*
+                                     * In 1.0, {@link
+                                     * WebView#loadDataWithBaseURL} can access
+                                     * local asset files as long as the data is
+                                     * valid. In the new WebKit, the restriction
+                                     * is tightened. To be compatible with 1.0,
+                                     * we automatically add the scheme of the
+                                     * baseUrl for local access as long as it is
+                                     * not http(s)/ftp(s)/about/javascript
+                                     */ 
+                                    String scheme = baseUrl.substring(0, i);
+                                    if (!scheme.startsWith("http") &&
+                                            !scheme.startsWith("ftp") &&
+                                            !scheme.startsWith("about") &&
+                                            !scheme.startsWith("javascript")) {
+                                        nativeRegisterURLSchemeAsLocal(scheme);
+                                    }
+                                }
+                            }
+                            mBrowserFrame.loadData(baseUrl,
                                     (String) loadParams.get("data"),
                                     (String) loadParams.get("mimeType"),
                                     (String) loadParams.get("encoding"),
@@ -622,8 +669,7 @@
                             // up with native side
                             if (mBrowserFrame.committed()
                                     && !mBrowserFrame.firstLayoutDone()) {
-                                mBrowserFrame.didFirstLayout(mBrowserFrame
-                                        .currentUrl());
+                                mBrowserFrame.didFirstLayout();
                             }
                             // Do this after syncing up the layout state.
                             stopLoading();
@@ -634,11 +680,11 @@
                             break;
 
                         case KEY_DOWN:
-                            keyDown(msg.arg1, (KeyEvent) msg.obj);
+                            keyDown(msg.arg1, msg.arg2, (KeyEvent) msg.obj);
                             break;
 
                         case KEY_UP:
-                            keyUp(msg.arg1, (KeyEvent) msg.obj);
+                            keyUp(msg.arg1, msg.arg2, (KeyEvent) msg.obj);
                             break;
 
                         case VIEW_SIZE_CHANGED:
@@ -646,12 +692,16 @@
                                     ((Float) msg.obj).floatValue());
                             break;
 
-                        case SET_VISIBLE_RECT:
-                            Rect r = (Rect) msg.obj;
+                        case SET_SCROLL_OFFSET:
                             // note: these are in document coordinates
                             // (inv-zoom)
-                            nativeSetVisibleRect(r.left, r.top, r.width(),
-                                    r.height());
+                            nativeSetScrollOffset(msg.arg1, msg.arg2);
+                            break;
+                            
+                        case SET_GLOBAL_BOUNDS:
+                            Rect r = (Rect) msg.obj;
+                            nativeSetGlobalBounds(r.left, r.top, r.width(),
+                                r.height());
                             break;
 
                         case GO_BACK_FORWARD:
@@ -745,30 +795,6 @@
                             break;
                         }
 
-                        case FIND:
-                            /* arg1:
-                             *   1 - Find next
-                             *  -1 - Find previous
-                             *   0 - Find first
-                             */
-                            Message response = (Message) msg.obj;
-                            boolean find = nativeFind(msg.getData().getString("find"),
-                                    msg.arg1 != -1, msg.arg1 != 0);
-                            response.arg1 = find ? 1 : 0;
-                            response.sendToTarget();
-                            break;
-                            
-                        case FIND_ALL:
-                            int found = nativeFindAll(msg.getData().getString("find"));
-                            Message resAll = (Message) msg.obj;
-                            resAll.arg1 = found;
-                            resAll.sendToTarget();
-                            break;
-                            
-                        case CLEAR_MATCHES:
-                            nativeClearMatches();
-                            break;
-
                         case CLEAR_SSL_PREF_TABLE:
                             Network.getInstance(mContext)
                                     .clearUserSslPrefTable();
@@ -784,6 +810,17 @@
                                     touchUpData.mRetry);
                             break;
 
+                        case TOUCH_EVENT: {
+                            TouchEventData ted = (TouchEventData) msg.obj;
+                            if (nativeHandleTouchEvent(ted.mAction, ted.mX,
+                                    ted.mY)) {
+                                Message.obtain(mWebView.mPrivateHandler,
+                                        WebView.PREVENT_TOUCH_ID)
+                                        .sendToTarget();
+                            }
+                            break;
+                        }
+
                         case ADD_JS_INTERFACE:
                             HashMap map = (HashMap) msg.obj;
                             Object obj = map.get("object");
@@ -826,27 +863,17 @@
                         case REQUEST_FOCUS_HREF: {
                             Message hrefMsg = (Message) msg.obj;
                             String res = nativeRetrieveHref(msg.arg1, msg.arg2);
-                            Bundle data = hrefMsg.getData();
-                            data.putString("url", res);
-                            hrefMsg.setData(data);
+                            hrefMsg.getData().putString("url", res);
                             hrefMsg.sendToTarget();
                             break;
                         }
                             
-                        case REQUEST_IMAGE_HREF: {
-                            Message refMsg = (Message) msg.obj;
-                            String ref = 
-                                    nativeRetrieveImageRef(msg.arg1, msg.arg2);
-                            Bundle data = refMsg.getData();
-                            data.putString("url", ref);
-                            refMsg.setData(data);
-                            refMsg.sendToTarget();
-                            break;
-                        }
-
                         case UPDATE_CACHE_AND_TEXT_ENTRY:
                             nativeUpdateFrameCache();
-                            sendViewInvalidate();
+                            // FIXME: this should provide a minimal rectangle
+                            if (mWebView != null) {
+                                mWebView.postInvalidate();
+                            }
                             sendUpdateTextEntry();
                             break;
 
@@ -901,9 +928,17 @@
                                     , WebView.UPDATE_CLIPBOARD, str)
                                     .sendToTarget();
                             break;
-                            
-                        case DUMP_WEBKIT:
-                            nativeDump();
+
+                        case DUMP_DOMTREE:
+                            nativeDumpDomTree(msg.arg1 == 1);
+                            break;
+
+                        case DUMP_RENDERTREE:
+                            nativeDumpRenderTree(msg.arg1 == 1);
+                            break;
+
+                        case DUMP_NAVTREE:
+                            nativeDumpNavTree();
                             break;
 
                         case SYNC_SCROLL:
@@ -914,6 +949,18 @@
                         case REFRESH_PLUGINS:
                             nativeRefreshPlugins(msg.arg1 != 0);
                             break;
+                            
+                        case SPLIT_PICTURE_SET:
+                            nativeSplitContent();
+                            mSplitPictureIsScheduled = false;
+                            break;
+                            
+                        case CLEAR_CONTENT:
+                            // Clear the view so that onDraw() will draw nothing
+                            // but white background
+                            // (See public method WebView.clearView)
+                            nativeClearContent();
+                            break;
                     }
                 }
             };
@@ -982,6 +1029,7 @@
         private synchronized void removeMessages() {
             // reset mDrawIsScheduled flag as WEBKIT_DRAW may be removed
             mDrawIsScheduled = false;
+            mSplitPictureIsScheduled = false;
             if (mMessages != null) {
                 mMessages.clear();
             } else {
@@ -1001,7 +1049,7 @@
     // Methods called by host activity (in the same thread)
     //-------------------------------------------------------------------------
 
-    public void stopLoading() {
+    void stopLoading() {
         if (LOGV_ENABLED) Log.v(LOGTAG, "CORE stopLoading");
         if (mBrowserFrame != null) {
             mBrowserFrame.stopLoading();
@@ -1082,23 +1130,48 @@
         mBrowserFrame.loadUrl(url);
     }
 
-    private void keyDown(int code, KeyEvent event) {
+    private void keyDown(int code, int target, KeyEvent event) {
         if (LOGV_ENABLED) {
             Log.v(LOGTAG, "CORE keyDown at " + System.currentTimeMillis()
                     + ", " + event);
         }
+        switch (target) {
+            case EventHub.KEYEVENT_UNHANDLED_TYPE:
+                break;
+            case EventHub.KEYEVENT_FOCUS_NODE_TYPE:
+                if (nativeSendKeyToFocusNode(code, event.getUnicodeChar(),
+                                             event.getRepeatCount(),
+                                             event.isShiftPressed(),
+                                             event.isAltPressed(),
+                                             KEY_ACTION_DOWN)) {
+                    return;
+                }
+                break;
+        }
+        // If we get here, no one handled it, so call our proxy
         mCallbackProxy.onUnhandledKeyEvent(event);
     }
 
-    private void keyUp(int code, KeyEvent event) {
+    private void keyUp(int code, int target, KeyEvent event) {
         if (LOGV_ENABLED) {
             Log.v(LOGTAG, "CORE keyUp at " + System.currentTimeMillis()
                     + ", " + event);
         }
-        if (!nativeKeyUp(code, event.getUnicodeChar())) {
-            mCallbackProxy.onUnhandledKeyEvent(event);
+        switch (target) {
+            case EventHub.KEYEVENT_UNHANDLED_TYPE:
+                if (!nativeKeyUp(code, event.getUnicodeChar())) {
+                    mCallbackProxy.onUnhandledKeyEvent(event);
+                }
+                break;
+            case EventHub.KEYEVENT_FOCUS_NODE_TYPE:
+                nativeSendKeyToFocusNode(code, event.getUnicodeChar(),
+                                         event.getRepeatCount(),
+                                         event.isShiftPressed(),
+                                         event.isAltPressed(),
+                                         KEY_ACTION_UP);
+                break;
+            }
         }
-    }
 
     // These values are used to avoid requesting a layout based on old values
     private int mCurrentViewWidth = 0;
@@ -1140,8 +1213,9 @@
         mCurrentViewHeight = h;
         if (needInvalidate) {
             // ensure {@link #webkitDraw} is called as we were blocking in
-            // {@link #contentInvalidate} when mCurrentViewWidth is 0
-            contentInvalidate();
+            // {@link #contentDraw} when mCurrentViewWidth is 0
+            if (LOGV_ENABLED) Log.v(LOGTAG, "viewSizeChanged");
+            contentDraw();
         }
         mEventHub.sendMessage(Message.obtain(null,
                 EventHub.UPDATE_CACHE_AND_TEXT_ENTRY));
@@ -1156,30 +1230,42 @@
 
     // Used to avoid posting more than one draw message.
     private boolean mDrawIsScheduled;
+    
+    // Used to avoid posting more than one split picture message.
+    private boolean mSplitPictureIsScheduled;
+
+    // Used to suspend drawing.
+    private boolean mDrawIsPaused;
 
     // Used to end scale+scroll mode, accessed by both threads
     boolean mEndScaleZoom = false;
     
+    public class DrawData {
+        public DrawData() {
+            mInvalRegion = new Region();
+            mWidthHeight = new Point();
+        }
+        public Region mInvalRegion;
+        public Point mViewPoint;
+        public Point mWidthHeight;
+    }
+    
     private void webkitDraw() {
         mDrawIsScheduled = false;
-        nativeDraw(mContentPictureB);
-        int w;
-        int h;
-        synchronized (this) {
-            Picture temp = mContentPictureB;
-            mContentPictureB = mContentPictureA;
-            mContentPictureA = temp;
-            w = mContentPictureA.getWidth();
-            h = mContentPictureA.getHeight();
+        DrawData draw = new DrawData();
+        if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw start");
+        if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight) 
+                == false) {
+            if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw abort");
+            return;
         }
-
         if (mWebView != null) {
             // Send the native view size that was used during the most recent
             // layout.
+            draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
+            if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
             Message.obtain(mWebView.mPrivateHandler,
-                    WebView.NEW_PICTURE_MSG_ID, w, h,
-                    new Point(mCurrentViewWidth, mCurrentViewHeight))
-                    .sendToTarget();
+                    WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
             if (mWebkitScrollX != 0 || mWebkitScrollY != 0) {
                 // as we have the new picture, try to sync the scroll position
                 Message.obtain(mWebView.mPrivateHandler,
@@ -1217,37 +1303,18 @@
             df = mScrollFilter;
         }
         canvas.setDrawFilter(df);
-        synchronized (this) {
-            Picture picture = mContentPictureA;
-            int sc = canvas.save(Canvas.CLIP_SAVE_FLAG);
-            Rect clip = new Rect(0, 0, picture.getWidth(), picture.getHeight());
-            canvas.clipRect(clip, Region.Op.DIFFERENCE);
-            canvas.drawColor(color);
-            canvas.restoreToCount(sc);
-    // experiment commented out
-    //      if (TEST_BUCKET) {
-    //          nativeDrawContentPicture(canvas);
-    //      } else {
-                canvas.drawPicture(picture);
-    //      }
-        }
+        boolean tookTooLong = nativeDrawContent(canvas, color);
         canvas.setDrawFilter(null);
-    }
-
-    /* package */ void clearContentPicture() {
-    // experiment commented out
-    //   if (TEST_BUCKET) {
-    //        nativeClearContentPicture();
-    //    }
-        synchronized (this) {
-            mContentPictureA = new Picture();
+        if (tookTooLong && mSplitPictureIsScheduled == false) {
+            mSplitPictureIsScheduled = true;
+            sendMessage(EventHub.SPLIT_PICTURE_SET);
         }
     }
 
     /*package*/ Picture copyContentPicture() {
-        synchronized (this) {
-            return new Picture(mContentPictureA);
-        }
+        Picture result = new Picture();
+        nativeCopyContentToPicture(result);
+        return result;
     }
 
     static void pauseUpdate(WebViewCore core) {
@@ -1263,7 +1330,7 @@
         // webcore thread priority is still lowered.
         if (core != null) {
             synchronized (core) {
-                core.mDrawIsScheduled = true;
+                core.mDrawIsPaused = true;
                 core.mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
             }
         }
@@ -1278,7 +1345,9 @@
         if (core != null) {
             synchronized (core) {
                 core.mDrawIsScheduled = false;
-                core.contentInvalidate();
+                core.mDrawIsPaused = false;
+                if (LOGV_ENABLED) Log.v(LOGTAG, "resumeUpdate");
+                core.contentDraw();
             }
         }
     }
@@ -1309,7 +1378,7 @@
     //-------------------------------------------------------------------------
 
     // called from JNI or WebView thread
-    /* package */ void contentInvalidate() {
+    /* package */ void contentDraw() {
         // don't update the Picture until we have an initial width and finish
         // the first layout
         if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) {
@@ -1317,14 +1386,14 @@
         }
         // only fire an event if this is our first request
         synchronized (this) {
-            if (mDrawIsScheduled) {
+            if (mDrawIsPaused || mDrawIsScheduled) {
                 return;
             }
             mDrawIsScheduled = true;
             mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
         }
     }
-
+    
     // called by JNI
     private void contentScrollBy(int dx, int dy) {
         if (!mBrowserFrame.firstLayoutDone()) {
@@ -1397,6 +1466,7 @@
         sWebCoreHandler.removeMessages(WebCoreThread.CACHE_TICKER);
         sWebCoreHandler.sendMessage(sWebCoreHandler
                 .obtainMessage(WebCoreThread.CACHE_TICKER));
+        contentDraw();
     }
 
     // called by JNI
@@ -1408,9 +1478,9 @@
     }
 
     // called by JNI
-    private void sendViewInvalidate() {
+    private void sendViewInvalidate(int left, int top, int right, int bottom) {
         if (mWebView != null) {
-            mWebView.postInvalidate();
+            mWebView.postInvalidate(left, top, right, bottom);
         }
     }
 
@@ -1421,7 +1491,7 @@
     private native void setViewportSettingsFromNative();
     
     // called by JNI
-    private void didFirstLayout(String url) {
+    private void didFirstLayout() {
         // Trick to ensure that the Picture has the exact height for the content
         // by forcing to layout with 0 height after the page is ready, which is
         // indicated by didFirstLayout. This is essential to get rid of the 
@@ -1435,7 +1505,7 @@
                     mWebView.mLastHeightSent, -1.0f));
         }
 
-        mBrowserFrame.didFirstLayout(url);
+        mBrowserFrame.didFirstLayout();
 
         // reset the scroll position as it is a new page now
         mWebkitScrollX = mWebkitScrollY = 0;
@@ -1517,7 +1587,16 @@
             mRestoredScale = scale;
         }
     }
-    
+
+    // called by JNI
+    private void needTouchEvents(boolean need) {
+        if (mWebView != null) {
+            Message.obtain(mWebView.mPrivateHandler,
+                    WebView.WEBCORE_NEED_TOUCH_EVENTS, need ? 1 : 0, 0)
+                    .sendToTarget();
+        }
+    }
+
     // called by JNI
     private void updateTextfield(int ptr, boolean changeToPassword,
             String text, int textGeneration) {
@@ -1530,9 +1609,10 @@
         }
     }
 
-    // these must be in document space (i.e. not scaled/zoomed.
-    private native void nativeSetVisibleRect(int x, int y, int width,
-            int height);
+    // these must be in document space (i.e. not scaled/zoomed).
+    private native void nativeSetScrollOffset(int dx, int dy);
+
+    private native void nativeSetGlobalBounds(int x, int y, int w, int h);
 
     // called by JNI
     private void requestListBox(String[] array, boolean[] enabledArray,
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index b367e27..96f3698 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -39,7 +39,7 @@
     // log tag
     protected static final String LOGTAG = "webviewdatabase";
 
-    private static final int DATABASE_VERSION = 8;
+    private static final int DATABASE_VERSION = 9;
     // 2 -> 3 Modified Cache table to allow cache of redirects
     // 3 -> 4 Added Oma-Downloads table
     // 4 -> 5 Modified Cache table to support persistent contentLength
@@ -47,6 +47,7 @@
     // 5 -> 6 Add INDEX for cache table
     // 6 -> 7 Change cache localPath from int to String
     // 7 -> 8 Move cache to its own db
+    // 8 -> 9 Store both scheme and host when storing passwords
     private static final int CACHE_DATABASE_VERSION = 1;
 
     private static WebViewDatabase mInstance = null;
@@ -172,7 +173,6 @@
                 mDatabase.beginTransaction();
                 try {
                     upgradeDatabase();
-                    bootstrapDatabase();
                     mDatabase.setTransactionSuccessful();
                 } finally {
                     mDatabase.endTransaction();
@@ -200,6 +200,10 @@
                 } finally {
                     mCacheDatabase.endTransaction();
                 }
+                // Erase the files from the file system in the 
+                // case that the database was updated and the 
+                // there were existing cache content
+                CacheManager.removeAllCacheFiles();
             }
 
             if (mCacheDatabase != null) {
@@ -237,24 +241,26 @@
         if (oldVersion != 0) {
             Log.i(LOGTAG, "Upgrading database from version "
                     + oldVersion + " to "
-                    + DATABASE_VERSION + ", which will destroy all old data");
+                    + DATABASE_VERSION + ", which will destroy old data");
+        }
+        boolean justPasswords = 8 == oldVersion && 9 == DATABASE_VERSION;
+        if (!justPasswords) {
+            mDatabase.execSQL("DROP TABLE IF EXISTS "
+                    + mTableNames[TABLE_COOKIES_ID]);
+            mDatabase.execSQL("DROP TABLE IF EXISTS cache");
+            mDatabase.execSQL("DROP TABLE IF EXISTS "
+                    + mTableNames[TABLE_FORMURL_ID]);
+            mDatabase.execSQL("DROP TABLE IF EXISTS "
+                    + mTableNames[TABLE_FORMDATA_ID]);
+            mDatabase.execSQL("DROP TABLE IF EXISTS "
+                    + mTableNames[TABLE_HTTPAUTH_ID]);
         }
         mDatabase.execSQL("DROP TABLE IF EXISTS "
-                + mTableNames[TABLE_COOKIES_ID]);
-        mDatabase.execSQL("DROP TABLE IF EXISTS cache");
-        mDatabase.execSQL("DROP TABLE IF EXISTS "
                 + mTableNames[TABLE_PASSWORD_ID]);
-        mDatabase.execSQL("DROP TABLE IF EXISTS "
-                + mTableNames[TABLE_FORMURL_ID]);
-        mDatabase.execSQL("DROP TABLE IF EXISTS "
-                + mTableNames[TABLE_FORMDATA_ID]);
-        mDatabase.execSQL("DROP TABLE IF EXISTS "
-                + mTableNames[TABLE_HTTPAUTH_ID]);
-        mDatabase.setVersion(DATABASE_VERSION);
-    }
 
-    private static void bootstrapDatabase() {
-        if (mDatabase != null) {
+        mDatabase.setVersion(DATABASE_VERSION);
+
+        if (!justPasswords) {
             // cookies
             mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_COOKIES_ID]
                     + " (" + ID_COL + " INTEGER PRIMARY KEY, "
@@ -265,14 +271,6 @@
             mDatabase.execSQL("CREATE INDEX cookiesIndex ON "
                     + mTableNames[TABLE_COOKIES_ID] + " (path)");
 
-            // password
-            mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_PASSWORD_ID]
-                    + " (" + ID_COL + " INTEGER PRIMARY KEY, "
-                    + PASSWORD_HOST_COL + " TEXT, " + PASSWORD_USERNAME_COL
-                    + " TEXT, " + PASSWORD_PASSWORD_COL + " TEXT," + " UNIQUE ("
-                    + PASSWORD_HOST_COL + ", " + PASSWORD_USERNAME_COL
-                    + ") ON CONFLICT REPLACE);");
-
             // formurl
             mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMURL_ID]
                     + " (" + ID_COL + " INTEGER PRIMARY KEY, " + FORMURL_URL_COL
@@ -295,6 +293,13 @@
                     + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL + ", "
                     + HTTPAUTH_USERNAME_COL + ") ON CONFLICT REPLACE);");
         }
+        // passwords
+        mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_PASSWORD_ID]
+                + " (" + ID_COL + " INTEGER PRIMARY KEY, "
+                + PASSWORD_HOST_COL + " TEXT, " + PASSWORD_USERNAME_COL
+                + " TEXT, " + PASSWORD_PASSWORD_COL + " TEXT," + " UNIQUE ("
+                + PASSWORD_HOST_COL + ", " + PASSWORD_USERNAME_COL
+                + ") ON CONFLICT REPLACE);");
     }
 
     private static void upgradeCacheDatabase() {
@@ -639,10 +644,11 @@
         if (cursor.moveToFirst()) {
             int batchSize = 100;
             StringBuilder pathStr = new StringBuilder(20 + 16 * batchSize);
-            pathStr.append("DELETE FROM cache WHERE filepath = ?");
+            pathStr.append("DELETE FROM cache WHERE filepath IN (?");
             for (int i = 1; i < batchSize; i++) {
-                pathStr.append(" OR filepath = ?");
+                pathStr.append(", ?");
             }
+            pathStr.append(")");
             SQLiteStatement statement = mCacheDatabase.compileStatement(pathStr
                     .toString());
             // as bindString() uses 1-based index, initialize index to 1
@@ -658,6 +664,7 @@
                 pathList.add(filePath);
                 if (index++ == batchSize) {
                     statement.execute();
+                    statement.clearBindings();
                     index = 1;
                 }
             } while (cursor.moveToNext() && amount > 0);
@@ -679,19 +686,20 @@
     /**
      * Set password. Tuple (PASSWORD_HOST_COL, PASSWORD_USERNAME_COL) is unique.
      *
-     * @param host The host for the password
+     * @param schemePlusHost The scheme and host for the password
      * @param username The username for the password. If it is null, it means
      *            password can't be saved.
      * @param password The password
      */
-    void setUsernamePassword(String host, String username, String password) {
-        if (host == null || mDatabase == null) {
+    void setUsernamePassword(String schemePlusHost, String username,
+                String password) {
+        if (schemePlusHost == null || mDatabase == null) {
             return;
         }
 
         synchronized (mPasswordLock) {
             final ContentValues c = new ContentValues();
-            c.put(PASSWORD_HOST_COL, host);
+            c.put(PASSWORD_HOST_COL, schemePlusHost);
             c.put(PASSWORD_USERNAME_COL, username);
             c.put(PASSWORD_PASSWORD_COL, password);
             mDatabase.insert(mTableNames[TABLE_PASSWORD_ID], PASSWORD_HOST_COL,
@@ -702,12 +710,12 @@
     /**
      * Retrieve the username and password for a given host
      *
-     * @param host The host which passwords applies to
+     * @param schemePlusHost The scheme and host which passwords applies to
      * @return String[] if found, String[0] is username, which can be null and
      *         String[1] is password. Return null if it can't find anything.
      */
-    String[] getUsernamePassword(String host) {
-        if (host == null || mDatabase == null) {
+    String[] getUsernamePassword(String schemePlusHost) {
+        if (schemePlusHost == null || mDatabase == null) {
             return null;
         }
 
@@ -718,8 +726,8 @@
         synchronized (mPasswordLock) {
             String[] ret = null;
             Cursor cursor = mDatabase.query(mTableNames[TABLE_PASSWORD_ID],
-                    columns, selection, new String[] { host }, null, null,
-                    null);
+                    columns, selection, new String[] { schemePlusHost }, null,
+                    null, null);
             if (cursor.moveToFirst()) {
                 ret = new String[2];
                 ret[0] = cursor.getString(
diff --git a/core/java/android/webkit/gears/AndroidWifiDataProvider.java b/core/java/android/webkit/gears/AndroidWifiDataProvider.java
new file mode 100644
index 0000000..7379f59
--- /dev/null
+++ b/core/java/android/webkit/gears/AndroidWifiDataProvider.java
@@ -0,0 +1,136 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package android.webkit.gears;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Config;
+import android.util.Log;
+import android.webkit.WebView;
+import java.util.List;
+
+/**
+ * WiFi data provider implementation for Android.
+ * {@hide}
+ */
+public final class AndroidWifiDataProvider extends BroadcastReceiver {
+  /**
+   * Logging tag
+   */
+  private static final String TAG = "Gears-J-WifiProvider";
+  /**
+   * Our Wifi manager instance.
+   */
+  private WifiManager mWifiManager;
+  /**
+   * The native object ID.
+   */
+  private long mNativeObject;
+  /**
+   * The Context instance.
+   */
+  private Context mContext;
+
+  /**
+   * Constructs a instance of this class and registers for wifi scan
+   * updates. Note that this constructor must be called on a Looper
+   * thread. Suitable threads can be created on the native side using
+   * the AndroidLooperThread C++ class.
+   */
+  public AndroidWifiDataProvider(WebView webview, long object) {
+    mNativeObject = object;
+    mContext = webview.getContext();
+    mWifiManager =
+        (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+    if (mWifiManager == null) {
+      Log.e(TAG,
+          "AndroidWifiDataProvider: could not get location manager.");
+      throw new NullPointerException(
+          "AndroidWifiDataProvider: locationManager is null.");
+    }
+
+    // Create a Handler that identifies the message loop associated
+    // with the current thread. Note that it is not necessary to
+    // override handleMessage() at all since the Intent
+    // ReceiverDispatcher (see the ActivityThread class) only uses
+    // this handler to post a Runnable to this thread's loop.
+    Handler handler = new Handler(Looper.myLooper());
+
+    IntentFilter filter = new IntentFilter();
+    filter.addAction(mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+    mContext.registerReceiver(this, filter, null, handler);
+
+    // Get the last scan results and pass them to the native side.
+    // We can't just invoke the callback here, so we queue a message
+    // to this thread's loop.
+    handler.post(new Runnable() {
+        public void run() {
+          onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
+        }
+      });
+  }
+
+  /**
+   * Called when the provider is no longer needed.
+   */
+  public void shutdown() {
+    mContext.unregisterReceiver(this);
+    if (Config.LOGV) {
+      Log.v(TAG, "Wifi provider closed.");
+    }
+  }
+
+  /**
+   * This method is called when the AndroidWifiDataProvider is receiving an
+   * Intent broadcast.
+   * @param context The Context in which the receiver is running.
+   * @param intent The Intent being received.
+   */
+  public void onReceive(Context context, Intent intent) {
+    if (intent.getAction().equals(
+            mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+      if (Config.LOGV) {
+        Log.v(TAG, "Wifi scan resulst available");
+      }
+      onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
+    }
+  }
+
+ /**
+   * The native method called when new wifi data is available.
+   * @param scanResults is a list of ScanResults  to pass to the native side.
+   * @param nativeObject is a pointer to the corresponding
+   * AndroidWifiDataProvider C++ instance.
+   */
+  private static native void onUpdateAvailable(
+      List<ScanResult> scanResults, long nativeObject);
+}
diff --git a/core/java/android/webkit/gears/DesktopAndroid.java b/core/java/android/webkit/gears/DesktopAndroid.java
index 00a9a47..ee8ca49 100644
--- a/core/java/android/webkit/gears/DesktopAndroid.java
+++ b/core/java/android/webkit/gears/DesktopAndroid.java
@@ -40,8 +40,6 @@
 public class DesktopAndroid {
 
   private static final String TAG = "Gears-J-Desktop";
-  private static final String BROWSER = "com.android.browser";
-  private static final String BROWSER_ACTIVITY = BROWSER + ".BrowserActivity";
   private static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
   private static final String ACTION_INSTALL_SHORTCUT =
       "com.android.launcher.action.INSTALL_SHORTCUT";
@@ -78,11 +76,9 @@
         String url, String imagePath) {
     Context context = webview.getContext();
 
-    ComponentName browser = new ComponentName(BROWSER, BROWSER_ACTIVITY);
-
     Intent viewWebPage = new Intent(Intent.ACTION_VIEW);
-    viewWebPage.setComponent(browser);
     viewWebPage.setData(Uri.parse(url));
+    viewWebPage.addCategory(Intent.CATEGORY_BROWSABLE);
 
     Intent intent = new Intent(ACTION_INSTALL_SHORTCUT);
     intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, viewWebPage);
diff --git a/core/java/android/webkit/gears/HttpRequestAndroid.java b/core/java/android/webkit/gears/HttpRequestAndroid.java
index 8668c54..30f855f 100644
--- a/core/java/android/webkit/gears/HttpRequestAndroid.java
+++ b/core/java/android/webkit/gears/HttpRequestAndroid.java
@@ -163,7 +163,20 @@
     // Setup the connection. This doesn't go to the wire yet - it
     // doesn't block.
     try {
-      connection = (HttpURLConnection) new URL(url).openConnection();
+      URL url_object = new URL(url);
+      // Check that the protocol is indeed HTTP(S).
+      String protocol = url_object.getProtocol();
+      if (protocol == null) {
+        log("null protocol for URL " + url);
+        return false;
+      }
+      protocol = protocol.toLowerCase();
+      if (!"http".equals(protocol) && !"https".equals(protocol)) {
+        log("Url has wrong protocol: " + url);
+        return false;
+      }
+
+      connection = (HttpURLConnection) url_object.openConnection();
       connection.setRequestMethod(method);
       // Manually follow redirects.
       connection.setInstanceFollowRedirects(false);
@@ -197,11 +210,13 @@
       log("interrupt() called but no child thread");
       return;
     }
-    if (inBlockingOperation) {
-      log("Interrupting blocking operation");
-      childThread.interrupt();
-    } else {
-      log("Nothing to interrupt");
+    synchronized (this) {
+      if (inBlockingOperation) {
+        log("Interrupting blocking operation");
+        childThread.interrupt();
+      } else {
+        log("Nothing to interrupt");
+      }
     }
   }
 
@@ -472,7 +487,7 @@
     String encoding = cacheResult.getEncoding();
     // Encoding may not be specified. No default.
     String contentType = mimeType;
-    if (encoding != null) {
+    if (encoding != null && encoding.length() > 0) {
       contentType += "; charset=" + encoding;
     }
     setResponseHeader(KEY_CONTENT_TYPE, contentType);
diff --git a/core/java/android/webkit/gears/NativeDialog.java b/core/java/android/webkit/gears/NativeDialog.java
new file mode 100644
index 0000000..9e2b375
--- /dev/null
+++ b/core/java/android/webkit/gears/NativeDialog.java
@@ -0,0 +1,142 @@
+// Copyright 2008 The Android Open Source Project
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package android.webkit.gears;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import java.io.File;
+import java.lang.InterruptedException;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Utility class to call a modal native dialog on Android
+ * The dialog itself is an Activity defined in the Browser.
+ * @hide
+ */
+public class NativeDialog {
+
+  private static final String TAG = "Gears-J-NativeDialog";
+
+  private final String DIALOG_PACKAGE = "com.android.browser";
+  private final String DIALOG_CLASS = DIALOG_PACKAGE + ".GearsNativeDialog";
+
+  private static Lock mLock = new ReentrantLock();
+  private static Condition mDialogFinished = mLock.newCondition();
+  private static String mResults = null;
+
+  private static boolean mAsynchronousDialog;
+
+  /**
+   * Utility function to build the intent calling the
+   * dialog activity
+   */
+  private Intent createIntent(String type, String arguments) {
+    Intent intent = new Intent();
+    intent.setClassName(DIALOG_PACKAGE, DIALOG_CLASS);
+    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+    intent.putExtra("dialogArguments", arguments);
+    intent.putExtra("dialogType", type);
+    return intent;
+  }
+
+  /**
+   * Opens a native dialog synchronously and waits for its completion.
+   *
+   * The dialog is an activity (GearsNativeDialog) provided by the Browser
+   * that we call via startActivity(). Contrary to a normal activity though,
+   * we need to block until it returns. To do so, we define a static lock
+   * object in this class, which GearsNativeDialog can unlock once done
+   */
+  public String showDialog(Context context, String file,
+      String arguments) {
+
+    try {
+      mAsynchronousDialog = false;
+      mLock.lock();
+      File path = new File(file);
+      String fileName = path.getName();
+      String type = fileName.substring(0, fileName.indexOf(".html"));
+      Intent intent = createIntent(type, arguments);
+
+      mResults = null;
+      context.startActivity(intent);
+      mDialogFinished.await();
+    } catch (InterruptedException e) {
+      Log.e(TAG, "exception e: " + e);
+    } catch (ActivityNotFoundException e) {
+      Log.e(TAG, "exception e: " + e);
+    } finally {
+      mLock.unlock();
+    }
+
+    return mResults;
+  }
+
+  /**
+   * Opens a native dialog asynchronously
+   *
+   * The dialog is an activity (GearsNativeDialog) provided by the
+   * Browser.
+   */
+  public void showAsyncDialog(Context context, String type,
+                           String arguments) {
+    mAsynchronousDialog = true;
+    Intent intent = createIntent(type, arguments);
+    context.startActivity(intent);
+  }
+
+  /**
+   * Static method that GearsNativeDialog calls to unlock us
+   */
+  public static void signalFinishedDialog() {
+    if (!mAsynchronousDialog) {
+      mLock.lock();
+      mDialogFinished.signal();
+      mLock.unlock();
+    } else {
+      // we call the native callback
+      closeAsynchronousDialog(mResults);
+    }
+  }
+
+  /**
+   * Static method that GearsNativeDialog calls to set the
+   * dialog's result
+   */
+  public static void closeDialog(String res) {
+    mResults = res;
+  }
+
+  /**
+   * Native callback method
+   */
+  private native static void closeAsynchronousDialog(String res);
+}
diff --git a/core/java/android/webkit/gears/PluginSettings.java b/core/java/android/webkit/gears/PluginSettings.java
new file mode 100644
index 0000000..2d0cc13
--- /dev/null
+++ b/core/java/android/webkit/gears/PluginSettings.java
@@ -0,0 +1,79 @@
+// Copyright 2008 The Android Open Source Project
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package android.webkit.gears;
+
+import android.content.Context;
+import android.util.Log;
+import android.webkit.Plugin;
+import android.webkit.Plugin.PreferencesClickHandler;
+
+/**
+ * Simple bridge class intercepting the click in the
+ * browser plugin list and calling the Gears settings
+ * dialog.
+ */
+public class PluginSettings {
+
+  private static final String TAG = "Gears-J-PluginSettings";
+  private Context mContext;
+
+  public PluginSettings(Plugin plugin) {
+    plugin.setClickHandler(new ClickHandler());
+  }
+
+  /**
+   * We do not call the dialog synchronously here as the main
+   * message loop would be blocked, so we call it via a secondary thread.
+   */
+  private class ClickHandler implements PreferencesClickHandler {
+    public void handleClickEvent(Context context) {
+      mContext = context.getApplicationContext();
+      Thread startDialog = new Thread(new StartDialog(context));
+      startDialog.start();
+    }
+  }
+
+  /**
+   * Simple wrapper class to call the gears native method in
+   * a separate thread (the native code will then instanciate a NativeDialog
+   * object which will start the GearsNativeDialog activity defined in
+   * the Browser).
+   */
+  private class StartDialog implements Runnable {
+    Context mContext;
+
+    public StartDialog(Context context) {
+      mContext = context;
+    }
+
+    public void run() {
+      runSettingsDialog(mContext);
+    }
+  }
+
+  private static native void runSettingsDialog(Context c);
+
+}
diff --git a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
index 95fc30f..288240e 100644
--- a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
+++ b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
@@ -407,6 +407,8 @@
         true); // forceCache
 
     if (cacheResult == null) {
+      // With the no-cache policy we could end up
+      // with a null result
       return null;
     }
 
@@ -444,8 +446,7 @@
     // be used for input.
     cacheResult = CacheManager.getCacheFile(gearsUrl, null);
     if (cacheResult != null) {
-      if (logEnabled)
-        log("Returning surrogate result");
+      log("Returning surrogate result");
       return cacheResult;
     } else {
       // Not an expected condition, but handle gracefully. Perhaps out
@@ -476,7 +477,10 @@
   }
 
   /**
-   * Convenience debug function. Calls Android logging mechanism.
+   * Convenience debug function. Calls the Android logging
+   * mechanism. logEnabled is not a constant, so if the string
+   * evaluation is potentially expensive, the caller also needs to
+   * check it.
    * @param str String to log to the Android console.
    */
   private void log(String str) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 19b1ce0..1440522 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -58,6 +58,8 @@
  * @attr ref android.R.styleable#AbsListView_textFilterEnabled
  * @attr ref android.R.styleable#AbsListView_transcriptMode
  * @attr ref android.R.styleable#AbsListView_cacheColorHint
+ * @attr ref android.R.styleable#AbsListView_fastScrollEnabled
+ * @attr ref android.R.styleable#AbsListView_smoothScrollbar
  */
 public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
         ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
@@ -116,6 +118,11 @@
      * Indicates the view is in the process of being flung
      */
     static final int TOUCH_MODE_FLING = 4;
+    
+    /**
+     * Indicates that the user is currently dragging the fast scroll thumb
+     */
+    static final int TOUCH_MODE_FAST_SCROLL = 5;
 
     /**
      * Regular layout - usually an unsolicited layout from the view system
@@ -304,6 +311,11 @@
      * bitmap cache after scrolling.
      */
     boolean mScrollingCacheEnabled;
+    
+    /**
+     * Whether or not to enable the fast scroll feature on this list
+     */
+    boolean mFastScrollEnabled;
 
     /**
      * Optional callback to notify client when scroll position has changed
@@ -321,6 +333,12 @@
     EditText mTextFilter;
 
     /**
+     * Indicates whether to use pixels-based or position-based scrollbar
+     * properties.
+     */
+    private boolean mSmoothScrollbarEnabled = true;
+
+    /**
      * Indicates that this view supports filtering
      */
     private boolean mTextFilterEnabled;
@@ -401,6 +419,11 @@
     private int mLastScrollState = OnScrollListener.SCROLL_STATE_IDLE;
 
     /**
+     * Helper object that renders and controls the fast scroll thumb.
+     */
+    private FastScroller mFastScroller;
+
+    /**
      * Interface definition for a callback to be invoked when the list or grid
      * has been scrolled.
      */
@@ -493,11 +516,84 @@
 
         int color = a.getColor(R.styleable.AbsListView_cacheColorHint, 0);
         setCacheColorHint(color);
+        
+        boolean enableFastScroll = a.getBoolean(R.styleable.AbsListView_fastScrollEnabled, false);
+        setFastScrollEnabled(enableFastScroll);
 
+        boolean smoothScrollbar = a.getBoolean(R.styleable.AbsListView_smoothScrollbar, true);
+        setSmoothScrollbarEnabled(smoothScrollbar);
+        
         a.recycle();
     }
 
     /**
+     * Enables fast scrolling by letting the user quickly scroll through lists by 
+     * dragging the fast scroll thumb. The adapter attached to the list may want 
+     * to implement {@link SectionIndexer} if it wishes to display alphabet preview and
+     * jump between sections of the list. 
+     * @see SectionIndexer
+     * @see #isFastScrollEnabled()
+     * @param enabled whether or not to enable fast scrolling
+     */
+    public void setFastScrollEnabled(boolean enabled) {
+        mFastScrollEnabled = enabled;
+        if (enabled) {
+            if (mFastScroller == null) {
+                mFastScroller = new FastScroller(getContext(), this);
+            }
+        } else {
+            if (mFastScroller != null) {
+                mFastScroller.stop();
+                mFastScroller = null;
+            }
+        }
+    }
+    
+    /**
+     * Returns the current state of the fast scroll feature.
+     * @see #setFastScrollEnabled(boolean)
+     * @return true if fast scroll is enabled, false otherwise
+     */
+    @ViewDebug.ExportedProperty
+    public boolean isFastScrollEnabled() {
+        return mFastScrollEnabled;
+    }
+
+    /**
+     * When smooth scrollbar is enabled, the position and size of the scrollbar thumb
+     * is computed based on the number of visible pixels in the visible items. This
+     * however assumes that all list items have the same height. If you use a list in
+     * which items have different heights, the scrollbar will change appearance as the
+     * user scrolls through the list. To avoid this issue, you need to disable this
+     * property.
+     *
+     * When smooth scrollbar is disabled, the position and size of the scrollbar thumb
+     * is based solely on the number of items in the adapter and the position of the
+     * visible items inside the adapter. This provides a stable scrollbar as the user
+     * navigates through a list of items with varying heights. 
+     *
+     * @param enabled Whether or not to enable smooth scrollbar.
+     *
+     * @see #setSmoothScrollbarEnabled(boolean) 
+     * @attr ref android.R.styleable#AbsListView_smoothScrollbar
+     */
+    public void setSmoothScrollbarEnabled(boolean enabled) {
+        mSmoothScrollbarEnabled = enabled;
+    }
+
+    /**
+     * Returns the current state of the fast scroll feature.
+     *
+     * @return True if smooth scrollbar is enabled is enabled, false otherwise.
+     *
+     * @see #setSmoothScrollbarEnabled(boolean)
+     */
+    @ViewDebug.ExportedProperty
+    public boolean isSmoothScrollbarEnabled() {
+        return mSmoothScrollbarEnabled;
+    }
+
+    /**
      * Set the listener that will receive notifications every time the list scrolls.
      *
      * @param l the scroll listener
@@ -511,6 +607,9 @@
      * Notify our scroll listener (if there is one) of a change in scroll state
      */
     void invokeOnItemScrollListener() {
+        if (mFastScroller != null) {
+            mFastScroller.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
+        }
         if (mOnScrollListener != null) {
             mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
         }
@@ -525,6 +624,7 @@
      * @see #setScrollingCacheEnabled(boolean)
      * @see View#setDrawingCacheEnabled(boolean)
      */
+    @ViewDebug.ExportedProperty
     public boolean isScrollingCacheEnabled() {
         return mScrollingCacheEnabled;
     }
@@ -571,6 +671,7 @@
      * @see #setTextFilterEnabled(boolean)
      * @see Filterable
      */
+    @ViewDebug.ExportedProperty
     public boolean isTextFilterEnabled() {
         return mTextFilterEnabled;
     }
@@ -595,10 +696,12 @@
         setWillNotDraw(false);
         setAlwaysDrawnWithCacheEnabled(false);
         setScrollingCacheEnabled(true);
+        setScrollContainer(true);
     }
 
     private void useDefaultSelector() {
-        setSelector(getResources().getDrawable(com.android.internal.R.drawable.list_selector_background));
+        setSelector(getResources().getDrawable(
+                com.android.internal.R.drawable.list_selector_background));
     }
 
     /**
@@ -607,6 +710,7 @@
      *
      * @return true if the content is stacked from the bottom edge, false otherwise
      */
+    @ViewDebug.ExportedProperty
     public boolean isStackFromBottom() {
         return mStackFromBottom;
     }
@@ -843,35 +947,54 @@
     protected int computeVerticalScrollExtent() {
         final int count = getChildCount();
         if (count > 0) {
-            int extent = count * 100;
+            if (mSmoothScrollbarEnabled) {
+                int extent = count * 100;
 
-            View view = getChildAt(0);
-            final int top = view.getTop();
-            int height = view.getHeight();
-            if (height > 0) {
-                extent += (top * 100) / height;
+                View view = getChildAt(0);
+                final int top = view.getTop();
+                int height = view.getHeight();
+                if (height > 0) {
+                    extent += (top * 100) / height;
+                }
+
+                view = getChildAt(count - 1);
+                final int bottom = view.getBottom();
+                height = view.getHeight();
+                if (height > 0) {
+                    extent -= ((bottom - getHeight()) * 100) / height;
+                }
+
+                return extent;
+            } else {
+                return 1;
             }
-
-            view = getChildAt(count - 1);
-            final int bottom = view.getBottom();
-            height = view.getHeight();
-            if (height > 0) {
-                extent -= ((bottom - getHeight()) * 100) / height;
-            }
-
-            return extent;
         }
         return 0;
     }
 
     @Override
     protected int computeVerticalScrollOffset() {
-        if (mFirstPosition >= 0 && getChildCount() > 0) {
-            final View view = getChildAt(0);
-            final int top = view.getTop();
-            int height = view.getHeight();
-            if (height > 0) {
-                return Math.max(mFirstPosition * 100 - (top * 100) / height, 0);
+        final int firstPosition = mFirstPosition;
+        final int childCount = getChildCount();
+        if (firstPosition >= 0 && childCount > 0) {
+            if (mSmoothScrollbarEnabled) {
+                final View view = getChildAt(0);
+                final int top = view.getTop();
+                int height = view.getHeight();
+                if (height > 0) {
+                    return Math.max(firstPosition * 100 - (top * 100) / height, 0);
+                }
+            } else {
+                int index;
+                final int count = mItemCount;
+                if (firstPosition == 0) {
+                    index = 0;
+                } else if (firstPosition + childCount == count) {
+                    index = count;
+                } else {
+                    index = firstPosition + childCount / 2;
+                }
+                return (int) (firstPosition + childCount * (index / (float) count));
             }
         }
         return 0;
@@ -879,7 +1002,7 @@
 
     @Override
     protected int computeVerticalScrollRange() {
-        return Math.max(mItemCount * 100, 0);
+        return mSmoothScrollbarEnabled ? Math.max(mItemCount * 100, 0) : mItemCount;
     }
 
     @Override
@@ -1140,6 +1263,9 @@
             mDataChanged = true;
             rememberSyncState();
         }
+        if (mFastScroller != null) {
+            mFastScroller.onSizeChanged(w, h, oldw, oldh);
+        }
     }
 
     /**
@@ -1669,6 +1795,13 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
+        
+        if (mFastScroller != null) {
+            boolean intercepted = mFastScroller.onTouchEvent(ev);
+            if (intercepted) {
+                return true;
+            }            
+        }
         final int action = ev.getAction();
         final int x = (int) ev.getX();
         final int y = (int) ev.getY();
@@ -1684,28 +1817,30 @@
         switch (action) {
         case MotionEvent.ACTION_DOWN: {
             int motionPosition = pointToPosition(x, y);
-            if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)
-                    && (getAdapter().isEnabled(motionPosition))) {
-                // User clicked on an actual view (and was not stopping a fling). It might be a
-                // click or a scroll. Assume it is a click until proven otherwise
-                mTouchMode = TOUCH_MODE_DOWN;
-                // FIXME Debounce
-                if (mPendingCheckForTap == null) {
-                    mPendingCheckForTap = new CheckForTap();
+            if (!mDataChanged) {
+                if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)
+                        && (getAdapter().isEnabled(motionPosition))) {
+                    // User clicked on an actual view (and was not stopping a fling). It might be a
+                    // click or a scroll. Assume it is a click until proven otherwise
+                    mTouchMode = TOUCH_MODE_DOWN;
+                    // FIXME Debounce
+                    if (mPendingCheckForTap == null) {
+                        mPendingCheckForTap = new CheckForTap();
+                    }
+                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
+                } else {
+                    if (ev.getEdgeFlags() != 0 && motionPosition < 0) {
+                        // If we couldn't find a view to click on, but the down event was touching
+                        // the edge, we will bail out and try again. This allows the edge correcting
+                        // code in ViewRoot to try to find a nearby view to select
+                        return false;
+                    }
+                    // User clicked on whitespace, or stopped a fling. It is a scroll.
+                    createScrollingCache();
+                    mTouchMode = TOUCH_MODE_SCROLL;
+                    motionPosition = findMotionRow(y);
+                    reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
                 }
-                postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
-            } else {
-                if (ev.getEdgeFlags() != 0 && motionPosition < 0) {
-                    // If we couldn't find a view to click on, but the down event was touching
-                    // the edge, we will bail out and try again. This allows the edge correcting
-                    // code in ViewRoot to try to find a nearby view to select
-                    return false;
-                }
-                // User clicked on whitespace, or stopped a fling. It is a scroll.
-                createScrollingCache();
-                mTouchMode = TOUCH_MODE_SCROLL;
-                motionPosition = findMotionRow(y);
-                reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
             }
 
             if (motionPosition >= 0) {
@@ -1897,6 +2032,14 @@
 
         return true;
     }
+    
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        if (mFastScroller != null) {
+            mFastScroller.draw(canvas);
+        }
+    }
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
@@ -1904,6 +2047,14 @@
         int x = (int) ev.getX();
         int y = (int) ev.getY();
         View v;
+        
+        if (mFastScroller != null) {
+            boolean intercepted = mFastScroller.onInterceptTouchEvent(ev);
+            if (intercepted) {
+                return true;
+            }
+        }
+        
         switch (action) {
         case MotionEvent.ACTION_DOWN: {
             int motionPosition = findMotionRow(y);
@@ -1965,7 +2116,14 @@
         }
     }
 
-    private void reportScrollStateChange(int newState) {
+    /**
+     * Fires an "on scroll state changed" event to the registered
+     * {@link android.widget.AbsListView.OnScrollListener}, if any. The state change
+     * is fired only if the specified state is different from the previously known state.
+     *
+     * @param newState The new scroll state.
+     */
+    void reportScrollStateChange(int newState) {
         if (newState != mLastScrollState) {
             if (mOnScrollListener != null) {
                 mOnScrollListener.onScrollStateChanged(this, newState);
@@ -2013,10 +2171,7 @@
 
         private void endFling() {
             mTouchMode = TOUCH_MODE_REST;
-            if (mOnScrollListener != null) {
-                mOnScrollListener.onScrollStateChanged(AbsListView.this,
-                        OnScrollListener.SCROLL_STATE_IDLE);
-            }
+            reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
             clearScrollingCache();
         }
 
@@ -2411,7 +2566,9 @@
         if (selectedPos >= 0) {
             mLayoutMode = LAYOUT_SPECIFIC;
             setSelectionInt(selectedPos);
+            invokeOnItemScrollListener();
         }
+        reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
 
         return selectedPos >= 0;
     }
@@ -2547,7 +2704,7 @@
         // Make sure we have a window before showing the popup
         if (getWindowVisibility() == View.VISIBLE) {
             int screenHeight = WindowManagerImpl.getDefault().getDefaultDisplay().getHeight();
-            final int[] xy = mLocation;
+            final int[] xy = new int[2];
             getLocationOnScreen(xy);
             int bottomGap = screenHeight - xy[1] - getHeight() + 20;
             mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL,
@@ -2689,6 +2846,7 @@
                     com.android.internal.R.layout.typing_filter, null);
             mTextFilter.addTextChangedListener(this);
             p.setFocusable(false);
+            p.setTouchable(false);
             p.setContentView(mTextFilter);
             p.setWidth(LayoutParams.WRAP_CONTENT);
             p.setHeight(LayoutParams.WRAP_CONTENT);
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 1fa7318..65ca885 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -242,6 +242,7 @@
                 
             case MotionEvent.ACTION_MOVE:
                 trackTouchEvent(event);
+                attemptClaimDrag();
                 break;
                 
             case MotionEvent.ACTION_UP:
@@ -281,6 +282,16 @@
         
         setProgress((int) progress, true);
     }
+
+    /**
+     * Tries to claim the user's drag motion, and requests disallowing any
+     * ancestors from stealing events in the drag.
+     */
+    private void attemptClaimDrag() {
+        if (mParent != null) {
+            mParent.requestDisallowInterceptTouchEvent(true);
+        }
+    }
     
     /**
      * This is called when the user has started touching this widget.
diff --git a/core/java/android/widget/AbsoluteLayout.java b/core/java/android/widget/AbsoluteLayout.java
index 36a3b10..c77f7ae 100644
--- a/core/java/android/widget/AbsoluteLayout.java
+++ b/core/java/android/widget/AbsoluteLayout.java
@@ -32,7 +32,11 @@
  * <p><strong>XML attributes</strong></p> <p> See {@link
  * android.R.styleable#ViewGroup ViewGroup Attributes}, {@link
  * android.R.styleable#View View Attributes}</p>
+ * 
+ * @deprecated Use {@link android.widget.FrameLayout}, {@link android.widget.RelativeLayout}
+ *             or a custom layout instead.
  */
+@Deprecated
 @RemoteView
 public class AbsoluteLayout extends ViewGroup {
     public AbsoluteLayout(Context context) {
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index e096612..173e80f 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -140,7 +140,7 @@
      * The position within the adapter's data set of the item to select
      * during the next layout.
      */
-    @ViewDebug.ExportedProperty
+    @ViewDebug.ExportedProperty    
     int mNextSelectedPosition = INVALID_POSITION;
 
     /**
@@ -151,7 +151,7 @@
     /**
      * The position within the adapter's data set of the currently selected item.
      */
-    @ViewDebug.ExportedProperty
+    @ViewDebug.ExportedProperty    
     int mSelectedPosition = INVALID_POSITION;
 
     /**
@@ -520,6 +520,7 @@
      *
      * @return int Position (starting at 0), or {@link #INVALID_POSITION} if there is nothing selected.
      */
+    @ViewDebug.CapturedViewProperty
     public int getSelectedItemPosition() {
         return mNextSelectedPosition;
     }
@@ -528,6 +529,7 @@
      * @return The id corresponding to the currently selected item, or {@link #INVALID_ROW_ID}
      * if nothing is selected.
      */
+    @ViewDebug.CapturedViewProperty
     public long getSelectedItemId() {
         return mNextSelectedRowId;
     }
@@ -557,6 +559,7 @@
      *         AdapterView. (This is the number of data items, which may be
      *         larger than the number of visible view.)
      */
+    @ViewDebug.CapturedViewProperty
     public int getCount() {
         return mItemCount;
     }
diff --git a/core/java/android/widget/AlphabetIndexer.java b/core/java/android/widget/AlphabetIndexer.java
new file mode 100644
index 0000000..bbabaaa
--- /dev/null
+++ b/core/java/android/widget/AlphabetIndexer.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.util.SparseIntArray;
+
+/**
+ * A helper class for adapters that implement the SectionIndexer interface.
+ * If the items in the adapter are sorted by simple alphabet-based sorting, then
+ * this class provides a way to do fast indexing of large lists using binary search.
+ * It caches the indices that have been determined through the binary search and also
+ * invalidates the cache if changes occur in the cursor.
+ * <p/>
+ * Your adapter is responsible for updating the cursor by calling {@link #setCursor} if the
+ * cursor changes. {@link #getPositionForSection} method does the binary search for the starting 
+ * index of a given section (alphabet).
+ * @hide pending API council approval
+ */
+public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
+
+    /**
+     * Cursor that is used by the adapter of the list view.
+     */
+    protected Cursor mDataCursor;
+    
+    /**
+     * The index of the cursor column that this list is sorted on.
+     */
+    protected int mColumnIndex;
+    
+    /**
+     * The string of characters that make up the indexing sections.
+     */
+    protected CharSequence mAlphabet;
+    
+    /**
+     * Cached length of the alphabet array.
+     */
+    private int mAlphabetLength;
+    
+    /**
+     * This contains a cache of the computed indices so far. It will get reset whenever
+     * the dataset changes or the cursor changes.
+     */
+    private SparseIntArray mAlphaMap;
+    
+    /**
+     * Use a collator to compare strings in a localized manner.
+     */
+    private java.text.Collator mCollator;
+    
+    /**
+     * The section array converted from the alphabet string.
+     */
+    private String[] mAlphabetArray;
+
+    /**
+     * Constructs the indexer.
+     * @param cursor the cursor containing the data set
+     * @param sortedColumnIndex the column number in the cursor that is sorted 
+     *        alphabetically
+     * @param alphabet string containing the alphabet, with space as the first character. 
+     *        For example, use the string " ABCDEFGHIJKLMNOPQRSTUVWXYZ" for English indexing.
+     *        The characters must be uppercase and be sorted in ascii/unicode order. Basically
+     *        characters in the alphabet will show up as preview letters.
+     */
+    public AlphabetIndexer(Cursor cursor, int sortedColumnIndex, CharSequence alphabet) {
+        mDataCursor = cursor;
+        mColumnIndex = sortedColumnIndex;
+        mAlphabet = alphabet;
+        mAlphabetLength = alphabet.length();
+        mAlphabetArray = new String[mAlphabetLength];
+        for (int i = 0; i < mAlphabetLength; i++) {
+            mAlphabetArray[i] = Character.toString(mAlphabet.charAt(i));
+        }
+        mAlphaMap = new SparseIntArray(mAlphabetLength);
+        if (cursor != null) {
+            cursor.registerDataSetObserver(this);
+        }
+        // Get a Collator for the current locale for string comparisons.
+        mCollator = java.text.Collator.getInstance();
+        mCollator.setStrength(java.text.Collator.PRIMARY);
+    }
+
+    /**
+     * Returns the section array constructed from the alphabet provided in the constructor.
+     * @return the section array
+     */
+    public Object[] getSections() {
+        return mAlphabetArray;
+    }
+    
+    /**
+     * Sets a new cursor as the data set and resets the cache of indices.
+     * @param cursor the new cursor to use as the data set
+     */
+    public void setCursor(Cursor cursor) {
+        if (mDataCursor != null) {
+            mDataCursor.unregisterDataSetObserver(this);
+        }
+        mDataCursor = cursor;
+        if (cursor != null) {
+            mDataCursor.registerDataSetObserver(this);
+        }
+        mAlphaMap.clear();
+    }
+
+    /**
+     * Default implementation compares the first character of word with letter.
+     */
+    protected int compare(String word, String letter) {
+        return mCollator.compare(word.substring(0, 1), letter);
+    }
+    
+    /**
+     * Performs a binary search or cache lookup to find the first row that
+     * matches a given section's starting letter.
+     * @param sectionIndex the section to search for
+     * @return the row index of the first occurrence, or the nearest next letter.
+     * For instance, if searching for "T" and no "T" is found, then the first
+     * row starting with "U" or any higher letter is returned. If there is no
+     * data following "T" at all, then the list size is returned.
+     */
+    public int getPositionForSection(int sectionIndex) {
+        final SparseIntArray alphaMap = mAlphaMap;
+        final Cursor cursor = mDataCursor;
+
+        if (cursor == null || mAlphabet == null) {
+            return 0;
+        }
+        
+        // Check bounds
+        if (sectionIndex <= 0) {
+            return 0;
+        }
+        if (sectionIndex >= mAlphabetLength) {
+            sectionIndex = mAlphabetLength - 1;
+        }
+
+        int savedCursorPos = cursor.getPosition();
+
+        int count = cursor.getCount();
+        int start = 0;
+        int end = count;
+        int pos;
+
+        char letter = mAlphabet.charAt(sectionIndex);
+        String targetLetter = Character.toString(letter);
+        int key = letter;
+        // Check map
+        if (Integer.MIN_VALUE != (pos = alphaMap.get(key, Integer.MIN_VALUE))) {
+            // Is it approximate? Using negative value to indicate that it's 
+            // an approximation and positive value when it is the accurate
+            // position.
+            if (pos < 0) {
+                pos = -pos;
+                end = pos;
+            } else {
+                // Not approximate, this is the confirmed start of section, return it
+                return pos;
+            }
+        }
+
+        // Do we have the position of the previous section?
+        if (sectionIndex > 0) {
+            int prevLetter =
+                    mAlphabet.charAt(sectionIndex - 1);
+            int prevLetterPos = alphaMap.get(prevLetter, Integer.MIN_VALUE);
+            if (prevLetterPos != Integer.MIN_VALUE) {
+                start = Math.abs(prevLetterPos);
+            }
+        }
+
+        // Now that we have a possibly optimized start and end, let's binary search
+
+        pos = (end + start) / 2;
+
+        while (pos < end) {
+            // Get letter at pos
+            cursor.moveToPosition(pos);
+            String curName = cursor.getString(mColumnIndex);
+            if (curName == null) {
+                if (pos == 0) {
+                    break;
+                } else {
+                    pos--;
+                    continue;
+                }
+            }
+            int diff = compare(curName, targetLetter);
+            if (diff != 0) {
+                // Commenting out approximation code because it doesn't work for certain 
+                // lists with custom comparators
+                // Enter approximation in hash if a better solution doesn't exist
+                // String startingLetter = Character.toString(getFirstLetter(curName));
+                // int startingLetterKey = startingLetter.charAt(0);
+                // int curPos = alphaMap.get(startingLetterKey, Integer.MIN_VALUE);
+                // if (curPos == Integer.MIN_VALUE || Math.abs(curPos) > pos) {
+                //     Negative pos indicates that it is an approximation
+                //     alphaMap.put(startingLetterKey, -pos);
+                // }
+                // if (mCollator.compare(startingLetter, targetLetter) < 0) {
+                if (diff < 0) {
+                    start = pos + 1;
+                    if (start >= count) {
+                        pos = count;
+                        break;
+                    }
+                } else {
+                    end = pos;
+                }
+            } else {
+                // They're the same, but that doesn't mean it's the start
+                if (start == pos) {
+                    // This is it
+                    break;
+                } else {
+                    // Need to go further lower to find the starting row
+                    end = pos;
+                }
+            }
+            pos = (start + end) / 2;
+        }
+        alphaMap.put(key, pos);
+        cursor.moveToPosition(savedCursorPos);
+        return pos;
+    }
+
+    /**
+     * Returns the section index for a given position in the list by querying the item
+     * and comparing it with all items in the section array.
+     */
+    public int getSectionForPosition(int position) {
+        int savedCursorPos = mDataCursor.getPosition();
+        mDataCursor.moveToPosition(position);
+        mDataCursor.moveToPosition(savedCursorPos);
+        String curName = mDataCursor.getString(mColumnIndex);
+        // Linear search, as there are only a few items in the section index
+        // Could speed this up later if it actually gets used.
+        for (int i = 0; i < mAlphabetLength; i++) {
+            char letter = mAlphabet.charAt(i);
+            String targetLetter = Character.toString(letter);
+            if (compare(curName, targetLetter) == 0) {
+                return i;
+            }
+        }
+        return 0; // Don't recognize the letter - falls under zero'th section    
+    }
+    
+    /*
+     * @hide
+     */
+    @Override
+    public void onChanged() {
+        super.onChanged();
+        mAlphaMap.clear();
+    }
+
+    /*
+     * @hide
+     */
+    @Override
+    public void onInvalidated() {
+        super.onInvalidated();
+        mAlphaMap.clear();
+    }
+}
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 808104e..fbb0105 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -25,9 +25,9 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.text.format.Time;
 import android.util.AttributeSet;
 import android.view.View;
-import android.pim.Time;
 
 import java.util.TimeZone;
 
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 582117f..5fa00e7 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -18,7 +18,6 @@
 
 import com.android.internal.R;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
@@ -31,9 +30,17 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+
 import java.io.File;
+import java.text.Collator;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -56,15 +63,15 @@
         BOTH
     }
 
-    private final String TAG = "AppSecurityPermissions";
+    private final static String TAG = "AppSecurityPermissions";
     private boolean localLOGV = false;
     private Context mContext;
     private LayoutInflater mInflater;
     private PackageManager mPm;
     private LinearLayout mPermsView;
-    private HashMap<String, String> mDangerousMap;
-    private HashMap<String, String> mNormalMap;
-    private ArrayList<PermissionInfo> mPermsList;
+    private Map<String, String> mDangerousMap;
+    private Map<String, String> mNormalMap;
+    private List<PermissionInfo> mPermsList;
     private String mDefaultGrpLabel;
     private String mDefaultGrpName="DefaultGrp";
     private String mPermFormat;
@@ -79,18 +86,129 @@
     private State mCurrentState;
     private LinearLayout mNonDangerousList;
     private LinearLayout mDangerousList;
-    private HashMap<String, String> mGroupLabelCache;
+    private HashMap<String, CharSequence> mGroupLabelCache;
     private View mNoPermsView;
-
-    public AppSecurityPermissions(Context context) {
-        this(context, null);
+    
+    public AppSecurityPermissions(Context context, List<PermissionInfo> permList) {
+        mContext = context;
+        mPm = mContext.getPackageManager();
+        mPermsList = permList;
+    }
+    
+    public AppSecurityPermissions(Context context, String packageName) {
+        mContext = context;
+        mPm = mContext.getPackageManager();
+        mPermsList = new ArrayList<PermissionInfo>();
+        Set<PermissionInfo> permSet = new HashSet<PermissionInfo>();
+        PackageInfo pkgInfo;
+        try {
+            pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Could'nt retrieve permissions for package:"+packageName);
+            return;
+        }
+        // Extract all user permissions
+        if((pkgInfo.applicationInfo != null) && (pkgInfo.applicationInfo.uid != -1)) {
+            getAllUsedPermissions(pkgInfo.applicationInfo.uid, permSet);
+        }
+        for(PermissionInfo tmpInfo : permSet) {
+            mPermsList.add(tmpInfo);
+        }
+    }
+    
+    public AppSecurityPermissions(Context context, PackageParser.Package pkg) {
+        mContext = context;
+        mPm = mContext.getPackageManager();
+        mPermsList = new ArrayList<PermissionInfo>();
+        Set<PermissionInfo> permSet = new HashSet<PermissionInfo>();
+        if(pkg == null) {
+            return;
+        }
+        // Extract shared user permissions if any
+        if(pkg.mSharedUserId != null) {
+            int sharedUid;
+            try {
+                sharedUid = mPm.getUidForSharedUser(pkg.mSharedUserId);
+            } catch (NameNotFoundException e) {
+                Log.w(TAG, "Could'nt retrieve shared user id for:"+pkg.packageName);
+                return;
+            }
+            getAllUsedPermissions(sharedUid, permSet);
+        } else {
+            ArrayList<String> strList = pkg.requestedPermissions;
+            int size;
+            if((strList == null) || ((size = strList.size()) == 0)) {
+                return;
+            }
+            // Extract permissions defined in current package
+            extractPerms(strList.toArray(new String[size]), permSet);
+        }
+        for(PermissionInfo tmpInfo : permSet) {
+            mPermsList.add(tmpInfo);
+        }
+    }
+    
+    public PackageParser.Package getPackageInfo(Uri packageURI) {
+        final String archiveFilePath = packageURI.getPath();
+        PackageParser packageParser = new PackageParser(archiveFilePath);
+        File sourceFile = new File(archiveFilePath);
+        DisplayMetrics metrics = new DisplayMetrics();
+        metrics.setToDefaults();
+        return packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);
+    }
+    
+    private void getAllUsedPermissions(int sharedUid, Set<PermissionInfo> permSet) {
+        String sharedPkgList[] = mPm.getPackagesForUid(sharedUid);
+        if(sharedPkgList == null || (sharedPkgList.length == 0)) {
+            return;
+        }
+        for(String sharedPkg : sharedPkgList) {
+            getPermissionsForPackage(sharedPkg, permSet);
+        }
+    }
+    
+    private void getPermissionsForPackage(String packageName, 
+            Set<PermissionInfo> permSet) {
+        PackageInfo pkgInfo;
+        try {
+            pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Could'nt retrieve permissions for package:"+packageName);
+            return;
+        }
+        if(pkgInfo == null) {
+            return;
+        }
+        String strList[] = pkgInfo.requestedPermissions;
+        if(strList == null) {
+            return;
+        }
+        extractPerms(strList, permSet);
+    }
+    
+    private void extractPerms(String strList[], Set<PermissionInfo> permSet) {
+        if((strList == null) || (strList.length == 0)) {
+            return;
+        }
+        for(String permName:strList) {
+            try {
+                PermissionInfo tmpPermInfo = mPm.getPermissionInfo(permName, 0);
+                if(tmpPermInfo != null) {
+                    permSet.add(tmpPermInfo);
+                }
+            } catch (NameNotFoundException e) {
+                Log.i(TAG, "Ignoring unknown permission:"+permName);
+            }
+        }
+    }
+    
+    public int getPermissionCount() {
+        return mPermsList.size();
     }
 
-    public AppSecurityPermissions(Context context, ArrayList<PermissionInfo> permList) {
-        mContext = context;
-        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        mPm = context.getPackageManager();
-        mPermsList = permList;
+    public View getPermissionsView() {
+        
+        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mPermsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null);
         mShowMore = mPermsView.findViewById(R.id.show_more);
         mShowMoreIcon = (ImageView) mShowMore.findViewById(R.id.show_more_icon);
@@ -112,32 +230,9 @@
         mDangerousIcon = mContext.getResources().getDrawable(R.drawable.ic_bullet_key_permission);
         mShowMaxIcon = mContext.getResources().getDrawable(R.drawable.expander_ic_maximized);
         mShowMinIcon = mContext.getResources().getDrawable(R.drawable.expander_ic_minimized);
-    }
-
-    public void setSecurityPermissionsView() {
+        
+        // Set permissions view
         setPermissions(mPermsList);
-    }
-
-    public void setSecurityPermissionsView(Uri pkgURI) {
-        final String archiveFilePath = pkgURI.getPath();
-        PackageParser packageParser = new PackageParser(archiveFilePath);
-        File sourceFile = new File(archiveFilePath);
-        DisplayMetrics metrics = new DisplayMetrics();
-        metrics.setToDefaults();
-        PackageParser.Package pkgInfo = packageParser.parsePackage(sourceFile,
-                archiveFilePath, metrics, 0);
-        mPermsList = generatePermissionsInfo(pkgInfo.requestedPermissions);
-        //For packages that havent been installed we need the application info object
-        //to load the labels and other resources.
-        setPermissions(mPermsList, pkgInfo.applicationInfo);
-    }
-
-    public void setSecurityPermissionsView(PackageInfo pInfo) {
-        mPermsList = generatePermissionsInfo(pInfo.requestedPermissions);
-        setPermissions(mPermsList);
-    }
-
-    public View getPermissionsView() {
         return mPermsView;
     }
 
@@ -164,74 +259,30 @@
      * is null the other non null value is returned without formatting
      * this is to placate initial error checks
      */
-    private String formatPermissions(String groupDesc, String permDesc) {
-        if(groupDesc == null) {
-            return permDesc;
-        }
-        groupDesc = canonicalizeGroupDesc(groupDesc);
-        if(permDesc == null) {
-            return groupDesc;
-        }
-        return String.format(mPermFormat, groupDesc, permDesc);
-    }
-
-    /**
-     * Utility method that concatenates two strings defined by mPermFormat.
-     */
     private String formatPermissions(String groupDesc, CharSequence permDesc) {
+        if(groupDesc == null) {
+            if(permDesc == null) {
+                return null;
+            }
+            return permDesc.toString();
+        }
         groupDesc = canonicalizeGroupDesc(groupDesc);
         if(permDesc == null) {
             return groupDesc;
         }
-        // Format only if str1 and str2 are not null.
-        return formatPermissions(groupDesc, permDesc.toString());
+        // groupDesc and permDesc are non null
+        return String.format(mPermFormat, groupDesc, permDesc.toString());
     }
 
-    private ArrayList<PermissionInfo> generatePermissionsInfo(String[] strList) {
-        ArrayList<PermissionInfo> permInfoList = new ArrayList<PermissionInfo>();
-        if(strList == null) {
-            return permInfoList;
-        }
-        PermissionInfo tmpPermInfo = null;
-        for(int i = 0; i < strList.length; i++) {
-            try {
-                tmpPermInfo = mPm.getPermissionInfo(strList[i], 0);
-                permInfoList.add(tmpPermInfo);
-            } catch (NameNotFoundException e) {
-                Log.i(TAG, "Ignoring unknown permisison:"+strList[i]);
-                continue;
-            }
-        }
-        return permInfoList;
-    }
-
-    private ArrayList<PermissionInfo> generatePermissionsInfo(ArrayList<String> strList) {
-        ArrayList<PermissionInfo> permInfoList = new ArrayList<PermissionInfo>();
-        if(strList != null) {
-            PermissionInfo tmpPermInfo = null;
-            for(String permName:strList) {
-                try {
-                    tmpPermInfo = mPm.getPermissionInfo(permName, 0);
-                    permInfoList.add(tmpPermInfo);
-                } catch (NameNotFoundException e) {
-                    Log.i(TAG, "Ignoring unknown permisison:"+permName);
-                    continue;
-                }
-            }
-        }
-        return permInfoList;
-    }
-
-    private String getGroupLabel(String grpName) {
+    private CharSequence getGroupLabel(String grpName) {
         if (grpName == null) {
             //return default label
             return mDefaultGrpLabel;
         }
-        String cachedLabel = mGroupLabelCache.get(grpName);
+        CharSequence cachedLabel = mGroupLabelCache.get(grpName);
         if (cachedLabel != null) {
             return cachedLabel;
         }
-
         PermissionGroupInfo pgi;
         try {
             pgi = mPm.getPermissionGroupInfo(grpName, 0);
@@ -239,7 +290,7 @@
             Log.i(TAG, "Invalid group name:" + grpName);
             return null;
         }
-        String label = pgi.loadLabel(mPm).toString();
+        CharSequence label = pgi.loadLabel(mPm).toString();
         mGroupLabelCache.put(grpName, label);
         return label;
     }
@@ -249,13 +300,13 @@
      * list of permission descriptions.
      */
     private void displayPermissions(boolean dangerous) {
-        HashMap<String, String> permInfoMap = dangerous ? mDangerousMap : mNormalMap;
+        Map<String, String> permInfoMap = dangerous ? mDangerousMap : mNormalMap;
         LinearLayout permListView = dangerous ? mDangerousList : mNonDangerousList;
         permListView.removeAllViews();
 
         Set<String> permInfoStrSet = permInfoMap.keySet();
         for (String loopPermGrpInfoStr : permInfoStrSet) {
-            String grpLabel = getGroupLabel(loopPermGrpInfoStr);
+            CharSequence grpLabel = getGroupLabel(loopPermGrpInfoStr);
             //guaranteed that grpLabel wont be null since permissions without groups
             //will belong to the default group
             if(localLOGV) Log.i(TAG, "Adding view group:" + grpLabel + ", desc:"
@@ -269,7 +320,7 @@
         mNoPermsView.setVisibility(View.VISIBLE);
     }
 
-    private View getPermissionItemView(String grpName, String permList,
+    private View getPermissionItemView(CharSequence grpName, String permList,
             boolean dangerous) {
         View permView = mInflater.inflate(R.layout.app_permission_item, null);
         Drawable icon = dangerous ? mDangerousIcon : mNormalIcon;
@@ -334,35 +385,105 @@
         }
         return false;
     }
-
-    private void setPermissions(ArrayList<PermissionInfo> permList) {
-        setPermissions(permList, null);    
+    
+    /*
+     * Utility method that aggregates all permission descriptions categorized by group
+     * Say group1 has perm11, perm12, perm13, the group description will be
+     * perm11_Desc, perm12_Desc, perm13_Desc
+     */
+    private void aggregateGroupDescs(
+            Map<String, List<PermissionInfo> > map, Map<String, String> retMap) {
+        if(map == null) {
+            return;
+        }
+        if(retMap == null) {
+           return;
+        }
+        Set<String> grpNames = map.keySet();
+        Iterator<String> grpNamesIter = grpNames.iterator();
+        while(grpNamesIter.hasNext()) {
+            String grpDesc = null;
+            String grpNameKey = grpNamesIter.next();
+            List<PermissionInfo> grpPermsList = map.get(grpNameKey);
+            if(grpPermsList == null) {
+                continue;
+            }
+            for(PermissionInfo permInfo: grpPermsList) {
+                CharSequence permDesc = permInfo.loadLabel(mPm);
+                grpDesc = formatPermissions(grpDesc, permDesc);
+            }
+            // Insert grpDesc into map
+            if(grpDesc != null) {
+                if(localLOGV) Log.i(TAG, "Group:"+grpNameKey+" description:"+grpDesc.toString());
+                retMap.put(grpNameKey, grpDesc.toString());
+            }
+        }
     }
     
-    private void setPermissions(ArrayList<PermissionInfo> permList, ApplicationInfo appInfo) {
-        mDangerousMap = new HashMap<String, String>();
-        mNormalMap = new HashMap<String, String>();
-        mGroupLabelCache = new HashMap<String, String>();
+    private static class PermissionInfoComparator implements Comparator<PermissionInfo> {
+        private PackageManager mPm;
+        private final Collator sCollator = Collator.getInstance();
+        PermissionInfoComparator(PackageManager pm) {
+            mPm = pm;
+        }
+        public final int compare(PermissionInfo a, PermissionInfo b) {
+            CharSequence sa = a.loadLabel(mPm);
+            CharSequence sb = b.loadLabel(mPm);
+            return sCollator.compare(sa, sb);
+        }
+    }
+    
+    private void setPermissions(List<PermissionInfo> permList) {
+        mGroupLabelCache = new HashMap<String, CharSequence>();
         //add the default label so that uncategorized permissions can go here
         mGroupLabelCache.put(mDefaultGrpName, mDefaultGrpLabel);
+        
+        // Map containing group names and a list of permissions under that group
+        // categorized as dangerous
+        mDangerousMap = new HashMap<String, String>();
+        // Map containing group names and a list of permissions under that group
+        // categorized as normal
+        mNormalMap = new HashMap<String, String>();
+        
+        // Additional structures needed to ensure that permissions are unique under 
+        // each group
+        Map<String, List<PermissionInfo>> dangerousMap = 
+            new HashMap<String,  List<PermissionInfo>>();
+        Map<String, List<PermissionInfo> > normalMap = 
+            new HashMap<String,  List<PermissionInfo>>();
+        PermissionInfoComparator permComparator = new PermissionInfoComparator(mPm);
+        
         if (permList != null) {
+            // First pass to group permissions
             for (PermissionInfo pInfo : permList) {
+                if(localLOGV) Log.i(TAG, "Processing permission:"+pInfo.name);
                 if(!isDisplayablePermission(pInfo)) {
+                    if(localLOGV) Log.i(TAG, "Permission:"+pInfo.name+" is not displayable");
                     continue;
                 }
-                String grpName = (pInfo.group == null) ? mDefaultGrpName : pInfo.group;
-                HashMap<String, String> permInfoMap =
+                Map<String, List<PermissionInfo> > permInfoMap =
                     (pInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) ?
-                            mDangerousMap : mNormalMap;
-                // Check to make sure we have a label for the group
-                if (getGroupLabel(grpName) == null) {
-                    continue;
+                            dangerousMap : normalMap;
+                String grpName = (pInfo.group == null) ? mDefaultGrpName : pInfo.group;
+                if(localLOGV) Log.i(TAG, "Permission:"+pInfo.name+" belongs to group:"+grpName);
+                List<PermissionInfo> grpPermsList = permInfoMap.get(grpName);
+                if(grpPermsList == null) {
+                    grpPermsList = new ArrayList<PermissionInfo>();
+                    permInfoMap.put(grpName, grpPermsList);
+                    grpPermsList.add(pInfo);
+                } else {
+                    int idx = Collections.binarySearch(grpPermsList, pInfo, permComparator);
+                    if(localLOGV) Log.i(TAG, "idx="+idx+", list.size="+grpPermsList.size());
+                    if (idx < 0) {
+                        idx = -idx-1;
+                        grpPermsList.add(idx, pInfo);
+                    }
                 }
-                CharSequence permDesc = pInfo.loadLabel(mPm);
-                String grpDesc = permInfoMap.get(grpName);
-                permInfoMap.put(grpName, formatPermissions(grpDesc, permDesc));
-                if(localLOGV) Log.i(TAG, pInfo.name + "    :  " + permDesc+"    :    " + grpName);
             }
+            // Second pass to actually form the descriptions
+            // Look at dangerous permissions first
+            aggregateGroupDescs(dangerousMap, mDangerousMap);
+            aggregateGroupDescs(normalMap, mNormalMap);
         }
 
         mCurrentState = State.NO_PERMS;
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index fe50a01..c65a3ce 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -28,7 +28,7 @@
 
 /**
  * A ListAdapter that manages a ListView backed by an array of arbitrary
- * objects.  By default this class expects that the provided resource id referecnes
+ * objects.  By default this class expects that the provided resource id references
  * a single TextView.  If you want to use a more complex layout, use the constructors that
  * also takes a field id.  That field id should reference a TextView in the larger layout
  * resource.
@@ -179,7 +179,7 @@
     }
 
     /**
-     * Inserts the spcified object at the specified index in the array.
+     * Inserts the specified object at the specified index in the array.
      *
      * @param object The object to insert into the array.
      * @param index The index at which the object must be inserted.
@@ -385,7 +385,7 @@
     }
 
     /**
-     * <p>An array filters constrains the content of the array adapter with
+     * <p>An array filter constrains the content of the array adapter with
      * a prefix. Each item that does not start with the supplied prefix
      * is removed from the list.</p>
      */
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index e1f6fa8..d8fa603 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -23,11 +23,17 @@
 import android.text.Editable;
 import android.text.Selection;
 import android.text.TextUtils;
+import android.text.TextWatcher;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.EditorInfo;
 
 import com.android.internal.R;
 
@@ -55,7 +61,7 @@
  *         super.onCreate(icicle);
  *         setContentView(R.layout.countries);
  *
- *         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+ *         ArrayAdapter&lt;String&gt; adapter = new ArrayAdapter&lt;String&gt;(this,
  *                 android.R.layout.simple_dropdown_item_1line, COUNTRIES);
  *         AutoCompleteTextView textView = (AutoCompleteTextView)
  *                 findViewById(R.id.countries_list);
@@ -74,6 +80,9 @@
  * @attr ref android.R.styleable#AutoCompleteTextView_dropDownSelector
  */
 public class AutoCompleteTextView extends EditText implements Filter.FilterListener {
+    static final boolean DEBUG = false;
+    static final String TAG = "AutoCompleteTextView";
+
     private static final int HINT_VIEW_ID = 0x17;
 
     private CharSequence mHintText;
@@ -85,6 +94,8 @@
 
     private PopupWindow mPopup;
     private DropDownListView mDropDownList;
+    private int mDropDownVerticalOffset;
+    private int mDropDownHorizontalOffset;
 
     private Drawable mDropDownListHighlight;
 
@@ -94,7 +105,12 @@
     private final DropDownItemClickListener mDropDownItemClickListener =
             new DropDownItemClickListener();
 
-    private boolean mTextChanged;
+    private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
+    private boolean mOpenBefore;
+
+    private Validator mValidator = null;
+
+    private AutoCompleteTextView.ListSelectorHider mHideSelector;
 
     public AutoCompleteTextView(Context context) {
         this(context, null);
@@ -107,7 +123,8 @@
     public AutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        mPopup = new PopupWindow(context, attrs, com.android.internal.R.attr.autoCompleteTextViewStyle);
+        mPopup = new PopupWindow(context, attrs,
+                com.android.internal.R.attr.autoCompleteTextViewStyle);
 
         TypedArray a =
             context.obtainStyledAttributes(
@@ -120,13 +137,34 @@
 
         mDropDownListHighlight = a.getDrawable(
                 R.styleable.AutoCompleteTextView_dropDownSelector);
+        mDropDownVerticalOffset = (int)
+                a.getDimension(R.styleable.AutoCompleteTextView_dropDownVerticalOffset, 0.0f);
+        mDropDownHorizontalOffset = (int)
+                a.getDimension(R.styleable.AutoCompleteTextView_dropDownHorizontalOffset, 0.0f);
 
         mHintResource = a.getResourceId(R.styleable.AutoCompleteTextView_completionHintView,
                 R.layout.simple_dropdown_hint);
 
+        // A little trickiness for backwards compatibility: if the app
+        // didn't specify an explicit content type, then we will fill in the
+        // auto complete flag for them.
+        int contentType = a.getInt(
+                R.styleable.AutoCompleteTextView_inputType,
+                EditorInfo.TYPE_NULL);
+        if (contentType == EditorInfo.TYPE_NULL) {
+            contentType = getInputType();
+            if ((contentType&EditorInfo.TYPE_MASK_CLASS)
+                    == EditorInfo.TYPE_CLASS_TEXT) {
+                contentType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE;
+                setRawInputType(contentType);
+            }
+        }
+
         a.recycle();
 
         setFocusable(true);
+
+        addTextChangedListener(new MyWatcher());
     }
 
     /**
@@ -209,7 +247,10 @@
      * in the drop down list.</p>
      *
      * @return the item click listener
+     *
+     * @deprecated Use {@link #getOnItemClickListener()} intead
      */
+    @Deprecated
     public AdapterView.OnItemClickListener getItemClickListener() {
         return mItemClickListener;
     }
@@ -219,12 +260,35 @@
      * item in the drop down list.</p>
      *
      * @return the item selected listener
+     *
+     * @deprecated Use {@link #getOnItemSelectedListener()} intead
      */
+    @Deprecated
     public AdapterView.OnItemSelectedListener getItemSelectedListener() {
         return mItemSelectedListener;
     }
 
     /**
+     * <p>Returns the listener that is notified whenever the user clicks an item
+     * in the drop down list.</p>
+     *
+     * @return the item click listener
+     */
+    public AdapterView.OnItemClickListener getOnItemClickListener() {
+        return mItemClickListener;
+    }
+
+    /**
+     * <p>Returns the listener that is notified whenever the user selects an
+     * item in the drop down list.</p>
+     *
+     * @return the item selected listener
+     */
+    public AdapterView.OnItemSelectedListener getOnItemSelectedListener() {
+        return mItemSelectedListener;
+    }
+
+    /**
      * <p>Returns a filterable list adapter used for auto completion.</p>
      *
      * @return a data adapter used for auto completion
@@ -258,6 +322,19 @@
     }
 
     @Override
+    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+        if (isPopupShowing()) {
+            // special case for the back key, we do not even try to send it
+            // to the drop down list but instead, consume it immediately
+            if (keyCode == KeyEvent.KEYCODE_BACK) {
+                dismissDropDown();
+                return true;
+            }
+        }
+        return super.onKeyPreIme(keyCode, event);
+    }
+
+    @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         if (isPopupShowing()) {
             boolean consumed = mDropDownList.onKeyUp(keyCode, event);
@@ -280,18 +357,41 @@
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         // when the drop down is shown, we drive it directly
         if (isPopupShowing()) {
-            // special case for the back key, we do not even try to send it
-            // to the drop down list but instead, consume it immediately
-            if (keyCode == KeyEvent.KEYCODE_BACK) {
-                dismissDropDown();
-                return true;
-
             // the key events are forwarded to the list in the drop down view
             // note that ListView handles space but we don't want that to happen
-            } else if (keyCode != KeyEvent.KEYCODE_SPACE) {
-                boolean consumed = mDropDownList.onKeyDown(keyCode, event);
-
+            if (keyCode != KeyEvent.KEYCODE_SPACE) {
+                int curIndex = mDropDownList.getSelectedItemPosition();
+                boolean consumed;
+                if (keyCode == KeyEvent.KEYCODE_DPAD_UP && curIndex <= 0) {
+                    // When the selection is at the top, we block the key
+                    // event to prevent focus from moving.
+                    mDropDownList.hideSelector();
+                    mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+                    mPopup.update();
+                    return true;
+                }
+                consumed = mDropDownList.onKeyDown(keyCode, event);
+                if (DEBUG) Log.v(TAG, "Key down: code=" + keyCode + " list consumed="
+                        + consumed);
                 if (consumed) {
+                    // If it handled the key event, then the user is
+                    // navigating in the list, so we should put it in front.
+                    mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+                    // Here's a little trick we need to do to make sure that
+                    // the list view is actually showing its focus indicator,
+                    // by ensuring it has focus and getting its window out
+                    // of touch mode.
+                    mDropDownList.requestFocusFromTouch();
+                    if (false) {
+                        // Update whether the pop-up is in front of or behind
+                        // the input method, depending on whether the user has
+                        // moved down in it.
+                        mPopup.setInputMethodMode(curIndex > 0
+                                ? PopupWindow.INPUT_METHOD_NOT_NEEDED
+                                : PopupWindow.INPUT_METHOD_NEEDED);
+                    }
+                    mPopup.update();
+
                     switch (keyCode) {
                         // avoid passing the focus from the text view to the
                         // next component
@@ -301,22 +401,14 @@
                         case KeyEvent.KEYCODE_DPAD_UP:
                             return true;
                     }
-                } else{
-                    int index = mDropDownList.getSelectedItemPosition();
-                    switch (keyCode) {
-                        case KeyEvent.KEYCODE_DPAD_UP:
-                            if (index == 0) {
-                                return true;
-                            }
-                            break;
+                } else {
+                    if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
                         // when the selection is at the bottom, we block the
                         // event to avoid going to the next focusable widget
-                        case KeyEvent.KEYCODE_DPAD_DOWN:
-                            Adapter adapter = mDropDownList.getAdapter();
-                            if (index == adapter.getCount() - 1) {
-                                return true;
-                            }
-                            break;
+                        Adapter adapter = mDropDownList.getAdapter();
+                        if (curIndex == adapter.getCount() - 1) {
+                            return true;
+                        }
                     }
                 }
             }
@@ -327,37 +419,9 @@
             }
         }
 
-        // when text is changed, inserted or deleted, we attempt to show
-        // the drop down
-        boolean openBefore = isPopupShowing();
-        mTextChanged = false;
-
+        mLastKeyCode = keyCode;
         boolean handled = super.onKeyDown(keyCode, event);
-
-        // if the list was open before the keystroke, but closed afterwards,
-        // then something in the keystroke processing (an input filter perhaps)
-        // called performCompletion() and we shouldn't do any more processing.
-        if (openBefore && !isPopupShowing()) {
-            return handled;
-        }
-
-        if (mTextChanged) { // would have been set in onTextChanged()
-            // the drop down is shown only when a minimum number of characters
-            // was typed in the text view
-            if (enoughToFilter()) {
-                if (mFilter != null) {
-                    performFiltering(getText(), keyCode);
-                }
-            } else {
-                // drop down is automatically dismissed when enough characters
-                // are deleted from the text view
-                dismissDropDown();
-                if (mFilter != null) {
-                    mFilter.filter(null);
-                }
-            }
-            return true;
-        }
+        mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
 
         return handled;
     }
@@ -369,14 +433,58 @@
      * triggered.
      */
     public boolean enoughToFilter() {
+        if (DEBUG) Log.v(TAG, "Enough to filter: len=" + getText().length()
+                + " threshold=" + mThreshold);
         return getText().length() >= mThreshold;
     }
 
-    @Override
-    protected void onTextChanged(CharSequence text, int start, int before,
-                                 int after) {
-        super.onTextChanged(text, start, before, after);
-        mTextChanged = true;
+    /**
+     * This is used to watch for edits to the text view.  Note that we call
+     * to methods on the auto complete text view class so that we can access
+     * private vars without going through thunks.
+     */
+    private class MyWatcher implements TextWatcher {
+        public void afterTextChanged(Editable s) {
+            doAfterTextChanged();
+        }
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            doBeforeTextChanged();
+        }
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+        }
+    }
+
+    void doBeforeTextChanged() {
+        // when text is changed, inserted or deleted, we attempt to show
+        // the drop down
+        mOpenBefore = isPopupShowing();
+        if (DEBUG) Log.v(TAG, "before text changed: open=" + mOpenBefore);
+    }
+
+    void doAfterTextChanged() {
+        // if the list was open before the keystroke, but closed afterwards,
+        // then something in the keystroke processing (an input filter perhaps)
+        // called performCompletion() and we shouldn't do any more processing.
+        if (DEBUG) Log.v(TAG, "after text changed: openBefore=" + mOpenBefore
+                + " open=" + isPopupShowing());
+        if (mOpenBefore && !isPopupShowing()) {
+            return;
+        }
+
+        // the drop down is shown only when a minimum number of characters
+        // was typed in the text view
+        if (enoughToFilter()) {
+            if (mFilter != null) {
+                performFiltering(getText(), mLastKeyCode);
+            }
+        } else {
+            // drop down is automatically dismissed when enough characters
+            // are deleted from the text view
+            dismissDropDown();
+            if (mFilter != null) {
+                mFilter.filter(null);
+            }
+        }
     }
 
     /**
@@ -407,7 +515,8 @@
      * <code>text</code>.</p>
      *
      * @param text the filtering pattern
-     * @param keyCode the last character inserted in the edit box
+     * @param keyCode the last character inserted in the edit box; beware that
+     * this will be null when text is being added through a soft input method.
      */
     @SuppressWarnings({ "UnusedDeclaration" })
     protected void performFiltering(CharSequence text, int keyCode) {
@@ -423,6 +532,19 @@
         performCompletion(null, -1, -1);
     }
 
+    @Override public void onCommitCompletion(CompletionInfo completion) {
+        if (isPopupShowing()) {
+            replaceText(completion.getText());
+            if (mItemClickListener != null) {
+                final DropDownListView list = mDropDownList;
+                // Note that we don't have a View here, so we will need to
+                // supply null.  Hopefully no existing apps crash...
+                mItemClickListener.onItemClick(list, null, completion.getPosition(),
+                        completion.getId());
+            }
+        }
+    }
+
     private void performCompletion(View selectedView, int position, long id) {
         if (isPopupShowing()) {
             Object selectedItem;
@@ -464,7 +586,7 @@
 
     public void onFilterComplete(int count) {
         /*
-         * This checks enoughToFilter() again because filtering requests    
+         * This checks enoughToFilter() again because filtering requests
          * are asynchronous, so the result may come back after enough text
          * has since been deleted to make it no longer appropriate
          * to filter.
@@ -497,22 +619,32 @@
         }
     }
 
+    @Override
+    protected void onDetachedFromWindow() {
+        dismissDropDown();
+        super.onDetachedFromWindow();
+    }
+
     /**
      * <p>Closes the drop down if present on screen.</p>
      */
     public void dismissDropDown() {
-        mPopup.dismiss();
-        if (mDropDownList != null) {
-            // start next time with no selection
-            mDropDownList.hideSelector();
+        InputMethodManager imm = InputMethodManager.peekInstance();
+        if (imm != null) {
+            imm.displayCompletions(this, null);
         }
+        mPopup.dismiss();
+        mPopup.setContentView(null);
+        mDropDownList = null;
     }
 
     @Override
     protected boolean setFrame(int l, int t, int r, int b) {
         boolean result = super.setFrame(l, t, r, b);
 
-        mPopup.update(this, getMeasuredWidth(), -1);
+        if (mPopup.isShowing()) {
+            mPopup.update(this, getMeasuredWidth() - mPaddingLeft - mPaddingRight, -1);
+        }
 
         return result;
     }
@@ -523,11 +655,20 @@
     public void showDropDown() {
         int height = buildDropDown();
         if (mPopup.isShowing()) {
-            mPopup.update(this, getMeasuredWidth() - mPaddingLeft - mPaddingRight, height);
+            mPopup.update(this, mDropDownHorizontalOffset, mDropDownVerticalOffset,
+                    getMeasuredWidth() - mPaddingLeft - mPaddingRight, height);
         } else {
-            mPopup.setHeight(height);
+            mPopup.setWindowLayoutMode(0, ViewGroup.LayoutParams.WRAP_CONTENT);
             mPopup.setWidth(getMeasuredWidth() - mPaddingLeft - mPaddingRight);
-            mPopup.showAsDropDown(this);
+            mPopup.setHeight(height);
+            mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+            mPopup.setOutsideTouchable(true);
+            mPopup.setTouchInterceptor(new PopupTouchIntercepter());
+            mPopup.showAsDropDown(this, mDropDownHorizontalOffset, mDropDownVerticalOffset);
+            mDropDownList.hideSelector();
+            mDropDownList.setSelection(0);
+            mDropDownList.requestFocus();
+            post(mHideSelector);
         }
     }
 
@@ -541,14 +682,34 @@
         ViewGroup dropDownView;
         int otherHeights = 0;
 
+        if (mAdapter != null) {
+            InputMethodManager imm = InputMethodManager.peekInstance();
+            if (imm != null) {
+                int N = mAdapter.getCount();
+                if (N > 20) N = 20;
+                CompletionInfo[] completions = new CompletionInfo[N];
+                for (int i=0; i<N; i++) {
+                    Object item = mAdapter.getItem(i);
+                    long id = mAdapter.getItemId(i);
+                    completions[i] = new CompletionInfo(id, i,
+                            convertSelectionToString(item));
+                }
+                imm.displayCompletions(this, completions);
+            }
+        }
+
         if (mDropDownList == null) {
             Context context = getContext();
 
+            mHideSelector = new ListSelectorHider();
+
             mDropDownList = new DropDownListView(context);
             mDropDownList.setSelector(mDropDownListHighlight);
             mDropDownList.setAdapter(mAdapter);
             mDropDownList.setVerticalFadingEdgeEnabled(true);
             mDropDownList.setOnItemClickListener(mDropDownItemClickListener);
+            mDropDownList.setFocusable(true);
+            mDropDownList.setFocusableInTouchMode(true);
 
             if (mItemSelectedListener != null) {
                 mDropDownList.setOnItemSelectedListener(mItemSelectedListener);
@@ -614,6 +775,73 @@
         }
     }
 
+    /**
+     * Sets the validator used to perform text validation.
+     *
+     * @param validator The validator used to validate the text entered in this widget.
+     *
+     * @see #getValidator()
+     * @see #performValidation()
+     */
+    public void setValidator(Validator validator) {
+        mValidator = validator;
+    }
+
+    /**
+     * Returns the Validator set with {@link #setValidator},
+     * or <code>null</code> if it was not set.
+     *
+     * @see #setValidator(android.widget.AutoCompleteTextView.Validator)
+     * @see #performValidation()
+     */
+    public Validator getValidator() {
+        return mValidator;
+    }
+
+    /**
+     * If a validator was set on this view and the current string is not valid,
+     * ask the validator to fix it.
+     *
+     * @see #getValidator()
+     * @see #setValidator(android.widget.AutoCompleteTextView.Validator)
+     */
+    public void performValidation() {
+        if (mValidator == null) return;
+
+        CharSequence text = getText();
+
+        if (!TextUtils.isEmpty(text) && !mValidator.isValid(text)) {
+            setText(mValidator.fixText(text));
+        }
+    }
+
+    /**
+     * Returns the Filter obtained from {@link Filterable#getFilter},
+     * or <code>null</code> if {@link #setAdapter} was not called with
+     * a Filterable.
+     */
+    protected Filter getFilter() {
+        return mFilter;
+    }
+
+    private class ListSelectorHider implements Runnable {
+        public void run() {
+            if (mDropDownList != null) {
+                mDropDownList.hideSelector();
+            }
+        }
+    }
+
+    private class PopupTouchIntercepter implements OnTouchListener {
+        public boolean onTouch(View v, MotionEvent event) {
+            if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+                mPopup.update();
+            }
+            return false;
+        }
+    }
+    
     private class DropDownItemClickListener implements AdapterView.OnItemClickListener {
         public void onItemClick(AdapterView parent, View v, int position, long id) {
             performCompletion(v, position, id);
@@ -701,6 +929,21 @@
         public boolean hasFocus() {
             return true;
         }
+        
+        protected int[] onCreateDrawableState(int extraSpace) {
+            int[] res = super.onCreateDrawableState(extraSpace);
+            if (false) {
+                StringBuilder sb = new StringBuilder("Created drawable state: [");
+                for (int i=0; i<res.length; i++) {
+                    if (i > 0) sb.append(", ");
+                    sb.append("0x");
+                    sb.append(Integer.toHexString(res[i]));
+                }
+                sb.append("]");
+                Log.i(TAG, sb.toString());
+            }
+            return res;
+        }
     }
 
     /**
@@ -709,54 +952,26 @@
      * this View with an incorrect value in it, all we can do is try to fix it ourselves
      * when this happens.
      */
-    static public interface Validator {
+    public interface Validator {
         /**
-         * @return true if the text currently in the text editor is valid.
+         * Validates the specified text.
+         *
+         * @return true If the text currently in the text editor is valid.
+         *
+         * @see #fixText(CharSequence)
          */
         boolean isValid(CharSequence text);
 
         /**
-         * @param invalidText a string that doesn't pass validation:
-         * isValid(invalidText) returns false
-         * @return a string based on invalidText such as invoking isValid() on it returns true.
+         * Corrects the specified text to make it valid.
+         *
+         * @param invalidText A string that doesn't pass validation: isValid(invalidText)
+         *        returns false
+         *
+         * @return A string based on invalidText such as invoking isValid() on it returns true.
+         *
+         * @see #isValid(CharSequence)
          */
         CharSequence fixText(CharSequence invalidText);
     }
-
-    private Validator mValidator = null;
-    
-    public void setValidator(Validator validator) {
-        mValidator = validator;
-    }
-
-    /**
-     * Returns the Validator set with {@link #setValidator},
-     * or <code>null</code> if it was not set.
-     */
-    public Validator getValidator() {
-        return mValidator;
-    }
-    
-    /**
-     * If a validator was set on this view and the current string is not valid,
-     * ask the validator to fix it. 
-     */
-    public void performValidation() {
-        if (mValidator == null) return;
-
-        CharSequence text = getText();
-        
-        if (!TextUtils.isEmpty(text) && !mValidator.isValid(text)) {
-            setText(mValidator.fixText(text));
-        }
-    }
-
-    /**
-     * Returns the Filter obtained from {@link Filterable#getFilter},
-     * or <code>null</code> if {@link #setAdapter} was not called with
-     * a Filterable.
-     */
-    protected Filter getFilter() {
-        return mFilter;
-    }
 }
diff --git a/core/java/android/widget/BaseExpandableListAdapter.java b/core/java/android/widget/BaseExpandableListAdapter.java
index 3a8bb2a..1bba7f0 100644
--- a/core/java/android/widget/BaseExpandableListAdapter.java
+++ b/core/java/android/widget/BaseExpandableListAdapter.java
@@ -71,7 +71,7 @@
      * <p>
      * Base implementation returns a long:
      * <li> bit 0: Whether this ID points to a child (unset) or group (set), so for this method
-     *             this bit will be 0.
+     *             this bit will be 1.
      * <li> bit 1-31: Lower 31 bits of the groupId
      * <li> bit 32-63: Lower 32 bits of the childId.
      * <p> 
@@ -86,7 +86,7 @@
      * <p>
      * Base implementation returns a long:
      * <li> bit 0: Whether this ID points to a child (unset) or group (set), so for this method
-     *             this bit will be 1.
+     *             this bit will be 0.
      * <li> bit 1-31: Lower 31 bits of the groupId
      * <li> bit 32-63: Lower 32 bits of the childId.
      * <p> 
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index 31d2063..7086ae2 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -22,7 +22,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
-import android.pim.DateUtils;
+import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.widget.RemoteViews.RemoteView;
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index cacaeab..555f216 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -357,9 +357,8 @@
 
         @Override
         public void onChange(boolean selfChange) {
-            if (mAutoRequery && mCursor != null) {
-                if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor +
-                        " due to update");
+            if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {
+                if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor + " due to update");
                 mDataValid = mCursor.requery();
             }
         }
diff --git a/core/java/android/widget/CursorTreeAdapter.java b/core/java/android/widget/CursorTreeAdapter.java
index fa8fd4b..7b9b7bd 100644
--- a/core/java/android/widget/CursorTreeAdapter.java
+++ b/core/java/android/widget/CursorTreeAdapter.java
@@ -450,10 +450,9 @@
         }
         
         void changeCursor(Cursor cursor, boolean releaseCursors) {
-            if (mCursor != null) {
-                mCursor.unregisterContentObserver(mContentObserver);
-                mCursor.unregisterDataSetObserver(mDataSetObserver);
-            }
+            if (cursor == mCursor) return;
+
+            deactivate();
             mCursor = cursor;
             if (cursor != null) {
                 cursor.registerContentObserver(mContentObserver);
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index c03bd32..67010b2 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -21,7 +21,7 @@
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.pim.DateFormat;
+import android.text.format.DateFormat;
 import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.view.LayoutInflater;
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index 3ca2c81..379883a 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -21,8 +21,8 @@
 import android.database.ContentObserver;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.pim.DateFormat;
 import android.provider.Settings;
+import android.text.format.DateFormat;
 import android.util.AttributeSet;
 
 import java.util.Calendar;
@@ -105,13 +105,7 @@
      * Pulls 12/24 mode from system settings
      */
     private boolean get24HourMode() {
-        String value = Settings.System.getString(
-                getContext().getContentResolver(),
-                Settings.System.TIME_12_24);
-
-        if (value == null || value.equals("12"))
-            return false;
-        return true;
+        return android.text.format.DateFormat.is24HourFormat(getContext());
     }
 
     private void setFormat() {
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index e89a2bd..57aca24 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -19,7 +19,6 @@
 import android.text.*;
 import android.text.method.*;
 import android.content.Context;
-import android.content.res.Resources;
 import android.util.AttributeSet;
 
 
@@ -99,4 +98,13 @@
     public void extendSelection(int index) {
         Selection.extendSelection(getText(), index);
     }
+
+    @Override
+    public void setEllipsize(TextUtils.TruncateAt ellipsis) {
+        if (ellipsis == TextUtils.TruncateAt.MARQUEE) {
+            throw new IllegalArgumentException("EditText cannot use the ellipsize mode "
+                    + "TextUtils.TruncateAt.MARQUEE");
+        }
+        super.setEllipsize(ellipsis);
+    }
 }
diff --git a/core/java/android/widget/ExpandableListConnector.java b/core/java/android/widget/ExpandableListConnector.java
index ddedea3..ccce7c1 100644
--- a/core/java/android/widget/ExpandableListConnector.java
+++ b/core/java/android/widget/ExpandableListConnector.java
@@ -19,11 +19,13 @@
 import android.database.DataSetObserver;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.view.KeyEvent;
+import android.os.SystemClock;
 import android.view.View;
 import android.view.ViewGroup;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /*
  * Implementation notes:
@@ -120,7 +122,7 @@
              * either), so flPos must be a group and its group pos will be the
              * same as its flPos
              */
-            return new PositionMetadata(flPos, ExpandableListPosition.GROUP, flPos,
+            return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, flPos,
                     -1, null, 0);
         }
 
@@ -159,7 +161,7 @@
                  * The flat list position is this middle group's flat list
                  * position, so we've found an exact hit
                  */
-                return new PositionMetadata(flPos, ExpandableListPosition.GROUP,
+                return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP,
                         midExpGm.gPos, -1, midExpGm, midExpGroupIndex);
             } else if (flPos <= midExpGm.lastChildFlPos
                     /* && flPos > midGm.flPos as deduced from previous
@@ -172,7 +174,7 @@
                  * the group
                  */
                 final int childPos = flPos - (midExpGm.flPos + 1);
-                return new PositionMetadata(flPos, ExpandableListPosition.CHILD,
+                return PositionMetadata.obtain(flPos, ExpandableListPosition.CHILD,
                         midExpGm.gPos, childPos, midExpGm, midExpGroupIndex);
             } 
         }
@@ -184,11 +186,13 @@
          */
 
 
-        /* If we are to expand this group later, where would it go in the
-         * mExpGroupMetadataList ? */
+        /**
+         * If we are to expand this group later, where would it go in the
+         * mExpGroupMetadataList ?
+         */
         int insertPosition = 0;
         
-        /* What is its group position from the list of all groups? */
+        /** What is its group position in the list of all groups? */
         int groupPos = 0;
         
         /*
@@ -237,7 +241,7 @@
             throw new RuntimeException("Unknown state");
         }
         
-        return new PositionMetadata(flPos, ExpandableListPosition.GROUP, groupPos, -1,
+        return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, groupPos, -1,
                 null, insertPosition);
     }
 
@@ -250,7 +254,7 @@
      * @param pos a {@link ExpandableListPosition} representing either a group position
      *        or child position
      * @return the flat list position encompassed in a {@link PositionMetadata}
-     *         object that contains additional useful info for insertion, etc.
+     *         object that contains additional useful info for insertion, etc., or null.
      */
     PositionMetadata getFlattenedPos(final ExpandableListPosition pos) {
         final ArrayList<GroupMetadata> egml = mExpGroupMetadataList;
@@ -268,7 +272,7 @@
              * its flPos will be the same as its group pos.  The
              * insert position is 0 (since the list is empty).
              */
-            return new PositionMetadata(pos.groupPos, pos.type,
+            return PositionMetadata.obtain(pos.groupPos, pos.type,
                     pos.groupPos, pos.childPos, null, 0);
         }
 
@@ -298,11 +302,11 @@
                 
                 if (pos.type == ExpandableListPosition.GROUP) {
                     /* If it's a group, give them this matched group's flPos */
-                    return new PositionMetadata(midExpGm.flPos, pos.type,
+                    return PositionMetadata.obtain(midExpGm.flPos, pos.type,
                             pos.groupPos, pos.childPos, midExpGm, midExpGroupIndex);
                 } else if (pos.type == ExpandableListPosition.CHILD) {
                     /* If it's a child, calculate the flat list pos */
-                    return new PositionMetadata(midExpGm.flPos + pos.childPos
+                    return PositionMetadata.obtain(midExpGm.flPos + pos.childPos
                             + 1, pos.type, pos.groupPos, pos.childPos,
                             midExpGm, midExpGroupIndex);
                 } else {
@@ -341,7 +345,7 @@
                     leftExpGm.lastChildFlPos
                             + (pos.groupPos - leftExpGm.gPos);
 
-            return new PositionMetadata(flPos, pos.type, pos.groupPos,
+            return PositionMetadata.obtain(flPos, pos.type, pos.groupPos,
                     pos.childPos, null, leftExpGroupIndex);
         } else if (rightExpGroupIndex < midExpGroupIndex) {
 
@@ -355,7 +359,7 @@
             final int flPos =
                     rightExpGm.flPos
                             - (rightExpGm.gPos - pos.groupPos);
-            return new PositionMetadata(flPos, pos.type, pos.groupPos,
+            return PositionMetadata.obtain(flPos, pos.type, pos.groupPos,
                     pos.childPos, null, rightExpGroupIndex);
         } else {
             return null;
@@ -370,13 +374,18 @@
     @Override
     public boolean isEnabled(int flatListPos) {
         final ExpandableListPosition pos = getUnflattenedPos(flatListPos).position;
-
+        
+        boolean retValue;
         if (pos.type == ExpandableListPosition.CHILD) {
-            return mExpandableListAdapter.isChildSelectable(pos.groupPos, pos.childPos);
+            retValue = mExpandableListAdapter.isChildSelectable(pos.groupPos, pos.childPos);
         } else {
             // Groups are always selectable
-            return true;
+            retValue = true;
         }
+        
+        pos.recycle();
+        
+        return retValue;
     }
 
     public int getCount() {
@@ -391,62 +400,80 @@
     public Object getItem(int flatListPos) {
         final PositionMetadata posMetadata = getUnflattenedPos(flatListPos);
 
+        Object retValue;
         if (posMetadata.position.type == ExpandableListPosition.GROUP) {
-            return mExpandableListAdapter
+            retValue = mExpandableListAdapter
                     .getGroup(posMetadata.position.groupPos);
         } else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
-            return mExpandableListAdapter.getChild(posMetadata.position.groupPos,
+            retValue = mExpandableListAdapter.getChild(posMetadata.position.groupPos,
                     posMetadata.position.childPos);
         } else {
             // TODO: clean exit
             throw new RuntimeException("Flat list position is of unknown type");
         }
+        
+        posMetadata.recycle();
+        
+        return retValue;
     }
 
     public long getItemId(int flatListPos) {
         final PositionMetadata posMetadata = getUnflattenedPos(flatListPos);
         final long groupId = mExpandableListAdapter.getGroupId(posMetadata.position.groupPos);
         
+        long retValue;
         if (posMetadata.position.type == ExpandableListPosition.GROUP) {
-            return mExpandableListAdapter.getCombinedGroupId(groupId);
+            retValue = mExpandableListAdapter.getCombinedGroupId(groupId);
         } else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
             final long childId = mExpandableListAdapter.getChildId(posMetadata.position.groupPos,
                     posMetadata.position.childPos);
-            return mExpandableListAdapter.getCombinedChildId(groupId, childId);
+            retValue = mExpandableListAdapter.getCombinedChildId(groupId, childId);
         } else {
             // TODO: clean exit
             throw new RuntimeException("Flat list position is of unknown type");
         }
+        
+        posMetadata.recycle();
+        
+        return retValue;
     }
 
     public View getView(int flatListPos, View convertView, ViewGroup parent) {
         final PositionMetadata posMetadata = getUnflattenedPos(flatListPos);
 
+        View retValue;
         if (posMetadata.position.type == ExpandableListPosition.GROUP) {
-            return mExpandableListAdapter.getGroupView(posMetadata.position.groupPos, posMetadata
+            retValue = mExpandableListAdapter.getGroupView(posMetadata.position.groupPos, posMetadata
                     .isExpanded(), convertView, parent);
         } else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
             final boolean isLastChild = posMetadata.groupMetadata.lastChildFlPos == flatListPos;
             
-            final View view = mExpandableListAdapter.getChildView(posMetadata.position.groupPos,
+            retValue = mExpandableListAdapter.getChildView(posMetadata.position.groupPos,
                     posMetadata.position.childPos, isLastChild, convertView, parent);
-            
-            return view;
         } else {
             // TODO: clean exit
             throw new RuntimeException("Flat list position is of unknown type");
         }
+        
+        posMetadata.recycle();
+        
+        return retValue;
     }
 
     @Override
     public int getItemViewType(int flatListPos) {
         final ExpandableListPosition pos = getUnflattenedPos(flatListPos).position;
 
+        int retValue;
         if (pos.type == ExpandableListPosition.GROUP) {
-            return 0;
+            retValue = 0;
         } else {
-            return 1;
+            retValue = 1;
         }
+        
+        pos.recycle();
+        
+        return retValue;
     }
 
     @Override
@@ -464,22 +491,51 @@
      * positions.
      * 
      * @param forceChildrenCountRefresh Forces refreshing of the children count
-     *            for all expanded groups.
+     *        for all expanded groups.
+     * @param syncGroupPositions Whether to search for the group positions
+     *         based on the group IDs. This should only be needed when calling
+     *         this from an onChanged callback.
      */
-    private void refreshExpGroupMetadataList(boolean forceChildrenCountRefresh) {
+    @SuppressWarnings("unchecked")
+    private void refreshExpGroupMetadataList(boolean forceChildrenCountRefresh,
+            boolean syncGroupPositions) {
         final ArrayList<GroupMetadata> egml = mExpGroupMetadataList;
-        final int egmlSize = egml.size();
+        int egmlSize = egml.size();
         int curFlPos = 0;
         
         /* Update child count as we go through */
         mTotalExpChildrenCount = 0;
         
-        GroupMetadata curGm;
+        if (syncGroupPositions) {
+            // We need to check whether any groups have moved positions
+            boolean positionsChanged = false;
+            
+            for (int i = egmlSize - 1; i >= 0; i--) {
+                GroupMetadata curGm = egml.get(i);
+                int newGPos = findGroupPosition(curGm.gId, curGm.gPos);
+                if (newGPos != curGm.gPos) {
+                    if (newGPos == AdapterView.INVALID_POSITION) {
+                        // Doh, just remove it from the list of expanded groups
+                        egml.remove(i);
+                        egmlSize--;
+                    }
+                    
+                    curGm.gPos = newGPos;
+                    if (!positionsChanged) positionsChanged = true;
+                }
+            }
+            
+            if (positionsChanged) {
+                // At least one group changed positions, so re-sort
+                Collections.sort(egml);
+            }
+        }
+        
         int gChildrenCount;
         int lastGPos = 0;
         for (int i = 0; i < egmlSize; i++) {
             /* Store in local variable since we'll access freq */
-            curGm = egml.get(i);
+            GroupMetadata curGm = egml.get(i);
             
             /*
              * Get the number of children, try to refrain from calling
@@ -518,8 +574,13 @@
      * @param groupPos position of the group to collapse
      */
     boolean collapseGroup(int groupPos) {
-        return collapseGroup(getFlattenedPos(new ExpandableListPosition(ExpandableListPosition.GROUP,
-                groupPos, -1, -1)));
+        PositionMetadata pm = getFlattenedPos(ExpandableListPosition.obtain(
+                ExpandableListPosition.GROUP, groupPos, -1, -1)); 
+        if (pm == null) return false;
+        
+        boolean retValue = collapseGroup(pm);
+        pm.recycle();
+        return retValue;
     }
     
     boolean collapseGroup(PositionMetadata posMetadata) {
@@ -538,7 +599,7 @@
         mExpGroupMetadataList.remove(posMetadata.groupMetadata);
 
         // Refresh the metadata
-        refreshExpGroupMetadataList(false);
+        refreshExpGroupMetadataList(false, false);
         
         // Notify of change
         notifyDataSetChanged();
@@ -554,8 +615,11 @@
      * @param groupPos the group to be expanded
      */
     boolean expandGroup(int groupPos) {
-        return expandGroup(getFlattenedPos(new ExpandableListPosition(ExpandableListPosition.GROUP, 
-                groupPos, -1, -1)));
+        PositionMetadata pm = getFlattenedPos(ExpandableListPosition.obtain(
+                ExpandableListPosition.GROUP, groupPos, -1, -1));
+        boolean retValue = expandGroup(pm);
+        pm.recycle();
+        return retValue;
     }
 
     boolean expandGroup(PositionMetadata posMetadata) {
@@ -590,16 +654,16 @@
             }
         }
         
-        GroupMetadata expandedGm = new GroupMetadata();
-        
-        expandedGm.gPos = posMetadata.position.groupPos;
-        expandedGm.flPos = GroupMetadata.REFRESH;
-        expandedGm.lastChildFlPos = GroupMetadata.REFRESH;
+        GroupMetadata expandedGm = GroupMetadata.obtain(
+                GroupMetadata.REFRESH,
+                GroupMetadata.REFRESH,
+                posMetadata.position.groupPos,
+                mExpandableListAdapter.getGroupId(posMetadata.position.groupPos));
         
         mExpGroupMetadataList.add(posMetadata.groupInsertIndex, expandedGm);
 
         // Refresh the metadata
-        refreshExpGroupMetadataList(false);
+        refreshExpGroupMetadataList(false, false);
         
         // Notify of change
         notifyDataSetChanged();
@@ -669,7 +733,7 @@
         }
         
         mExpGroupMetadataList = expandedGroupMetadataList;
-        refreshExpGroupMetadataList(true);
+        refreshExpGroupMetadataList(true, false);
     }
     
     @Override
@@ -678,17 +742,104 @@
         return adapter != null ? adapter.isEmpty() : true;
     }
 
+    /**
+     * Searches the expandable list adapter for a group position matching the
+     * given group ID. The search starts at the given seed position and then
+     * alternates between moving up and moving down until 1) we find the right
+     * position, or 2) we run out of time, or 3) we have looked at every
+     * position
+     * 
+     * @return Position of the row that matches the given row ID, or
+     *         {@link AdapterView#INVALID_POSITION} if it can't be found
+     * @see AdapterView#findSyncPosition()
+     */
+    int findGroupPosition(long groupIdToMatch, int seedGroupPosition) {
+        int count = mExpandableListAdapter.getGroupCount();
+
+        if (count == 0) {
+            return AdapterView.INVALID_POSITION;
+        }
+
+        // If there isn't a selection don't hunt for it
+        if (groupIdToMatch == AdapterView.INVALID_ROW_ID) {
+            return AdapterView.INVALID_POSITION;
+        }
+
+        // Pin seed to reasonable values
+        seedGroupPosition = Math.max(0, seedGroupPosition);
+        seedGroupPosition = Math.min(count - 1, seedGroupPosition);
+
+        long endTime = SystemClock.uptimeMillis() + AdapterView.SYNC_MAX_DURATION_MILLIS;
+
+        long rowId;
+
+        // first position scanned so far
+        int first = seedGroupPosition;
+
+        // last position scanned so far
+        int last = seedGroupPosition;
+
+        // True if we should move down on the next iteration
+        boolean next = false;
+
+        // True when we have looked at the first item in the data
+        boolean hitFirst;
+
+        // True when we have looked at the last item in the data
+        boolean hitLast;
+
+        // Get the item ID locally (instead of getItemIdAtPosition), so
+        // we need the adapter
+        ExpandableListAdapter adapter = getAdapter();
+        if (adapter == null) {
+            return AdapterView.INVALID_POSITION;
+        }
+
+        while (SystemClock.uptimeMillis() <= endTime) {
+            rowId = adapter.getGroupId(seedGroupPosition);
+            if (rowId == groupIdToMatch) {
+                // Found it!
+                return seedGroupPosition;
+            }
+
+            hitLast = last == count - 1;
+            hitFirst = first == 0;
+
+            if (hitLast && hitFirst) {
+                // Looked at everything
+                break;
+            }
+
+            if (hitFirst || (next && !hitLast)) {
+                // Either we hit the top, or we are trying to move down
+                last++;
+                seedGroupPosition = last;
+                // Try going up next time
+                next = false;
+            } else if (hitLast || (!next && !hitFirst)) {
+                // Either we hit the bottom, or we are trying to move up
+                first--;
+                seedGroupPosition = first;
+                // Try going down next time
+                next = true;
+            }
+
+        }
+
+        return AdapterView.INVALID_POSITION;
+    }
+
     protected class MyDataSetObserver extends DataSetObserver {
         @Override
         public void onChanged() {
-            refreshExpGroupMetadataList(true);
+            refreshExpGroupMetadataList(true, true);
             
             notifyDataSetChanged();
         }
 
         @Override
         public void onInvalidated() {
-            refreshExpGroupMetadataList(true);
+            refreshExpGroupMetadataList(true, true);
             
             notifyDataSetInvalidated();
         }
@@ -699,7 +850,7 @@
      * position to either a) group position for groups, or b) child position for
      * children
      */
-    static class GroupMetadata implements Parcelable {
+    static class GroupMetadata implements Parcelable, Comparable {
         final static int REFRESH = -1;
         
         /** This group's flat list position */
@@ -717,6 +868,31 @@
          * This group's group position
          */
         int gPos;
+        
+        /**
+         * This group's id
+         */
+        long gId;
+        
+        private GroupMetadata() {
+        }
+
+        static GroupMetadata obtain(int flPos, int lastChildFlPos, int gPos, long gId) {
+            GroupMetadata gm = new GroupMetadata();
+            gm.flPos = flPos;
+            gm.lastChildFlPos = lastChildFlPos;
+            gm.gPos = gPos;
+            gm.gId = gId;
+            return gm;
+        }
+        
+        public int compareTo(Object another) {
+            if (another == null || !(another instanceof GroupMetadata)) {
+                throw new ClassCastException();
+            }
+            
+            return gPos - ((GroupMetadata) another).gPos;
+        }
 
         public int describeContents() {
             return 0;
@@ -726,16 +902,18 @@
             dest.writeInt(flPos);
             dest.writeInt(lastChildFlPos);
             dest.writeInt(gPos);
+            dest.writeLong(gId);
         }
         
         public static final Parcelable.Creator<GroupMetadata> CREATOR =
                 new Parcelable.Creator<GroupMetadata>() {
             
             public GroupMetadata createFromParcel(Parcel in) {
-                GroupMetadata gm = new GroupMetadata();
-                gm.flPos = in.readInt();
-                gm.lastChildFlPos = in.readInt();
-                gm.gPos = in.readInt();
+                GroupMetadata gm = GroupMetadata.obtain(
+                        in.readInt(),
+                        in.readInt(),
+                        in.readInt(),
+                        in.readLong());
                 return gm;
             }
     
@@ -752,6 +930,11 @@
      * where to insert into the flat list, etc.)
      */
     static public class PositionMetadata {
+        
+        private static final int MAX_POOL_SIZE = 5;
+        private static ArrayList<PositionMetadata> sPool =
+                new ArrayList<PositionMetadata>(MAX_POOL_SIZE);
+        
         /** Data type to hold the position and its type (child/group) */
         public ExpandableListPosition position;
         
@@ -771,17 +954,46 @@
          */
         public int groupInsertIndex;
         
-        public PositionMetadata(int flatListPos, int type, int groupPos,
-                int childPos) {
-            position = new ExpandableListPosition(type, groupPos, childPos, flatListPos);
+        private void resetState() {
+            position = null;
+            groupMetadata = null;
+            groupInsertIndex = 0;
         }
         
-        protected PositionMetadata(int flatListPos, int type, int groupPos,
+        /**
+         * Use {@link #obtain(int, int, int, int, GroupMetadata, int)}
+         */
+        private PositionMetadata() {
+        }
+        
+        static PositionMetadata obtain(int flatListPos, int type, int groupPos,
                 int childPos, GroupMetadata groupMetadata, int groupInsertIndex) {
-            position = new ExpandableListPosition(type, groupPos, childPos, flatListPos);
-            
-            this.groupMetadata = groupMetadata;
-            this.groupInsertIndex = groupInsertIndex;
+            PositionMetadata pm = getRecycledOrCreate();
+            pm.position = ExpandableListPosition.obtain(type, groupPos, childPos, flatListPos);
+            pm.groupMetadata = groupMetadata;
+            pm.groupInsertIndex = groupInsertIndex;
+            return pm;
+        }
+        
+        private static PositionMetadata getRecycledOrCreate() {
+            PositionMetadata pm;
+            synchronized (sPool) {
+                if (sPool.size() > 0) {
+                    pm = sPool.remove(0);
+                } else {
+                    return new PositionMetadata();
+                }
+            }
+            pm.resetState();
+            return pm;
+        }
+        
+        public void recycle() {
+            synchronized (sPool) {
+                if (sPool.size() < MAX_POOL_SIZE) {
+                    sPool.add(this);
+                }
+            }
         }
         
         /**
diff --git a/core/java/android/widget/ExpandableListPosition.java b/core/java/android/widget/ExpandableListPosition.java
index 71e970c..e8d6113 100644
--- a/core/java/android/widget/ExpandableListPosition.java
+++ b/core/java/android/widget/ExpandableListPosition.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import java.util.ArrayList;
+
 /**
  * ExpandableListPosition can refer to either a group's position or a child's
  * position. Referring to a child's position requires both a group position (the
@@ -24,6 +26,11 @@
  * {@link #obtainGroupPosition(int)}.
  */
 class ExpandableListPosition {
+    
+    private static final int MAX_POOL_SIZE = 5;
+    private static ArrayList<ExpandableListPosition> sPool =
+        new ArrayList<ExpandableListPosition>(MAX_POOL_SIZE);
+    
     /**
      * This data type represents a child position
      */
@@ -56,21 +63,14 @@
      */
     public int type;
     
-    ExpandableListPosition(int type, int groupPos, int childPos, int flatListPos) {
-        this.type = type;
-        this.flatListPos = flatListPos;
-        this.groupPos = groupPos;
-        this.childPos = childPos;
+    private void resetState() {
+        groupPos = 0;
+        childPos = 0;
+        flatListPos = 0;
+        type = 0;
     }
-
-    /**
-     * Used internally by the {@link #obtainChildPosition} and
-     * {@link #obtainGroupPosition} methods to construct a new object.
-     */
-    private ExpandableListPosition(int type, int groupPos, int childPos) {
-        this.type = type;
-        this.groupPos = groupPos;
-        this.childPos = childPos;
+    
+    private ExpandableListPosition() {
     }
     
     long getPackedPosition() {
@@ -79,11 +79,11 @@
     }
 
     static ExpandableListPosition obtainGroupPosition(int groupPosition) {
-        return new ExpandableListPosition(GROUP, groupPosition, 0);
+        return obtain(GROUP, groupPosition, 0, 0);
     }
     
     static ExpandableListPosition obtainChildPosition(int groupPosition, int childPosition) {
-        return new ExpandableListPosition(CHILD, groupPosition, childPosition);
+        return obtain(CHILD, groupPosition, childPosition, 0);
     }
 
     static ExpandableListPosition obtainPosition(long packedPosition) {
@@ -91,12 +91,45 @@
             return null;
         }
         
-        final int type = ExpandableListView.getPackedPositionType(packedPosition) ==
-            ExpandableListView.PACKED_POSITION_TYPE_CHILD ? CHILD : GROUP;
-        
-        return new ExpandableListPosition(type, ExpandableListView
-                .getPackedPositionGroup(packedPosition), ExpandableListView
-                .getPackedPositionChild(packedPosition));
+        ExpandableListPosition elp = getRecycledOrCreate(); 
+        elp.groupPos = ExpandableListView.getPackedPositionGroup(packedPosition);
+        if (ExpandableListView.getPackedPositionType(packedPosition) ==
+                ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
+            elp.type = CHILD;
+            elp.childPos = ExpandableListView.getPackedPositionChild(packedPosition);
+        } else {
+            elp.type = GROUP;
+        }
+        return elp;
     }
     
+    static ExpandableListPosition obtain(int type, int groupPos, int childPos, int flatListPos) {
+        ExpandableListPosition elp = getRecycledOrCreate(); 
+        elp.type = type;
+        elp.groupPos = groupPos;
+        elp.childPos = childPos;
+        elp.flatListPos = flatListPos;
+        return elp;
+    }
+    
+    private static ExpandableListPosition getRecycledOrCreate() {
+        ExpandableListPosition elp;
+        synchronized (sPool) {
+            if (sPool.size() > 0) {
+                elp = sPool.remove(0);
+            } else {
+                return new ExpandableListPosition();
+            }
+        }
+        elp.resetState();
+        return elp;
+    }
+    
+    public void recycle() {
+        synchronized (sPool) {
+            if (sPool.size() < MAX_POOL_SIZE) {
+                sPool.add(this);
+            }
+        }
+    }
 }
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 138cace..3de561a 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -25,6 +25,7 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
@@ -184,7 +185,8 @@
     
     /** Drawable to be used as a divider when it is adjacent to any children */
     private Drawable mChildDivider;
-    
+    private boolean mClipChildDivider;
+
     public ExpandableListView(Context context) {
         this(context, null);
     }
@@ -245,7 +247,7 @@
 
         final int myB = mBottom; 
         
-        PositionMetadata pos;
+        PositionMetadata pos = null;
         View item;
         Drawable indicator; 
         int t, b;
@@ -297,28 +299,27 @@
                 lastItemType = pos.position.type; 
             }
 
-            if (indicatorRect.left == indicatorRect.right) {
-                // The left and right bounds are the same, so nothing will be drawn
-                continue;
-            }
-
-            // Use item's full height + the divider height
-            if (mStackFromBottom) {
-                // See ListView#dispatchDraw
-                indicatorRect.top = t - mDividerHeight;
-                indicatorRect.bottom = b;
-            } else {
-                indicatorRect.top = t;
-                indicatorRect.bottom = b + mDividerHeight;
+            if (indicatorRect.left != indicatorRect.right) {
+                // Use item's full height + the divider height
+                if (mStackFromBottom) {
+                    // See ListView#dispatchDraw
+                    indicatorRect.top = t - mDividerHeight;
+                    indicatorRect.bottom = b;
+                } else {
+                    indicatorRect.top = t;
+                    indicatorRect.bottom = b + mDividerHeight;
+                }
+                
+                // Get the indicator (with its state set to the item's state)
+                indicator = getIndicator(pos);
+                if (indicator != null) {
+                    // Draw the indicator
+                    indicator.setBounds(indicatorRect);
+                    indicator.draw(canvas);
+                }
             }
             
-            // Get the indicator (with its state set to the item's state)
-            indicator = getIndicator(pos);
-            if (indicator == null) continue;
-            
-            // Draw the indicator
-            indicator.setBounds(indicatorRect);
-            indicator.draw(canvas);
+            pos.recycle();
         }
 
         if (clipToPadding) {
@@ -376,6 +377,7 @@
      */
     public void setChildDivider(Drawable childDivider) {
         mChildDivider = childDivider;
+        mClipChildDivider = childDivider != null && childDivider instanceof ColorDrawable;
     }
 
     @Override
@@ -387,14 +389,25 @@
         if (flatListPosition >= 0) {
             PositionMetadata pos = mConnector.getUnflattenedPos(flatListPosition);
             // If this item is a child, or it is a non-empty group that is expanded
-            if ((pos.position.type == ExpandableListPosition.CHILD)
-                    || (pos.isExpanded() &&
-                            pos.groupMetadata.lastChildFlPos != pos.groupMetadata.flPos)) {
+            if ((pos.position.type == ExpandableListPosition.CHILD) || (pos.isExpanded() &&
+                    pos.groupMetadata.lastChildFlPos != pos.groupMetadata.flPos)) {
                 // These are the cases where we draw the child divider
-                mChildDivider.setBounds(bounds);
-                mChildDivider.draw(canvas);
+                final Drawable divider = mChildDivider;
+                final boolean clip = mClipChildDivider;
+                if (!clip) {
+                    divider.setBounds(bounds);
+                } else {
+                    canvas.save();
+                    canvas.clipRect(bounds);
+                }
+                divider.draw(canvas);
+                if (clip) {
+                    canvas.restore();
+                }
+                pos.recycle();
                 return;
             }
+            pos.recycle();
         }
         
         // Otherwise draw the default divider
@@ -495,6 +508,7 @@
         
         id = getChildOrGroupId(posMetadata.position);
         
+        boolean returnValue;
         if (posMetadata.position.type == ExpandableListPosition.GROUP) {
             /* It's a group, so handle collapsing/expanding */
             
@@ -513,6 +527,7 @@
                 if (mOnGroupClickListener != null) {
                     if (mOnGroupClickListener.onGroupClick(this, v,
                             posMetadata.position.groupPos, id)) {
+                        posMetadata.recycle();
                         return true;
                     }
                 }
@@ -527,7 +542,7 @@
                 }
             }
             
-            return true;
+            returnValue = true;
         } else {
             /* It's a child, so pass on event */
             if (mOnChildClickListener != null) {
@@ -536,8 +551,12 @@
                         posMetadata.position.childPos, id);
             }
             
-            return false;
+            returnValue = false;
         }
+        
+        posMetadata.recycle();
+        
+        return returnValue;
     }
 
     /**
@@ -676,7 +695,10 @@
      *         in packed position representation.
      */
     public long getExpandableListPosition(int flatListPosition) {
-        return mConnector.getUnflattenedPos(flatListPosition).position.getPackedPosition();
+        PositionMetadata pm = mConnector.getUnflattenedPos(flatListPosition);
+        long packedPos = pm.position.getPackedPosition();
+        pm.recycle();
+        return packedPos;
     }
     
     /**
@@ -691,8 +713,11 @@
      * @return The flat list position for the given child or group.
      */
     public int getFlatListPosition(long packedPosition) {
-        return mConnector.getFlattenedPos(ExpandableListPosition.obtainPosition(packedPosition)).
-            position.flatListPos;
+        PositionMetadata pm = mConnector.getFlattenedPos(ExpandableListPosition
+                .obtainPosition(packedPosition));
+        int retValue = pm.position.flatListPos;
+        pm.recycle();
+        return retValue;
     }
 
     /**
@@ -737,8 +762,11 @@
      */
     public void setSelectedGroup(int groupPosition) {
         ExpandableListPosition elGroupPos = ExpandableListPosition
-                .obtainGroupPosition(groupPosition); 
-        super.setSelection(mConnector.getFlattenedPos(elGroupPos).position.flatListPos);
+                .obtainGroupPosition(groupPosition);
+        PositionMetadata pm = mConnector.getFlattenedPos(elGroupPos);
+        elGroupPos.recycle();
+        super.setSelection(pm.position.flatListPos);
+        pm.recycle();
     }
     
     /**
@@ -775,6 +803,9 @@
         
         super.setSelection(flatChildPos.position.flatListPos);
         
+        elChildPos.recycle();
+        flatChildPos.recycle();
+        
         return true;
     }
 
@@ -883,11 +914,15 @@
 
     @Override
     ContextMenuInfo createContextMenuInfo(View view, int flatListPosition, long id) {
-        ExpandableListPosition pos = mConnector.getUnflattenedPos(flatListPosition).position;
+        PositionMetadata pm = mConnector.getUnflattenedPos(flatListPosition);
+        ExpandableListPosition pos = pm.position;
+        pm.recycle();
         
         id = getChildOrGroupId(pos);
+        long packedPosition = pos.getPackedPosition();
+        pos.recycle();
         
-        return new ExpandableListContextMenuInfo(view, pos.getPackedPosition(), id);
+        return new ExpandableListContextMenuInfo(view, packedPosition, id);
     }
 
     /**
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
new file mode 100644
index 0000000..bdcfeef
--- /dev/null
+++ b/core/java/android/widget/FastScroller.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+
+/**
+ * Helper class for AbsListView to draw and control the Fast Scroll thumb
+ */
+class FastScroller {
+   
+    
+    // Scroll thumb not showing
+    private static final int STATE_NONE = 0;
+    // Not implemented yet - fade-in transition
+    private static final int STATE_ENTER = 1;
+    // Scroll thumb visible and moving along with the scrollbar
+    private static final int STATE_VISIBLE = 2;
+    // Scroll thumb being dragged by user
+    private static final int STATE_DRAGGING = 3;
+    // Scroll thumb fading out due to inactivity timeout
+    private static final int STATE_EXIT = 4;
+    
+    private Drawable mThumbDrawable;
+    private Drawable mOverlayDrawable;
+
+    private int mThumbH;
+    private int mThumbW;
+    private int mThumbY;
+
+    private RectF mOverlayPos;
+    private int mOverlaySize = 104;
+
+    private AbsListView mList;
+    private boolean mScrollCompleted;
+    private int mVisibleItem;
+    private Paint mPaint;
+    private int mListOffset;
+    
+    private Object [] mSections;
+    private String mSectionText;
+    private boolean mDrawOverlay;
+    private ScrollFade mScrollFade;
+    
+    private int mState;
+    
+    private Handler mHandler = new Handler();
+    
+    private BaseAdapter mListAdapter;
+    private SectionIndexer mSectionIndexer;
+
+    private boolean mChangedBounds;
+    
+    public FastScroller(Context context, AbsListView listView) {
+        mList = listView;
+        init(context);
+    }
+
+    public void setState(int state) {
+        switch (state) {
+            case STATE_NONE:
+                mHandler.removeCallbacks(mScrollFade);
+                mList.invalidate();
+                break;
+            case STATE_VISIBLE:
+                if (mState != STATE_VISIBLE) { // Optimization
+                    resetThumbPos();
+                }
+                // Fall through
+            case STATE_DRAGGING:
+                mHandler.removeCallbacks(mScrollFade);
+                break;
+            case STATE_EXIT:
+                int viewWidth = mList.getWidth();
+                mList.invalidate(viewWidth - mThumbW, mThumbY, viewWidth, mThumbY + mThumbH);
+                break;
+        }
+        mState = state;
+    }
+    
+    public int getState() {
+        return mState;
+    }
+    
+    private void resetThumbPos() {
+        final int viewWidth = mList.getWidth();
+        // Bounds are always top right. Y coordinate get's translated during draw
+        mThumbDrawable.setBounds(viewWidth - mThumbW, 0, viewWidth, mThumbH);
+        mThumbDrawable.setAlpha(ScrollFade.ALPHA_MAX);
+    }
+    
+    private void useThumbDrawable(Drawable drawable) {
+        mThumbDrawable = drawable;
+        mThumbW = 64; //mCurrentThumb.getIntrinsicWidth();
+        mThumbH = 52; //mCurrentThumb.getIntrinsicHeight();
+        mChangedBounds = true;
+    }
+
+    private void init(Context context) {
+        // Get both the scrollbar states drawables
+        final Resources res = context.getResources();
+        useThumbDrawable(res.getDrawable(
+                com.android.internal.R.drawable.scrollbar_handle_accelerated_anim2));
+        
+        mOverlayDrawable = res.getDrawable(
+                com.android.internal.R.drawable.menu_submenu_background);
+        
+        mScrollCompleted = true;
+
+        getSections();
+        
+        mOverlayPos = new RectF();
+        mScrollFade = new ScrollFade();
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setTextAlign(Paint.Align.CENTER);
+        mPaint.setTextSize(mOverlaySize / 2);
+        TypedArray ta = context.getTheme().obtainStyledAttributes(new int[] { 
+                android.R.attr.textColorPrimary });
+        ColorStateList textColor = ta.getColorStateList(ta.getIndex(0));
+        int textColorNormal = textColor.getDefaultColor();
+        mPaint.setColor(textColorNormal);
+        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+        
+        mState = STATE_NONE;
+    }
+    
+    void stop() {
+        setState(STATE_NONE);
+    }
+    
+    public void draw(Canvas canvas) {
+        
+        if (mState == STATE_NONE) {
+            // No need to draw anything
+            return;
+        }
+
+        final int y = mThumbY;
+        final int viewWidth = mList.getWidth();
+        final FastScroller.ScrollFade scrollFade = mScrollFade;
+
+        int alpha = -1;
+        if (mState == STATE_EXIT) {
+            alpha = scrollFade.getAlpha();
+            if (alpha < ScrollFade.ALPHA_MAX / 2) {
+                mThumbDrawable.setAlpha(alpha * 2);
+            }
+            int left = viewWidth - (mThumbW * alpha) / ScrollFade.ALPHA_MAX;
+            mThumbDrawable.setBounds(left, 0, viewWidth, mThumbH);
+            mChangedBounds = true;
+        }
+
+        canvas.translate(0, y);
+        mThumbDrawable.draw(canvas);
+        canvas.translate(0, -y);
+
+        // If user is dragging the scroll bar, draw the alphabet overlay
+        if (mState == STATE_DRAGGING && mDrawOverlay) {
+            mOverlayDrawable.draw(canvas);
+            final Paint paint = mPaint;
+            float descent = paint.descent();
+            final RectF rectF = mOverlayPos;
+            canvas.drawText(mSectionText, (int) (rectF.left + rectF.right) / 2,
+                    (int) (rectF.bottom + rectF.top) / 2 + mOverlaySize / 4 - descent, paint);
+        } else if (mState == STATE_EXIT) {
+            if (alpha == 0) { // Done with exit
+                setState(STATE_NONE);
+            } else {
+                mList.invalidate(viewWidth - mThumbW, y, viewWidth, y + mThumbH);            
+            }
+        }
+    }
+
+    void onSizeChanged(int w, int h, int oldw, int oldh) {
+        if (mThumbDrawable != null) {
+            mThumbDrawable.setBounds(w - mThumbW, 0, w, mThumbH);
+        }
+        final RectF pos = mOverlayPos;
+        pos.left = (w - mOverlaySize) / 2;
+        pos.right = pos.left + mOverlaySize;
+        pos.top = h / 10; // 10% from top
+        pos.bottom = pos.top + mOverlaySize;
+        if (mOverlayDrawable != null) {
+            mOverlayDrawable.setBounds((int) pos.left, (int) pos.top,
+                (int) pos.right, (int) pos.bottom);
+        }
+    }
+    
+    void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 
+            int totalItemCount) {
+        
+        if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING ) {
+            mThumbY = ((mList.getHeight() - mThumbH) * firstVisibleItem) 
+                    / (totalItemCount - visibleItemCount);
+            if (mChangedBounds) {
+                resetThumbPos();
+                mChangedBounds = false;
+            }
+        }
+        mScrollCompleted = true;
+        if (firstVisibleItem == mVisibleItem) {
+            return;
+        }
+        mVisibleItem = firstVisibleItem;
+        if (mState != STATE_DRAGGING) {
+            setState(STATE_VISIBLE);
+            mHandler.postDelayed(mScrollFade, 1500);
+        }
+    }
+
+    private void getSections() {
+        Adapter adapter = mList.getAdapter();
+        mSectionIndexer = null;
+        if (adapter instanceof HeaderViewListAdapter) {
+            mListOffset = ((HeaderViewListAdapter)adapter).getHeadersCount();
+            adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter();
+        }
+        if (adapter instanceof ExpandableListConnector) {
+            ExpandableListAdapter expAdapter = ((ExpandableListConnector)adapter).getAdapter();
+            if (expAdapter instanceof SectionIndexer) {
+                mSectionIndexer = (SectionIndexer) expAdapter;
+                mListAdapter = (BaseAdapter) adapter;
+                mSections = mSectionIndexer.getSections();
+            }
+        } else {
+            if (adapter instanceof SectionIndexer) {
+                mListAdapter = (BaseAdapter) adapter;
+                mSectionIndexer = (SectionIndexer) adapter;
+                mSections = mSectionIndexer.getSections();
+                
+            } else {
+                mListAdapter = (BaseAdapter) adapter;
+                mSections = new String[] { " " };
+            }
+        }
+    }
+
+    private void scrollTo(float position) {
+        int count = mList.getCount();
+        mScrollCompleted = false;
+        float fThreshold = (1.0f / count) / 8;
+        final Object[] sections = mSections;
+        int sectionIndex;
+        if (sections != null && sections.length > 1) {
+            final int nSections = sections.length;
+            int section = (int) (position * nSections);
+            if (section >= nSections) {
+                section = nSections - 1;
+            }
+            int exactSection = section;
+            sectionIndex = section;
+            int index = mSectionIndexer.getPositionForSection(section);
+            // Given the expected section and index, the following code will
+            // try to account for missing sections (no names starting with..)
+            // It will compute the scroll space of surrounding empty sections
+            // and interpolate the currently visible letter's range across the
+            // available space, so that there is always some list movement while
+            // the user moves the thumb.
+            int nextIndex = count;
+            int prevIndex = index;
+            int prevSection = section;
+            int nextSection = section + 1;
+            // Assume the next section is unique
+            if (section < nSections - 1) {
+                nextIndex = mSectionIndexer.getPositionForSection(section + 1);
+            }
+            
+            // Find the previous index if we're slicing the previous section
+            if (nextIndex == index) {
+                // Non-existent letter
+                while (section > 0) {
+                    section--;
+                     prevIndex = mSectionIndexer.getPositionForSection(section);
+                     if (prevIndex != index) {
+                         prevSection = section;
+                         sectionIndex = section;
+                         break;
+                     }
+                }
+            }
+            // Find the next index, in case the assumed next index is not
+            // unique. For instance, if there is no P, then request for P's 
+            // position actually returns Q's. So we need to look ahead to make
+            // sure that there is really a Q at Q's position. If not, move 
+            // further down...
+            int nextNextSection = nextSection + 1;
+            while (nextNextSection < nSections &&
+                    mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) {
+                nextNextSection++;
+                nextSection++;
+            }
+            // Compute the beginning and ending scroll range percentage of the
+            // currently visible letter. This could be equal to or greater than
+            // (1 / nSections). 
+            float fPrev = (float) prevSection / nSections;
+            float fNext = (float) nextSection / nSections;
+            if (prevSection == exactSection && position - fPrev < fThreshold) {
+                index = prevIndex;
+            } else {
+                index = prevIndex + (int) ((nextIndex - prevIndex) * (position - fPrev) 
+                    / (fNext - fPrev));
+            }
+            // Don't overflow
+            if (index > count - 1) index = count - 1;
+            
+            if (mList instanceof ExpandableListView) {
+                ExpandableListView expList = (ExpandableListView) mList;
+                expList.setSelectionFromTop(expList.getFlatListPosition(
+                        ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0);
+            } else if (mList instanceof ListView) {
+                ((ListView)mList).setSelectionFromTop(index + mListOffset, 0);
+            } else {
+                mList.setSelection(index + mListOffset);
+            }
+        } else {
+            int index = (int) (position * count);
+            if (mList instanceof ExpandableListView) {
+                ExpandableListView expList = (ExpandableListView) mList;
+                expList.setSelectionFromTop(expList.getFlatListPosition(
+                        ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0);
+            } else if (mList instanceof ListView) {
+                ((ListView)mList).setSelectionFromTop(index + mListOffset, 0);
+            } else {
+                mList.setSelection(index + mListOffset);
+            }
+            sectionIndex = -1;
+        }
+
+        if (sectionIndex >= 0) {
+            String text = mSectionText = sections[sectionIndex].toString();
+            mDrawOverlay = (text.length() != 1 || text.charAt(0) != ' ') &&
+                    sectionIndex < sections.length;
+        } else {
+            mDrawOverlay = false;
+        }
+    }
+
+    private void cancelFling() {
+        // Cancel the list fling
+        MotionEvent cancelFling = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
+        mList.onTouchEvent(cancelFling);
+        cancelFling.recycle();
+    }
+    
+    boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (mState > STATE_NONE && ev.getAction() == MotionEvent.ACTION_DOWN) {
+            if (ev.getX() > mList.getWidth() - mThumbW && ev.getY() >= mThumbY &&
+                    ev.getY() <= mThumbY + mThumbH) {
+                setState(STATE_DRAGGING);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean onTouchEvent(MotionEvent me) {
+        if (mState == STATE_NONE) {
+            return false;
+        }
+        if (me.getAction() == MotionEvent.ACTION_DOWN) {
+            if (me.getX() > mList.getWidth() - mThumbW
+                    && me.getY() >= mThumbY 
+                    && me.getY() <= mThumbY + mThumbH) {
+                
+                setState(STATE_DRAGGING);
+                if (mListAdapter == null && mList != null) {
+                    getSections();
+                }
+
+                cancelFling();
+                return true;
+            }
+        } else if (me.getAction() == MotionEvent.ACTION_UP) {
+            if (mState == STATE_DRAGGING) {
+                setState(STATE_VISIBLE);
+                final Handler handler = mHandler;
+                handler.removeCallbacks(mScrollFade);
+                handler.postDelayed(mScrollFade, 1000);
+                return true;
+            }
+        } else if (me.getAction() == MotionEvent.ACTION_MOVE) {
+            if (mState == STATE_DRAGGING) {
+                final int viewHeight = mList.getHeight();
+                // Jitter
+                int newThumbY = (int) me.getY() - mThumbH + 10;
+                if (newThumbY < 0) {
+                    newThumbY = 0;
+                } else if (newThumbY + mThumbH > viewHeight) {
+                    newThumbY = viewHeight - mThumbH;
+                }
+                if (Math.abs(mThumbY - newThumbY) < 2) {
+                    return true;
+                }
+                mThumbY = newThumbY;
+                // If the previous scrollTo is still pending
+                if (mScrollCompleted) {
+                    scrollTo((float) mThumbY / (viewHeight - mThumbH));
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    public class ScrollFade implements Runnable {
+        
+        long mStartTime;
+        long mFadeDuration;
+        static final int ALPHA_MAX = 208;
+        static final long FADE_DURATION = 200;
+        
+        void startFade() {
+            mFadeDuration = FADE_DURATION;
+            mStartTime = SystemClock.uptimeMillis();
+            setState(STATE_EXIT);
+        }
+        
+        int getAlpha() {
+            if (getState() != STATE_EXIT) {
+                return ALPHA_MAX;
+            }
+            int alpha;
+            long now = SystemClock.uptimeMillis();
+            if (now > mStartTime + mFadeDuration) {
+                alpha = 0;
+            } else {
+                alpha = (int) (ALPHA_MAX - ((now - mStartTime) * ALPHA_MAX) / mFadeDuration); 
+            }
+            return alpha;
+        }
+        
+        public void run() {
+            if (getState() != STATE_EXIT) {
+                startFade();
+                return;
+            }
+            
+            if (getAlpha() > 0) {
+                mList.invalidate();
+            } else {
+                setState(STATE_NONE);
+            }
+        }
+    }
+}
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index acf9400..d886155 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -122,7 +122,7 @@
      * Whether to continuously callback on the item selected listener during a
      * fling.
      */
-    private boolean mShouldCallbackDuringFling;
+    private boolean mShouldCallbackDuringFling = true;
 
     /**
      * Whether to callback when an item that is not selected is clicked.
@@ -133,6 +133,13 @@
      * If true, do not callback to item selected listener. 
      */
     private boolean mSuppressSelectionChanged;
+
+    /**
+     * If true, we have received the "invoke" (center or enter buttons) key
+     * down. This is checked before we action on the "invoke" key up, and is
+     * subsequently cleared.
+     */
+    private boolean mReceivedInvokeKeyDown;
     
     private AdapterContextMenuInfo mContextMenuInfo;
     
@@ -882,8 +889,8 @@
          */
         mParent.requestDisallowInterceptTouchEvent(true);
         
-        // As the user scrolls, we want to callback selection changes so related
-        // into on the screen is up-to-date with the user's selection
+        // As the user scrolls, we want to callback selection changes so related-
+        // info on the screen is up-to-date with the gallery's selection
         if (mSuppressSelectionChanged) {
             mSuppressSelectionChanged = false;
         }
@@ -1062,6 +1069,11 @@
                 playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
             }
             return true;
+
+        case KeyEvent.KEYCODE_DPAD_CENTER:
+        case KeyEvent.KEYCODE_ENTER:
+            mReceivedInvokeKeyDown = true;
+            // fallthrough to default handling
         }
         
         return super.onKeyDown(keyCode, event);
@@ -1072,19 +1084,26 @@
         switch (keyCode) {
         case KeyEvent.KEYCODE_DPAD_CENTER:
         case KeyEvent.KEYCODE_ENTER: {
-            if (mItemCount > 0) {
-
-                dispatchPress(mSelectedChild);
-                postDelayed(new Runnable() {
-                    public void run() {
-                        dispatchUnpress();
-                    }
-                }, ViewConfiguration.getPressedStateDuration());
-
-                int selectedIndex = mSelectedPosition - mFirstPosition;
-                performItemClick(getChildAt(selectedIndex), mSelectedPosition, mAdapter
-                        .getItemId(mSelectedPosition));
+            
+            if (mReceivedInvokeKeyDown) {
+                if (mItemCount > 0) {
+    
+                    dispatchPress(mSelectedChild);
+                    postDelayed(new Runnable() {
+                        public void run() {
+                            dispatchUnpress();
+                        }
+                    }, ViewConfiguration.getPressedStateDuration());
+    
+                    int selectedIndex = mSelectedPosition - mFirstPosition;
+                    performItemClick(getChildAt(selectedIndex), mSelectedPosition, mAdapter
+                            .getItemId(mSelectedPosition));
+                }
             }
+            
+            // Clear the flag
+            mReceivedInvokeKeyDown = false;
+            
             return true;
         }
         }
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 268bf84..38bfc7c 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -36,7 +36,8 @@
     public static final int NO_STRETCH = 0;
     public static final int STRETCH_SPACING = 1;
     public static final int STRETCH_COLUMN_WIDTH = 2;
-
+    public static final int STRETCH_SPACING_UNIFORM = 3;
+    
     public static final int AUTO_FIT = -1;
 
     private int mNumColumns = AUTO_FIT;
@@ -228,12 +229,12 @@
     }
 
     private View makeRow(int startPos, int y, boolean flow) {
-        int last;
-        int nextLeft = mListPadding.left;
-
         final int columnWidth = mColumnWidth;
         final int horizontalSpacing = mHorizontalSpacing;
 
+        int last;
+        int nextLeft = mListPadding.left + ((mStretchMode == STRETCH_SPACING_UNIFORM) ? horizontalSpacing : 0);
+
         if (!mStackFromBottom) {
             last = Math.min(startPos + mNumColumns, mItemCount);
         } else {
@@ -878,6 +879,17 @@
                     mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver;
                 }
                 break;
+
+            case STRETCH_SPACING_UNIFORM:
+                // Stretch the spacing between columns
+                mColumnWidth = requestedColumnWidth;
+                if (mNumColumns > 1) {
+                    mHorizontalSpacing = requestedHorizontalSpacing + 
+                        spaceLeftOver / (mNumColumns + 1);
+                } else {
+                    mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver;
+                }
+                break;
             }
 
             break;
@@ -1379,7 +1391,6 @@
                     handled = arrowScroll(FOCUS_LEFT);
                     break;
 
-
                 case KeyEvent.KEYCODE_DPAD_RIGHT:
                     handled = arrowScroll(FOCUS_RIGHT);
                     break;
@@ -1420,7 +1431,6 @@
                     }
                     break;
             }
-
         }
 
         if (!handled) {
@@ -1460,6 +1470,7 @@
 
         if (nextPage >= 0) {
             setSelectionInt(nextPage);
+            invokeOnItemScrollListener();
             return true;
         }
 
@@ -1478,10 +1489,12 @@
         if (direction == FOCUS_UP) {
             mLayoutMode = LAYOUT_SET_SELECTION;
             setSelectionInt(0);
+            invokeOnItemScrollListener();
             moved = true;
         } else if (direction == FOCUS_DOWN) {
             mLayoutMode = LAYOUT_SET_SELECTION;
             setSelectionInt(mItemCount - 1);
+            invokeOnItemScrollListener();
             moved = true;
         }
 
@@ -1547,6 +1560,7 @@
 
         if (moved) {
             playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
+            invokeOnItemScrollListener();
         }
 
         return moved;
@@ -1684,7 +1698,7 @@
      * Control how items are stretched to fill their space.
      *
      * @param stretchMode Either {@link #NO_STRETCH},
-     * {@link #STRETCH_SPACING}, or {@link #STRETCH_COLUMN_WIDTH}.
+     * {@link #STRETCH_SPACING}, {@link #STRETCH_SPACING_UNIFORM}, or {@link #STRETCH_COLUMN_WIDTH}.
      *
      * @attr ref android.R.styleable#GridView_stretchMode
      */
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index de74fa4..36ed8bd 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -952,12 +952,13 @@
         if (majorGravity != Gravity.TOP) {
            switch (majorGravity) {
                case Gravity.BOTTOM:
-                   childTop = mBottom - mTop - mPaddingBottom - mTotalLength;
+                   // mTotalLength contains the padding already, we add the top
+                   // padding to compensate
+                   childTop = mBottom - mTop + mPaddingTop - mTotalLength;
                    break;
 
                case Gravity.CENTER_VERTICAL:
-                   childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) -
-                           mTotalLength) / 2;
+                   childTop += ((mBottom - mTop)  - mTotalLength) / 2;
                    break;
            }
            
@@ -1039,12 +1040,13 @@
         if (majorGravity != Gravity.LEFT) {
             switch (majorGravity) {
                 case Gravity.RIGHT:
-                    childLeft = mRight - mLeft - mPaddingRight - mTotalLength;
+                    // mTotalLength contains the padding already, we add the left
+                    // padding to compensate
+                    childLeft = mRight - mLeft + mPaddingLeft - mTotalLength;
                     break;
 
                 case Gravity.CENTER_HORIZONTAL:
-                    childLeft += ((mRight - mLeft - mPaddingLeft - mPaddingRight) -
-                            mTotalLength) / 2;
+                    childLeft += ((mRight - mLeft) - mTotalLength) / 2;
                     break;
             }
        }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index d52e51f..dfc7bc3 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -21,6 +21,7 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
@@ -36,6 +37,7 @@
 import android.view.SoundEffectConstants;
 
 import com.google.android.collect.Lists;
+import com.android.internal.R;
 
 import java.util.ArrayList;
 
@@ -57,6 +59,8 @@
  * @attr ref android.R.styleable#ListView_divider
  * @attr ref android.R.styleable#ListView_dividerHeight
  * @attr ref android.R.styleable#ListView_choiceMode
+ * @attr ref android.R.styleable#ListView_headerDividersEnabled
+ * @attr ref android.R.styleable#ListView_footerDividersEnabled
  */
 public class ListView extends AbsListView {
     /**
@@ -92,10 +96,16 @@
      */
     private static final int MIN_SCROLL_PREVIEW_PIXELS = 2;
 
-    // TODO: document
-    class FixedViewInfo {
+    /**
+     * A class that represents a fixed view in a list, for example a header at the top
+     * or a footer at the bottom.
+     */
+    public class FixedViewInfo {
+        /** The view to add to the list */
         public View view;
+        /** The data backing the view. This is returned from {@link ListAdapter#getItem(int)}. */
         public Object data;
+        /** <code>true</code> if the fixed view should be selectable in the list */
         public boolean isSelectable;
     }
 
@@ -104,6 +114,9 @@
 
     Drawable mDivider;
     int mDividerHeight;
+    private boolean mClipDivider;
+    private boolean mHeaderDividersEnabled;
+    private boolean mFooterDividersEnabled;
 
     private boolean mAreAllItemsSelectable = true;
 
@@ -137,8 +150,8 @@
     public ListView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        TypedArray a =
-            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ListView, defStyle, 0);
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.ListView, defStyle, 0);
 
         CharSequence[] entries = a.getTextArray(
                 com.android.internal.R.styleable.ListView_entries);
@@ -149,19 +162,20 @@
 
         final Drawable d = a.getDrawable(com.android.internal.R.styleable.ListView_divider);
         if (d != null) {
-
             // If a divider is specified use its intrinsic height for divider height
             setDivider(d);
-        } else {
-
-            // Else use the height specified, zero being the default
-            final int dividerHeight = a.getDimensionPixelSize(
-                    com.android.internal.R.styleable.ListView_dividerHeight, 0);
-            if (dividerHeight != 0) {
-                setDividerHeight(dividerHeight);
-            }
         }
 
+        // Use the height specified, zero being the default
+        final int dividerHeight = a.getDimensionPixelSize(
+                com.android.internal.R.styleable.ListView_dividerHeight, 0);
+        if (dividerHeight != 0) {
+            setDividerHeight(dividerHeight);
+        }
+
+        mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true);
+        mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true);
+
         a.recycle();
     }
 
@@ -198,8 +212,7 @@
                     // We only are looking to see if we are too low, not too high
                     delta = 0;
                 }
-            }
-            else {
+            } else {
                 // we are too high, slide all views down to align with bottom
                 child = getChildAt(childCount - 1);
                 delta = child.getBottom() - (getHeight() - mListPadding.bottom);
@@ -1989,6 +2002,7 @@
                 }
 
                 setSelectionInt(position);
+                invokeOnItemScrollListener();
                 invalidate();
 
                 return true;
@@ -2014,6 +2028,7 @@
                 if (position >= 0) {
                     mLayoutMode = LAYOUT_FORCE_TOP;
                     setSelectionInt(position);
+                    invokeOnItemScrollListener();
                 }
                 moved = true;
             }
@@ -2023,6 +2038,7 @@
                 if (position >= 0) {
                     mLayoutMode = LAYOUT_FORCE_BOTTOM;
                     setSelectionInt(position);
+                    invokeOnItemScrollListener();
                 }
                 moved = true;
             }
@@ -2739,36 +2755,46 @@
             bounds.right = mRight - mLeft - mPaddingRight;
 
             final int count = getChildCount();
-            int i;
+            final int headerCount = mHeaderViewInfos.size();
+            final int footerLimit = mItemCount - mFooterViewInfos.size() - 1;
+            final boolean headerDividers = mHeaderDividersEnabled;
+            final boolean footerDividers = mFooterDividersEnabled;
+            final int first = mFirstPosition;
 
-            if (mStackFromBottom) {
-                int top;
-                int listTop = mListPadding.top;
+            if (!mStackFromBottom) {
+                int bottom;
+                int listBottom = mBottom - mTop - mListPadding.bottom;
 
-                for (i = 0; i < count; ++i) {
-                    View child = getChildAt(i);
-                    top = child.getTop();
-                    if (top > listTop) {
-                        bounds.top = top - dividerHeight;
-                        bounds.bottom = top;
-                        // Give the method the child ABOVE the divider, so we
-                        // subtract one from our child
-                        // position. Give -1 when there is no child above the
-                        // divider.
-                        drawDivider(canvas, bounds, i - 1);
+                for (int i = 0; i < count; i++) {
+                    if ((headerDividers || first + i >= headerCount) &&
+                            (footerDividers || first + i < footerLimit)) {
+                        View child = getChildAt(i);
+                        bottom = child.getBottom();
+                        if (bottom < listBottom) {
+                            bounds.top = bottom;
+                            bounds.bottom = bottom + dividerHeight;
+                            drawDivider(canvas, bounds, i);
+                        }
                     }
                 }
             } else {
-                int bottom;
-                int listBottom = getHeight() - mListPadding.bottom;
+                int top;
+                int listTop = mListPadding.top;
 
-                for (i = 0; i < count; ++i) {
-                    View child = getChildAt(i);
-                    bottom = child.getBottom();
-                    if (bottom < listBottom) {
-                        bounds.top = bottom;
-                        bounds.bottom = bottom + dividerHeight;
-                        drawDivider(canvas, bounds, i);
+                for (int i = 0; i < count; i++) {
+                    if ((headerDividers || first + i >= headerCount) &&
+                            (footerDividers || first + i < footerLimit)) {
+                        View child = getChildAt(i);
+                        top = child.getTop();
+                        if (top > listTop) {
+                            bounds.top = top - dividerHeight;
+                            bounds.bottom = top;
+                            // Give the method the child ABOVE the divider, so we
+                            // subtract one from our child
+                            // position. Give -1 when there is no child above the
+                            // divider.
+                            drawDivider(canvas, bounds, i - 1);
+                        }
                     }
                 }
             }
@@ -2789,8 +2815,21 @@
      */
     void drawDivider(Canvas canvas, Rect bounds, int childIndex) {
         // This widget draws the same divider for all children
-        mDivider.setBounds(bounds);
-        mDivider.draw(canvas);
+        final Drawable divider = mDivider;
+        final boolean clipDivider = mClipDivider;
+
+        if (!clipDivider) {
+            divider.setBounds(bounds);
+        } else {
+            canvas.save();
+            canvas.clipRect(bounds);
+        }
+
+        divider.draw(canvas);
+
+        if (clipDivider) {
+            canvas.restore();
+        }
     }
 
     /**
@@ -2811,8 +2850,10 @@
     public void setDivider(Drawable divider) {
         if (divider != null) {
             mDividerHeight = divider.getIntrinsicHeight();
+            mClipDivider = divider instanceof ColorDrawable;
         } else {
             mDividerHeight = 0;
+            mClipDivider = false;
         }
         mDivider = divider;
         requestLayoutIfNecessary();
@@ -2836,6 +2877,32 @@
         requestLayoutIfNecessary();
     }
 
+    /**
+     * Enables or disables the drawing of the divider for header views.
+     *
+     * @param headerDividersEnabled True to draw the headers, false otherwise.
+     *
+     * @see #setFooterDividersEnabled(boolean)
+     * @see #addHeaderView(android.view.View)
+     */
+    public void setHeaderDividersEnabled(boolean headerDividersEnabled) {
+        mHeaderDividersEnabled = headerDividersEnabled;
+        invalidate();
+    }
+
+    /**
+     * Enables or disables the drawing of the divider for footer views.
+     *
+     * @param footerDividersEnabled True to draw the footers, false otherwise.
+     *
+     * @see #setHeaderDividersEnabled(boolean)
+     * @see #addFooterView(android.view.View)
+     */
+    public void setFooterDividersEnabled(boolean footerDividersEnabled) {
+        mFooterDividersEnabled = footerDividersEnabled;
+        invalidate();
+    }
+
     @Override
     protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index ad8433f..6c0c164 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -271,6 +271,7 @@
             p.y = anchorpos[1] + mAnchor.getHeight() - p.height;
             p.format = PixelFormat.TRANSLUCENT;
             p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+            p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
             p.token = null;
             p.windowAnimations = 0; // android.R.style.DropDownAnimationDown;
             mWindowManager.addView(mDecor, p);
@@ -387,6 +388,7 @@
         int keyCode = event.getKeyCode();
         if (event.getRepeatCount() == 0 && event.isDown() && (
                 keyCode ==  KeyEvent.KEYCODE_HEADSETHOOK ||
+                keyCode ==  KeyEvent.KEYCODE_PLAYPAUSE ||
                 keyCode ==  KeyEvent.KEYCODE_SPACE)) {
             doPauseResume();
             show(sDefaultTimeout);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 6a7b1fb..b5c4384 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -22,9 +22,9 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
 import android.view.Gravity;
 import android.view.ViewGroup;
+import android.view.View.OnTouchListener;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -43,31 +43,58 @@
  */
 public class PopupWindow {
     /**
-     * The height of the status bar so we know how much of the screen we can
-     * actually be displayed in.
-     * <p>
-     * TODO: This IS NOT the right way to do this.
-     * Instead of knowing how much of the screen is available, a popup that
-     * wants anchor and maximize space shouldn't be setting a height, instead
-     * the PopupViewContainer should have its layout height as fill_parent and
-     * properly position the popup.
+     * Mode for {@link #setInputMethodMode(int): the requirements for the
+     * input method should be based on the focusability of the popup.  That is
+     * if it is focusable than it needs to work with the input method, else
+     * it doesn't.
      */
-    private static final int STATUS_BAR_HEIGHT = 30;
+    public static final int INPUT_METHOD_FROM_FOCUSABLE = 0;
+    
+    /**
+     * Mode for {@link #setInputMethodMode(int): this popup always needs to
+     * work with an input method, regardless of whether it is focusable.  This
+     * means that it will always be displayed so that the user can also operate
+     * the input method while it is shown.
+     */
+    
+    public static final int INPUT_METHOD_NEEDED = 1;
+    
+    /**
+     * Mode for {@link #setInputMethodMode(int): this popup never needs to
+     * work with an input method, regardless of whether it is focusable.  This
+     * means that it will always be displayed to use as much space on the
+     * screen as needed, regardless of whether this covers the input method.
+     */
+    public static final int INPUT_METHOD_NOT_NEEDED = 2;
+    
+    private final Context mContext;
+    private final WindowManager mWindowManager;
     
     private boolean mIsShowing;
+    private boolean mIsDropdown;
 
     private View mContentView;
     private View mPopupView;
     private boolean mFocusable;
+    private int mInputMethodMode = INPUT_METHOD_FROM_FOCUSABLE;
+    private boolean mTouchable = true;
+    private boolean mOutsideTouchable = false;
+    private boolean mClippingEnabled = true;
 
+    private OnTouchListener mTouchInterceptor;
+    
+    private int mWidthMode;
     private int mWidth;
+    private int mHeightMode;
     private int mHeight;
 
+    private int mPopupWidth;
+    private int mPopupHeight;
+    
     private int[] mDrawingLocation = new int[2];
-    private int[] mRootLocation = new int[2];
+    private int[] mScreenLocation = new int[2];
     private Rect mTempRect = new Rect();
     
-    private Context mContext;
     private Drawable mBackground;
 
     private boolean mAboveAnchor;
@@ -106,6 +133,8 @@
      */
     public PopupWindow(Context context, AttributeSet attrs, int defStyle) {
         mContext = context;
+        mWindowManager = (WindowManager)context.getSystemService(
+                Context.WINDOW_SERVICE);
 
         TypedArray a =
             context.obtainStyledAttributes(
@@ -183,6 +212,9 @@
      */
     public PopupWindow(View contentView, int width, int height,
             boolean focusable) {
+        mContext = contentView.getContext();
+        mWindowManager = (WindowManager)mContext.getSystemService(
+                Context.WINDOW_SERVICE);
         setContentView(contentView);
         setWidth(width);
         setHeight(height);
@@ -218,11 +250,15 @@
     }
     
     /**
-     * set the flag on popup to ignore cheek press events
-     * This method has to be invoked before displaying the content view
-     * of the popup for the window flags to take effect and will be ignored
-     * if the pop up is already displayed. By default this flag is set to false
+     * Set the flag on popup to ignore cheek press eventt; by default this flag
+     * is set to false
      * which means the pop wont ignore cheek press dispatch events.
+     * 
+     * <p>If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown or through a manual call to one of
+     * the {@link #update()} methods.</p>
+     * 
+     * @see #update()
      */
     public void setIgnoreCheekPress() {
         mIgnoreCheekPress = true;
@@ -230,9 +266,17 @@
     
 
     /**
-     * <p>Change the animation style for this popup.</p>
+     * <p>Change the animation style resource for this popup.</p>
      *
-     * @param animationStyle animation style to use when the popup appears and disappears
+     * <p>If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown or through a manual call to one of
+     * the {@link #update()} methods.</p>
+     *
+     * @param animationStyle animation style to use when the popup appears
+     *      and disappears.  Set to -1 for the default animation, 0 for no
+     *      animation, or a resource identifier for an explicit animation.
+     *      
+     * @see #update()
      */
     public void setAnimationStyle(int animationStyle) {
         mAnimationStyle = animationStyle;
@@ -253,7 +297,8 @@
      * <p>Change the popup's content. The content is represented by an instance
      * of {@link android.view.View}.</p>
      *
-     * <p>This method has no effect if called when the popup is showing.</p>
+     * <p>This method has no effect if called when the popup is showing.  To
+     * apply it while a popup is showing, call </p>
      *
      * @param contentView the new content for the popup
      *
@@ -269,6 +314,14 @@
     }
 
     /**
+     * Set a callback for all touch events being dispatched to the popup
+     * window.
+     */
+    public void setTouchInterceptor(OnTouchListener l) {
+        mTouchInterceptor = l;
+    }
+    
+    /**
      * <p>Indicate whether the popup window can grab the focus.</p>
      *
      * @return true if the popup is focusable, false otherwise
@@ -282,21 +335,169 @@
     /**
      * <p>Changes the focusability of the popup window. When focusable, the
      * window will grab the focus from the current focused widget if the popup
-     * contains a focusable {@link android.view.View}.</p>
+     * contains a focusable {@link android.view.View}.  By default a popup
+     * window is not focusable.</p>
      *
      * <p>If the popup is showing, calling this method will take effect only
-     * the next time the popup is shown.</p>
+     * the next time the popup is shown or through a manual call to one of
+     * the {@link #update()} methods.</p>
      *
-     * @param focusable true if the popup should grab focus, false otherwise
+     * @param focusable true if the popup should grab focus, false otherwise.
      *
      * @see #isFocusable()
      * @see #isShowing() 
+     * @see #update()
      */
     public void setFocusable(boolean focusable) {
         mFocusable = focusable;
     }
 
     /**
+     * Return the current value in {@link #setInputMethodMode(int)}.
+     * 
+     * @see #setInputMethodMode(int)
+     */
+    public int getInputMethodMode() {
+        return mInputMethodMode;
+        
+    }
+    
+    /**
+     * Control how the popup operates with an input method: one of
+     * {@link #INPUT_METHOD_FROM_FOCUSABLE}, {@link #INPUT_METHOD_NEEDED},
+     * or {@link #INPUT_METHOD_NOT_NEEDED}.
+     * 
+     * <p>If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown or through a manual call to one of
+     * the {@link #update()} methods.</p>
+     * 
+     * @see #getInputMethodMode()
+     * @see #update()
+     */
+    public void setInputMethodMode(int mode) {
+        mInputMethodMode = mode;
+    }
+    
+    /**
+     * <p>Indicates whether the popup window receives touch events.</p>
+     * 
+     * @return true if the popup is touchable, false otherwise
+     * 
+     * @see #setTouchable(boolean)
+     */
+    public boolean isTouchable() {
+        return mTouchable;
+    }
+
+    /**
+     * <p>Changes the touchability of the popup window. When touchable, the
+     * window will receive touch events, otherwise touch events will go to the
+     * window below it. By default the window is touchable.</p>
+     *
+     * <p>If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown or through a manual call to one of
+     * the {@link #update()} methods.</p>
+     *
+     * @param touchable true if the popup should receive touch events, false otherwise
+     *
+     * @see #isTouchable()
+     * @see #isShowing() 
+     * @see #update()
+     */
+    public void setTouchable(boolean touchable) {
+        mTouchable = touchable;
+    }
+
+    /**
+     * <p>Indicates whether the popup window will be informed of touch events
+     * outside of its window.</p>
+     * 
+     * @return true if the popup is outside touchable, false otherwise
+     * 
+     * @see #setOutsideTouchable(boolean)
+     */
+    public boolean isOutsideTouchable() {
+        return mOutsideTouchable;
+    }
+
+    /**
+     * <p>Controls whether the pop-up will be informed of touch events outside
+     * of its window.  This only makes sense for pop-ups that are touchable
+     * but not focusable, which means touches outside of the window will
+     * be delivered to the window behind.  The default is false.</p>
+     *
+     * <p>If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown or through a manual call to one of
+     * the {@link #update()} methods.</p>
+     *
+     * @param touchable true if the popup should receive outside
+     * touch events, false otherwise
+     *
+     * @see #isOutsideTouchable()
+     * @see #isShowing() 
+     * @see #update()
+     */
+    public void setOutsideTouchable(boolean touchable) {
+        mOutsideTouchable = touchable;
+    }
+
+    /**
+     * <p>Indicates whether clipping of the popup window is enabled.</p>
+     * 
+     * @return true if the clipping is enabled, false otherwise
+     * 
+     * @see #setClippingEnabled(boolean)
+     */
+    public boolean isClippingEnabled() {
+        return mClippingEnabled;
+    }
+
+    /**
+     * <p>Allows the popup window to extend beyond the bounds of the screen. By default the
+     * window is clipped to the screen boundaries. Setting this to false will allow windows to be
+     * accurately positioned.</p>
+     * 
+     * <p>If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown or through a manual call to one of
+     * the {@link #update()} methods.</p>
+     *
+     * @param enabled false if the window should be allowed to extend outside of the screen
+     * @see #isShowing() 
+     * @see #isClippingEnabled()
+     * @see #update()
+     */
+    public void setClippingEnabled(boolean enabled) {
+        mClippingEnabled = enabled;
+    }
+
+    /**
+     * <p>Change the width and height measure specs that are given to the
+     * window manager by the popup.  By default these are 0, meaning that
+     * the current width or height is requested as an explicit size from
+     * the window manager.  You can supply
+     * {@link ViewGroup.LayoutParams#WRAP_CONTENT} or 
+     * {@link ViewGroup.LayoutParams#FILL_PARENT} to have that measure
+     * spec supplied instead, replacing the absolute width and height that
+     * has been set in the popup.</p>
+     *
+     * <p>If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown.</p>
+     *
+     * @param widthSpec an explicit width measure spec mode, either
+     * {@link ViewGroup.LayoutParams#WRAP_CONTENT},
+     * {@link ViewGroup.LayoutParams#FILL_PARENT}, or 0 to use the absolute
+     * width.
+     * @param heightSpec an explicit height measure spec mode, either
+     * {@link ViewGroup.LayoutParams#WRAP_CONTENT},
+     * {@link ViewGroup.LayoutParams#FILL_PARENT}, or 0 to use the absolute
+     * height.
+     */
+    public void setWindowLayoutMode(int widthSpec, int heightSpec) {
+        mWidthMode = widthSpec;
+        mHeightMode = heightSpec;
+    }
+    
+    /**
      * <p>Return this popup's height MeasureSpec</p>
      *
      * @return the height MeasureSpec of the popup
@@ -377,11 +578,10 @@
         }
 
         mIsShowing = true;
+        mIsDropdown = false;
 
         WindowManager.LayoutParams p = createPopupLayout(parent.getWindowToken());
-        if (mAnimationStyle != -1) {
-            p.windowAnimations = mAnimationStyle;
-        }
+        p.windowAnimations = computeAnimationResource();
        
         preparePopup(p);
         if (gravity == Gravity.NO_GRAVITY) {
@@ -426,6 +626,7 @@
         }
 
         mIsShowing = true;
+        mIsDropdown = true;
 
         WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken());
         preparePopup(p);
@@ -433,13 +634,9 @@
             mPopupView.refreshDrawableState();
         }
         mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff);
-        if (mAnimationStyle == -1) {
-            p.windowAnimations = mAboveAnchor
-                    ? com.android.internal.R.style.Animation_DropDownUp
-                    : com.android.internal.R.style.Animation_DropDownDown;
-        } else {
-            p.windowAnimations = mAnimationStyle;
-        }
+        if (mHeightMode < 0) p.height = mHeightMode;
+        if (mWidthMode < 0) p.width = mWidthMode;
+        p.windowAnimations = computeAnimationResource();
         invokePopup(p);
     }
 
@@ -479,7 +676,8 @@
         } else {
             mPopupView = mContentView;
         }
-        
+        mPopupWidth = p.width;
+        mPopupHeight = p.height;
     }
 
     /**
@@ -491,8 +689,7 @@
      * @param p the layout parameters of the popup's content view
      */
     private void invokePopup(WindowManager.LayoutParams p) {
-        WindowManagerImpl wm = WindowManagerImpl.getDefault();
-        wm.addView(mPopupView, p);
+        mWindowManager.addView(mPopupView, p);
     }
 
     /**
@@ -518,18 +715,56 @@
         } else {
             p.format = PixelFormat.TRANSLUCENT;
         }
-        if(mIgnoreCheekPress) {
-            p.flags |= WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
-        }
-        if (!mFocusable) {
-            p.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        }
+        p.flags = computeFlags(p.flags);
         p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
         p.token = token;
         
         return p;
     }
 
+    private int computeFlags(int curFlags) {
+        curFlags &= ~(
+                WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES |
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
+                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
+                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
+                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
+                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+        if(mIgnoreCheekPress) {
+            curFlags |= WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
+        }
+        if (!mFocusable) {
+            curFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+            if (mInputMethodMode == INPUT_METHOD_NEEDED) {
+                curFlags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            }
+        } else if (mInputMethodMode == INPUT_METHOD_NOT_NEEDED) {
+            curFlags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        }
+        if (!mTouchable) {
+            curFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+        }
+        if (mTouchable) {
+            curFlags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+        }
+        if (!mClippingEnabled) {
+            curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+        }
+        return curFlags;
+    }
+    
+    private int computeAnimationResource() {
+        if (mAnimationStyle == -1) {
+            if (mIsDropdown) {
+                return mAboveAnchor
+                        ? com.android.internal.R.style.Animation_DropDownUp
+                        : com.android.internal.R.style.Animation_DropDownDown;
+            }
+            return 0;
+        }
+        return mAnimationStyle;
+    }
+    
     /**
      * <p>Positions the popup window on screen. When the popup window is too
      * tall to fit under the anchor, a parent scroll view is seeked and scrolled
@@ -548,33 +783,48 @@
         anchor.getLocationInWindow(mDrawingLocation);
         p.x = mDrawingLocation[0] + xoff;
         p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff;
-
+        
         boolean onTop = false;
 
-        if (p.y + p.height > WindowManagerImpl.getDefault().getDefaultDisplay().getHeight()) {
+        p.gravity = Gravity.LEFT | Gravity.TOP;
+        
+        anchor.getLocationOnScreen(mScreenLocation);
+        final Rect displayFrame = new Rect();
+        anchor.getWindowVisibleDisplayFrame(displayFrame);
+        
+        final View root = anchor.getRootView();
+        if (mScreenLocation[1] + anchor.getMeasuredHeight() + yoff + mPopupHeight > displayFrame.bottom
+                || p.x + mPopupWidth - root.getWidth() > 0) {
             // if the drop down disappears at the bottom of the screen. we try to
             // scroll a parent scrollview or move the drop down back up on top of
             // the edit box
-            View root = anchor.getRootView();
-            root.getLocationInWindow(mRootLocation);
-            int delta = p.y + p.height - mRootLocation[1] - root.getHeight();
-
-            if (delta > 0 || p.x + p.width - mRootLocation[0] - root.getWidth() > 0) {
-                Rect r = new Rect(anchor.getScrollX(), anchor.getScrollY(),
-                        p.width, p.height + anchor.getMeasuredHeight());
-
-                onTop = !anchor.requestRectangleOnScreen(r, true);
-
-                if (onTop) {
-                    p.y -= anchor.getMeasuredHeight() + p.height;
-                } else {
-                    anchor.getLocationOnScreen(mDrawingLocation);
-                    p.x = mDrawingLocation[0] + xoff;
-                    p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff;
-                }
+            int scrollX = anchor.getScrollX();
+            int scrollY = anchor.getScrollY();
+            Rect r = new Rect(scrollX, scrollY,  scrollX + mPopupWidth,
+                    scrollY + mPopupHeight + anchor.getMeasuredHeight());
+            anchor.requestRectangleOnScreen(r, true);
+            
+            // now we re-evaluate the space available, and decide from that
+            // whether the pop-up will go above or below the anchor.
+            anchor.getLocationInWindow(mDrawingLocation);
+            p.x = mDrawingLocation[0] + xoff;
+            p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff;
+            
+            // determine whether there is more space above or below the anchor
+            anchor.getLocationOnScreen(mScreenLocation);
+            
+            onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getMeasuredHeight() - yoff)
+                    < (mScreenLocation[1] - yoff - displayFrame.top);
+            if (onTop) {
+                p.gravity = Gravity.LEFT | Gravity.BOTTOM;
+                p.y = root.getHeight() - mDrawingLocation[1] - yoff;
+            } else {
+                p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff;
             }
         }
 
+        p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
+        
         return onTop;
     }
     
@@ -589,18 +839,18 @@
      *         shown.
      */
     public int getMaxAvailableHeight(View anchor) {
-        // TODO: read comment on STATUS_BAR_HEIGHT
-        final int screenHeight = WindowManagerImpl.getDefault().getDefaultDisplay().getHeight()
-                - STATUS_BAR_HEIGHT;
+        final Rect displayFrame = new Rect();
+        anchor.getWindowVisibleDisplayFrame(displayFrame);
 
         final int[] anchorPos = mDrawingLocation;
         anchor.getLocationOnScreen(anchorPos);
-        anchorPos[1] -= STATUS_BAR_HEIGHT;
-
-        final int distanceFromAnchorToBottom = screenHeight - (anchorPos[1] + anchor.getHeight());
         
+        final int distanceToBottom = displayFrame.bottom
+                - (anchorPos[1] + anchor.getHeight());
+        final int distanceToTop = anchorPos[1] - displayFrame.top;
+
         // anchorPos[1] is distance from anchor to top of screen
-        int returnedHeight = Math.max(anchorPos[1], distanceFromAnchorToBottom);
+        int returnedHeight = Math.max(distanceToBottom, distanceToTop);
         if (mBackground != null) {
             mBackground.getPadding(mTempRect);
             returnedHeight -= mTempRect.top + mTempRect.bottom; 
@@ -618,11 +868,11 @@
      */
     public void dismiss() {
         if (isShowing() && mPopupView != null) {
-            WindowManagerImpl wm = WindowManagerImpl.getDefault();
-            wm.removeView(mPopupView);
+            mWindowManager.removeView(mPopupView);
             if (mPopupView != mContentView && mPopupView instanceof ViewGroup) {
                 ((ViewGroup) mPopupView).removeView(mContentView);
             }
+            mPopupView = null;
             mIsShowing = false;
 
             if (mOnDismissListener != null) {
@@ -641,8 +891,44 @@
     }
     
     /**
+     * Updates the state of the popup window, if it is currently being displayed,
+     * from the currently set state.  This include:
+     * {@link #setClippingEnabled(boolean)}, {@link #setFocusable(boolean)},
+     * {@link #setIgnoreCheekPress()}, {@link #setInputMethodMode(int)},
+     * {@link #setTouchable(boolean)}, and {@link #setAnimationStyle(int)}.
+     */
+    public void update() {
+        if (!isShowing() || mContentView == null) {
+            return;
+        }
+        
+        WindowManager.LayoutParams p = (WindowManager.LayoutParams)
+                mPopupView.getLayoutParams();
+        
+        boolean update = false;
+        
+        final int newAnim = computeAnimationResource();
+        if (newAnim != p.windowAnimations) {
+            p.windowAnimations = newAnim;
+            update = true;
+        }
+
+        final int newFlags = computeFlags(p.flags);
+        if (newFlags != p.flags) {
+            p.flags = newFlags;
+            update = true;
+        }
+        
+        if (update) {
+            mWindowManager.updateViewLayout(mPopupView, p);
+        }
+    }
+    
+    /**
      * <p>Updates the position and the dimension of the popup window. Width and
-     * height can be set to -1 to update location only.</p>
+     * height can be set to -1 to update location only.  Calling this function
+     * also updates the window with the current popup state as
+     * described for {@link #update()}.</p>
      *
      * @param x the new x location
      * @param y the new y location
@@ -667,13 +953,15 @@
 
         boolean update = false;
 
-        if (width != -1 && p.width != width) {
-            p.width = width;
+        final int finalWidth = mWidthMode < 0 ? mWidthMode : p.width;
+        if (width != -1 && p.width != finalWidth) {
+            p.width = finalWidth;
             update = true;
         }
 
-        if (height != -1 && p.height != height) {
-            p.height = height;
+        final int finalHeight = mHeightMode < 0 ? mHeightMode : p.height;
+        if (height != -1 && p.height != finalHeight) {
+            p.height = finalHeight;
             update = true;
         }
 
@@ -687,6 +975,18 @@
             update = true;
         }
 
+        final int newAnim = computeAnimationResource();
+        if (newAnim != p.windowAnimations) {
+            p.windowAnimations = newAnim;
+            update = true;
+        }
+
+        final int newFlags = computeFlags(p.flags);
+        if (newFlags != p.flags) {
+            p.flags = newFlags;
+            update = true;
+        }
+        
         if (update) {
             if (mPopupView != mContentView) {
                 final View popupViewContainer = mPopupView;
@@ -704,14 +1004,15 @@
                 }
             }
 
-            WindowManagerImpl wm = WindowManagerImpl.getDefault();
-            wm.updateViewLayout(mPopupView, p);
+            mWindowManager.updateViewLayout(mPopupView, p);
         }
     }
 
     /**
      * <p>Updates the position and the dimension of the popup window. Width and
-     * height can be set to -1 to update location only.</p>
+     * height can be set to -1 to update location only.  Calling this function
+     * also updates the window with the current popup state as
+     * described for {@link #update()}.</p>
      *
      * @param anchor the popup's anchor view
      * @param width the new width, can be -1 to ignore
@@ -723,7 +1024,9 @@
 
     /**
      * <p>Updates the position and the dimension of the popup window. Width and
-     * height can be set to -1 to update location only.</p>
+     * height can be set to -1 to update location only.  Calling this function
+     * also updates the window with the current popup state as
+     * described for {@link #update()}.</p>
      *
      * @param anchor the popup's anchor view
      * @param xoff x offset from the view's left edge
@@ -739,17 +1042,25 @@
         WindowManager.LayoutParams p = (WindowManager.LayoutParams)
                 mPopupView.getLayoutParams();
 
-        int x = p.x;
-        int y = p.y;
+        if (width == -1) {
+            width = mPopupWidth;
+        } else {
+            mPopupWidth = width;
+        }
+        if (height == -1) {
+            height = mPopupHeight;
+        } else {
+            mPopupHeight = height;
+        }
+        
         findDropDownPosition(anchor, p, xoff, yoff);
-
-        update(x, y, width, height);
+        update(p.x, p.y, width, height);
     }
     
     /**
      * Listener that is called when this popup window is dismissed.
      */
-    interface OnDismissListener {
+    public interface OnDismissListener {
         /**
          * Called when this popup window is dismissed.
          */
@@ -785,6 +1096,14 @@
         }
 
         @Override
+        public boolean dispatchTouchEvent(MotionEvent ev) {
+            if (mTouchInterceptor != null && mTouchInterceptor.onTouch(this, ev)) {
+                return true;
+            }
+            return super.dispatchTouchEvent(ev);
+        }
+
+        @Override
         public boolean onTouchEvent(MotionEvent event) {
             final int x = (int) event.getX();
             final int y = (int) event.getY();
@@ -793,6 +1112,9 @@
                     && ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {
                 dismiss();
                 return true;
+            } else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+                dismiss();
+                return true;
             } else {
                 return super.onTouchEvent(event);
             }
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index c1de010..abba6d0 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -22,6 +22,7 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Shader;
+import android.graphics.Rect;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ClipDrawable;
@@ -40,6 +41,8 @@
 import android.view.animation.LinearInterpolator;
 import android.view.animation.Transformation;
 import android.widget.RemoteViews.RemoteView;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.SystemClock;
 
 import com.android.internal.R;
@@ -427,7 +430,7 @@
     Drawable getCurrentDrawable() {
         return mCurrentDrawable;
     }
-    
+
     @Override
     protected boolean verifyDrawable(Drawable who) {
         return who == mProgressDrawable || who == mIndeterminateDrawable
@@ -700,7 +703,7 @@
         mAnimation = null;
         mTransformation = null;
         if (mIndeterminateDrawable instanceof AnimationDrawable) {
-            ((AnimationDrawable)mIndeterminateDrawable).stop();
+            ((AnimationDrawable) mIndeterminateDrawable).stop();
             mShouldStartAnimationDrawable = false;
         }
     }
@@ -754,17 +757,31 @@
     @Override
     public void invalidateDrawable(Drawable dr) {
         if (!mInDrawing) {
-            super.invalidateDrawable(dr);
+            if (dr == mProgressDrawable || dr == mIndeterminateDrawable) {
+                final Rect dirty = dr.getBounds();
+                final int scrollX = mScrollX + mPaddingLeft;
+                final int scrollY = mScrollY + mPaddingRight;
+
+                invalidate(dirty.left + scrollX, dirty.top + scrollY,
+                        dirty.right + scrollX, dirty.bottom + scrollY);
+            } else {
+                super.invalidateDrawable(dr);
+            }
         }
     }
 
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        Drawable d = mCurrentDrawable;
-        if (d != null) {
-            // onDraw will translate the canvas so we draw starting at 0,0
-            d.setBounds(0, 0, w - mPaddingRight - mPaddingLeft, 
-                    h - mPaddingBottom - mPaddingTop);
+        // onDraw will translate the canvas so we draw starting at 0,0
+        int right = w - mPaddingRight - mPaddingLeft;
+        int bottom = h - mPaddingBottom - mPaddingTop;
+
+        if (mIndeterminateDrawable != null) {
+            mIndeterminateDrawable.setBounds(0, 0, right, bottom);
+        }
+        
+        if (mProgressDrawable != null) {
+            mProgressDrawable.setBounds(0, 0, right, bottom);
         }
     }
 
@@ -795,8 +812,9 @@
             }
             d.draw(canvas);
             canvas.restore();
-            if (mShouldStartAnimationDrawable && mCurrentDrawable instanceof AnimationDrawable) {
-                ((AnimationDrawable)mCurrentDrawable).start();
+            if (mShouldStartAnimationDrawable && d instanceof AnimationDrawable) {
+                ((AnimationDrawable) d).start();
+                mShouldStartAnimationDrawable = false;
             }
         }
     }
@@ -817,4 +835,64 @@
         setMeasuredDimension(resolveSize(dw, widthMeasureSpec),
                 resolveSize(dh, heightMeasureSpec));
     }
+    
+    static class SavedState extends BaseSavedState {
+        int progress;
+        int secondaryProgress;
+        
+        /**
+         * Constructor called from {@link ProgressBar#onSaveInstanceState()}
+         */
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+        
+        /**
+         * Constructor called from {@link #CREATOR}
+         */
+        private SavedState(Parcel in) {
+            super(in);
+            progress = in.readInt();
+            secondaryProgress = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(progress);
+            out.writeInt(secondaryProgress);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR
+                = new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        // Force our ancestor class to save its state
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        
+        ss.progress = mProgress;
+        ss.secondaryProgress = mSecondaryProgress;
+        
+        return ss;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+        
+        setProgress(ss.progress);
+        setSecondaryProgress(ss.secondaryProgress);
+    }
 }
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index 5df2b6d..17f9128 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -111,7 +111,10 @@
         }
 
         Rect r = getBounds();
-
+        if (canvas.quickReject(r.left, r.top, r.right, r.bottom, 
+                Canvas.EdgeType.AA)) {
+            return;
+        }
         if (drawTrack) {
             drawTrack(canvas, r, vertical);
         }
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 23a27ac..a2133b2 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -20,6 +20,8 @@
 import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Config;
+import android.util.Log;
 import android.view.FocusFinder;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -57,6 +59,9 @@
  * <p>ScrollView only supports vertical scrolling.
  */
 public class ScrollView extends FrameLayout {
+    static final String TAG = "ScrollView";
+    static final boolean localLOGV = false || Config.LOGV;
+    
     private static final int ANIMATED_SCROLL_GAP = 250;
 
     /**
@@ -194,6 +199,7 @@
         setFocusable(true);
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
         setWillNotDraw(false);
+        setScrollContainer(true);
     }
 
     @Override
@@ -839,12 +845,16 @@
     public final void smoothScrollBy(int dx, int dy) {
         long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll;
         if (duration > ANIMATED_SCROLL_GAP) {
+            if (localLOGV) Log.v(TAG, "Smooth scroll: mScrollY=" + mScrollY
+                    + " dy=" + dy);
             mScroller.startScroll(mScrollX, mScrollY, dx, dy);
             invalidate();
         } else {
             if (!mScroller.isFinished()) {
                 mScroller.abortAnimation();
             }
+            if (localLOGV) Log.v(TAG, "Immediate scroll: mScrollY=" + mScrollY
+                    + " dy=" + dy);
             scrollBy(dx, dy);
         }
         mLastScroll = AnimationUtils.currentAnimationTimeMillis();
@@ -927,14 +937,19 @@
                 View child = getChildAt(0);
                 mScrollX = clamp(x, this.getWidth(), child.getWidth());
                 mScrollY = clamp(y, this.getHeight(), child.getHeight());
+                if (localLOGV) Log.v(TAG, "mScrollY=" + mScrollY + " y=" + y
+                        + " height=" + this.getHeight()
+                        + " child height=" + child.getHeight());
             } else {
                 mScrollX = x;
                 mScrollY = y;
             }            
             if (oldX != mScrollX || oldY != mScrollY) {
                 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
-                postInvalidate();  // So we draw again
             }
+            
+            // Keep on drawing until the animation has finished.
+            postInvalidate();
         }
     }
 
@@ -1005,6 +1020,9 @@
 
         int scrollYDelta = 0;
 
+        if (localLOGV) Log.v(TAG, "child=" + rect.toShortString()
+                + " screenTop=" + screenTop + " screenBottom=" + screenBottom
+                + " height=" + height);
         if (rect.bottom > screenBottom && rect.top > screenTop) {
             // need to move down to get it in view: move down just enough so
             // that the entire rectangle is in view (or at least the first
@@ -1021,6 +1039,8 @@
             // make sure we aren't scrolling beyond the end of our content
             int bottom = getChildAt(getChildCount() - 1).getBottom();
             int distanceToBottom = bottom - screenBottom;
+            if (localLOGV) Log.v(TAG, "scrollYDelta=" + scrollYDelta
+                    + " distanceToBottom=" + distanceToBottom);
             scrollYDelta = Math.min(scrollYDelta, distanceToBottom);
 
         } else if (rect.top < screenTop && rect.bottom < screenBottom) {
@@ -1098,8 +1118,7 @@
         rectangle.offset(child.getLeft() - child.getScrollX(),
                 child.getTop() - child.getScrollY());
 
-        // note: until bug 1137695 is fixed, disable smooth scrolling for this api
-        return scrollToChildRect(rectangle, true);//immediate);
+        return scrollToChildRect(rectangle, immediate);
     }
 
     @Override
@@ -1122,6 +1141,24 @@
         scrollTo(mScrollX, mScrollY);
     }
 
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        View currentFocused = findFocus();
+        if (null == currentFocused || this == currentFocused)
+            return;
+
+        final int maxJump = mBottom - mTop;
+
+        if (isWithinDeltaOfScreen(currentFocused, maxJump)) {
+            currentFocused.getDrawingRect(mTempRect);
+            offsetDescendantRectToMyCoords(currentFocused, mTempRect);
+            int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
+            doScrollY(scrollDelta);
+        }
+    }    
+
     /**
      * Return true if child is an descendant of parent, (or equal to the parent).
      */
diff --git a/core/java/android/widget/SectionIndexer.java b/core/java/android/widget/SectionIndexer.java
new file mode 100644
index 0000000..24f894c
--- /dev/null
+++ b/core/java/android/widget/SectionIndexer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+/**
+ * Interface that should be implemented on Adapters to enable fast scrolling 
+ * in an {@link AbsListView} between sections of the list. A section is a group of list items
+ * to jump to that have something in common. For example, they may begin with the
+ * same letter or they may be songs from the same artist. 
+ */
+public interface SectionIndexer {
+    /**
+     * This provides the list view with an array of section objects. In the simplest
+     * case these are Strings, each containing one letter of the alphabet.
+     * They could be more complex objects that indicate the grouping for the adapter's
+     * consumption. The list view will call toString() on the objects to get the
+     * preview letter to display while scrolling.
+     * @return the array of objects that indicate the different sections of the list.
+     */
+    Object[] getSections();
+    
+    /**
+     * Provides the starting index in the list for a given section.
+     * @param section the index of the section to jump to.
+     * @return the starting position of that section. If the section is out of bounds, the
+     * position must be clipped to fall within the size of the list.
+     */
+    int getPositionForSection(int section);
+    
+    /**
+     * This is a reverse mapping to fetch the section index for a given position
+     * in the list.
+     * @param position the position for which to return the section
+     * @return the section index. If the position is out of bounds, the section index
+     * must be clipped to fall within the size of the section array.
+     */
+    int getSectionForPosition(int position);    
+}
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index df52b69..261da9f 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -115,10 +115,22 @@
         View v;
         if (convertView == null) {
             v = mInflater.inflate(resource, parent, false);
+
+            final int[] to = mTo;
+            final int count = to.length;
+            final View[] holder = new View[count];
+
+            for (int i = 0; i < count; i++) {
+                holder[i] = v.findViewById(to[i]);
+            }
+
+            v.setTag(holder);
         } else {
             v = convertView;
         }
+
         bindView(position, v);
+
         return v;
     }
 
@@ -143,12 +155,14 @@
             return;
         }
 
+        final ViewBinder binder = mViewBinder;
+        final View[] holder = (View[]) view.getTag();
         final String[] from = mFrom;
         final int[] to = mTo;
-        final int len = to.length;
+        final int count = to.length;
 
-        for (int i = 0; i < len; i++) {
-            final View v = view.findViewById(to[i]);
+        for (int i = 0; i < count; i++) {
+            final View v = holder[i];
             if (v != null) {
                 final Object data = dataSet.get(from[i]);
                 String text = data == null ? "" : data.toString();
@@ -157,8 +171,8 @@
                 }
 
                 boolean bound = false;
-                if (mViewBinder != null) {
-                    bound = mViewBinder.setViewValue(v, data, text);
+                if (binder != null) {
+                    bound = binder.setViewValue(v, data, text);
                 }
 
                 if (!bound) {
diff --git a/core/java/android/widget/SimpleCursorAdapter.java b/core/java/android/widget/SimpleCursorAdapter.java
index 4d2fab3..74a9964 100644
--- a/core/java/android/widget/SimpleCursorAdapter.java
+++ b/core/java/android/widget/SimpleCursorAdapter.java
@@ -20,6 +20,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.view.View;
+import android.view.ViewGroup;
 
 /**
  * An easy adapter to map columns from a cursor to TextViews or ImageViews
@@ -79,14 +80,36 @@
      *            are given the values of the first N columns in the from
      *            parameter.
      */
-    public SimpleCursorAdapter(Context context, int layout, Cursor c,
-                               String[] from, int[] to) {
+    public SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
         super(context, layout, c);
         mTo = to;
         mOriginalFrom = from;
         findColumns(from);
     }
-    
+
+    @Override
+    public View newView(Context context, Cursor cursor, ViewGroup parent) {
+        return generateViewHolder(super.newView(context, cursor, parent));
+    }
+
+    @Override
+    public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) {
+        return generateViewHolder(super.newDropDownView(context, cursor, parent));
+    }
+
+    private View generateViewHolder(View v) {
+        final int[] to = mTo;
+        final int count = to.length;
+        final View[] holder = new View[count];
+
+        for (int i = 0; i < count; i++) {
+            holder[i] = v.findViewById(to[i]);
+        }
+        v.setTag(holder);
+
+        return v;
+    }
+
     /**
      * Binds all of the field names passed into the "to" parameter of the
      * constructor with their corresponding cursor columns as specified in the
@@ -113,17 +136,22 @@
      */
     @Override
     public void bindView(View view, Context context, Cursor cursor) {
-        for (int i = 0; i < mTo.length; i++) {
-            final View v = view.findViewById(mTo[i]);
+        final View[] holder = (View[]) view.getTag();
+        final ViewBinder binder = mViewBinder;
+        final int count = mTo.length;
+        final int[] from = mFrom;
+
+        for (int i = 0; i < count; i++) {
+            final View v = holder[i];
             if (v != null) {
-                String text = cursor.getString(mFrom[i]);
+                String text = cursor.getString(from[i]);
                 if (text == null) {
                     text = "";
                 }
 
                 boolean bound = false;
-                if (mViewBinder != null) {
-                    bound = mViewBinder.setViewValue(v, cursor, mFrom[i]);
+                if (binder != null) {
+                    bound = binder.setViewValue(v, cursor, from[i]);
                 }
 
                 if (!bound) {
diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java
index d72ffb1..afa2f3b 100644
--- a/core/java/android/widget/TableLayout.java
+++ b/core/java/android/widget/TableLayout.java
@@ -101,11 +101,9 @@
     public TableLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        TypedArray a =
-                context.obtainStyledAttributes(attrs, R.styleable.TableLayout);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TableLayout);
 
-        String stretchedColumns =
-                a.getString(R.styleable.TableLayout_stretchColumns);
+        String stretchedColumns = a.getString(R.styleable.TableLayout_stretchColumns);
         if (stretchedColumns != null) {
             if (stretchedColumns.charAt(0) == '*') {
                 mStretchAllColumns = true;
@@ -114,8 +112,7 @@
             }
         }
 
-        String shrinkedColumns =
-                a.getString(R.styleable.TableLayout_shrinkColumns);
+        String shrinkedColumns = a.getString(R.styleable.TableLayout_shrinkColumns);
         if (shrinkedColumns != null) {
             if (shrinkedColumns.charAt(0) == '*') {
                 mShrinkAllColumns = true;
@@ -124,8 +121,7 @@
             }
         }
 
-        String collapsedColumns =
-                a.getString(R.styleable.TableLayout_collapseColumns);
+        String collapsedColumns = a.getString(R.styleable.TableLayout_collapseColumns);
         if (collapsedColumns != null) {
             mCollapsedColumns = parseColumns(collapsedColumns);
         }
@@ -356,7 +352,7 @@
      * @return true if the column is shrinkable, false otherwise. Default is false.
      */
     public boolean isColumnShrinkable(int columnIndex) {
-        return mShrinkAllColumns || mStretchableColumns.get(columnIndex);
+        return mShrinkAllColumns || mShrinkableColumns.get(columnIndex);
     }
 
     /**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bd5db33..9e5f019 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -20,6 +20,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Path;
@@ -27,10 +28,12 @@
 import android.graphics.RectF;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.os.Message;
 import android.text.BoringLayout;
 import android.text.DynamicLayout;
 import android.text.Editable;
@@ -49,12 +52,16 @@
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.text.TextWatcher;
+import android.text.method.DateKeyListener;
+import android.text.method.DateTimeKeyListener;
 import android.text.method.DialerKeyListener;
 import android.text.method.DigitsKeyListener;
 import android.text.method.KeyListener;
 import android.text.method.LinkMovementMethod;
 import android.text.method.MetaKeyKeyListener;
 import android.text.method.MovementMethod;
+import android.text.method.TimeKeyListener;
+
 import android.text.method.PasswordTransformationMethod;
 import android.text.method.SingleLineTransformationMethod;
 import android.text.method.TextKeyListener;
@@ -78,12 +85,22 @@
 import android.view.ViewTreeObserver;
 import android.view.ViewGroup.LayoutParams;
 import android.view.animation.AnimationUtils;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.EditorInfo;
 import android.widget.RemoteViews.RemoteView;
 
+import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
 import com.android.internal.util.FastMath;
+import com.android.internal.widget.EditableInputConnection;
+
+import org.xmlpull.v1.XmlPullParserException;
 
 /**
  * Displays text to the user and optionally allows them to edit it.  A TextView
@@ -146,6 +163,7 @@
  * @attr ref android.R.styleable#TextView_drawableLeft
  * @attr ref android.R.styleable#TextView_lineSpacingExtra
  * @attr ref android.R.styleable#TextView_lineSpacingMultiplier
+ * @attr ref android.R.styleable#TextView_marqueeRepeatLimit
  */
 @RemoteView
 public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
@@ -182,22 +200,44 @@
     private static final int SIGNED = 2;
     private static final int DECIMAL = 4;
 
-    private Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight;
-    private int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight;
-    private int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight;
-    private boolean mDrawables;
-    private int mDrawablePadding;
+    class Drawables {
+        final Rect mCompoundRect = new Rect();
+        Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight;
+        int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight;
+        int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight;
+        int mDrawablePadding;
+    };
+    private Drawables mDrawables;
 
     private CharSequence mError;
     private boolean mErrorWasChanged;
     private PopupWindow mPopup;
 
     private CharWrapper mCharWrapper = null;
-    private Rect mCompoundRect;
 
     private boolean mSelectionMoved = false;
 
-    /* 
+    private Marquee mMarquee;
+    private boolean mRestartMarquee;
+
+    private int mMarqueeRepeatLimit = 3;
+
+    class InputContentType {
+        String privateContentType;
+        Bundle extras;
+    }
+    InputContentType mInputContentType;
+
+    class InputMethodState {
+        Rect mCursorRectInWindow = new Rect();
+        RectF mTmpRectF = new RectF();
+        float[] mTmpOffset = new float[2];
+        ExtractedTextRequest mExtracting;
+        final ExtractedText mTmpExtracted = new ExtractedText();
+    }
+    InputMethodState mInputMethodState;
+
+    /*
      * Kick-start the font cache for the zygote process (to pay the cost of
      * initializing freetype for our default font only once).
      */
@@ -221,7 +261,6 @@
                     AttributeSet attrs,
                     int defStyle) {
         super(context, attrs, defStyle);
-
         mText = "";
 
         mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
@@ -250,7 +289,7 @@
          * Look the appearance up without checking first if it exists because
          * almost every TextView has one and it greatly simplifies the logic
          * to be able to parse the appearance first and then let specific tags
-         * for this View override it.   
+         * for this View override it.
          */
         TypedArray appearance = null;
         int ap = a.getResourceId(com.android.internal.R.styleable.TextView_textAppearance, -1);
@@ -317,6 +356,7 @@
         int shadowcolor = 0;
         float dx = 0, dy = 0, r = 0;
         boolean password = false;
+        int contentType = EditorInfo.TYPE_NULL;
 
         int n = a.getIndexCount();
         for (int i = 0; i < n; i++) {
@@ -461,6 +501,10 @@
                 ellipsize = a.getInt(attr, ellipsize);
                 break;
 
+            case com.android.internal.R.styleable.TextView_marqueeRepeatLimit:
+                setMarqueeRepeatLimit(a.getInt(attr, mMarqueeRepeatLimit));
+                break;
+
             case com.android.internal.R.styleable.TextView_includeFontPadding:
                 if (!a.getBoolean(attr, true)) {
                     setIncludeFontPadding(false);
@@ -544,12 +588,37 @@
             case com.android.internal.R.styleable.TextView_lineSpacingMultiplier:
                 mSpacingMult = a.getFloat(attr, mSpacingMult);
                 break;
+
+            case com.android.internal.R.styleable.TextView_inputType:
+                contentType = a.getInt(attr, mInputType);
+                break;
+
+            case com.android.internal.R.styleable.TextView_editorPrivateContentType:
+                setPrivateContentType(a.getString(attr));
+                break;
+
+            case com.android.internal.R.styleable.TextView_editorExtras:
+                try {
+                    setInputExtras(a.getResourceId(attr, 0));
+                } catch (XmlPullParserException e) {
+                    Log.w("TextView", "Failure reading input extras", e);
+                } catch (IOException e) {
+                    Log.w("TextView", "Failure reading input extras", e);
+                }
+                break;
             }
         }
         a.recycle();
 
         BufferType bufferType = BufferType.EDITABLE;
 
+        if ((contentType&(EditorInfo.TYPE_MASK_CLASS
+                |EditorInfo.TYPE_MASK_VARIATION))
+                == (EditorInfo.TYPE_CLASS_TEXT
+                        |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) {
+            password = true;
+        }
+
         if (inputMethod != null) {
             Class c;
 
@@ -566,27 +635,58 @@
             } catch (IllegalAccessException ex) {
                 throw new RuntimeException(ex);
             }
+            try {
+                mInputType = contentType != EditorInfo.TYPE_NULL
+                        ? contentType
+                        : mInput.getInputType();
+            } catch (IncompatibleClassChangeError e) {
+                mInputType = EditorInfo.TYPE_CLASS_TEXT;
+            }
         } else if (digits != null) {
             mInput = DigitsKeyListener.getInstance(digits.toString());
+            mInputType = contentType;
+        } else if (contentType != EditorInfo.TYPE_NULL) {
+            setInputType(contentType, true);
+            singleLine = (contentType&(EditorInfo.TYPE_MASK_CLASS
+                            | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)) !=
+                    (EditorInfo.TYPE_CLASS_TEXT
+                            | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE);
         } else if (phone) {
             mInput = DialerKeyListener.getInstance();
+            contentType = EditorInfo.TYPE_CLASS_PHONE;
         } else if (numeric != 0) {
             mInput = DigitsKeyListener.getInstance((numeric & SIGNED) != 0,
                                                    (numeric & DECIMAL) != 0);
+            contentType = EditorInfo.TYPE_CLASS_NUMBER;
+            if ((numeric & SIGNED) != 0) {
+                contentType |= EditorInfo.TYPE_NUMBER_FLAG_SIGNED;
+            }
+            if ((numeric & DECIMAL) != 0) {
+                contentType |= EditorInfo.TYPE_NUMBER_FLAG_DECIMAL;
+            }
+            mInputType = contentType;
         } else if (autotext || autocap != -1) {
             TextKeyListener.Capitalize cap;
 
+            contentType = EditorInfo.TYPE_CLASS_TEXT;
+            if (!singleLine) {
+                contentType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+            }
+
             switch (autocap) {
             case 1:
                 cap = TextKeyListener.Capitalize.SENTENCES;
+                contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES;
                 break;
 
             case 2:
                 cap = TextKeyListener.Capitalize.WORDS;
+                contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
                 break;
 
             case 3:
                 cap = TextKeyListener.Capitalize.CHARACTERS;
+                contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS;
                 break;
 
             default:
@@ -595,8 +695,10 @@
             }
 
             mInput = TextKeyListener.getInstance(autotext, cap);
+            mInputType = contentType;
         } else if (editable) {
             mInput = TextKeyListener.getInstance();
+            mInputType = EditorInfo.TYPE_CLASS_TEXT;
         } else {
             mInput = null;
 
@@ -611,6 +713,12 @@
                     bufferType = BufferType.EDITABLE;
                     break;
             }
+            mInputType = EditorInfo.TYPE_CLASS_TEXT;
+        }
+
+        if (password) {
+            mInputType = (mInputType & ~(EditorInfo.TYPE_MASK_VARIATION))
+                | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD;
         }
 
         if (selectallonfocus) {
@@ -642,6 +750,10 @@
             case 3:
                 setEllipsize(TextUtils.TruncateAt.END);
                 break;
+            case 4:
+                setHorizontalFadingEdgeEnabled(true);
+                setEllipsize(TextUtils.TruncateAt.MARQUEE);
+                break;
         }
 
         setTextColor(textColor != null ? textColor : ColorStateList.valueOf(0xFF000000));
@@ -774,11 +886,14 @@
     }
 
     /**
-     * Return the text the TextView is displaying.  If setText() was called
-     * with an argument of BufferType.SPANNABLE or BufferType.EDITABLE,
-     * you can cast the return value from this method to Spannable
-     * or Editable, respectively.
+     * Return the text the TextView is displaying. If setText() was called with
+     * an argument of BufferType.SPANNABLE or BufferType.EDITABLE, you can cast
+     * the return value from this method to Spannable or Editable, respectively.
+     *
+     * Note: The content of the return value should not be modified. If you want
+     * a modifiable one, you should make your own copy first.
      */
+    @ViewDebug.CapturedViewProperty
     public CharSequence getText() {
         return mText;
     }
@@ -791,6 +906,16 @@
     }
 
     /**
+     * Return the text the TextView is displaying as an Editable object.  If
+     * the text is not editable, null is returned.
+     *
+     * @see #getText
+     */
+    public Editable getEditableText() {
+        return (mText instanceof Editable) ? (Editable)mText : null;
+    }
+
+    /**
      * @return the height of one standard line in pixels.  Note that markup
      * within the text can cause individual lines to be taller or shorter
      * than this height, and the layout may contain additional first-
@@ -819,7 +944,12 @@
 
     /**
      * Sets the key listener to be used with this TextView.  This can be null
-     * to disallow user input.
+     * to disallow user input.  Note that this method has significant and
+     * subtle interactions with soft keyboards and other input method:
+     * see {@link KeyListener#getInputType() KeyListener.getContentType()}
+     * for important details.  Calling this method will replace the current
+     * content type of the text view with the content type returned by the
+     * key listener.
      * <p>
      * Be warned that if you want a TextView with a key listener or movement
      * method not to be focusable, or if you want a TextView without a
@@ -835,13 +965,37 @@
      * @attr ref android.R.styleable#TextView_autoText
      */
     public void setKeyListener(KeyListener input) {
-        mInput = input;
+        setKeyListenerOnly(input);
+        fixFocusableAndClickableSettings();
 
+        if (input != null) {
+            try {
+                mInputType = mInput.getInputType();
+            } catch (IncompatibleClassChangeError e) {
+                mInputType = EditorInfo.TYPE_CLASS_TEXT;
+            }
+            if ((mInputType&EditorInfo.TYPE_MASK_CLASS)
+                    == EditorInfo.TYPE_CLASS_TEXT) {
+                if (mSingleLine) {
+                    mInputType &= ~EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+                } else {
+                    mInputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+                }
+            }
+        } else {
+            mInputType = EditorInfo.TYPE_NULL;
+        }
+
+        InputMethodManager imm = InputMethodManager.peekInstance();
+        if (imm != null) imm.restartInput(this);
+    }
+
+    private void setKeyListenerOnly(KeyListener input) {
+        mInput = input;
         if (mInput != null && !(mText instanceof Editable))
             setText(mText);
 
         setFilters((Editable) mText, mFilters);
-        fixFocusableAndClickableSettings();
     }
 
     /**
@@ -873,7 +1027,7 @@
     }
 
     private void fixFocusableAndClickableSettings() {
-        if (mMovement != null || mInput != null) {
+        if ((mMovement != null) || mInput != null) {
             setFocusable(true);
             setClickable(true);
             setLongClickable(true);
@@ -917,10 +1071,11 @@
      * Drawable if any.
      */
     public int getCompoundPaddingTop() {
-        if (mDrawableTop == null) {
+        final Drawables dr = mDrawables;
+        if (dr == null || dr.mDrawableTop == null) {
             return mPaddingTop;
         } else {
-            return mPaddingTop + mDrawablePadding + mDrawableSizeTop;
+            return mPaddingTop + dr.mDrawablePadding + dr.mDrawableSizeTop;
         }
     }
 
@@ -929,10 +1084,11 @@
      * Drawable if any.
      */
     public int getCompoundPaddingBottom() {
-        if (mDrawableBottom == null) {
+        final Drawables dr = mDrawables;
+        if (dr == null || dr.mDrawableBottom == null) {
             return mPaddingBottom;
         } else {
-            return mPaddingBottom + mDrawablePadding + mDrawableSizeBottom;
+            return mPaddingBottom + dr.mDrawablePadding + dr.mDrawableSizeBottom;
         }
     }
 
@@ -941,10 +1097,11 @@
      * Drawable if any.
      */
     public int getCompoundPaddingLeft() {
-        if (mDrawableLeft == null) {
+        final Drawables dr = mDrawables;
+        if (dr == null || dr.mDrawableLeft == null) {
             return mPaddingLeft;
         } else {
-            return mPaddingLeft + mDrawablePadding + mDrawableSizeLeft;
+            return mPaddingLeft + dr.mDrawablePadding + dr.mDrawableSizeLeft;
         }
     }
 
@@ -953,10 +1110,11 @@
      * Drawable if any.
      */
     public int getCompoundPaddingRight() {
-        if (mDrawableRight == null) {
+        final Drawables dr = mDrawables;
+        if (dr == null || dr.mDrawableRight == null) {
             return mPaddingRight;
         } else {
-            return mPaddingRight + mDrawablePadding + mDrawableSizeRight;
+            return mPaddingRight + dr.mDrawablePadding + dr.mDrawableSizeRight;
         }
     }
 
@@ -1043,7 +1201,7 @@
     }
 
     /**
-     * Returns the total top padding of the view, including the top 
+     * Returns the total top padding of the view, including the top
      * Drawable if any, the extra space to keep more than maxLines
      * from showing, and the vertical offset for gravity, if any.
      */
@@ -1073,62 +1231,79 @@
      */
     public void setCompoundDrawables(Drawable left, Drawable top,
                                      Drawable right, Drawable bottom) {
-        mDrawableLeft = left;
-        mDrawableTop = top;
-        mDrawableRight = right;
-        mDrawableBottom = bottom;
+        Drawables dr = mDrawables;
 
-        mDrawables = mDrawableLeft != null
-                || mDrawableRight != null
-                || mDrawableTop != null
-                || mDrawableBottom != null;
+        final boolean drawables = left != null || top != null
+                || right != null || bottom != null;
 
-        if (mCompoundRect == null &&
-                (left != null || top != null || right != null || bottom != null)) {
-            mCompoundRect = new Rect();
-        }
+        if (!drawables) {
+            // Clearing drawables...  can we free the data structure?
+            if (dr != null) {
+                if (dr.mDrawablePadding == 0) {
+                    mDrawables = null;
+                } else {
+                    // We need to retain the last set padding, so just clear
+                    // out all of the fields in the existing structure.
+                    dr.mDrawableLeft = null;
+                    dr.mDrawableTop = null;
+                    dr.mDrawableRight = null;
+                    dr.mDrawableBottom = null;
+                    dr.mDrawableSizeLeft = dr.mDrawableHeightLeft = 0;
+                    dr.mDrawableSizeRight = dr.mDrawableHeightRight = 0;
+                    dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
+                    dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0;
+                }
+            }
+        } else {
+            if (dr == null) {
+                mDrawables = dr = new Drawables();
+            }
 
-        final Rect compoundRect = mCompoundRect;
-        int[] state = null;
-        
-        if (mDrawables) {
+            dr.mDrawableLeft = left;
+            dr.mDrawableTop = top;
+            dr.mDrawableRight = right;
+            dr.mDrawableBottom = bottom;
+
+            final Rect compoundRect = dr.mCompoundRect;
+            int[] state = null;
+
             state = getDrawableState();
-        }
-        
-        if (mDrawableLeft != null) {
-            mDrawableLeft.setState(state);
-            mDrawableLeft.copyBounds(compoundRect);
-            mDrawableSizeLeft = compoundRect.width();
-            mDrawableHeightLeft = compoundRect.height();
-        } else {
-            mDrawableSizeLeft = mDrawableHeightLeft = 0;
-        }
 
-        if (mDrawableRight != null) {
-            mDrawableRight.setState(state);
-            mDrawableRight.copyBounds(compoundRect);
-            mDrawableSizeRight = compoundRect.width();
-            mDrawableHeightRight = compoundRect.height();
-        } else {
-            mDrawableSizeRight = mDrawableHeightRight = 0;
-        }
+            if (left != null) {
+                left.setState(state);
+                left.copyBounds(compoundRect);
+                dr.mDrawableSizeLeft = compoundRect.width();
+                dr.mDrawableHeightLeft = compoundRect.height();
+            } else {
+                dr.mDrawableSizeLeft = dr.mDrawableHeightLeft = 0;
+            }
 
-        if (mDrawableTop != null) {
-            mDrawableTop.setState(state);
-            mDrawableTop.copyBounds(compoundRect);
-            mDrawableSizeTop = compoundRect.height();
-            mDrawableWidthTop = compoundRect.width();
-        } else {
-            mDrawableSizeTop = mDrawableWidthTop = 0;
-        }
+            if (right != null) {
+                right.setState(state);
+                right.copyBounds(compoundRect);
+                dr.mDrawableSizeRight = compoundRect.width();
+                dr.mDrawableHeightRight = compoundRect.height();
+            } else {
+                dr.mDrawableSizeRight = dr.mDrawableHeightRight = 0;
+            }
 
-        if (mDrawableBottom != null) {
-            mDrawableBottom.setState(state);
-            mDrawableBottom.copyBounds(compoundRect);
-            mDrawableSizeBottom = compoundRect.height();
-            mDrawableWidthBottom = compoundRect.width();
-        } else {
-            mDrawableSizeBottom = mDrawableWidthBottom = 0;
+            if (top != null) {
+                top.setState(state);
+                top.copyBounds(compoundRect);
+                dr.mDrawableSizeTop = compoundRect.height();
+                dr.mDrawableWidthTop = compoundRect.width();
+            } else {
+                dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
+            }
+
+            if (bottom != null) {
+                bottom.setState(state);
+                bottom.copyBounds(compoundRect);
+                dr.mDrawableSizeBottom = compoundRect.height();
+                dr.mDrawableWidthBottom = compoundRect.width();
+            } else {
+                dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0;
+            }
         }
 
         invalidate();
@@ -1137,8 +1312,32 @@
 
     /**
      * Sets the Drawables (if any) to appear to the left of, above,
+     * to the right of, and below the text.  Use 0 if you do not
+     * want a Drawable there. The Drawables' bounds will be set to
+     * their intrinsic bounds.
+     *
+     * @param left Resource identifier of the left Drawable.
+     * @param top Resource identifier of the top Drawable.
+     * @param right Resource identifier of the right Drawable.
+     * @param bottom Resource identifier of the bottom Drawable.
+     *
+     * @attr ref android.R.styleable#TextView_drawableLeft
+     * @attr ref android.R.styleable#TextView_drawableTop
+     * @attr ref android.R.styleable#TextView_drawableRight
+     * @attr ref android.R.styleable#TextView_drawableBottom
+     */
+    public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) {
+        final Resources resources = getContext().getResources();
+        setCompoundDrawables(left != 0 ? resources.getDrawable(left) : null,
+                top != 0 ? resources.getDrawable(top) : null,
+                right != 0 ? resources.getDrawable(right) : null,
+                bottom != 0 ? resources.getDrawable(bottom) : null);
+    }
+
+    /**
+     * Sets the Drawables (if any) to appear to the left of, above,
      * to the right of, and below the text.  Use null if you do not
-     * want a Drawable there.  The Drawables' bounds will be set to
+     * want a Drawable there. The Drawables' bounds will be set to
      * their intrinsic bounds.
      *
      * @attr ref android.R.styleable#TextView_drawableLeft
@@ -1146,24 +1345,20 @@
      * @attr ref android.R.styleable#TextView_drawableRight
      * @attr ref android.R.styleable#TextView_drawableBottom
      */
-    public void setCompoundDrawablesWithIntrinsicBounds(Drawable left,
-                                     Drawable top,
-                                     Drawable right, Drawable bottom) {
+    public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top,
+            Drawable right, Drawable bottom) {
+
         if (left != null) {
-            left.setBounds(0, 0,
-                           left.getIntrinsicWidth(), left.getIntrinsicHeight());
+            left.setBounds(0, 0, left.getIntrinsicWidth(), left.getIntrinsicHeight());
         }
         if (right != null) {
-            right.setBounds(0, 0,
-                           right.getIntrinsicWidth(), right.getIntrinsicHeight());
+            right.setBounds(0, 0, right.getIntrinsicWidth(), right.getIntrinsicHeight());
         }
         if (top != null) {
-            top.setBounds(0, 0,
-                           top.getIntrinsicWidth(), top.getIntrinsicHeight());
+            top.setBounds(0, 0, top.getIntrinsicWidth(), top.getIntrinsicHeight());
         }
         if (bottom != null) {
-            bottom.setBounds(0, 0,
-                           bottom.getIntrinsicWidth(), bottom.getIntrinsicHeight());
+            bottom.setBounds(0, 0, bottom.getIntrinsicWidth(), bottom.getIntrinsicHeight());
         }
         setCompoundDrawables(left, top, right, bottom);
     }
@@ -1172,9 +1367,14 @@
      * Returns drawables for the left, top, right, and bottom borders.
      */
     public Drawable[] getCompoundDrawables() {
-        return new Drawable[] {
-            mDrawableLeft, mDrawableTop, mDrawableRight, mDrawableBottom
-        };
+        final Drawables dr = mDrawables;
+        if (dr != null) {
+            return new Drawable[] {
+                dr.mDrawableLeft, dr.mDrawableTop, dr.mDrawableRight, dr.mDrawableBottom
+            };
+        } else {
+            return new Drawable[] { null, null, null, null };
+        }
     }
 
     /**
@@ -1184,7 +1384,17 @@
      * @attr ref android.R.styleable#TextView_drawablePadding
      */
     public void setCompoundDrawablePadding(int pad) {
-        mDrawablePadding = pad;
+        Drawables dr = mDrawables;
+        if (pad == 0) {
+            if (dr != null) {
+                dr.mDrawablePadding = pad;
+            }
+        } else {
+            if (dr == null) {
+                mDrawables = dr = new Drawables();
+            }
+            dr.mDrawablePadding = pad;
+        }
 
         invalidate();
         requestLayout();
@@ -1194,7 +1404,8 @@
      * Returns the padding between the compound drawables and the text.
      */
     public int getCompoundDrawablePadding() {
-        return mDrawablePadding;
+        final Drawables dr = mDrawables;
+        return dr != null ? dr.mDrawablePadding : 0;
     }
 
     @Override
@@ -1910,18 +2121,21 @@
             updateTextColors();
         }
 
-        int[] state = getDrawableState();
-        if (mDrawableTop != null && mDrawableTop.isStateful()) {
-            mDrawableTop.setState(state);
-        }
-        if (mDrawableBottom != null && mDrawableBottom.isStateful()) {
-            mDrawableBottom.setState(state);
-        }
-        if (mDrawableLeft != null && mDrawableLeft.isStateful()) {
-            mDrawableLeft.setState(state);
-        }
-        if (mDrawableRight != null && mDrawableRight.isStateful()) {
-            mDrawableRight.setState(state);
+        final Drawables dr = mDrawables;
+        if (dr != null) {
+            int[] state = getDrawableState();
+            if (dr.mDrawableTop != null && dr.mDrawableTop.isStateful()) {
+                dr.mDrawableTop.setState(state);
+            }
+            if (dr.mDrawableBottom != null && dr.mDrawableBottom.isStateful()) {
+                dr.mDrawableBottom.setState(state);
+            }
+            if (dr.mDrawableLeft != null && dr.mDrawableLeft.isStateful()) {
+                dr.mDrawableLeft.setState(state);
+            }
+            if (dr.mDrawableRight != null && dr.mDrawableRight.isStateful()) {
+                dr.mDrawableRight.setState(state);
+            }
         }
     }
 
@@ -1982,12 +2196,12 @@
     @Override
     public Parcelable onSaveInstanceState() {
         Parcelable superState = super.onSaveInstanceState();
-        
+
         // Save state if we are forced to
         boolean save = mFreezesText;
         int start = 0;
         int end = 0;
-        
+
         if (mText != null) {
             start = Selection.getSelectionStart(mText);
             end = Selection.getSelectionEnd(mText);
@@ -1996,7 +2210,7 @@
                 save = true;
             }
         }
-        
+
         if (save) {
             SavedState ss = new SavedState(superState);
             // XXX Should also save the current scroll position!
@@ -2030,15 +2244,20 @@
 
             return ss;
         }
-        
-        return null;
+
+        return superState;
     }
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
         SavedState ss = (SavedState)state;
         super.onRestoreInstanceState(ss.getSuperState());
-        
+
         // XXX restore buffer type too, as well as lots of other stuff
         if (ss.text != null) {
             setText(ss.text);
@@ -2165,6 +2384,12 @@
             text = "";
         }
 
+        if (text instanceof Spanned &&
+            ((Spanned) text).getSpanStart(TextUtils.TruncateAt.MARQUEE) >= 0) {
+            setHorizontalFadingEdgeEnabled(true);
+            setEllipsize(TextUtils.TruncateAt.MARQUEE);
+        }
+
         int n = mFilters.length;
         for (int i = 0; i < n; i++) {
             CharSequence out = mFilters[i].filter(text, 0, text.length(),
@@ -2183,11 +2408,19 @@
             }
         }
 
-        if (type == BufferType.EDITABLE || mInput != null) {
+        boolean needEditableForNotification = false;
+
+        if (mListeners != null && mListeners.size() != 0) {
+            needEditableForNotification = true;
+        }
+
+        if (type == BufferType.EDITABLE || mInput != null ||
+            needEditableForNotification) {
             Editable t = mEditableFactory.newEditable(text);
             text = t;
-
             setFilters(t, mFilters);
+            InputMethodManager imm = InputMethodManager.peekInstance();
+            if (imm != null) imm.restartInput(this);
         } else if (type == BufferType.SPANNABLE || mMovement != null) {
             text = mSpannableFactory.newSpannable(text);
         } else if (!(text instanceof CharWrapper)) {
@@ -2256,7 +2489,7 @@
             }
 
             if (mMovement != null) {
-                mMovement.initialize(this, (Spannable) text);            
+                mMovement.initialize(this, (Spannable) text);
 
                 /*
                  * Initializing the movement method will have set the
@@ -2273,6 +2506,10 @@
 
         sendOnTextChanged(text, 0, oldlen, textLength);
         onTextChanged(text, 0, oldlen, textLength);
+
+        if (needEditableForNotification) {
+            sendAfterTextChanged((Editable) text);
+        }
     }
 
     /**
@@ -2401,8 +2638,11 @@
 
     /**
      * Sets the text to be displayed when the text of the TextView is empty.
-     * Null means to use the normal empty text.  The hint does not
-     * currently participate in determining the size of the view.
+     * Null means to use the normal empty text. The hint does not currently
+     * participate in determining the size of the view.
+     *
+     * This method is deprecated. Use {link #setHint(int, String)} or
+     * {link #setHint(CharSequence, String)} instead.
      *
      * @attr ref android.R.styleable#TextView_hint
      */
@@ -2421,6 +2661,9 @@
      * Sets the text to be displayed when the text of the TextView is empty,
      * from a resource.
      *
+     * This method is deprecated. Use {link #setHint(int, String)} or
+     * {link #setHint(CharSequence, String)} instead.
+     *
      * @attr ref android.R.styleable#TextView_hint
      */
     public final void setHint(int resid) {
@@ -2433,11 +2676,177 @@
      *
      * @attr ref android.R.styleable#TextView_hint
      */
+    @ViewDebug.CapturedViewProperty
     public CharSequence getHint() {
         return mHint;
     }
 
     /**
+     * Set the type of the content with a constant as defined for
+     * {@link EditorInfo#inputType}.  This will take care of changing
+     * the key listener, by calling {@link #setKeyListener(KeyListener)}, to
+     * match the given content type.  If the given content type is
+     * {@link EditorInfo#TYPE_NULL} then a soft keyboard will
+     * not be displayed for this text view.
+     *
+     * @see #getInputType()
+     * @see #setRawInputType(int)
+     * @see android.text.InputType
+     * @attr ref android.R.styleable#TextView_inputType
+     */
+    public void setInputType(int type) {
+        setInputType(type, false);
+        if ((type&(EditorInfo.TYPE_MASK_CLASS
+                |EditorInfo.TYPE_MASK_VARIATION))
+                == (EditorInfo.TYPE_CLASS_TEXT
+                        |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) {
+            setTransformationMethod(PasswordTransformationMethod.getInstance());
+            setTypefaceByIndex(MONOSPACE, 0);
+        }
+        boolean multiLine = (type&(EditorInfo.TYPE_MASK_CLASS
+                        | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)) ==
+                (EditorInfo.TYPE_CLASS_TEXT
+                        | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE);
+        if (mSingleLine == multiLine) {
+            setSingleLine(!multiLine);
+        }
+        InputMethodManager imm = InputMethodManager.peekInstance();
+        if (imm != null) imm.restartInput(this);
+    }
+
+    /**
+     * Directly change the content type integer of the text view, without
+     * modifying any other state.
+     * @see #setContentType
+     * @see android.text.InputType
+     * @attr ref android.R.styleable#TextView_inputType
+     */
+    public void setRawInputType(int type) {
+        mInputType = type;
+    }
+
+    private void setInputType(int type, boolean direct) {
+        final int cls = type & EditorInfo.TYPE_MASK_CLASS;
+        KeyListener input;
+        if (cls == EditorInfo.TYPE_CLASS_TEXT) {
+            boolean autotext = (type & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT)
+                    != 0;
+            TextKeyListener.Capitalize cap;
+            if ((type & EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) {
+                cap = TextKeyListener.Capitalize.CHARACTERS;
+            } else if ((type & EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS) != 0) {
+                cap = TextKeyListener.Capitalize.WORDS;
+            } else if ((type & EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES) != 0) {
+                cap = TextKeyListener.Capitalize.SENTENCES;
+            } else {
+                cap = TextKeyListener.Capitalize.NONE;
+            }
+            input = TextKeyListener.getInstance(autotext, cap);
+        } else if (cls == EditorInfo.TYPE_CLASS_NUMBER) {
+            input = DigitsKeyListener.getInstance(
+                    (type & EditorInfo.TYPE_NUMBER_FLAG_SIGNED) != 0,
+                    (type & EditorInfo.TYPE_NUMBER_FLAG_DECIMAL) != 0);
+        } else if (cls == EditorInfo.TYPE_CLASS_DATETIME) {
+            switch (type & EditorInfo.TYPE_MASK_VARIATION) {
+                case EditorInfo.TYPE_DATETIME_VARIATION_DATE:
+                    input = DateKeyListener.getInstance();
+                    break;
+                case EditorInfo.TYPE_DATETIME_VARIATION_TIME:
+                    input = TimeKeyListener.getInstance();
+                    break;
+                default:
+                    input = DateTimeKeyListener.getInstance();
+                    break;
+            }
+        } else if (cls == EditorInfo.TYPE_CLASS_PHONE) {
+            input = DialerKeyListener.getInstance();
+        } else {
+            input = TextKeyListener.getInstance();
+        }
+        mInputType = type;
+        if (direct) mInput = input;
+        else {
+            setKeyListenerOnly(input);
+        }
+    }
+
+    /**
+     * Get the type of the content.
+     *
+     * @see #setInputType(int)
+     * @see android.text.InputType
+     */
+    public int getInputType() {
+        return mInputType;
+    }
+
+    /**
+     * Set the private content type of the text, which is the
+     * {@link EditorInfo#privateContentType TextBoxAttribute.privateContentType}
+     * field that will be filled in when creating an input connection.
+     *
+     * @see #getPrivateContentType()
+     * @see EditorInfo#privateContentType
+     * @attr ref android.R.styleable#TextView_editorPrivateContentType
+     */
+    public void setPrivateContentType(String type) {
+        if (mInputContentType == null) mInputContentType = new InputContentType();
+        mInputContentType.privateContentType = type;
+    }
+
+    /**
+     * Get the private type of the content.
+     *
+     * @see #setPrivateContentType(String)
+     * @see EditorInfo#privateContentType
+     */
+    public String getPrivateContentType() {
+        return mInputContentType != null
+                ? mInputContentType.privateContentType : null;
+    }
+
+    /**
+     * Set the extra input data of the text, which is the
+     * {@link EditorInfo#extras TextBoxAttribute.extras}
+     * Bundle that will be filled in when creating an input connection.  The
+     * given integer is the resource ID of an XML resource holding an
+     * {@link android.R.styleable#InputExtras &lt;input-extras&gt;} XML tree.
+     *
+     * @see #getInputExtras()
+     * @see EditorInfo#extras
+     * @attr ref android.R.styleable#TextView_editorExtras
+     */
+    public void setInputExtras(int xmlResId)
+            throws XmlPullParserException, IOException {
+        XmlResourceParser parser = getResources().getXml(xmlResId);
+        if (mInputContentType == null) mInputContentType = new InputContentType();
+        mInputContentType.extras = new Bundle();
+        getResources().parseBundleExtras(parser, mInputContentType.extras);
+    }
+
+    /**
+     * Retrieve the input extras currently associated with the text view, which
+     * can be viewed as well as modified.
+     *
+     * @param create If true, the extras will be created if they don't already
+     * exist.  Otherwise, null will be returned if none have been created.
+     * @see #setInputExtras(int)
+     * @see EditorInfo#extras
+     * @attr ref android.R.styleable#TextView_editorExtras
+     */
+    public Bundle getInputExtras(boolean create) {
+        if (mInputContentType == null) {
+            if (!create) return null;
+            mInputContentType = new InputContentType();
+        }
+        if (mInputContentType.extras == null) {
+            if (!create) return null;
+            mInputContentType.extras = new Bundle();
+        }
+        return mInputContentType.extras;
+    }
+
+    /**
      * Returns the error message that was set to be displayed with
      * {@link #setError}, or <code>null</code> if no error was set
      * or if it the error was cleared by the widget after user input.
@@ -2481,8 +2890,13 @@
 
         mError = error;
         mErrorWasChanged = true;
-        setCompoundDrawables(mDrawableLeft, mDrawableTop,
-                             icon, mDrawableBottom);
+        final Drawables dr = mDrawables;
+        if (dr != null) {
+            setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop,
+                                 icon, dr.mDrawableBottom);
+        } else {
+            setCompoundDrawables(null, null, icon, null);
+        }
 
         if (error == null) {
             if (mPopup != null) {
@@ -2525,9 +2939,11 @@
          * The "25" is the distance between the point and the right edge
          * of the background
          */
-        
+
+        final Drawables dr = mDrawables;
         return getWidth() - mPopup.getWidth()
-                - getPaddingRight() - mDrawableSizeRight / 2 + 25;
+                - getPaddingRight()
+                - (dr != null ? dr.mDrawableSizeRight : 0) / 2 + 25;
     }
 
     /**
@@ -2542,17 +2958,19 @@
         int vspace = mBottom - mTop -
                      getCompoundPaddingBottom() - getCompoundPaddingTop();
 
-        int icontop = getCompoundPaddingTop() +
-                                 (vspace - mDrawableHeightRight) / 2;
+        final Drawables dr = mDrawables;
+        int icontop = getCompoundPaddingTop()
+                + (vspace - (dr != null ? dr.mDrawableHeightRight : 0)) / 2;
 
         /*
          * The "2" is the distance between the point and the top edge
          * of the background.
          */
 
-        return icontop + mDrawableHeightRight - getHeight() - 2;
+        return icontop + (dr != null ? dr.mDrawableHeightRight : 0)
+                - getHeight() - 2;
     }
-    
+
     private void hideError() {
         if (mPopup != null) {
             if (mPopup.isShowing()) {
@@ -2599,6 +3017,11 @@
             mPopup.update(this, getErrorX(), getErrorY(), -1, -1);
         }
 
+        if (mRestartMarquee && mEllipsize == TextUtils.TruncateAt.MARQUEE) {
+            mRestartMarquee = false;
+            startMarquee();
+        }
+
         return result;
     }
 
@@ -2659,10 +3082,10 @@
             int boxht;
 
             if (l == mHintLayout) {
-                boxht = getMeasuredHeight() - getCompoundPaddingTop() - 
+                boxht = getMeasuredHeight() - getCompoundPaddingTop() -
                         getCompoundPaddingBottom();
             } else {
-                boxht = getMeasuredHeight() - getExtendedPaddingTop() - 
+                boxht = getMeasuredHeight() - getExtendedPaddingTop() -
                         getExtendedPaddingBottom();
             }
             int textht = l.getHeight();
@@ -2690,10 +3113,10 @@
             int boxht;
 
             if (l == mHintLayout) {
-                boxht = getMeasuredHeight() - getCompoundPaddingTop() - 
+                boxht = getMeasuredHeight() - getCompoundPaddingTop() -
                         getCompoundPaddingBottom();
             } else {
-                boxht = getMeasuredHeight() - getExtendedPaddingTop() - 
+                boxht = getMeasuredHeight() - getExtendedPaddingTop() -
                         getExtendedPaddingBottom();
             }
             int textht = l.getHeight();
@@ -2713,15 +3136,32 @@
             invalidateCursor();
         } else {
             synchronized (sTempRect) {
+                /*
+                 * The reason for this concern about the thickness of the
+                 * cursor and doing the floor/ceil on the coordinates is that
+                 * some EditTexts (notably textfields in the Browser) have
+                 * anti-aliased text where not all the characters are
+                 * necessarily at integer-multiple locations.  This should
+                 * make sure the entire cursor gets invalidated instead of
+                 * sometimes missing half a pixel.
+                 */
+
+                float thick = FloatMath.ceil(mTextPaint.getStrokeWidth());
+                if (thick < 1.0f) {
+                    thick = 1.0f;
+                }
+
+                thick /= 2;
+
                 mHighlightPath.computeBounds(sTempRect, false);
 
                 int left = getCompoundPaddingLeft();
                 int top = getExtendedPaddingTop() + getVerticalOffset(true);
 
-                invalidate((int) sTempRect.left + left,
-                           (int) sTempRect.top + top,
-                           (int) sTempRect.right + left + 1,
-                           (int) sTempRect.bottom + top + 1);
+                invalidate((int) FloatMath.floor(left + sTempRect.left - thick),
+                           (int) FloatMath.floor(top + sTempRect.top - thick),
+                           (int) FloatMath.ceil(left + sTempRect.right + thick),
+                           (int) FloatMath.ceil(top + sTempRect.bottom + thick));
             }
         }
     }
@@ -2837,6 +3277,35 @@
                 mPreDrawState = PREDRAW_NOT_REGISTERED;
             }
         }
+
+        if (mError != null) {
+            hideError();
+        }
+    }
+
+    @Override
+    protected boolean isPaddingOffsetRequired() {
+        return mShadowRadius != 0;
+    }
+
+    @Override
+    protected int getLeftPaddingOffset() {
+        return (int) Math.min(0, mShadowDx - mShadowRadius);
+    }
+
+    @Override
+    protected int getTopPaddingOffset() {
+        return (int) Math.min(0, mShadowDy - mShadowRadius);
+    }
+
+    @Override
+    protected int getBottomPaddingOffset() {
+        return (int) Math.max(0, mShadowDy + mShadowRadius);
+    }
+
+    @Override
+    protected int getRightPaddingOffset() {
+        return (int) Math.max(0, mShadowDx + mShadowRadius);
     }
 
     @Override
@@ -2855,7 +3324,8 @@
         final int bottom = mBottom;
         final int top = mTop;
 
-        if (mDrawables) {
+        final Drawables dr = mDrawables;
+        if (dr != null) {
             /*
              * Compound, not extended, because the icon is not clipped
              * if the text height is smaller.
@@ -2864,37 +3334,37 @@
             int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop;
             int hspace = right - left - compoundPaddingRight - compoundPaddingLeft;
 
-            if (mDrawableLeft != null) {
+            if (dr.mDrawableLeft != null) {
                 canvas.save();
                 canvas.translate(scrollX + mPaddingLeft,
                                  scrollY + compoundPaddingTop +
-                                 (vspace - mDrawableHeightLeft) / 2);
-                mDrawableLeft.draw(canvas);
+                                 (vspace - dr.mDrawableHeightLeft) / 2);
+                dr.mDrawableLeft.draw(canvas);
                 canvas.restore();
             }
 
-            if (mDrawableRight != null) {
+            if (dr.mDrawableRight != null) {
                 canvas.save();
-                canvas.translate(scrollX + right - left - mPaddingRight - mDrawableSizeRight,
-                         scrollY + compoundPaddingTop + (vspace - mDrawableHeightRight) / 2);
-                mDrawableRight.draw(canvas);
+                canvas.translate(scrollX + right - left - mPaddingRight - dr.mDrawableSizeRight,
+                         scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2);
+                dr.mDrawableRight.draw(canvas);
                 canvas.restore();
             }
 
-            if (mDrawableTop != null) {
+            if (dr.mDrawableTop != null) {
                 canvas.save();
-                canvas.translate(scrollX + compoundPaddingLeft + (hspace - mDrawableWidthTop) / 2,
+                canvas.translate(scrollX + compoundPaddingLeft + (hspace - dr.mDrawableWidthTop) / 2,
                         scrollY + mPaddingTop);
-                mDrawableTop.draw(canvas);
+                dr.mDrawableTop.draw(canvas);
                 canvas.restore();
             }
 
-            if (mDrawableBottom != null) {
+            if (dr.mDrawableBottom != null) {
                 canvas.save();
                 canvas.translate(scrollX + compoundPaddingLeft +
-                        (hspace - mDrawableWidthBottom) / 2,
-                         scrollY + bottom - top - mPaddingBottom - mDrawableSizeBottom);
-                mDrawableBottom.draw(canvas);
+                        (hspace - dr.mDrawableWidthBottom) / 2,
+                         scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom);
+                dr.mDrawableBottom.draw(canvas);
                 canvas.restore();
             }
         }
@@ -2929,7 +3399,7 @@
 
         canvas.save();
         /*  Would be faster if we didn't have to do this. Can we chop the
-            (displayable) text so that we don't need to do this ever? 
+            (displayable) text so that we don't need to do this ever?
         */
 
         int extendedPaddingTop = getExtendedPaddingTop();
@@ -2963,7 +3433,20 @@
             canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);
         }
 
+        if (mEllipsize == TextUtils.TruncateAt.MARQUEE) {
+            if (!mSingleLine && getLineCount() == 1 && canMarquee() &&
+                    (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
+                canvas.translate(mLayout.getLineRight(0) - (mRight - mLeft -
+                        getCompoundPaddingLeft() - getCompoundPaddingRight()), 0.0f);
+            }
+
+            if (mMarquee != null && mMarquee.isRunning()) {
+                canvas.translate(-mMarquee.mScroll, 0.0f);
+            }
+        }
+
         Path highlight = null;
+        int selStart = -1, selEnd = -1;
 
         //  If there is no movement method, then there can be no selection.
         //  Check that first and attempt to skip everything having to do with
@@ -2971,19 +3454,19 @@
         //  XXX This is not strictly true -- a program could set the
         //  selection manually if it really wanted to.
         if (mMovement != null && (isFocused() || isPressed())) {
-            int start = Selection.getSelectionStart(mText);
-            int end = Selection.getSelectionEnd(mText);
+            selStart = Selection.getSelectionStart(mText);
+            selEnd = Selection.getSelectionEnd(mText);
 
-            if (mCursorVisible && start >= 0 && isEnabled()) {
+            if (mCursorVisible && selStart >= 0 && isEnabled()) {
                 if (mHighlightPath == null)
                     mHighlightPath = new Path();
 
-                if (start == end) {
+                if (selStart == selEnd) {
                     if ((SystemClock.uptimeMillis() - mShowCursor) % (2 * BLINK)
                         < BLINK) {
                         if (mHighlightPathBogus) {
                             mHighlightPath.reset();
-                            mLayout.getCursorPath(start, mHighlightPath, mText);
+                            mLayout.getCursorPath(selStart, mHighlightPath, mText);
                             mHighlightPathBogus = false;
                         }
 
@@ -2996,7 +3479,7 @@
                 } else {
                     if (mHighlightPathBogus) {
                         mHighlightPath.reset();
-                        mLayout.getSelectionPath(start, end, mHighlightPath);
+                        mLayout.getSelectionPath(selStart, selEnd, mHighlightPath);
                         mHighlightPathBogus = false;
                     }
 
@@ -3020,6 +3503,31 @@
         }
         */
 
+        InputMethodManager imm = InputMethodManager.peekInstance();
+        if (highlight != null && mInputMethodState != null && imm != null) {
+            imm.updateSelection(this, selStart, selEnd);
+            
+            if (imm.isWatchingCursor(this)) {
+                final InputMethodState ims = mInputMethodState;
+                highlight.computeBounds(ims.mTmpRectF, true);
+                ims.mTmpOffset[0] = ims.mTmpOffset[1] = 0;
+
+                canvas.getMatrix().mapPoints(ims.mTmpOffset);
+                ims.mTmpRectF.offset(ims.mTmpOffset[0], ims.mTmpOffset[1]);
+
+                ims.mTmpRectF.offset(0, voffsetCursor - voffsetText);
+
+                ims.mCursorRectInWindow.set((int)(ims.mTmpRectF.left + 0.5),
+                        (int)(ims.mTmpRectF.top + 0.5),
+                        (int)(ims.mTmpRectF.right + 0.5),
+                        (int)(ims.mTmpRectF.bottom + 0.5));
+
+                imm.updateCursor(this,
+                        ims.mCursorRectInWindow.left, ims.mCursorRectInWindow.top,
+                        ims.mCursorRectInWindow.right, ims.mCursorRectInWindow.bottom);
+            }
+        }
+
         layout.draw(canvas, highlight, mHighlightPaint, voffsetCursor - voffsetText);
 
         /*  Comment out until we decide what to do about animations
@@ -3050,6 +3558,14 @@
 
         r.left = (int) mLayout.getPrimaryHorizontal(sel);
         r.right = r.left + 1;
+
+        // Adjust for padding and gravity.
+        int paddingLeft = getCompoundPaddingLeft();
+        int paddingTop = getExtendedPaddingTop();
+        if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
+            paddingTop += getVerticalOffset(false);
+        }
+        r.offset(paddingLeft, paddingTop);
     }
 
     /**
@@ -3106,20 +3622,67 @@
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (!isEnabled()) {
+        int which = doKeyDown(keyCode, event);
+        if (which == 0) {
+            // Go through default dispatching.
             return super.onKeyDown(keyCode, event);
         }
 
+        return true;
+    }
+
+    @Override
+    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
+        KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
+
+        int which = doKeyDown(keyCode, down);
+        if (which == 0) {
+            // Go through default dispatching.
+            return super.onKeyMultiple(keyCode, repeatCount, event);
+        }
+
+        // We are going to dispatch the remaining events to either the input
+        // or movement method.  To do this, we will just send a repeated stream
+        // of down and up events until we have done the complete repeatCount.
+        // It would be nice if those interfaces had an onKeyMultiple() method,
+        // but adding that is a more complicated change.
+        KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP);
+        if (which == 1) {
+            mInput.onKeyUp(this, (Editable)mText, keyCode, up);
+            while (--repeatCount > 0) {
+                mInput.onKeyDown(this, (Editable)mText, keyCode, down);
+                mInput.onKeyUp(this, (Editable)mText, keyCode, up);
+            }
+            if (mError != null && !mErrorWasChanged) {
+                setError(null, null);
+            }
+
+        } else if (which == 2) {
+            mMovement.onKeyUp(this, (Spannable)mText, keyCode, up);
+            while (--repeatCount > 0) {
+                mMovement.onKeyDown(this, (Spannable)mText, keyCode, down);
+                mMovement.onKeyUp(this, (Spannable)mText, keyCode, up);
+            }
+        }
+
+        return true;
+    }
+
+    private int doKeyDown(int keyCode, KeyEvent event) {
+        if (!isEnabled()) {
+            return 0;
+        }
+
         switch (keyCode) {
             case KeyEvent.KEYCODE_DPAD_CENTER:
             case KeyEvent.KEYCODE_ENTER:
                 if (mSingleLine && mInput != null) {
-                    return super.onKeyDown(keyCode, event);
+                    return 0;
                 }
         }
 
         if (mInput != null) {
-            /*  
+            /*
              * Keep track of what the error was before doing the input
              * so that if an input filter changed the error, we leave
              * that error showing.  Otherwise, we take down whatever
@@ -3131,7 +3694,7 @@
                 if (mError != null && !mErrorWasChanged) {
                     setError(null, null);
                 }
-                return true;
+                return 1;
             }
         }
 
@@ -3140,9 +3703,9 @@
 
         if (mMovement != null && mLayout != null)
             if (mMovement.onKeyDown(this, (Spannable)mText, keyCode, event))
-                return true;
+                return 2;
 
-        return super.onKeyDown(keyCode, event);
+        return 0;
     }
 
     @Override
@@ -3199,6 +3762,108 @@
         return super.onKeyUp(keyCode, event);
     }
 
+    @Override public InputConnection createInputConnection(EditorInfo outAttrs) {
+        if (mInputType != EditorInfo.TYPE_NULL) {
+            if (mInputMethodState == null) {
+                mInputMethodState = new InputMethodState();
+            }
+            outAttrs.inputType = mInputType;
+            outAttrs.hintText = mHint;
+            if (mInputContentType != null) {
+                outAttrs.privateContentType = mInputContentType.privateContentType;
+                outAttrs.extras = mInputContentType.extras;
+            }
+            if (mText instanceof Editable) {
+                InputConnection ic = new EditableInputConnection(this);
+                outAttrs.initialSelStart = Selection.getSelectionStart(mText);
+                outAttrs.initialSelEnd = Selection.getSelectionEnd(mText);
+                outAttrs.initialCapsMode = ic.getCursorCapsMode(mInputType);
+                return ic;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * If this TextView contains editable content, extract a portion of it
+     * based on the information in <var>request</var> in to <var>outText</var>.
+     * @return Returns true if the text is editable and was successfully
+     * extracted, else false.
+     */
+    public boolean extractText(ExtractedTextRequest request,
+            ExtractedText outText) {
+        Editable content = getEditableText();
+        if (content != null) {
+            outText.text = content.subSequence(0, content.length());
+            outText.startOffset = 0;
+            outText.selectionStart = Selection.getSelectionStart(content);
+            outText.selectionEnd = Selection.getSelectionEnd(content);
+            return true;
+        }
+        return false;
+    }
+    
+    void reportExtractedText() {
+        if (mInputMethodState != null) {
+            final ExtractedTextRequest req = mInputMethodState.mExtracting;
+            if (req != null) {
+                InputMethodManager imm = InputMethodManager.peekInstance();
+                if (imm != null) {
+                    if (extractText(req, mInputMethodState.mTmpExtracted)) {
+                        imm.updateExtractedText(this, req.token,
+                                mInputMethodState.mTmpExtracted);
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Apply to this text view the given extracted text, as previously
+     * returned by {@link #extractText(ExtractedTextRequest, ExtractedText)}.
+     */
+    public void setExtractedText(ExtractedText text) {
+        setText(text.text, TextView.BufferType.EDITABLE);
+        Selection.setSelection((Spannable)getText(),
+                text.selectionStart, text.selectionEnd);
+    }
+    
+    /**
+     * @hide
+     */
+    public void setExtracting(ExtractedTextRequest req) {
+        if (mInputMethodState != null) {
+            mInputMethodState.mExtracting = req;
+        }
+    }
+    
+    /**
+     * Called by the framework in response to a text completion from
+     * the current input method, provided by it calling
+     * {@link InputConnection#commitCompletion
+     * InputConnection.commitCompletion()}.  The default implementation does
+     * nothing; text views that are supporting auto-completion should override
+     * this to do their desired behavior.
+     *
+     * @param text The auto complete text the user has selected.
+     */
+    public void onCommitCompletion(CompletionInfo text) {
+    }
+
+    /**
+     * Called by the framework in response to a private command from the
+     * current method, provided by it calling
+     * {@link InputConnection#performPrivateCommand
+     * InputConnection.performPrivateCommand()}.
+     *
+     * @param action The action name of the command.
+     * @param data Any additional data for the command.  This may be null.
+     * @return Return true if you handled the command, else false.
+     */
+    public boolean onPrivateIMECommand(String action, Bundle data) {
+        return false;
+    }
+
     private void nullLayouts() {
         if (mLayout instanceof BoringLayout && mSavedLayout == null) {
             mSavedLayout = (BoringLayout) mLayout;
@@ -3240,6 +3905,8 @@
                                  BoringLayout.Metrics boring,
                                  BoringLayout.Metrics hintBoring,
                                  int ellipsisWidth, boolean bringIntoView) {
+        stopMarquee();
+
         mHighlightPathBogus = true;
 
         if (w < 0) {
@@ -3371,6 +4038,18 @@
         if (bringIntoView) {
             registerForPreDraw();
         }
+
+        if (mEllipsize == TextUtils.TruncateAt.MARQUEE) {
+            final int height = mLayoutParams.height;
+            // If the size of the view does not depend on the size of the text, try to
+            // start the marquee immediately
+            if (height != LayoutParams.WRAP_CONTENT && height != LayoutParams.FILL_PARENT) {
+                startMarquee();
+            } else {
+                // Defer the start of the marquee until we know our width (see setFrame())
+                mRestartMarquee = true;
+            }
+        }
     }
 
     private static int desired(Layout layout) {
@@ -3458,8 +4137,11 @@
                 width = boring.width;
             }
 
-            width = Math.max(width, mDrawableWidthTop);
-            width = Math.max(width, mDrawableWidthBottom);
+            final Drawables dr = mDrawables;
+            if (dr != null) {
+                width = Math.max(width, dr.mDrawableWidthTop);
+                width = Math.max(width, dr.mDrawableWidthBottom);
+            }
 
             if (mHint != null) {
                 int hintDes = -1;
@@ -3509,7 +4191,7 @@
 
             // Check against our minimum width
             width = Math.max(width, getSuggestedMinimumWidth());
-            
+
             if (widthMode == MeasureSpec.AT_MOST) {
                 width = Math.min(widthSize, width);
             }
@@ -3596,8 +4278,11 @@
         int pad = getCompoundPaddingTop() + getCompoundPaddingBottom();
         int desired = layout.getLineTop(linecount);
 
-        desired = Math.max(desired, mDrawableHeightLeft);
-        desired = Math.max(desired, mDrawableHeightRight);
+        final Drawables dr = mDrawables;
+        if (dr != null) {
+            desired = Math.max(desired, dr.mDrawableHeightLeft);
+            desired = Math.max(desired, dr.mDrawableHeightRight);
+        }
 
         desired += pad;
 
@@ -3611,8 +4296,10 @@
                     desired = layout.getLineTop(mMaximum) +
                               layout.getBottomPadding();
 
-                    desired = Math.max(desired, mDrawableHeightLeft);
-                    desired = Math.max(desired, mDrawableHeightRight);
+                    if (dr != null) {
+                        desired = Math.max(desired, dr.mDrawableHeightLeft);
+                        desired = Math.max(desired, dr.mDrawableHeightRight);
+                    }
 
                     desired += pad;
                     linecount = mMaximum;
@@ -3632,7 +4319,7 @@
 
         // Check against our minimum height
         desired = Math.max(desired, getSuggestedMinimumHeight());
-        
+
         return desired;
     }
 
@@ -3978,8 +4665,12 @@
 
     private void getInterestingRect(Rect r, int h, int top, int bottom,
                                     int line) {
-        top += getExtendedPaddingTop();
-        bottom += getExtendedPaddingTop();
+        int paddingTop = getExtendedPaddingTop();
+        if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
+            paddingTop += getVerticalOffset(false);
+        }
+        top += paddingTop;
+        bottom += paddingTop;
         h += getCompoundPaddingLeft();
 
         if (line == 0)
@@ -3987,7 +4678,7 @@
         if (line == mLayout.getLineCount() - 1)
             bottom += getExtendedPaddingBottom();
 
-        r.set(h, top, h, bottom);
+        r.set(h, top, h+1, bottom);
         r.offset(-mScrollX, -mScrollY);
     }
 
@@ -4056,6 +4747,14 @@
      */
     public void setSingleLine(boolean singleLine) {
         mSingleLine = singleLine;
+        if ((mInputType&EditorInfo.TYPE_MASK_CLASS)
+                == EditorInfo.TYPE_CLASS_TEXT) {
+            if (singleLine) {
+                mInputType &= ~EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+            } else {
+                mInputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+            }
+        }
 
         if (singleLine) {
             setLines(1);
@@ -4089,9 +4788,20 @@
     }
 
     /**
+     * Sets how many times to repeat the marquee animation. Only applied if the
+     * TextView has marquee enabled. Set to -1 to repeat indefinitely.
+     *
+     * @attr ref android.R.styleable#TextView_marqueeRepeatLimit
+     */
+    public void setMarqueeRepeatLimit(int marqueeLimit) {
+        mMarqueeRepeatLimit = marqueeLimit;
+    }
+
+    /**
      * Returns where, if anywhere, words that are longer than the view
      * is wide should be ellipsized.
      */
+    @ViewDebug.ExportedProperty
     public TextUtils.TruncateAt getEllipsize() {
         return mEllipsize;
     }
@@ -4126,6 +4836,145 @@
         }
     }
 
+    private boolean canMarquee() {
+        int width = (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight());
+        return width > 0 && mLayout.getLineWidth(0) > width;
+    }
+
+    private void startMarquee() {
+        if ((mMarquee == null || mMarquee.isStopped()) && (isFocused() || isSelected()) &&
+                getLineCount() == 1 && canMarquee()) {
+            if (mMarquee == null) mMarquee = new Marquee(this);
+            mMarquee.start(mMarqueeRepeatLimit);
+        }
+    }
+
+    private void stopMarquee() {
+        if (mMarquee != null && !mMarquee.isStopped()) {
+            mMarquee.stop();
+        }
+    }
+
+    private void startStopMarquee(boolean start) {
+        if (mEllipsize == TextUtils.TruncateAt.MARQUEE) {
+            if (start) {
+                startMarquee();
+            } else {
+                stopMarquee();
+            }
+        }
+    }
+
+    private static final class Marquee extends Handler {
+        // TODO: Add an option to configure this
+        private static final int MARQUEE_DELAY = 1200;
+        private static final int MARQUEE_RESTART_DELAY = 1200;
+        private static final int MARQUEE_RESOLUTION = 1000 / 30;
+        private static final int MARQUEE_PIXELS_PER_SECOND = 30;
+
+        private static final byte MARQUEE_STOPPED = 0x0;
+        private static final byte MARQUEE_STARTING = 0x1;
+        private static final byte MARQUEE_RUNNING = 0x2;
+
+        private static final int MESSAGE_START = 0x1;
+        private static final int MESSAGE_TICK = 0x2;
+        private static final int MESSAGE_RESTART = 0x3;
+
+        private final WeakReference<TextView> mView;
+
+        private byte mStatus = MARQUEE_STOPPED;
+        private float mScrollUnit;
+        private float mMaxScroll;
+        private int mRepeatLimit;
+
+        float mScroll;
+
+        Marquee(TextView v) {
+            mView = new WeakReference<TextView>(v);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_START:
+                    mStatus = MARQUEE_RUNNING;
+                    tick();
+                    break;
+                case MESSAGE_TICK:
+                    tick();
+                    break;
+                case MESSAGE_RESTART:
+                    if (mStatus == MARQUEE_RUNNING) {
+                        if (mRepeatLimit >= 0) {
+                            mRepeatLimit--;
+                        }
+                        start(mRepeatLimit);
+                    }
+                    break;
+            }
+        }
+
+        void tick() {
+            if (mStatus != MARQUEE_RUNNING) {
+                return;
+            }
+
+            removeMessages(MESSAGE_TICK);
+
+            final TextView textView = mView.get();
+            if (textView != null && (textView.isFocused() || textView.isSelected())) {
+                mScroll += mScrollUnit;
+                if (mScroll > mMaxScroll) {
+                    mScroll = mMaxScroll;
+                    sendEmptyMessageDelayed(MESSAGE_RESTART, MARQUEE_RESTART_DELAY);
+                } else {
+                    sendEmptyMessageDelayed(MESSAGE_TICK, MARQUEE_RESOLUTION);
+                }
+                textView.invalidate();
+            }
+        }
+
+        void stop() {
+            mStatus = MARQUEE_STOPPED;
+            removeMessages(MESSAGE_START);
+            removeMessages(MESSAGE_RESTART);
+            removeMessages(MESSAGE_TICK);
+            resetScroll();
+        }
+
+        private void resetScroll() {
+            mScroll = 0.0f;
+            final TextView textView = mView.get();
+            if (textView != null) textView.invalidate();
+        }
+
+        void start(int repeatLimit) {
+            if (repeatLimit == 0) {
+                stop();
+                return;
+            }
+            mRepeatLimit = repeatLimit;
+            final TextView textView = mView.get();
+            if (textView != null && textView.mLayout != null) {
+                mStatus = MARQUEE_STARTING;
+                mScroll = 0.0f;
+                mScrollUnit = MARQUEE_PIXELS_PER_SECOND / (float) MARQUEE_RESOLUTION;
+                mMaxScroll = textView.mLayout.getLineWidth(0) - (textView.getWidth() -
+                        textView.getCompoundPaddingLeft() - textView.getCompoundPaddingRight());
+                textView.invalidate();
+                sendEmptyMessageDelayed(MESSAGE_START, MARQUEE_DELAY);
+            }
+        }
+
+        boolean isRunning() {
+            return mStatus == MARQUEE_RUNNING;
+        }
+
+        boolean isStopped() {
+            return mStatus == MARQUEE_STOPPED;
+        }
+    }
+
     /**
      * This method is called when the text is changed, in case any
      * subclasses would like to know.
@@ -4151,6 +5000,11 @@
     /**
      * Adds a TextWatcher to the list of those whose methods are called
      * whenever this TextView's text changes.
+     * <p>
+     * In 1.0, the {@link TextWatcher#afterTextChanged} method was erroneously
+     * not called after {@link #setText} calls.  Now, doing {@link #setText}
+     * if there are any text changed listeners forces the buffer type to
+     * Editable if it would not otherwise be and does call this method.
      */
     public void addTextChangedListener(TextWatcher watcher) {
         if (mListeners == null) {
@@ -4186,7 +5040,11 @@
         }
     }
 
-    private void sendOnTextChanged(CharSequence text, int start, int before,
+    /**
+     * Not private so it can be called from an inner class without going
+     * through a thunk.
+     */
+    void sendOnTextChanged(CharSequence text, int start, int before,
                                    int after) {
         if (mListeners != null) {
             final ArrayList<TextWatcher> list = mListeners;
@@ -4197,7 +5055,11 @@
         }
     }
 
-    private void sendAfterTextChanged(Editable text) {
+    /**
+     * Not private so it can be called from an inner class without going
+     * through a thunk.
+     */
+    void sendAfterTextChanged(Editable text) {
         if (mListeners != null) {
             final ArrayList<TextWatcher> list = mListeners;
             final int count = list.size();
@@ -4207,8 +5069,91 @@
         }
     }
 
+    /**
+     * Not private so it can be called from an inner class without going
+     * through a thunk.
+     */
+    void handleTextChanged(CharSequence buffer, int start,
+            int before, int after) {
+        invalidate();
+
+        int curs = Selection.getSelectionStart(buffer);
+
+        if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) ==
+                             Gravity.BOTTOM) {
+            registerForPreDraw();
+        }
+
+        if (curs >= 0) {
+            mHighlightPathBogus = true;
+
+            if (isFocused()) {
+                mShowCursor = SystemClock.uptimeMillis();
+                makeBlink();
+            }
+        }
+
+        checkForResize();
+
+        sendOnTextChanged(buffer, start, before, after);
+        onTextChanged(buffer, start, before, after);
+    }
+    
+    /**
+     * Not private so it can be called from an inner class without going
+     * through a thunk.
+     */
+    void spanChange(Spanned buf, Object what, int o, int n) {
+        // XXX Make the start and end move together if this ends up
+        // spending too much time invalidating.
+
+        if (what == Selection.SELECTION_END) {
+            mHighlightPathBogus = true;
+
+            if (!isFocused()) {
+                mSelectionMoved = true;
+            }
+
+            if (o >= 0 || n >= 0) {
+                invalidateCursor(Selection.getSelectionStart(buf), o, n);
+                registerForPreDraw();
+
+                if (isFocused()) {
+                    mShowCursor = SystemClock.uptimeMillis();
+                    makeBlink();
+                }
+            }
+        }
+
+        if (what == Selection.SELECTION_START) {
+            mHighlightPathBogus = true;
+
+            if (!isFocused()) {
+                mSelectionMoved = true;
+            }
+
+            if (o >= 0 || n >= 0) {
+                invalidateCursor(Selection.getSelectionEnd(buf), o, n);
+            }
+        }
+
+        if (what instanceof UpdateLayout ||
+            what instanceof ParagraphStyle) {
+            invalidate();
+            mHighlightPathBogus = true;
+            checkForResize();
+        }
+
+        if (MetaKeyKeyListener.isMetaTracker(buf, what)) {
+            mHighlightPathBogus = true;
+
+            if (Selection.getSelectionStart(buf) >= 0) {
+                invalidateCursor();
+            }
+        }
+    }
+
     private class ChangeWatcher
-    extends Handler
     implements TextWatcher, SpanWatcher {
         public void beforeTextChanged(CharSequence buffer, int start,
                                       int before, int after) {
@@ -4217,95 +5162,25 @@
 
         public void onTextChanged(CharSequence buffer, int start,
                                   int before, int after) {
-            invalidate();
-
-            int curs = Selection.getSelectionStart(buffer);
-
-            if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) ==
-                                 Gravity.BOTTOM) {
-                registerForPreDraw();
-            }
-
-            if (curs >= 0) {
-                mHighlightPathBogus = true;
-
-                if (isFocused()) {
-                    mShowCursor = SystemClock.uptimeMillis();
-                    makeBlink();
-                }
-            }
-
-            checkForResize();
-
-            TextView.this.sendOnTextChanged(buffer, start, before, after);
-            TextView.this.onTextChanged(buffer, start, before, after);
+            TextView.this.handleTextChanged(buffer, start, before, after);
         }
 
         public void afterTextChanged(Editable buffer) {
             TextView.this.sendAfterTextChanged(buffer);
-        }
-
-        private void spanChange(Spanned buf, Object what, int o, int n) {
-            // XXX Make the start and end move together if this ends up
-            // spending too much time invalidating.
-
-            if (what == Selection.SELECTION_END) {
-                mHighlightPathBogus = true;
-
-                if (!isFocused()) {
-                    mSelectionMoved = true;
-                }
-
-                if (o >= 0 || n >= 0) {
-                    invalidateCursor(Selection.getSelectionStart(buf), o, n);
-                    registerForPreDraw();
-
-                    if (isFocused()) {
-                        mShowCursor = SystemClock.uptimeMillis();
-                        makeBlink();
-                    }
-                }
-            }
-
-            if (what == Selection.SELECTION_START) {
-                mHighlightPathBogus = true;
-
-                if (!isFocused()) {
-                    mSelectionMoved = true;
-                }
-
-                if (o >= 0 || n >= 0) {
-                    invalidateCursor(Selection.getSelectionEnd(buf), o, n);
-                }
-            }
-
-            if (what instanceof UpdateLayout ||
-                what instanceof ParagraphStyle) {
-                invalidate();
-                mHighlightPathBogus = true;
-                checkForResize();
-            }
-
-            if (MetaKeyKeyListener.isMetaTracker(buf, what)) {
-                mHighlightPathBogus = true;
-
-                if (Selection.getSelectionStart(buf) >= 0) {
-                    invalidateCursor();
-                }
-            }
+            TextView.this.reportExtractedText();
         }
 
         public void onSpanChanged(Spannable buf,
                                   Object what, int s, int e, int st, int en) {
-            spanChange(buf, what, s, st);
+            TextView.this.spanChange(buf, what, s, st);
         }
 
         public void onSpanAdded(Spannable buf, Object what, int s, int e) {
-            spanChange(buf, what, -1, s);
+            TextView.this.spanChange(buf, what, -1, s);
         }
 
         public void onSpanRemoved(Spannable buf, Object what, int s, int e) {
-            spanChange(buf, what, s, -1);
+            TextView.this.spanChange(buf, what, s, -1);
         }
     }
 
@@ -4378,6 +5253,8 @@
             }
         }
 
+        startStopMarquee(focused);
+
         if (mTransformation != null) {
             mTransformation.onFocusChanged(this, mText, focused, direction,
                                            previouslyFocusedRect);
@@ -4386,6 +5263,7 @@
         super.onFocusChanged(focused, direction, previouslyFocusedRect);
     }
 
+    @Override
     public void onWindowFocusChanged(boolean hasWindowFocus) {
         super.onWindowFocusChanged(hasWindowFocus);
 
@@ -4403,6 +5281,23 @@
                 mBlink.cancel();
             }
         }
+
+        startStopMarquee(hasWindowFocus);
+    }
+
+    @Override
+    public void setSelected(boolean selected) {
+        boolean wasSelected = isSelected();
+
+        super.setSelected(selected);
+
+        if (selected != wasSelected && mEllipsize == TextUtils.TruncateAt.MARQUEE) {
+            if (selected) {
+                startMarquee();
+            } else {
+                stopMarquee();
+            }
+        }
     }
 
     @Override
@@ -4421,7 +5316,18 @@
 
         if (mMovement != null && mText instanceof Spannable &&
             mLayout != null) {
-            if (mMovement.onTouchEvent(this, (Spannable) mText, event)) {
+            boolean moved = mMovement.onTouchEvent(this, (Spannable) mText, event);
+
+            if (mText instanceof Editable
+                    && mInputType != EditorInfo.TYPE_NULL) {
+                if (event.getAction() == MotionEvent.ACTION_UP && isFocused()) {
+                    InputMethodManager imm = (InputMethodManager)
+                            getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+                    imm.showSoftInput(this);
+                }
+            }
+
+            if (moved) {
                 return true;
             }
         }
@@ -4490,6 +5396,52 @@
     }
 
     @Override
+    protected float getLeftFadingEdgeStrength() {
+        if (mEllipsize == TextUtils.TruncateAt.MARQUEE) {
+            if (mMarquee != null && !mMarquee.isStopped()) {
+                final Marquee marquee = mMarquee;
+                return marquee.mScroll / getHorizontalFadingEdgeLength();
+            } else if (getLineCount() == 1) {
+                switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+                    case Gravity.LEFT:
+                        return 0.0f;
+                    case Gravity.RIGHT:
+                        return (mLayout.getLineRight(0) - (mRight - mLeft) -
+                                getCompoundPaddingLeft() - getCompoundPaddingRight() -
+                                mLayout.getLineLeft(0)) / getHorizontalFadingEdgeLength();
+                    case Gravity.CENTER_HORIZONTAL:
+                        return 0.0f;
+                }
+            }
+        }
+        return super.getLeftFadingEdgeStrength();
+    }
+
+    @Override
+    protected float getRightFadingEdgeStrength() {
+        if (mEllipsize == TextUtils.TruncateAt.MARQUEE) {
+            if (mMarquee != null && !mMarquee.isStopped()) {
+                final Marquee marquee = mMarquee;
+                return (marquee.mMaxScroll - marquee.mScroll) / getHorizontalFadingEdgeLength();
+            } else if (getLineCount() == 1) {
+                switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+                    case Gravity.LEFT:
+                        return (mLayout.getLineRight(0) - mScrollX - (mRight - mLeft) -
+                                getCompoundPaddingLeft() - getCompoundPaddingRight()) /
+                                getHorizontalFadingEdgeLength();
+                    case Gravity.RIGHT:
+                        return 0.0f;
+                    case Gravity.CENTER_HORIZONTAL:
+                        return (mLayout.getLineWidth(0) - ((mRight - mLeft) -
+                                getCompoundPaddingLeft() - getCompoundPaddingRight())) /
+                                getHorizontalFadingEdgeLength();
+                }
+            }
+        }
+        return super.getRightFadingEdgeStrength();
+    }
+
+    @Override
     protected int computeHorizontalScrollRange() {
         if (mLayout != null)
             return mLayout.getWidth();
@@ -4599,6 +5551,10 @@
     }
 
     private boolean canCut() {
+        if (mTransformation instanceof PasswordTransformationMethod) {
+            return false;
+        }
+
         if (mText.length() > 0 && getSelectionStart() >= 0) {
             if (mText instanceof Editable && mInput != null) {
                 return true;
@@ -4609,6 +5565,10 @@
     }
 
     private boolean canCopy() {
+        if (mTransformation instanceof PasswordTransformationMethod) {
+            return false;
+        }
+
         if (mText.length() > 0 && getSelectionStart() >= 0) {
             return true;
         }
@@ -4632,8 +5592,22 @@
     @Override
     protected void onCreateContextMenu(ContextMenu menu) {
         super.onCreateContextMenu(menu);
+        boolean added = false;
 
         if (!isFocused()) {
+            if (isFocusable() && mInput != null) {
+                if (canCopy()) {
+                    MenuHandler handler = new MenuHandler();
+                    int name = com.android.internal.R.string.copyAll;
+
+                    menu.add(0, ID_COPY, 0, name).
+                        setOnMenuItemClickListener(handler).
+                        setAlphabeticShortcut('c');
+                    menu.setHeaderTitle(com.android.internal.R.string.
+                        editTextMenuTitle);
+                }
+            }
+
             return;
         }
 
@@ -4644,6 +5618,7 @@
                     com.android.internal.R.string.selectAll).
                 setOnMenuItemClickListener(handler).
                 setAlphabeticShortcut('a');
+            added = true;
         }
 
         boolean selection = getSelectionStart() != getSelectionEnd();
@@ -4659,6 +5634,7 @@
             menu.add(0, ID_CUT, 0, name).
                 setOnMenuItemClickListener(handler).
                 setAlphabeticShortcut('x');
+            added = true;
         }
 
         if (canCopy()) {
@@ -4672,12 +5648,14 @@
             menu.add(0, ID_COPY, 0, name).
                 setOnMenuItemClickListener(handler).
                 setAlphabeticShortcut('c');
+            added = true;
         }
 
         if (canPaste()) {
             menu.add(0, ID_PASTE, 0, com.android.internal.R.string.paste).
                     setOnMenuItemClickListener(handler).
                     setAlphabeticShortcut('v');
+            added = true;
         }
 
         if (mText instanceof Spanned) {
@@ -4693,15 +5671,28 @@
                 menu.add(0, ID_COPY_URL, 0,
                          com.android.internal.R.string.copyUrl).
                             setOnMenuItemClickListener(handler);
+                added = true;
             }
         }
+
+        InputMethodManager imm = InputMethodManager.peekInstance();
+        if (imm != null && imm.isActive(this)) {
+            menu.add(1, ID_SWITCH_IME, 0, com.android.internal.R.string.inputMethod).
+                    setOnMenuItemClickListener(handler);
+            added = true;
+        }
+
+        if (added) {
+            menu.setHeaderTitle(com.android.internal.R.string.editTextMenuTitle);
+        }
     }
 
-    private static final int ID_SELECT_ALL = 101;
-    private static final int ID_CUT = 102;
-    private static final int ID_COPY = 103;
-    private static final int ID_PASTE = 104;
-    private static final int ID_COPY_URL = 105;
+    private static final int ID_SELECT_ALL = com.android.internal.R.id.selectAll;
+    private static final int ID_CUT = com.android.internal.R.id.cut;
+    private static final int ID_COPY = com.android.internal.R.id.copy;
+    private static final int ID_PASTE = com.android.internal.R.id.paste;
+    private static final int ID_COPY_URL = com.android.internal.R.id.copyUrl;
+    private static final int ID_SWITCH_IME = com.android.internal.R.id.inputMethod;
 
     private class MenuHandler implements MenuItem.OnMenuItemClickListener {
         public boolean onMenuItemClick(MenuItem item) {
@@ -4713,6 +5704,11 @@
         int selStart = getSelectionStart();
         int selEnd = getSelectionEnd();
 
+        if (!isFocused()) {
+            selStart = 0;
+            selEnd = mText.length();
+        }
+
         int min = Math.min(selStart, selEnd);
         int max = Math.max(selStart, selEnd);
 
@@ -4769,7 +5765,14 @@
                 }
 
                 return true;
-        }
+
+            case ID_SWITCH_IME:
+                InputMethodManager imm = InputMethodManager.peekInstance();
+                if (imm != null) {
+                    imm.showInputMethodPicker();
+                }
+                return true;
+            }
 
         return false;
     }
@@ -4790,10 +5793,12 @@
     private CharSequence            mTransformed;
     private BufferType              mBufferType = BufferType.NORMAL;
 
+    private int                     mInputType = EditorInfo.TYPE_NULL;
     private CharSequence            mHint;
     private Layout                  mHintLayout;
 
     private KeyListener             mInput;
+
     private MovementMethod          mMovement;
     private TransformationMethod    mTransformation;
     private ChangeWatcher           mChangeWatcher;
@@ -4842,7 +5847,7 @@
     // tmp primitives, so we don't alloc them on each draw
     private Path                    mHighlightPath;
     private boolean                 mHighlightPathBogus = true;
-    private static RectF            sTempRect = new RectF();
+    private static final RectF      sTempRect = new RectF();
 
     // XXX should be much larger
     private static final int        VERY_WIDE = 16384;
@@ -4858,8 +5863,6 @@
 
     private BoringLayout mSavedLayout, mSavedHintLayout;
 
-
-
     private static final InputFilter[] NO_FILTERS = new InputFilter[0];
     private InputFilter[] mFilters = NO_FILTERS;
     private static final Spanned EMPTY_SPANNED = new SpannedString("");
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index da3c2aa..df401567 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -182,6 +182,7 @@
         try {
             mMediaPlayer = new MediaPlayer();
             mMediaPlayer.setOnPreparedListener(mPreparedListener);
+            mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
             mIsPrepared = false;
             mMediaPlayer.setOnCompletionListener(mCompletionListener);
             mMediaPlayer.setOnErrorListener(mErrorListener);
@@ -220,6 +221,17 @@
         }
     }
     
+    MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
+        new MediaPlayer.OnVideoSizeChangedListener() {
+            public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
+                mVideoWidth = mp.getVideoWidth();
+                mVideoHeight = mp.getVideoHeight();
+                if (mVideoWidth != 0 && mVideoHeight != 0) {
+                    getHolder().setFixedSize(mVideoWidth, mVideoHeight);
+                }
+            }
+    };
+    
     MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
         public void onPrepared(MediaPlayer mp) {
             // briefly show the mediacontroller
@@ -241,26 +253,32 @@
                     // start the video here instead of in the callback.
                     if (mSeekWhenPrepared != 0) {
                         mMediaPlayer.seekTo(mSeekWhenPrepared);
+                        mSeekWhenPrepared = 0;
                     }
                     if (mStartWhenPrepared) {
                         mMediaPlayer.start();
+                        mStartWhenPrepared = false;
                         if (mMediaController != null) {
                             mMediaController.show();
                         }
-                   } else if (!isPlaying() && (mSeekWhenPrepared != 0 || getCurrentPosition() > 0)) {
+                    } else if (!isPlaying() &&
+                            (mSeekWhenPrepared != 0 || getCurrentPosition() > 0)) {
                        if (mMediaController != null) {
-                           mMediaController.show(0);   // show the media controls when we're paused into a video and make 'em stick.
+                           // Show the media controls when we're paused into a video and make 'em stick.
+                           mMediaController.show(0);
                        }
                    }
                 }
             } else {
-                Log.d("VideoView", "Couldn't get video size after prepare(): " +
-                        mVideoWidth + "/" + mVideoHeight);
-                // The file was probably truncated or corrupt. Start anyway, so
-                // that we play whatever short snippet is there and then get
-                // the "playback completed" event.
+                // We don't know the video size yet, but should start anyway.
+                // The video size might be reported to us later.
+                if (mSeekWhenPrepared != 0) {
+                    mMediaPlayer.seekTo(mSeekWhenPrepared);
+                    mSeekWhenPrepared = 0;
+                }
                 if (mStartWhenPrepared) {
                     mMediaPlayer.start();
+                    mStartWhenPrepared = false;
                 }
             }
         }
@@ -370,9 +388,10 @@
         {
             mSurfaceWidth = w;
             mSurfaceHeight = h;
-            if (mIsPrepared && mVideoWidth == w && mVideoHeight == h) {
+            if (mMediaPlayer != null && mIsPrepared && mVideoWidth == w && mVideoHeight == h) {
                 if (mSeekWhenPrepared != 0) {
                     mMediaPlayer.seekTo(mSeekWhenPrepared);
+                    mSeekWhenPrepared = 0;
                 }
                 mMediaPlayer.start();
                 if (mMediaController != null) {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 53b9654..989f972 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -34,6 +34,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.view.WindowManager;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
@@ -68,23 +69,33 @@
     
     private View mView;
 
-    private Button mButton1;
+    private int mViewSpacingLeft;
+    
+    private int mViewSpacingTop;
+    
+    private int mViewSpacingRight;
+    
+    private int mViewSpacingBottom;
+    
+    private boolean mViewSpacingSpecified = false;
+    
+    private Button mButtonPositive;
 
-    private CharSequence mButton1Text;
+    private CharSequence mButtonPositiveText;
 
-    private Message mButton1Message;
+    private Message mButtonPositiveMessage;
 
-    private Button mButton2;
+    private Button mButtonNegative;
 
-    private CharSequence mButton2Text;
+    private CharSequence mButtonNegativeText;
 
-    private Message mButton2Message;
+    private Message mButtonNegativeMessage;
 
-    private Button mButton3;
+    private Button mButtonNeutral;
 
-    private CharSequence mButton3Text;
+    private CharSequence mButtonNeutralText;
 
-    private Message mButton3Message;
+    private Message mButtonNeutralMessage;
 
     private ScrollView mScrollView;
     
@@ -111,12 +122,12 @@
     View.OnClickListener mButtonHandler = new View.OnClickListener() {
         public void onClick(View v) {
             Message m = null;
-            if (v == mButton1 && mButton1Message != null) {
-                m = Message.obtain(mButton1Message);
-            } else if (v == mButton2 && mButton2Message != null) {
-                m = Message.obtain(mButton2Message);
-            } else if (v == mButton3 && mButton3Message != null) {
-                m = Message.obtain(mButton3Message);
+            if (v == mButtonPositive && mButtonPositiveMessage != null) {
+                m = Message.obtain(mButtonPositiveMessage);
+            } else if (v == mButtonNegative && mButtonNegativeMessage != null) {
+                m = Message.obtain(mButtonNegativeMessage);
+            } else if (v == mButtonNeutral && mButtonNeutralMessage != null) {
+                m = Message.obtain(mButtonNeutralMessage);
             }
             if (m != null) {
                 m.sendToTarget();
@@ -142,9 +153,9 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 
-                case DialogInterface.BUTTON1:
-                case DialogInterface.BUTTON2:
-                case DialogInterface.BUTTON3:
+                case DialogInterface.BUTTON_POSITIVE:
+                case DialogInterface.BUTTON_NEGATIVE:
+                case DialogInterface.BUTTON_NEUTRAL:
                     ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
                     break;
                     
@@ -165,6 +176,10 @@
         /* We use a custom title so never request a window title */
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
         
+        if (mView == null) {
+            mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+        }
         mWindow.setContentView(com.android.internal.R.layout.alert_dialog);
         setupView();
     }
@@ -191,66 +206,64 @@
     }
 
     /**
-     * Set the view to display in that dialog.
+     * Set the view to display in the dialog.
      */
     public void setView(View view) {
         mView = view;
+        mViewSpacingSpecified = false;
     }
-
-    public void setButton(CharSequence text, Message msg) {
-        mButton1Text = text;
-        mButton1Message = msg;
-    }
-
-    public void setButton2(CharSequence text, Message msg) {
-        mButton2Text = text;
-        mButton2Message = msg;
-    }
-
-    public void setButton3(CharSequence text, Message msg) {
-        mButton3Text = text;
-        mButton3Message = msg;
+    
+    /**
+     * Set the view to display in the dialog along with the spacing around that view
+     */
+    public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight,
+            int viewSpacingBottom) {
+        mView = view;
+        mViewSpacingSpecified = true;
+        mViewSpacingLeft = viewSpacingLeft;
+        mViewSpacingTop = viewSpacingTop;
+        mViewSpacingRight = viewSpacingRight;
+        mViewSpacingBottom = viewSpacingBottom;
     }
 
     /**
-     * Set a listener to be invoked when button 1 of the dialog is pressed.
-     * @param text The text to display in button 1.
+     * Sets a click listener or a message to be sent when the button is clicked.
+     * You only need to pass one of {@code listener} or {@code msg}.
+     * 
+     * @param whichButton Which button, can be one of
+     *            {@link DialogInterface#BUTTON_POSITIVE},
+     *            {@link DialogInterface#BUTTON_NEGATIVE}, or
+     *            {@link DialogInterface#BUTTON_NEUTRAL}
+     * @param text The text to display in positive button.
      * @param listener The {@link DialogInterface.OnClickListener} to use.
+     * @param msg The {@link Message} to be sent when clicked.
      */
-    public void setButton(CharSequence text, final DialogInterface.OnClickListener listener) {
-        mButton1Text = text;
-        if (listener != null) {
-            mButton1Message = mHandler.obtainMessage(DialogInterface.BUTTON1, listener);
-        } else {
-            mButton1Message = null;
+    public void setButton(int whichButton, CharSequence text,
+            DialogInterface.OnClickListener listener, Message msg) {
+
+        if (msg == null && listener != null) {
+            msg = mHandler.obtainMessage(whichButton, listener);
         }
-    }
+        
+        switch (whichButton) {
 
-    /**
-     * Set a listener to be invoked when button 2 of the dialog is pressed.
-     * @param text The text to display in button 2.
-     * @param listener The {@link DialogInterface.OnClickListener} to use.
-     */
-    public void setButton2(CharSequence text, final DialogInterface.OnClickListener listener) {
-        mButton2Text = text;
-        if (listener != null) {
-            mButton2Message = mHandler.obtainMessage(DialogInterface.BUTTON2, listener);
-        } else {
-            mButton2Message = null;
-        }
-    }
-
-    /**
-     * Set a listener to be invoked when button 3 of the dialog is pressed.
-     * @param text The text to display in button 3.
-     * @param listener The {@link DialogInterface.OnClickListener} to use.
-     */
-    public void setButton3(CharSequence text, final DialogInterface.OnClickListener listener) {
-        mButton3Text = text;
-        if (listener != null) {
-            mButton3Message = mHandler.obtainMessage(DialogInterface.BUTTON3, listener);
-        } else {
-            mButton3Message = null;
+            case DialogInterface.BUTTON_POSITIVE:
+                mButtonPositiveText = text;
+                mButtonPositiveMessage = msg;
+                break;
+                
+            case DialogInterface.BUTTON_NEGATIVE:
+                mButtonNegativeText = text;
+                mButtonNegativeMessage = msg;
+                break;
+                
+            case DialogInterface.BUTTON_NEUTRAL:
+                mButtonNeutralText = text;
+                mButtonNeutralMessage = msg;
+                break;
+                
+            default:
+                throw new IllegalArgumentException("Button does not exist");
         }
     }
 
@@ -285,6 +298,19 @@
         return mListView;
     }
     
+    public Button getButton(int whichButton) {
+        switch (whichButton) {
+            case DialogInterface.BUTTON_POSITIVE:
+                return mButtonPositiveMessage != null ? mButtonPositive : null;
+            case DialogInterface.BUTTON_NEGATIVE:
+                return mButtonNegativeMessage != null ? mButtonNegative : null;
+            case DialogInterface.BUTTON_NEUTRAL:
+                return mButtonNeutralMessage != null ? mButtonNeutral : null;
+            default:
+                return null;
+        }
+    }
+    
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (mScrollView != null && mScrollView.executeKeyEvent(event)) return true;
         return false;
@@ -303,7 +329,7 @@
         LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel);
         TypedArray a = mContext.obtainStyledAttributes(
                 null, com.android.internal.R.styleable.AlertDialog, com.android.internal.R.attr.alertDialogStyle, 0);
-        boolean hasTitle = setupTitle(topPanel, hasButtons);
+        boolean hasTitle = setupTitle(topPanel);
             
         View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
         if (!hasButtons) {
@@ -315,6 +341,10 @@
             customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);
             FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom);
             custom.addView(mView, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
+            if (mViewSpacingSpecified) {
+                custom.setPadding(mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
+                        mViewSpacingBottom);
+            }
         } else {
             mWindow.findViewById(R.id.customPanel).setVisibility(View.GONE);
         }
@@ -331,7 +361,7 @@
         a.recycle();
     }
 
-    private boolean setupTitle(LinearLayout topPanel, boolean hasButtons) {
+    private boolean setupTitle(LinearLayout topPanel) {
         boolean hasTitle = true;
         
         if (mCustomTitleView != null) {
@@ -352,40 +382,13 @@
                 
                 /* Display the title if a title is supplied, else hide it */
                 mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle);
-                
+
                 mTitleView.setText(mTitle);
-                
-                /* The title font size and icon varies depending on 
-                 * what else is displayed within the dialog.
-                 */
-                if (mListView != null) {
-                    
-                    /* If a ListView is displayed then ensure the title 
-                     * is only 1 line and use a special icon.
-                     */
-                    mTitleView.setSingleLine();
-                    mTitleView.setEllipsize(TruncateAt.END);
-                    mIconView.setImageResource(
-                            R.drawable.ic_dialog_menu_generic);
-                } else if ((mMessage != null) && hasButtons) {
-                    
-                    /* Has a message and buttons, we want the title to
-                     * be a single line but large.
-                     */
-                    mTitleView.setSingleLine();
-                    mTitleView.setEllipsize(TruncateAt.END);
-                    mTitleView.setTextSize(getLargeTextSize());
-                } else {
-                    
-                    /* We have a Title and buttons or we have title,
-                     * and custom content. In either case the layout
-                     * handles it so do nothing.
-                     */
-                }
+                mIconView.setImageResource(R.drawable.ic_dialog_menu_generic);
                 
                 /* Do this last so that if the user has supplied any
                  * icons we use them instead of the default ones. If the
-                 * user has specified 0 then make it dissapear.
+                 * user has specified 0 then make it disappear.
                  */
                 if (mIconId > 0) {
                     mIconView.setImageResource(mIconId);
@@ -414,17 +417,6 @@
         return hasTitle;
     }
 
-    private int getLargeTextSize() {
-        TypedArray a =
-            mContext.obtainStyledAttributes(
-                    R.style.TextAppearance_Large,
-                    R.styleable.TextAppearance);
-        int textSize = a.getDimensionPixelSize(
-                R.styleable.TextAppearance_textSize, 22);
-        a.recycle();
-        return textSize;
-    }
-
     private void setupContent(LinearLayout contentPanel) {
         mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
         mScrollView.setFocusable(false);
@@ -452,65 +444,65 @@
 
     private boolean setupButtons() {
         View defaultButton = null;
-        int BUTTON1 = 1;
-        int BUTTON2 = 2;
-        int BUTTON3 = 4;
-        int whichButton = 0;
-        mButton1 = (Button) mWindow.findViewById(R.id.button1);
-        mButton1.setOnClickListener(mButtonHandler);
+        int BIT_BUTTON_POSITIVE = 1;
+        int BIT_BUTTON_NEGATIVE = 2;
+        int BIT_BUTTON_NEUTRAL = 4;
+        int whichButtons = 0;
+        mButtonPositive = (Button) mWindow.findViewById(R.id.button1);
+        mButtonPositive.setOnClickListener(mButtonHandler);
 
-        if (TextUtils.isEmpty(mButton1Text)) {
-            mButton1.setVisibility(View.GONE);
+        if (TextUtils.isEmpty(mButtonPositiveText)) {
+            mButtonPositive.setVisibility(View.GONE);
         } else {
-            mButton1.setText(mButton1Text);
-            mButton1.setVisibility(View.VISIBLE);
-            defaultButton = mButton1;
-            whichButton = whichButton | BUTTON1;
+            mButtonPositive.setText(mButtonPositiveText);
+            mButtonPositive.setVisibility(View.VISIBLE);
+            defaultButton = mButtonPositive;
+            whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
         }
 
-        mButton2 = (Button) mWindow.findViewById(R.id.button2);
-        mButton2.setOnClickListener(mButtonHandler);
+        mButtonNegative = (Button) mWindow.findViewById(R.id.button2);
+        mButtonNegative.setOnClickListener(mButtonHandler);
 
-        if (TextUtils.isEmpty(mButton2Text)) {
-            mButton2.setVisibility(View.GONE);
+        if (TextUtils.isEmpty(mButtonNegativeText)) {
+            mButtonNegative.setVisibility(View.GONE);
         } else {
-            mButton2.setText(mButton2Text);
-            mButton2.setVisibility(View.VISIBLE);
+            mButtonNegative.setText(mButtonNegativeText);
+            mButtonNegative.setVisibility(View.VISIBLE);
 
             if (defaultButton == null) {
-                defaultButton = mButton2;
+                defaultButton = mButtonNegative;
             }
-            whichButton = whichButton | BUTTON2;
+            whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
         }
 
-        mButton3 = (Button) mWindow.findViewById(R.id.button3);
-        mButton3.setOnClickListener(mButtonHandler);
+        mButtonNeutral = (Button) mWindow.findViewById(R.id.button3);
+        mButtonNeutral.setOnClickListener(mButtonHandler);
 
-        if (TextUtils.isEmpty(mButton3Text)) {
-            mButton3.setVisibility(View.GONE);
+        if (TextUtils.isEmpty(mButtonNeutralText)) {
+            mButtonNeutral.setVisibility(View.GONE);
         } else {
-            mButton3.setText(mButton3Text);
-            mButton3.setVisibility(View.VISIBLE);
+            mButtonNeutral.setText(mButtonNeutralText);
+            mButtonNeutral.setVisibility(View.VISIBLE);
 
             if (defaultButton == null) {
-                defaultButton = mButton3;
+                defaultButton = mButtonNeutral;
             }
-            whichButton = whichButton | BUTTON3;
+            whichButtons = whichButtons | BIT_BUTTON_NEUTRAL;
         }
 
         /*
          * If we only have 1 button it should be centered on the layout and
          * expand to fill 50% of the available space.
          */
-        if (whichButton == BUTTON1) {
-            centerButton(mButton1);
-        } else if (whichButton == BUTTON2) {
-            centerButton(mButton3);
-        } else if (whichButton == BUTTON3) {
-            centerButton(mButton3);
+        if (whichButtons == BIT_BUTTON_POSITIVE) {
+            centerButton(mButtonPositive);
+        } else if (whichButtons == BIT_BUTTON_NEGATIVE) {
+            centerButton(mButtonNeutral);
+        } else if (whichButtons == BIT_BUTTON_NEUTRAL) {
+            centerButton(mButtonNeutral);
         }
         
-        return whichButton != 0;
+        return whichButtons != 0;
     }
 
     private void centerButton(Button button) {
@@ -677,6 +669,11 @@
         public ListAdapter mAdapter;
         public DialogInterface.OnClickListener mOnClickListener;
         public View mView;
+        public int mViewSpacingLeft;
+        public int mViewSpacingTop;
+        public int mViewSpacingRight;
+        public int mViewSpacingBottom;
+        public boolean mViewSpacingSpecified = false;
         public boolean[] mCheckedItems;
         public boolean mIsMultiChoice;
         public boolean mIsSingleChoice;
@@ -726,13 +723,16 @@
                 dialog.setMessage(mMessage);
             }
             if (mPositiveButtonText != null) {
-                dialog.setButton(mPositiveButtonText, mPositiveButtonListener);
+                dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
+                        mPositiveButtonListener, null);
             }
             if (mNegativeButtonText != null) {
-                dialog.setButton2(mNegativeButtonText, mNegativeButtonListener);
+                dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
+                        mNegativeButtonListener, null);
             }
             if (mNeutralButtonText != null) {
-                dialog.setButton3(mNeutralButtonText, mNeutralButtonListener);
+                dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
+                        mNeutralButtonListener, null);
             }
             if (mForceInverseBackground) {
                 dialog.setInverseBackgroundForced(true);
@@ -743,7 +743,12 @@
                 createListView(dialog);
             }
             if (mView != null) {
-                dialog.setView(mView);
+                if (mViewSpacingSpecified) {
+                    dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
+                            mViewSpacingBottom);
+                } else {
+                    dialog.setView(mView);
+                }
             }
             
             /*
@@ -764,8 +769,7 @@
                     adapter = new ArrayAdapter<CharSequence>(
                             mContext, R.layout.select_dialog_multichoice, R.id.text1, mItems) {
                         @Override
-                        public View getView(int position, View convertView,
-                                ViewGroup parent) {
+                        public View getView(int position, View convertView, ViewGroup parent) {
                             View view = super.getView(position, convertView, parent);
                             if (mCheckedItems != null) {
                                 boolean isItemChecked = mCheckedItems[position];
@@ -778,24 +782,27 @@
                     };
                 } else {
                     adapter = new CursorAdapter(mContext, mCursor, false) {
-    
+                        private final int mLabelIndex;
+                        private final int mIsCheckedIndex;
+
+                        {
+                            final Cursor cursor = getCursor();
+                            mLabelIndex = cursor.getColumnIndexOrThrow(mLabelColumn);
+                            mIsCheckedIndex = cursor.getColumnIndexOrThrow(mIsCheckedColumn);
+                        }
+
                         @Override
-                        public void bindView(View view, Context context,
-                                Cursor cursor) {
+                        public void bindView(View view, Context context, Cursor cursor) {
                             CheckedTextView text = (CheckedTextView) view.findViewById(R.id.text1);
-                            text.setText(cursor.getString(cursor.getColumnIndexOrThrow(mLabelColumn)));
+                            text.setText(cursor.getString(mLabelIndex));
+                            listView.setItemChecked(cursor.getPosition(),
+                                    cursor.getInt(mIsCheckedIndex) == 1);
                         }
     
                         @Override
-                        public View newView(Context context, Cursor cursor,
-                                ViewGroup parent) {
-                            View view = mInflater.inflate(
-                                    R.layout.select_dialog_multichoice, parent, false);
-                            bindView(view, context, cursor);
-                            if (cursor.getInt(cursor.getColumnIndexOrThrow(mIsCheckedColumn)) == 1) {
-                                listView.setItemChecked(cursor.getPosition(), true);
-                            }
-                            return view;
+                        public View newView(Context context, Cursor cursor, ViewGroup parent) {
+                            return mInflater.inflate(R.layout.select_dialog_multichoice,
+                                    parent, false);
                         }
                         
                     };
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
old mode 100755
new mode 100644
index bb9fa0b..434850c
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -16,9 +16,14 @@
 
 package com.android.internal.app;
 
+import com.android.internal.os.BatteryStatsImpl;
+
 interface IBatteryStats {
+    BatteryStatsImpl getStatistics();
     void noteStartWakelock(int uid, String name, int type);
     void noteStopWakelock(int uid, String name, int type);
+    void noteStartSensor(int uid, int sensor);
+    void noteStopSensor(int uid, int sensor);
     void setOnBattery(boolean onBattery);
     long getAwakeTimeBattery();
     long getAwakeTimePlugged();
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index d5a9f8c..e907a04 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -17,9 +17,6 @@
 package com.android.internal.app;
 
 import com.android.internal.R;
-
-import android.app.Activity;
-import android.app.ListActivity;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -33,19 +30,17 @@
 import android.os.PatternMatcher;
 import android.util.Config;
 import android.util.Log;
-import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.LayoutInflater;
-import android.view.Window;
 import android.widget.BaseAdapter;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.ImageView;
-import android.widget.ListView;
 import android.widget.TextView;
-
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -55,35 +50,37 @@
  * which there is more than one matching activity, allowing the user to decide
  * which to go to.  It is not normally used directly by application developers.
  */
-public class ResolverActivity extends AlertActivity implements 
+public class ResolverActivity extends AlertActivity implements
         DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
     private ResolveListAdapter mAdapter;
     private CheckBox mAlwaysCheck;
     private TextView mClearDefaultHint;
-    
+    private PackageManager mPm;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         onCreate(savedInstanceState, new Intent(getIntent()),
                 getResources().getText(com.android.internal.R.string.whichApplication),
                 true);
     }
-    
+
     protected void onCreate(Bundle savedInstanceState, Intent intent,
             CharSequence title, boolean alwaysUseOption) {
         super.onCreate(savedInstanceState);
-
+        mPm = getPackageManager();
         intent.setComponent(null);
 
         AlertController.AlertParams ap = mAlertParams;
-        
+
         ap.mTitle = title;
         ap.mOnClickListener = this;
-        
+
         if (alwaysUseOption) {
             LayoutInflater inflater = (LayoutInflater) getSystemService(
                     Context.LAYOUT_INFLATER_SERVICE);
             ap.mView = inflater.inflate(R.layout.always_use_checkbox, null);
             mAlwaysCheck = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+            mAlwaysCheck.setText(R.string.alwaysUse);
             mAlwaysCheck.setOnCheckedChangeListener(this);
             mClearDefaultHint = (TextView)ap.mView.findViewById(
                                                         com.android.internal.R.id.clearDefaultHint);
@@ -99,10 +96,10 @@
         } else {
             ap.mMessage = getResources().getText(com.android.internal.R.string.noApplications);
         }
-        
+
         setupAlert();
     }
-    
+
     public void onClick(DialogInterface dialog, int which) {
         ResolveInfo ri = mAdapter.resolveInfoForPosition(which);
         Intent intent = mAdapter.intentForPosition(which);
@@ -110,7 +107,7 @@
         if ((mAlwaysCheck != null) && mAlwaysCheck.isChecked()) {
             // Build a reasonable intent filter, based on what matched.
             IntentFilter filter = new IntentFilter();
-            
+
             if (intent.getAction() != null) {
                 filter.addAction(intent.getAction());
             }
@@ -121,7 +118,7 @@
                 }
             }
             filter.addCategory(Intent.CATEGORY_DEFAULT);
-            
+
             int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
             Uri data = intent.getData();
             if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
@@ -136,7 +133,7 @@
                 }
             } else if (data != null && data.getScheme() != null) {
                 filter.addDataScheme(data.getScheme());
-                
+
                 // Look through the resolved filter to determine which part
                 // of it matched the original Intent.
                 Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
@@ -163,13 +160,13 @@
                     }
                 }
             }
-            
+
             if (filter != null) {
                 final int N = mAdapter.mList.size();
                 ComponentName[] set = new ComponentName[N];
                 int bestMatch = 0;
                 for (int i=0; i<N; i++) {
-                    ResolveInfo r = mAdapter.mList.get(i);
+                    ResolveInfo r = mAdapter.mList.get(i).ri;
                     set[i] = new ComponentName(r.activityInfo.packageName,
                             r.activityInfo.name);
                     if (r.match > bestMatch) bestMatch = r.match;
@@ -178,51 +175,135 @@
                         intent.getComponent());
             }
         }
-        
+
         if (intent != null) {
             startActivity(intent);
         }
         finish();
     }
-    
+
+    private final class DisplayResolveInfo {
+        ResolveInfo ri;
+        CharSequence displayLabel;
+        CharSequence extendedInfo;
+
+        DisplayResolveInfo(ResolveInfo pri, CharSequence pLabel, CharSequence pInfo) {
+            ri = pri;
+            displayLabel = pLabel;
+            extendedInfo = pInfo;
+        }
+    }
+
     private final class ResolveListAdapter extends BaseAdapter {
         private final Intent mIntent;
         private final LayoutInflater mInflater;
 
-        private List<ResolveInfo> mList;
-        
+        private List<DisplayResolveInfo> mList;
+
         public ResolveListAdapter(Context context, Intent intent) {
             mIntent = new Intent(intent);
             mIntent.setComponent(null);
             mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
-            PackageManager pm = context.getPackageManager();
-            mList = pm.queryIntentActivities(
+            List<ResolveInfo> rList = mPm.queryIntentActivities(
                     intent, PackageManager.MATCH_DEFAULT_ONLY
                     | (mAlwaysCheck != null ? PackageManager.GET_RESOLVED_FILTER : 0));
-            if (mList != null) {
-                int N = mList.size();
-                if (N > 1) {
-                    // Only display the first matches that are either of equal
-                    // priority or have asked to be default options.
-                    ResolveInfo r0 = mList.get(0);
-                    for (int i=1; i<N; i++) {
-                        ResolveInfo ri = mList.get(i);
-                        if (Config.LOGV) Log.v(
-                            "ResolveListActivity",
-                            r0.activityInfo.name + "=" +
-                            r0.priority + "/" + r0.isDefault + " vs " +
-                            ri.activityInfo.name + "=" +
-                            ri.priority + "/" + ri.isDefault);
-                        if (r0.priority != ri.priority ||
-                            r0.isDefault != ri.isDefault) {
-                            while (i < N) {
-                                mList.remove(i);
-                                N--;
-                            }
+            int N;
+            if ((rList != null) && ((N = rList.size()) > 0)) {
+                // Only display the first matches that are either of equal
+                // priority or have asked to be default options.
+                ResolveInfo r0 = rList.get(0);
+                for (int i=1; i<N; i++) {
+                    ResolveInfo ri = rList.get(i);
+                    if (Config.LOGV) Log.v(
+                        "ResolveListActivity",
+                        r0.activityInfo.name + "=" +
+                        r0.priority + "/" + r0.isDefault + " vs " +
+                        ri.activityInfo.name + "=" +
+                        ri.priority + "/" + ri.isDefault);
+                   if (r0.priority != ri.priority ||
+                        r0.isDefault != ri.isDefault) {
+                        while (i < N) {
+                            rList.remove(i);
+                            N--;
                         }
                     }
-                    Collections.sort(mList, new ResolveInfo.DisplayNameComparator(pm));
+                }
+                if (N > 1) {
+                    ResolveInfo.DisplayNameComparator rComparator =
+                            new ResolveInfo.DisplayNameComparator(mPm);
+                    Collections.sort(rList, rComparator);
+                }
+                // Check for applications with same name and use application name or
+                // package name if necessary
+                mList = new ArrayList<DisplayResolveInfo>();
+                r0 = rList.get(0);
+                int start = 0;
+                CharSequence r0Label =  r0.loadLabel(mPm);
+                for (int i = 1; i < N; i++) {
+                    if (r0Label == null) {
+                        r0Label = r0.activityInfo.packageName;
+                    }
+                    ResolveInfo ri = rList.get(i);
+                    CharSequence riLabel = ri.loadLabel(mPm);
+                    if (riLabel == null) {
+                        riLabel = ri.activityInfo.packageName;
+                    }
+                    if (riLabel.equals(r0Label)) {
+                        continue;
+                    }
+                    processGroup(rList, start, (i-1), r0, r0Label);
+                    r0 = ri;
+                    r0Label = riLabel;
+                    start = i;
+                }
+                // Process last group
+                processGroup(rList, start, (N-1), r0, r0Label);
+            }
+        }
+
+        private void processGroup(List<ResolveInfo> rList, int start, int end, ResolveInfo ro,
+                CharSequence roLabel) {
+            // Process labels from start to i
+            int num = end - start+1;
+            if (num == 1) {
+                // No duplicate labels. Use label for entry at start
+                mList.add(new DisplayResolveInfo(ro, roLabel, null));
+            } else {
+                boolean usePkg = false;
+                CharSequence startApp = ro.activityInfo.applicationInfo.loadLabel(mPm);
+                if (startApp == null) {
+                    usePkg = true;
+                }
+                if (!usePkg) {
+                    // Use HashSet to track duplicates
+                    HashSet<CharSequence> duplicates =
+                        new HashSet<CharSequence>();
+                    duplicates.add(startApp);
+                    for (int j = start+1; j <= end ; j++) {
+                        ResolveInfo jRi = rList.get(j);
+                        CharSequence jApp = jRi.activityInfo.applicationInfo.loadLabel(mPm);
+                        if ( (jApp == null) || (duplicates.contains(jApp))) {
+                            usePkg = true;
+                            break;
+                        } else {
+                            duplicates.add(jApp);
+                        }
+                    }
+                    // Clear HashSet for later use
+                    duplicates.clear();
+                }
+                for (int k = start; k <= end; k++) {
+                    ResolveInfo add = rList.get(k);
+                    if (usePkg) {
+                        // Use application name for all entries from start to end-1
+                        mList.add(new DisplayResolveInfo(add, roLabel,
+                                add.activityInfo.packageName));
+                    } else {
+                        // Use package name for all entries from start to end-1
+                        mList.add(new DisplayResolveInfo(add, roLabel,
+                                add.activityInfo.applicationInfo.loadLabel(mPm)));
+                    }
                 }
             }
         }
@@ -232,7 +313,7 @@
                 return null;
             }
 
-            return mList.get(position);
+            return mList.get(position).ri;
         }
 
         public Intent intentForPosition(int position) {
@@ -243,7 +324,7 @@
             Intent intent = new Intent(mIntent);
             intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
                     |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
-            ActivityInfo ai = mList.get(position).activityInfo;
+            ActivityInfo ai = mList.get(position).ri.activityInfo;
             intent.setComponent(new ComponentName(
                     ai.applicationInfo.packageName, ai.name));
             return intent;
@@ -273,22 +354,24 @@
             return view;
         }
 
-        private final void bindView(View view, ResolveInfo info) {
+        private final void bindView(View view, DisplayResolveInfo info) {
             TextView text = (TextView)view.findViewById(com.android.internal.R.id.text1);
+            TextView text2 = (TextView)view.findViewById(com.android.internal.R.id.text2);
             ImageView icon = (ImageView)view.findViewById(R.id.icon);
-
-            PackageManager pm = getPackageManager();
-
-            CharSequence label = info.loadLabel(pm);
-            if (label == null) label = info.activityInfo.name;
-            text.setText(label);
-            icon.setImageDrawable(info.loadIcon(pm));
+            text.setText(info.displayLabel);
+            if (info.extendedInfo != null) {
+                text2.setVisibility(View.VISIBLE);
+                text2.setText(info.extendedInfo);
+            } else {
+                text2.setVisibility(View.GONE);
+            }
+            icon.setImageDrawable(info.ri.loadIcon(mPm));
         }
     }
 
     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
         if (mClearDefaultHint == null) return;
-        
+
         if(isChecked) {
             mClearDefaultHint.setVisibility(View.VISIBLE);
         } else {
diff --git a/core/java/com/android/internal/app/RingtonePickerActivity.java b/core/java/com/android/internal/app/RingtonePickerActivity.java
index 63fe952..9c83aa3 100644
--- a/core/java/com/android/internal/app/RingtonePickerActivity.java
+++ b/core/java/com/android/internal/app/RingtonePickerActivity.java
@@ -139,6 +139,9 @@
         }
         
         mCursor = mRingtoneManager.getCursor();
+        
+        // The volume keys will control the stream that we are choosing a ringtone for
+        setVolumeControlStream(mRingtoneManager.inferStreamType());
 
         // Get the URI whose list item should have a checkmark
         mExistingUri = intent
diff --git a/core/java/com/android/internal/app/UsbStorageActivity.java b/core/java/com/android/internal/app/UsbStorageActivity.java
index 5b2bde0..b8a2136 100644
--- a/core/java/com/android/internal/app/UsbStorageActivity.java
+++ b/core/java/com/android/internal/app/UsbStorageActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -61,7 +61,7 @@
         p.mPositiveButtonText = getString(com.android.internal.R.string.usb_storage_button_mount);
         p.mPositiveButtonListener = this;
         p.mNegativeButtonText = getString(com.android.internal.R.string.usb_storage_button_unmount);
-        p.mPositiveButtonListener = this;
+        p.mNegativeButtonListener = this;
         setupAlert();
     }
 
diff --git a/core/java/com/android/internal/database/ArrayListCursor.java b/core/java/com/android/internal/database/ArrayListCursor.java
index bcbcc41..2e1d8f1 100644
--- a/core/java/com/android/internal/database/ArrayListCursor.java
+++ b/core/java/com/android/internal/database/ArrayListCursor.java
@@ -17,6 +17,7 @@
 package com.android.internal.database;
 
 import android.database.AbstractCursor;
+import android.database.CursorWindow;
 
 import java.lang.System;
 import java.util.ArrayList;
@@ -25,105 +26,146 @@
  * A convenience class that presents a two-dimensional ArrayList
  * as a Cursor.
  */
-public class ArrayListCursor extends AbstractCursor
-{
-    public ArrayListCursor(String[] columnNames, ArrayList<ArrayList> rows)
-    {        
+public class ArrayListCursor extends AbstractCursor {
+    private String[] mColumnNames;
+    private ArrayList<Object>[] mRows;
+
+    @SuppressWarnings({"unchecked"})
+    public ArrayListCursor(String[] columnNames, ArrayList<ArrayList> rows) {
         int colCount = columnNames.length;
         boolean foundID = false;
         // Add an _id column if not in columnNames
-        for (int i=0; i<colCount; ++i) {            
+        for (int i = 0; i < colCount; ++i) {
             if (columnNames[i].compareToIgnoreCase("_id") == 0) {
                 mColumnNames = columnNames;
                 foundID = true;
                 break;
             }
         }
-        
+
         if (!foundID) {
             mColumnNames = new String[colCount + 1];
             System.arraycopy(columnNames, 0, mColumnNames, 0, columnNames.length);
             mColumnNames[colCount] = "_id";
         }
-        
+
         int rowCount = rows.size();
         mRows = new ArrayList[rowCount];
-        
-        for (int i = 0; i<rowCount; ++i) {
+
+        for (int i = 0; i < rowCount; ++i) {
             mRows[i] = rows.get(i);
             if (!foundID) {
-                mRows[i].add(Long.valueOf(i));
+                mRows[i].add(i);
             }
         }
-
-     }
+    }
 
     @Override
-    public int getCount()
-    {
+    public void fillWindow(int position, CursorWindow window) {
+        if (position < 0 || position > getCount()) {
+            return;
+        }
+
+        window.acquireReference();
+        try {
+            int oldpos = mPos;
+            mPos = position - 1;
+            window.clear();
+            window.setStartPosition(position);
+            int columnNum = getColumnCount();
+            window.setNumColumns(columnNum);
+            while (moveToNext() && window.allocRow()) {
+                for (int i = 0; i < columnNum; i++) {
+                    final Object data = mRows[mPos].get(i);
+                    if (data != null) {
+                        if (data instanceof byte[]) {
+                            byte[] field = (byte[]) data;
+                            if (!window.putBlob(field, mPos, i)) {
+                                window.freeLastRow();
+                                break;
+                            }
+                        } else {
+                            String field = data.toString();
+                            if (!window.putString(field, mPos, i)) {
+                                window.freeLastRow();
+                                break;
+                            }
+                        }
+                    } else {
+                        if (!window.putNull(mPos, i)) {
+                            window.freeLastRow();
+                            break;
+                        }
+                    }
+                }
+            }
+
+            mPos = oldpos;
+        } catch (IllegalStateException e){
+            // simply ignore it
+        } finally {
+            window.releaseReference();
+        }
+    }
+
+    @Override
+    public int getCount() {
         return mRows.length;
     }
 
     @Override
-    public boolean deleteRow()
-    {
+    public boolean deleteRow() {
         return false;
     }
 
     @Override
-    public String[] getColumnNames()
-    {
+    public String[] getColumnNames() {
         return mColumnNames;
     }
 
     @Override
-    public String getString(int columnIndex)
-    {
+    public byte[] getBlob(int columnIndex) {
+        return (byte[]) mRows[mPos].get(columnIndex);
+    }
+
+    @Override
+    public String getString(int columnIndex) {
         Object cell = mRows[mPos].get(columnIndex);
         return (cell == null) ? null : cell.toString();
     }
-    
+
     @Override
-    public short getShort(int columnIndex)
-    {
-        Number num = (Number)mRows[mPos].get(columnIndex);
+    public short getShort(int columnIndex) {
+        Number num = (Number) mRows[mPos].get(columnIndex);
         return num.shortValue();
     }
 
     @Override
-    public int getInt(int columnIndex)
-    {
-        Number num = (Number)mRows[mPos].get(columnIndex);
+    public int getInt(int columnIndex) {
+        Number num = (Number) mRows[mPos].get(columnIndex);
         return num.intValue();
     }
 
     @Override
-    public long getLong(int columnIndex)
-    {
-        Number num = (Number)mRows[mPos].get(columnIndex);
+    public long getLong(int columnIndex) {
+        Number num = (Number) mRows[mPos].get(columnIndex);
         return num.longValue();
     }
 
     @Override
-    public float getFloat(int columnIndex)
-    {
-        Number num = (Number)mRows[mPos].get(columnIndex);
+    public float getFloat(int columnIndex) {
+        Number num = (Number) mRows[mPos].get(columnIndex);
         return num.floatValue();
     }
 
     @Override
-    public double getDouble(int columnIndex)
-    {
-        Number num = (Number)mRows[mPos].get(columnIndex);
+    public double getDouble(int columnIndex) {
+        Number num = (Number) mRows[mPos].get(columnIndex);
         return num.doubleValue();
     }
 
     @Override
-    public boolean isNull(int columnIndex)
-    {
+    public boolean isNull(int columnIndex) {
         return mRows[mPos].get(columnIndex) == null;
     }
-
-    private String[] mColumnNames;
-    private ArrayList<Object>[] mRows;
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.aidl b/core/java/com/android/internal/os/BatteryStatsImpl.aidl
new file mode 100644
index 0000000..0c26a3c
--- /dev/null
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.internal.os;
+
+parcelable BatteryStatsImpl;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
new file mode 100644
index 0000000..8912960
--- /dev/null
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -0,0 +1,1661 @@
+/*
+ * Copyright (C) 2006-2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.os.ParcelFormatException;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * All information we are collecting about things that can happen that impact
+ * battery life.  All times are represented in microseconds except where indicated
+ * otherwise.
+ */
+public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
+
+    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
+    private static final int MAGIC = 0xBA757475; // 'BATSTATS' 
+
+    // Current on-disk Parcel version
+    private static final int VERSION = 13;
+
+    private final File mFile;
+    private final File mBackupFile;
+
+    /**
+     * The statistics we have collected organized by uids.
+     */
+    final SparseArray<BatteryStatsImpl.Uid> mUidStats =
+        new SparseArray<BatteryStatsImpl.Uid>();
+
+    // A set of pools of currently active timers.  When a timer is queried, we will divide the
+    // elapsed time by the number of active timers to arrive at that timer's share of the time.
+    // In order to do this, we must refresh each timer whenever the number of active timers
+    // changes.
+    final ArrayList<Timer> mPartialTimers = new ArrayList<Timer>();
+    final ArrayList<Timer> mFullTimers = new ArrayList<Timer>();
+    final ArrayList<Timer> mWindowTimers = new ArrayList<Timer>();
+    final ArrayList<Timer> mSensorTimers = new ArrayList<Timer>();
+
+    int mStartCount;
+
+    long mBatteryUptime;
+    long mBatteryLastUptime;
+    long mBatteryRealtime;
+    long mBatteryLastRealtime;
+
+    long mUptime;
+    long mUptimeStart;
+    long mLastUptime;
+    long mRealtime;
+    long mRealtimeStart;
+    long mLastRealtime;
+
+    /**
+     * These provide time bases that discount the time the device is plugged
+     * in to power.
+     */
+    boolean mOnBattery;
+    long mTrackBatteryPastUptime;
+    long mTrackBatteryUptimeStart;
+    long mTrackBatteryPastRealtime;
+    long mTrackBatteryRealtimeStart;
+
+    long mLastWriteTime = 0; // Milliseconds
+
+    // For debugging
+    public BatteryStatsImpl() {
+        mFile = mBackupFile = null;
+    }
+
+    /**
+     * State for keeping track of timing information.
+     */
+    public static final class Timer extends BatteryStats.Timer {
+        ArrayList<Timer> mTimerPool;
+        
+        int mType;
+        int mNesting;
+        
+        int mCount;
+        int mLoadedCount;
+        int mLastCount;
+        
+        // Times are in microseconds for better accuracy when dividing by the lock count
+        
+        long mTotalTime; // Add mUnpluggedTotalTime to get true value
+        long mLoadedTotalTime;
+        long mLastTotalTime;
+        long mStartTime;
+        long mUpdateTime;
+        
+        /**
+         * The value of mTotalTime when unplug() was last called, initially 0.
+         */
+        long mTotalTimeAtLastUnplug;
+
+        /** Constructor used for unmarshalling only. */
+        Timer() {}
+
+        Timer(int type, ArrayList<Timer> timerPool) {
+            mType = type;
+            mTimerPool = timerPool;
+        }
+        
+        public void writeToParcel(Parcel out) {
+            out.writeInt(mType);
+            out.writeInt(mNesting);
+            out.writeInt(mCount);
+            out.writeInt(mLoadedCount);
+            out.writeInt(mLastCount);
+            out.writeLong(mTotalTime);
+            out.writeLong(mLoadedTotalTime);
+            out.writeLong(mLastTotalTime);
+            out.writeLong(mStartTime);
+            out.writeLong(mUpdateTime);
+            out.writeLong(mTotalTimeAtLastUnplug);
+        }
+
+        public void readFromParcel(Parcel in) {
+            mType = in.readInt();
+            mNesting = in.readInt();
+            mCount = in.readInt();
+            mLoadedCount = in.readInt();
+            mLastCount = in.readInt();
+            mTotalTime = in.readLong();
+            mLoadedTotalTime = in.readLong();
+            mLastTotalTime = in.readLong();
+            mStartTime = in.readLong();
+            mUpdateTime = in.readLong();
+            mTotalTimeAtLastUnplug = in.readLong();
+        }
+        
+        private void unplug() {
+            mTotalTimeAtLastUnplug += mTotalTime;
+            mTotalTime = 0;
+        }
+
+        /**
+         * Writes a possibly null Timer to a Parcel.
+         *
+         * @param out the Parcel to be written to.
+         * @param timer a Timer, or null.
+         */
+        public static void writeTimerToParcel(Parcel out, Timer timer) {
+            if (timer == null) {
+                out.writeInt(0); // indicates null
+                return;
+            }
+            out.writeInt(1); // indicates non-null
+
+            timer.writeToParcel(out);
+        }
+
+        @Override
+        public long getTotalTime(long now, int which) {
+            long val;
+            if (which == STATS_LAST) {
+                val = mLastTotalTime;
+            } else {
+                val = computeRunTimeLocked(now);
+                if (which != STATS_UNPLUGGED) {
+                    val += mTotalTimeAtLastUnplug;
+                }
+                if ((which == STATS_CURRENT) || (which == STATS_UNPLUGGED)) {
+                    val -= mLoadedTotalTime;
+                }
+            }
+
+            return val;
+        }
+
+        @Override
+        public int getCount(int which) {
+            int val;
+            if (which == STATS_LAST) {
+                val = mLastCount;
+            } else {
+                val = mCount;
+                if ((which == STATS_CURRENT) || (which == STATS_UNPLUGGED)) {
+                    val -= mLoadedCount;
+                }
+            }
+
+            return val;
+        }
+
+        void startRunningLocked(BatteryStatsImpl stats) {
+            if (mNesting++ == 0) {
+                mStartTime = mUpdateTime =
+                    stats.getBatteryUptimeLocked(SystemClock.elapsedRealtime() * 1000);
+                // Accumulate time to all other active counters with the current value of mCount
+                refreshTimersLocked(stats);
+                // Add this timer to the active pool
+                mTimerPool.add(this);
+                // Increment the count
+                mCount++;
+            }
+        }
+
+        void stopRunningLocked(BatteryStatsImpl stats) {
+            // Ignore attempt to stop a timer that isn't running
+            if (mNesting == 0) {
+                return;
+            }
+            if (--mNesting == 0) {
+                // Accumulate time to all active counters with the current value of mCount
+                refreshTimersLocked(stats);
+                // Remove this timer from the active pool
+                mTimerPool.remove(this);
+                // Decrement the count
+                mCount--;
+            }
+        }
+
+        // Update the total time for all other running Timers with the same type as this Timer
+        // due to a change in timer count
+        private void refreshTimersLocked(BatteryStatsImpl stats) {
+            for (Timer t : mTimerPool) {
+                t.updateTimeLocked(stats);
+            }
+        }
+
+        /**
+         * Update totalTime and reset updateTime
+         * @param stats
+         */
+        private void updateTimeLocked(BatteryStatsImpl stats) {
+            long realtime = SystemClock.elapsedRealtime() * 1000; 
+            long heldTime = stats.getBatteryUptimeLocked(realtime) - mUpdateTime;
+            if (heldTime > 0) {
+                mTotalTime += (heldTime * 1000) / mCount;
+            }
+            mUpdateTime = stats.getBatteryUptimeLocked(realtime);
+        }
+
+        private long computeRunTimeLocked(long curBatteryUptime) {
+            return mTotalTime +
+                (mNesting > 0 ? ((curBatteryUptime * 1000) - mUpdateTime) / mCount : 0);
+        }
+
+        void writeSummaryFromParcelLocked(Parcel out, long curBatteryUptime) {
+            long runTime = computeRunTimeLocked(curBatteryUptime);
+            // Divide by 1000 for backwards compatibility
+            out.writeLong((runTime + 500) / 1000);
+            out.writeLong(((runTime - mLoadedTotalTime) + 500) / 1000);
+            out.writeInt(mCount);
+            out.writeInt(mCount - mLoadedCount);
+        }
+
+        void readSummaryFromParcelLocked(Parcel in) {
+            // Multiply by 1000 for backwards compatibility
+            mTotalTime = mLoadedTotalTime = in.readLong() * 1000;
+            mLastTotalTime = in.readLong();
+            mCount = mLoadedCount = in.readInt();
+            mLastCount = in.readInt();
+            mNesting = 0;
+        }
+    }
+    
+    public void unplugTimers() {
+        ArrayList<Timer> timers;
+        
+        timers = mPartialTimers;
+        for (int i = timers.size() - 1; i >= 0; i--) {
+            timers.get(i).unplug();
+        }
+        timers = mFullTimers;
+        for (int i = timers.size() - 1; i >= 0; i--) {
+            timers.get(i).unplug();
+        }
+        timers = mWindowTimers;
+        for (int i = timers.size() - 1; i >= 0; i--) {
+            timers.get(i).unplug();
+        }
+        timers = mSensorTimers;
+        for (int i = timers.size() - 1; i >= 0; i--) {
+            timers.get(i).unplug();
+        }
+    }
+    
+    @Override
+    public SparseArray<? extends BatteryStats.Uid> getUidStats() {
+        return mUidStats;
+    }
+
+    /**
+     * The statistics associated with a particular uid.
+     */
+    public final class Uid extends BatteryStats.Uid {
+
+        /**
+         * The statistics we have collected for this uid's wake locks.
+         */
+        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
+
+        /**
+         * The statistics we have collected for this uid's sensor activations.
+         */
+        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
+
+        /**
+         * The statistics we have collected for this uid's processes.
+         */
+        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
+
+        /**
+         * The statistics we have collected for this uid's processes.
+         */
+        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
+
+        @Override
+        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
+            return mWakelockStats;
+        }
+
+        @Override
+        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
+            return mSensorStats;
+        }
+
+        @Override
+        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
+            return mProcessStats;
+        }
+
+        @Override
+        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
+            return mPackageStats;
+        }
+
+        void writeToParcelLocked(Parcel out) {
+            out.writeInt(mWakelockStats.size());
+            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
+                out.writeString(wakelockEntry.getKey());
+                Uid.Wakelock wakelock = wakelockEntry.getValue();
+                wakelock.writeToParcelLocked(out);
+            }
+
+            out.writeInt(mSensorStats.size());
+            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
+                out.writeInt(sensorEntry.getKey());
+                Uid.Sensor sensor = sensorEntry.getValue();
+                sensor.writeToParcelLocked(out);
+            }
+
+            out.writeInt(mProcessStats.size());
+            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
+                out.writeString(procEntry.getKey());
+                Uid.Proc proc = procEntry.getValue();
+                proc.writeToParcelLocked(out);
+            }
+
+            out.writeInt(mPackageStats.size());
+            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
+                out.writeString(pkgEntry.getKey());
+                Uid.Pkg pkg = pkgEntry.getValue();
+                pkg.writeToParcelLocked(out);
+            }
+        }
+
+        void readFromParcelLocked(Parcel in) {
+            int numWakelocks = in.readInt();
+            mWakelockStats.clear();
+            for (int j = 0; j < numWakelocks; j++) {
+                String wakelockName = in.readString();
+                Uid.Wakelock wakelock = new Wakelock();
+                wakelock.readFromParcelLocked(in);
+                mWakelockStats.put(wakelockName, wakelock);
+            }
+
+            int numSensors = in.readInt();
+            mSensorStats.clear();
+            for (int k = 0; k < numSensors; k++) {
+                int sensorNumber = in.readInt();
+                Uid.Sensor sensor = new Sensor();
+                sensor.readFromParcelLocked(in);
+                mSensorStats.put(sensorNumber, sensor);
+            }
+
+            int numProcs = in.readInt();
+            mProcessStats.clear();
+            for (int k = 0; k < numProcs; k++) {
+                String processName = in.readString();
+                Uid.Proc proc = new Proc();
+                proc.readFromParcelLocked(in);
+                mProcessStats.put(processName, proc);
+            }
+
+            int numPkgs = in.readInt();
+            mPackageStats.clear();
+            for (int l = 0; l < numPkgs; l++) {
+                String packageName = in.readString();
+                Uid.Pkg pkg = new Pkg();
+                pkg.readFromParcelLocked(in);
+                mPackageStats.put(packageName, pkg);
+            }
+        }
+
+        /**
+         * The statistics associated with a particular wake lock.
+         */
+        public final class Wakelock extends BatteryStats.Uid.Wakelock {
+            /**
+             * How long (in ms) this uid has been keeping the device partially awake.
+             */
+            Timer wakeTimePartial;
+
+            /**
+             * How long (in ms) this uid has been keeping the device fully awake.
+             */
+            Timer wakeTimeFull;
+
+            /**
+             * How long (in ms) this uid has had a window keeping the device awake.
+             */
+            Timer wakeTimeWindow;
+
+            /**
+             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
+             * proper timer pool from the given BatteryStatsImpl object.
+             *
+             * @param in the Parcel to be read from.
+             * return a new Timer, or null.
+             */
+            private Timer readTimerFromParcel(Parcel in) {
+                if (in.readInt() == 0) {
+                    return null;
+                }
+
+                Timer timer = new Timer();
+                timer.readFromParcel(in);
+                // Set the timer pool for the timer according to its type
+                switch (timer.mType) {
+                case WAKE_TYPE_PARTIAL:
+                    timer.mTimerPool = mPartialTimers;
+                    break;
+                case WAKE_TYPE_FULL:
+                    timer.mTimerPool = mFullTimers;
+                    break;
+                case WAKE_TYPE_WINDOW:
+                    timer.mTimerPool = mWindowTimers;
+                    break;
+                }
+                // If the timer is active, add it to the pool
+                if (timer.mNesting > 0) {
+                    timer.mTimerPool.add(timer);
+                }
+                return timer;
+            }
+
+            void readFromParcelLocked(Parcel in) {
+                wakeTimePartial = readTimerFromParcel(in);
+                wakeTimeFull = readTimerFromParcel(in);
+                wakeTimeWindow = readTimerFromParcel(in);
+            }
+
+            void writeToParcelLocked(Parcel out) {
+                Timer.writeTimerToParcel(out, wakeTimePartial);
+                Timer.writeTimerToParcel(out, wakeTimeFull);
+                Timer.writeTimerToParcel(out, wakeTimeWindow);
+            }
+
+            @Override
+            public Timer getWakeTime(int type) {
+                switch (type) {
+                case WAKE_TYPE_FULL: return wakeTimeFull;
+                case WAKE_TYPE_PARTIAL: return wakeTimePartial;
+                case WAKE_TYPE_WINDOW: return wakeTimeWindow;
+                default: throw new IllegalArgumentException("type = " + type);
+                }
+            }
+        }
+
+        public final class Sensor extends BatteryStats.Uid.Sensor {
+            Timer sensorTime;
+
+            private Timer readTimerFromParcel(Parcel in) {
+                if (in.readInt() == 0) {
+                    return null;
+                }
+
+                Timer timer = new Timer();
+                timer.readFromParcel(in);
+                // Set the timer pool for the timer
+                timer.mTimerPool = mSensorTimers;
+
+                // If the timer is active, add it to the pool
+                if (timer.mNesting > 0) {
+                    timer.mTimerPool.add(timer);
+                }
+                return timer;
+            }
+
+            void readFromParcelLocked(Parcel in) {
+                sensorTime = readTimerFromParcel(in);
+            }
+
+            void writeToParcelLocked(Parcel out) {
+                Timer.writeTimerToParcel(out, sensorTime);
+            }
+
+            @Override
+            public Timer getSensorTime() {
+                return sensorTime;
+            }
+        }
+
+        /**
+         * The statistics associated with a particular process.
+         */
+        public final class Proc extends BatteryStats.Uid.Proc {
+            /**
+             * Total time (in 1/100 sec) spent executing in user code.
+             */
+            long mUserTime;
+
+            /**
+             * Total time (in 1/100 sec) spent executing in kernel code.
+             */
+            long mSystemTime;
+
+            /**
+             * Number of times the process has been started.
+             */
+            int mStarts;
+
+            /**
+             * The amount of user time loaded from a previous save.
+             */
+            long mLoadedUserTime;
+
+            /**
+             * The amount of system time loaded from a previous save.
+             */
+            long mLoadedSystemTime;
+
+            /**
+             * The number of times the process has started from a previous save.
+             */
+            int mLoadedStarts;
+
+            /**
+             * The amount of user time loaded from the previous run.
+             */
+            long mLastUserTime;
+
+            /**
+             * The amount of system time loaded from the previous run.
+             */
+            long mLastSystemTime;
+
+            /**
+             * The number of times the process has started from the previous run.
+             */
+            int mLastStarts;
+
+            void writeToParcelLocked(Parcel out) {
+                out.writeLong(mUserTime);
+                out.writeLong(mSystemTime);
+                out.writeInt(mStarts);
+                out.writeLong(mLoadedUserTime);
+                out.writeLong(mLoadedSystemTime);
+                out.writeInt(mLoadedStarts);
+                out.writeLong(mLastUserTime);
+                out.writeLong(mLastSystemTime);
+                out.writeInt(mLastStarts);
+            }
+
+            void readFromParcelLocked(Parcel in) {
+                mUserTime = in.readLong();
+                mSystemTime = in.readLong();
+                mStarts = in.readInt();
+                mLoadedUserTime = in.readLong();
+                mLoadedSystemTime = in.readLong();
+                mLoadedStarts = in.readInt();
+                mLastUserTime = in.readLong();
+                mLastSystemTime = in.readLong();
+                mLastStarts = in.readInt();
+            }
+
+            public BatteryStatsImpl getBatteryStats() {
+                return BatteryStatsImpl.this;
+            }
+
+            public void addCpuTimeLocked(int utime, int stime) {
+                mUserTime += utime;
+                mSystemTime += stime;
+            }
+
+            public void incStartsLocked() {
+                mStarts++;
+            }
+
+            @Override
+            public long getUserTime(int which) {
+                long val;
+                if (which == STATS_LAST) {
+                    val = mLastUserTime;
+                } else {
+                    val = mUserTime;
+                    if (which == STATS_CURRENT) {
+                        val -= mLoadedUserTime;
+                    }
+                }
+                return val;
+            }
+
+            @Override
+            public long getSystemTime(int which) {
+                long val;
+                if (which == STATS_LAST) {
+                    val = mLastSystemTime;
+                } else {
+                    val = mSystemTime;
+                    if (which == STATS_CURRENT) {
+                        val -= mLoadedSystemTime;
+                    }
+                }
+                return val;
+            }
+
+            @Override
+            public int getStarts(int which) {
+                int val;
+                if (which == STATS_LAST) {
+                    val = mLastStarts;
+                } else {
+                    val = mStarts;
+                    if (which == STATS_CURRENT) {
+                        val -= mLoadedStarts;
+                    }
+                }
+                return val;
+            }
+        }
+
+        /**
+         * The statistics associated with a particular package.
+         */
+        public final class Pkg extends BatteryStats.Uid.Pkg {
+            /**
+             * Number of times this package has done something that could wake up the
+             * device from sleep.
+             */
+            int mWakeups;
+
+            /**
+             * Number of things that could wake up the device loaded from a
+             * previous save.
+             */
+            int mLoadedWakeups;
+
+            /**
+             * Number of things that could wake up the device as of the
+             * last run.
+             */
+            int mLastWakeups;
+
+            /**
+             * The statics we have collected for this package's services.
+             */
+            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
+
+            void readFromParcelLocked(Parcel in) {
+                mWakeups = in.readInt();
+                mLoadedWakeups = in.readInt();
+                mLastWakeups = in.readInt();
+
+                int numServs = in.readInt();
+                mServiceStats.clear();
+                for (int m = 0; m < numServs; m++) {
+                    String serviceName = in.readString();
+                    Uid.Pkg.Serv serv = new Serv();
+                    mServiceStats.put(serviceName, serv);
+
+                    serv.readFromParcelLocked(in);
+                }
+            }
+
+            void writeToParcelLocked(Parcel out) {
+                out.writeInt(mWakeups);
+                out.writeInt(mLoadedWakeups);
+                out.writeInt(mLastWakeups);
+
+                out.writeInt(mServiceStats.size());
+                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
+                    out.writeString(servEntry.getKey());
+                    Uid.Pkg.Serv serv = servEntry.getValue();
+
+                    serv.writeToParcelLocked(out);
+                }
+            }
+
+            @Override
+            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
+                return mServiceStats;
+            }
+
+            @Override
+            public int getWakeups(int which) {
+                int val;
+                if (which == STATS_LAST) {
+                    val = mLastWakeups;
+                } else {
+                    val = mWakeups;
+                    if (which == STATS_CURRENT) {
+                        val -= mLoadedWakeups;
+                    }
+                }
+
+                return val;
+            }
+
+            /**
+             * The statistics associated with a particular service.
+             */
+            public final class Serv extends BatteryStats.Uid.Pkg.Serv {
+                /**
+                 * Total time (ms) the service has been left started.
+                 */
+                long mStartTime;
+
+                /**
+                 * If service has been started and not yet stopped, this is
+                 * when it was started.
+                 */
+                long mRunningSince;
+
+                /**
+                 * True if we are currently running.
+                 */
+                boolean mRunning;
+
+                /**
+                 * Total number of times startService() has been called.
+                 */
+                int mStarts;
+
+                /**
+                 * Total time (ms) the service has been left launched.
+                 */
+                long mLaunchedTime;
+
+                /**
+                 * If service has been launched and not yet exited, this is
+                 * when it was launched.
+                 */
+                long mLaunchedSince;
+
+                /**
+                 * True if we are currently launched.
+                 */
+                boolean mLaunched;
+
+                /**
+                 * Total number times the service has been launched.
+                 */
+                int mLaunches;
+
+                /**
+                 * The amount of time spent started loaded from a previous save.
+                 */
+                long mLoadedStartTime;
+
+                /**
+                 * The number of starts loaded from a previous save.
+                 */
+                int mLoadedStarts;
+
+                /**
+                 * The number of launches loaded from a previous save.
+                 */
+                int mLoadedLaunches;
+
+                /**
+                 * The amount of time spent started as of the last run.
+                 */
+                long mLastStartTime;
+
+                /**
+                 * The number of starts as of the last run.
+                 */
+                int mLastStarts;
+
+                /**
+                 * The number of launches as of the last run.
+                 */
+                int mLastLaunches;
+
+                void readFromParcelLocked(Parcel in) {
+                    mStartTime = in.readLong();
+                    mRunningSince = in.readLong();
+                    mRunning = in.readInt() != 0;
+                    mStarts = in.readInt();
+                    mLaunchedTime = in.readLong();
+                    mLaunchedSince = in.readLong();
+                    mLaunched = in.readInt() != 0;
+                    mLaunches = in.readInt();
+                    mLoadedStartTime = in.readLong();
+                    mLoadedStarts = in.readInt();
+                    mLoadedLaunches = in.readInt();
+                    mLastStartTime = in.readLong();
+                    mLastStarts = in.readInt();
+                    mLastLaunches = in.readInt();
+                }
+
+                void writeToParcelLocked(Parcel out) {
+                    out.writeLong(mStartTime);
+                    out.writeLong(mRunningSince);
+                    out.writeInt(mRunning ? 1 : 0);
+                    out.writeInt(mStarts);
+                    out.writeLong(mLaunchedTime);
+                    out.writeLong(mLaunchedSince);
+                    out.writeInt(mLaunched ? 1 : 0);
+                    out.writeInt(mLaunches);
+                    out.writeLong(mLoadedStartTime);
+                    out.writeInt(mLoadedStarts);
+                    out.writeInt(mLoadedLaunches);
+                    out.writeLong(mLastStartTime);
+                    out.writeInt(mLastStarts);
+                    out.writeInt(mLastLaunches);
+                }
+
+                long getLaunchTimeToNowLocked(long batteryUptime) {
+                    if (!mLaunched) return mLaunchedTime;
+                    return mLaunchedTime + batteryUptime - mLaunchedSince;
+                }
+
+                long getStartTimeToNowLocked(long batteryUptime) {
+                    if (!mRunning) return mStartTime;
+                    return mStartTime + batteryUptime - mRunningSince;
+                }
+
+                public void startLaunchedLocked() {
+                    if (!mLaunched) {
+                        mLaunches++;
+                        mLaunchedSince = getBatteryUptimeLocked();
+                        mLaunched = true;
+                    }
+                }
+
+                public void stopLaunchedLocked() {
+                    if (mLaunched) {
+                        long time = getBatteryUptimeLocked() - mLaunchedSince;
+                        if (time > 0) {
+                            mLaunchedTime += time;
+                        } else {
+                            mLaunches--;
+                        }
+                        mLaunched = false;
+                    }
+                }
+
+                public void startRunningLocked() {
+                    if (!mRunning) {
+                        mStarts++;
+                        mRunningSince = getBatteryUptimeLocked();
+                        mRunning = true;
+                    }
+                }
+
+                public void stopRunningLocked() {
+                    if (mRunning) {
+                        long time = getBatteryUptimeLocked() - mRunningSince;
+                        if (time > 0) {
+                            mStartTime += time;
+                        } else {
+                            mStarts--;
+                        }
+                        mRunning = false;
+                    }
+                }
+
+                public BatteryStatsImpl getBatteryStats() {
+                    return BatteryStatsImpl.this;
+                }
+
+                @Override
+                public int getLaunches(int which) {
+                    int val;
+
+                    if (which == STATS_LAST) {
+                        val = mLastLaunches;
+                    } else {
+                        val = mLaunches;
+                        if (which == STATS_CURRENT) {
+                            val -= mLoadedLaunches;
+                        }
+                    }
+
+                    return val;
+                }
+
+                @Override
+                public long getStartTime(long now, int which) {
+                    long val;
+                    if (which == STATS_LAST) {
+                        val = mLastStartTime;
+                    } else {
+                        val = getStartTimeToNowLocked(now);
+                        if (which == STATS_CURRENT) {
+                            val -= mLoadedStartTime;
+                        }
+                    }
+
+                    return val;
+                }
+
+                @Override
+                public int getStarts(int which) {
+                    int val;
+                    if (which == STATS_LAST) {
+                        val = mLastStarts;
+                    } else {
+                        val = mStarts;
+                        if (which == STATS_CURRENT) {
+                            val -= mLoadedStarts;
+                        }
+                    }
+
+                    return val;
+                }
+            }
+
+            public BatteryStatsImpl getBatteryStats() {
+                return BatteryStatsImpl.this;
+            }
+
+            public void incWakeupsLocked() {
+                mWakeups++;
+            }
+
+            final Serv newServiceStatsLocked() {
+                return new Serv();
+            }
+        }
+
+        /**
+         * Retrieve the statistics object for a particular process, creating
+         * if needed.
+         */
+        public Proc getProcessStatsLocked(String name) {
+            Proc ps = mProcessStats.get(name);
+            if (ps == null) {
+                ps = new Proc();
+                mProcessStats.put(name, ps);
+            }
+
+            return ps;
+        }
+
+        /**
+         * Retrieve the statistics object for a particular service, creating
+         * if needed.
+         */
+        public Pkg getPackageStatsLocked(String name) {
+            Pkg ps = mPackageStats.get(name);
+            if (ps == null) {
+                ps = new Pkg();
+                mPackageStats.put(name, ps);
+            }
+
+            return ps;
+        }
+
+        /**
+         * Retrieve the statistics object for a particular service, creating
+         * if needed.
+         */
+        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
+            Pkg ps = getPackageStatsLocked(pkg);
+            Pkg.Serv ss = ps.mServiceStats.get(serv);
+            if (ss == null) {
+                ss = ps.newServiceStatsLocked();
+                ps.mServiceStats.put(serv, ss);
+            }
+
+            return ss;
+        }
+
+        public Timer getWakeTimerLocked(String name, int type) {
+            Wakelock wl = mWakelockStats.get(name);
+            if (wl == null) {
+                wl = new Wakelock();
+                mWakelockStats.put(name, wl);
+            }
+            Timer t = null;
+            switch (type) {
+                case WAKE_TYPE_PARTIAL:
+                    t = wl.wakeTimePartial;
+                    if (t == null) {
+                        t = new Timer(WAKE_TYPE_PARTIAL, mPartialTimers);
+                        wl.wakeTimePartial = t;
+                    }
+                    return t;
+                case WAKE_TYPE_FULL:
+                    t = wl.wakeTimeFull;
+                    if (t == null) {
+                        t = new Timer(WAKE_TYPE_FULL, mFullTimers);
+                        wl.wakeTimeFull = t;
+                    }
+                    return t;
+                case WAKE_TYPE_WINDOW:
+                    t = wl.wakeTimeWindow;
+                    if (t == null) {
+                        t = new Timer(WAKE_TYPE_WINDOW, mWindowTimers);
+                        wl.wakeTimeWindow = t;
+                    }
+                    return t;
+                default:
+                    throw new IllegalArgumentException("type=" + type);
+            }
+        }
+
+        public Timer getSensorTimerLocked(int sensor, boolean create) {
+            Integer sId = Integer.valueOf(sensor);
+            Sensor se = mSensorStats.get(sId);
+            if (se == null) {
+                if (!create) {
+                    return null;
+                }
+                se = new Sensor();
+                mSensorStats.put(sId, se);
+            }
+            Timer t = se.sensorTime;
+            if (t == null) {
+                t = new Timer(0, mSensorTimers);
+                se.sensorTime = t;
+            }
+            return t;
+        }
+
+        public void noteStartWakeLocked(String name, int type) {
+            Timer t = getWakeTimerLocked(name, type);
+            if (t != null) {
+                t.startRunningLocked(BatteryStatsImpl.this);
+            }
+        }
+
+        public void noteStopWakeLocked(String name, int type) {
+            Timer t = getWakeTimerLocked(name, type);
+            if (t != null) {
+                t.stopRunningLocked(BatteryStatsImpl.this);
+            }
+        }
+        
+        public void noteStartSensor(int sensor) {
+            Timer t = getSensorTimerLocked(sensor, true);
+            if (t != null) {
+                t.startRunningLocked(BatteryStatsImpl.this);
+            }            
+        }
+
+        public void noteStopSensor(int sensor) {
+            // Don't create a timer if one doesn't already exist
+            Timer t = getSensorTimerLocked(sensor, false);
+            if (t != null) {
+                t.stopRunningLocked(BatteryStatsImpl.this);
+            }            
+        }
+
+        public BatteryStatsImpl getBatteryStats() {
+            return BatteryStatsImpl.this;
+        }
+    }
+
+    public BatteryStatsImpl(String filename) {
+        mFile = new File(filename);
+        mBackupFile = new File(filename + ".bak");
+        mStartCount++;
+        mOnBattery = true;
+        mTrackBatteryPastUptime = 0;
+        mTrackBatteryPastRealtime = 0;
+        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
+        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
+    }
+
+    public BatteryStatsImpl(Parcel p) {
+        mFile = mBackupFile = null;
+        readFromParcel(p);
+    }
+
+    @Override
+    public int getStartCount() {
+        return mStartCount;
+    }
+
+    public boolean isOnBattery() {
+        return mOnBattery;
+    }
+
+    public void setOnBattery(boolean onBattery) {
+        synchronized(this) {
+            if (mOnBattery != onBattery) {
+                long uptime = SystemClock.uptimeMillis() * 1000;
+                long mSecRealtime = SystemClock.elapsedRealtime();
+                long realtime = mSecRealtime * 1000;
+                if (onBattery) {
+                    mTrackBatteryUptimeStart = uptime;
+                    mTrackBatteryRealtimeStart = realtime;
+                    unplugTimers();
+                } else {
+                    mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
+                    mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
+                }
+                mOnBattery = onBattery;
+                if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) {
+                    if (mFile != null) {
+                        writeLocked();
+                    }
+                }
+            }
+        }
+    }
+
+    public long getAwakeTimeBattery() {
+        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
+    }
+
+    public long getAwakeTimePlugged() {
+        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
+    }
+
+    @Override
+    public long computeUptime(long curTime, int which) {
+        switch (which) {
+        case STATS_TOTAL: return mUptime + (curTime-mUptimeStart);
+        case STATS_LAST: return mLastUptime;
+        case STATS_CURRENT: return (curTime-mUptimeStart);
+        case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
+        }
+        return 0;
+    }
+
+    @Override
+    public long computeRealtime(long curTime, int which) {
+        switch (which) {
+        case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart);
+        case STATS_LAST: return mLastRealtime;
+        case STATS_CURRENT: return (curTime-mRealtimeStart);
+        case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
+        }
+        return 0;
+    }
+
+    @Override
+    public long computeBatteryUptime(long curTime, int which) {
+        switch (which) {
+        case STATS_TOTAL:
+            return mBatteryUptime + getBatteryUptime(curTime);
+        case STATS_LAST:
+            return mBatteryLastUptime;
+        case STATS_CURRENT:
+        case STATS_UNPLUGGED:
+            return getBatteryUptime(curTime);
+        }
+        return 0;
+    }
+
+    @Override
+    public long computeBatteryRealtime(long curTime, int which) {
+        switch (which) {
+        case STATS_TOTAL:
+            return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
+        case STATS_LAST:
+            return mBatteryLastRealtime;
+        case STATS_CURRENT:
+        case STATS_UNPLUGGED:
+            return getBatteryRealtimeLocked(curTime);
+        }
+        return 0;
+    }
+
+    long getBatteryUptimeLocked(long curTime) {
+        long time = mTrackBatteryPastUptime;
+        if (mOnBattery) {
+            time += curTime - mTrackBatteryUptimeStart;
+        }
+        return time;
+    }
+
+    long getBatteryUptimeLocked() {
+        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
+    }
+
+    @Override
+    public long getBatteryUptime(long curTime) {
+        return getBatteryUptimeLocked(curTime);
+    }
+
+    long getBatteryRealtimeLocked(long curTime) {
+        long time = mTrackBatteryPastRealtime;
+        if (mOnBattery) {
+            time += curTime - mTrackBatteryRealtimeStart;
+        }
+        return time;
+    }
+
+    @Override
+    public long getBatteryRealtime(long curTime) {
+        return getBatteryRealtimeLocked(curTime);
+    }
+
+    /**
+     * Retrieve the statistics object for a particular uid, creating if needed.
+     */
+    public Uid getUidStatsLocked(int uid) {
+        Uid u = mUidStats.get(uid);
+        if (u == null) {
+            u = new Uid();
+            mUidStats.put(uid, u);
+        }
+        return u;
+    }
+
+    /**
+     * Remove the statistics object for a particular uid.
+     */
+    public void removeUidStatsLocked(int uid) {
+        mUidStats.remove(uid);
+    }
+
+    /**
+     * Retrieve the statistics object for a particular process, creating
+     * if needed.
+     */
+    public Uid.Proc getProcessStatsLocked(int uid, String name) {
+        Uid u = getUidStatsLocked(uid);
+        return u.getProcessStatsLocked(name);
+    }
+
+    /**
+     * Retrieve the statistics object for a particular process, creating
+     * if needed.
+     */
+    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
+        Uid u = getUidStatsLocked(uid);
+        return u.getPackageStatsLocked(pkg);
+    }
+
+    /**
+     * Retrieve the statistics object for a particular service, creating
+     * if needed.
+     */
+    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
+        Uid u = getUidStatsLocked(uid);
+        return u.getServiceStatsLocked(pkg, name);
+    }
+
+    public void writeLocked() {
+        if ((mFile == null) || (mBackupFile == null)) {
+            Log.w("BatteryStats", "writeLocked: no file associated with this instance");
+            return;
+        }
+
+        // Keep the old file around until we know the new one has
+        // been successfully written.
+        if (mFile.exists()) {
+            if (mBackupFile.exists()) {
+                mBackupFile.delete();
+            }
+            mFile.renameTo(mBackupFile);
+        }
+
+        try {
+            FileOutputStream stream = new FileOutputStream(mFile);
+            Parcel out = Parcel.obtain();
+            writeSummaryToParcel(out);
+            stream.write(out.marshall());
+            out.recycle();
+
+            stream.flush();
+            stream.close();
+            mBackupFile.delete();
+
+            mLastWriteTime = SystemClock.elapsedRealtime();
+        } catch (IOException e) {
+            Log.e("BatteryStats", "Error writing battery statistics", e);
+        }
+    }
+
+    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
+        int pos = 0;
+        int avail = stream.available();
+        byte[] data = new byte[avail];
+        while (true) {
+            int amt = stream.read(data, pos, data.length-pos);
+            //Log.i("foo", "Read " + amt + " bytes at " + pos
+            //        + " of avail " + data.length);
+            if (amt <= 0) {
+                //Log.i("foo", "**** FINISHED READING: pos=" + pos
+                //        + " len=" + data.length);
+                return data;
+            }
+            pos += amt;
+            avail = stream.available();
+            if (avail > data.length-pos) {
+                byte[] newData = new byte[pos+avail];
+                System.arraycopy(data, 0, newData, 0, pos);
+                data = newData;
+            }
+        }
+    }
+
+    public void readLocked() {
+        if ((mFile == null) || (mBackupFile == null)) {
+            Log.w("BatteryStats", "readLocked: no file associated with this instance");
+            return;
+        }
+
+        mUidStats.clear();
+
+        FileInputStream stream = null;
+        if (mBackupFile.exists()) {
+            try {
+                stream = new FileInputStream(mBackupFile);
+            } catch (java.io.IOException e) {
+                // We'll try for the normal settings file.
+            }
+        }
+
+        try {
+            if (stream == null) {
+                if (!mFile.exists()) {
+                    return;
+                }
+                stream = new FileInputStream(mFile);
+            }
+
+            byte[] raw = readFully(stream);
+            Parcel in = Parcel.obtain();
+            in.unmarshall(raw, 0, raw.length);
+            in.setDataPosition(0);
+            stream.close();
+
+            readSummaryFromParcel(in);
+        } catch(java.io.IOException e) {
+            Log.e("BatteryStats", "Error reading battery statistics", e);
+        }
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    private void readSummaryFromParcel(Parcel in) {
+        final int version = in.readInt();
+        if (version != VERSION) {
+            Log.e("BatteryStats", "readFromParcel: version got " + version
+                + ", expected " + VERSION);
+            return;
+        }
+
+        mStartCount = in.readInt();
+        mBatteryUptime = in.readLong();
+        mBatteryLastUptime = in.readLong();
+        mBatteryRealtime = in.readLong();
+        mBatteryLastRealtime = in.readLong();
+        mUptime = in.readLong();
+        mLastUptime = in.readLong();
+        mRealtime = in.readLong();
+        mLastRealtime = in.readLong();
+        mStartCount++;
+
+        final int NU = in.readInt();
+        for (int iu=0; iu<NU; iu++) {
+            int uid = in.readInt();
+            Uid u = new Uid();
+            mUidStats.put(uid, u);
+
+            int NW = in.readInt();
+            for (int iw=0; iw<NW; iw++) {
+                String wlName = in.readString();
+                if (in.readInt() != 0) {
+                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
+                }
+                if (in.readInt() != 0) {
+                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
+                }
+                if (in.readInt() != 0) {
+                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
+                }
+            }
+
+            if (version >= 12) {
+                int NSE = in.readInt();
+                for (int is=0; is<NSE; is++) {
+                    int seNumber = in.readInt();
+                    if (in.readInt() != 0) {
+                        u.getSensorTimerLocked(seNumber, true).readSummaryFromParcelLocked(in);
+                    }
+                }
+            }
+
+            int NP = in.readInt();
+            for (int ip=0; ip<NP; ip++) {
+                String procName = in.readString();
+                Uid.Proc p = u.getProcessStatsLocked(procName);
+                p.mUserTime = p.mLoadedUserTime = in.readLong();
+                p.mLastUserTime = in.readLong();
+                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
+                p.mLastSystemTime = in.readLong();
+                p.mStarts = p.mLoadedStarts = in.readInt();
+                p.mLastStarts = in.readInt();
+            }
+
+            NP = in.readInt();
+            for (int ip=0; ip<NP; ip++) {
+                String pkgName = in.readString();
+                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
+                p.mWakeups = p.mLoadedWakeups = in.readInt();
+                p.mLastWakeups = in.readInt();
+                final int NS = in.readInt();
+                for (int is=0; is<NS; is++) {
+                    String servName = in.readString();
+                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
+                    s.mStartTime = s.mLoadedStartTime = in.readLong();
+                    s.mLastStartTime = in.readLong();
+                    s.mStarts = s.mLoadedStarts = in.readInt();
+                    s.mLastStarts = in.readInt();
+                    s.mLaunches = s.mLoadedLaunches = in.readInt();
+                    s.mLastLaunches = in.readInt();
+                }
+            }
+        }
+    }
+
+    /**
+     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
+     * disk.  This format does not allow a lossless round-trip.
+     *
+     * @param out the Parcel to be written to.
+     */
+    public void writeSummaryToParcel(Parcel out) {
+        final long NOW = getBatteryUptimeLocked();
+        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
+        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
+
+        out.writeInt(VERSION);
+
+        out.writeInt(mStartCount);
+        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_TOTAL));
+        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_CURRENT));
+        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_TOTAL));
+        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_CURRENT));
+        out.writeLong(computeUptime(NOW_SYS, STATS_TOTAL));
+        out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT));
+        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL));
+        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT));
+
+        final int NU = mUidStats.size();
+        out.writeInt(NU);
+        for (int iu=0; iu<NU; iu++) {
+            out.writeInt(mUidStats.keyAt(iu));
+            Uid u = mUidStats.valueAt(iu);
+
+            int NW = u.mWakelockStats.size();
+            out.writeInt(NW);
+            if (NW > 0) {
+                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
+                    : u.mWakelockStats.entrySet()) {
+                    out.writeString(ent.getKey());
+                    Uid.Wakelock wl = ent.getValue();
+                    if (wl.wakeTimeFull != null) {
+                        out.writeInt(1);
+                        wl.wakeTimeFull.writeSummaryFromParcelLocked(out, NOW);
+                    } else {
+                        out.writeInt(0);
+                    }
+                    if (wl.wakeTimePartial != null) {
+                        out.writeInt(1);
+                        wl.wakeTimePartial.writeSummaryFromParcelLocked(out, NOW);
+                    } else {
+                        out.writeInt(0);
+                    }
+                    if (wl.wakeTimeWindow != null) {
+                        out.writeInt(1);
+                        wl.wakeTimeWindow.writeSummaryFromParcelLocked(out, NOW);
+                    } else {
+                        out.writeInt(0);
+                    }
+                }
+            }
+
+            int NSE = u.mSensorStats.size();
+            out.writeInt(NSE);
+            if (NSE > 0) {
+                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
+                    : u.mSensorStats.entrySet()) {
+                    out.writeInt(ent.getKey());
+                    Uid.Sensor se = ent.getValue();
+                    if (se.sensorTime != null) {
+                        out.writeInt(1);
+                        se.sensorTime.writeSummaryFromParcelLocked(out, NOW);
+                    } else {
+                        out.writeInt(0);
+                    }
+                }
+            }
+
+            int NP = u.mProcessStats.size();
+            out.writeInt(NP);
+            if (NP > 0) {
+                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
+                    : u.mProcessStats.entrySet()) {
+                    out.writeString(ent.getKey());
+                    Uid.Proc ps = ent.getValue();
+                    out.writeLong(ps.mUserTime);
+                    out.writeLong(ps.mUserTime - ps.mLoadedUserTime);
+                    out.writeLong(ps.mSystemTime);
+                    out.writeLong(ps.mSystemTime - ps.mLoadedSystemTime);
+                    out.writeInt(ps.mStarts);
+                    out.writeInt(ps.mStarts - ps.mLoadedStarts);
+                }
+            }
+
+            NP = u.mPackageStats.size();
+            out.writeInt(NP);
+            if (NP > 0) {
+                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
+                    : u.mPackageStats.entrySet()) {
+                    out.writeString(ent.getKey());
+                    Uid.Pkg ps = ent.getValue();
+                    out.writeInt(ps.mWakeups);
+                    out.writeInt(ps.mWakeups - ps.mLoadedWakeups);
+                    final int NS = ps.mServiceStats.size();
+                    out.writeInt(NS);
+                    if (NS > 0) {
+                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
+                                : ps.mServiceStats.entrySet()) {
+                            out.writeString(sent.getKey());
+                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
+                            long time = ss.getStartTimeToNowLocked(NOW);
+                            out.writeLong(time);
+                            out.writeLong(time - ss.mLoadedStartTime);
+                            out.writeInt(ss.mStarts);
+                            out.writeInt(ss.mStarts - ss.mLoadedStarts);
+                            out.writeInt(ss.mLaunches);
+                            out.writeInt(ss.mLaunches - ss.mLoadedLaunches);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public void readFromParcel(Parcel in) {
+        readFromParcelLocked(in);
+    }
+    
+    void readFromParcelLocked(Parcel in) {
+        int magic = in.readInt();
+        if (magic != MAGIC) {
+            throw new ParcelFormatException("Bad magic number");
+        }
+
+        mStartCount = in.readInt();
+        mBatteryUptime = in.readLong();
+        mBatteryLastUptime = in.readLong();
+        mBatteryRealtime = in.readLong();
+        mBatteryLastRealtime = in.readLong();
+        mUptime = in.readLong();
+        mUptimeStart = in.readLong();
+        mLastUptime = in.readLong();
+        mRealtime = in.readLong();
+        mRealtimeStart = in.readLong();
+        mLastRealtime = in.readLong();
+        mOnBattery = in.readInt() != 0;
+        mTrackBatteryPastUptime = in.readLong();
+        mTrackBatteryUptimeStart = in.readLong();
+        mTrackBatteryPastRealtime = in.readLong();
+        mTrackBatteryRealtimeStart = in.readLong();
+        mLastWriteTime = in.readLong();
+
+        mPartialTimers.clear();
+        mFullTimers.clear();
+        mWindowTimers.clear();
+
+        int numUids = in.readInt();
+        mUidStats.clear();
+        for (int i = 0; i < numUids; i++) {
+            int key = in.readInt();
+            Uid uid = new Uid();
+            uid.readFromParcelLocked(in);
+            mUidStats.append(key, uid);
+        }
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        writeToParcelLocked(out, flags);
+    }
+    
+    @SuppressWarnings("unused") 
+    void writeToParcelLocked(Parcel out, int flags) {
+        out.writeInt(MAGIC);
+        out.writeInt(mStartCount);
+        out.writeLong(mBatteryUptime);
+        out.writeLong(mBatteryLastUptime);
+        out.writeLong(mBatteryRealtime);
+        out.writeLong(mBatteryLastRealtime);
+        out.writeLong(mUptime);
+        out.writeLong(mUptimeStart);
+        out.writeLong(mLastUptime);
+        out.writeLong(mRealtime);
+        out.writeLong(mRealtimeStart);
+        out.writeLong(mLastRealtime);
+        out.writeInt(mOnBattery ? 1 : 0);
+        out.writeLong(mTrackBatteryPastUptime);
+        out.writeLong(mTrackBatteryUptimeStart);
+        out.writeLong(mTrackBatteryPastRealtime);
+        out.writeLong(mTrackBatteryRealtimeStart);
+        out.writeLong(mLastWriteTime);
+
+        int size = mUidStats.size();
+        out.writeInt(size);
+        for (int i = 0; i < size; i++) {
+            out.writeInt(mUidStats.keyAt(i));
+            Uid uid = mUidStats.valueAt(i);
+
+            uid.writeToParcelLocked(out);
+        }
+    }
+
+    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
+        new Parcelable.Creator<BatteryStatsImpl>() {
+        public BatteryStatsImpl createFromParcel(Parcel in) {
+            return new BatteryStatsImpl(in);
+        }
+
+        public BatteryStatsImpl[] newArray(int size) {
+            return new BatteryStatsImpl[size];
+        }
+    };
+}
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
new file mode 100644
index 0000000..fd8fd5a
--- /dev/null
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -0,0 +1,166 @@
+package com.android.internal.os;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+public class HandlerCaller {
+    private static final String TAG = "HandlerCaller";
+    private static final boolean DEBUG = false;
+    
+    public final Context mContext;
+    
+    final Looper mMainLooper;
+    final Handler mH;
+
+    final Callback mCallback;
+    
+    public static class SomeArgs {
+        SomeArgs next;
+        
+        public Object arg1;
+        public Object arg2;
+        Object arg3;
+        public int argi1;
+        public int argi2;
+        public int argi3;
+        public int argi4;
+    }
+    
+    static final int ARGS_POOL_MAX_SIZE = 10;
+    int mArgsPoolSize;
+    SomeArgs mArgsPool;
+    
+    class MyHandler extends Handler {
+        MyHandler(Looper looper) {
+            super(looper);
+        }
+        
+        @Override
+        public void handleMessage(Message msg) {
+            mCallback.executeMessage(msg);
+        }
+    }
+    
+    public interface Callback {
+        public void executeMessage(Message msg);
+    }
+    
+    public HandlerCaller(Context context, Callback callback) {
+        mContext = context;
+        mMainLooper = context.getMainLooper();
+        mH = new MyHandler(mMainLooper);
+        mCallback = callback;
+    }
+
+    public SomeArgs obtainArgs() {
+        synchronized (mH) {
+            SomeArgs args = mArgsPool;
+            if (args != null) {
+                mArgsPool = args.next;
+                args.next = null;
+                mArgsPoolSize--;
+                return args;
+            }
+        }
+        return new SomeArgs();
+    }
+    
+    public void recycleArgs(SomeArgs args) {
+        synchronized (mH) {
+            if (mArgsPoolSize < ARGS_POOL_MAX_SIZE) {
+                args.next = mArgsPool;
+                mArgsPool = args;
+                mArgsPoolSize++;
+            }
+        }
+    }
+    
+    public void executeOrSendMessage(Message msg) {
+        // If we are calling this from the main thread, then we can call
+        // right through.  Otherwise, we need to send the message to the
+        // main thread.
+        if (Looper.myLooper() == mMainLooper) {
+            mCallback.executeMessage(msg);
+            msg.recycle();
+            return;
+        }
+        
+        mH.sendMessage(msg);
+    }
+    
+    public void sendMessage(Message msg) {
+        mH.sendMessage(msg);
+    }
+    
+    public Message obtainMessage(int what) {
+        return mH.obtainMessage(what);
+    }
+    
+    public Message obtainMessageBO(int what, boolean arg1, Object arg2) {
+        return mH.obtainMessage(what, arg1 ? 1 : 0, 0, arg2);
+    }
+    
+    public Message obtainMessageBOO(int what, boolean arg1, Object arg2, Object arg3) {
+        SomeArgs args = obtainArgs();
+        args.arg1 = arg2;
+        args.arg2 = arg3;
+        return mH.obtainMessage(what, arg1 ? 1 : 0, 0, args);
+    }
+    
+    public Message obtainMessageO(int what, Object arg1) {
+        return mH.obtainMessage(what, 0, 0, arg1);
+    }
+    
+    public Message obtainMessageIO(int what, int arg1, Object arg2) {
+        return mH.obtainMessage(what, arg1, 0, arg2);
+    }
+    
+    public Message obtainMessageIO(int what, int arg1, int arg2, Object arg3) {
+        return mH.obtainMessage(what, arg1, arg2, arg3);
+    }
+    
+    public Message obtainMessageIOO(int what, int arg1, Object arg2, Object arg3) {
+        SomeArgs args = obtainArgs();
+        args.arg1 = arg2;
+        args.arg2 = arg3;
+        return mH.obtainMessage(what, arg1, 0, args);
+    }
+    
+    public Message obtainMessageOO(int what, Object arg1, Object arg2) {
+        SomeArgs args = obtainArgs();
+        args.arg1 = arg1;
+        args.arg2 = arg2;
+        return mH.obtainMessage(what, 0, 0, args);
+    }
+    
+    public Message obtainMessageOOO(int what, Object arg1, Object arg2, Object arg3) {
+        SomeArgs args = obtainArgs();
+        args.arg1 = arg1;
+        args.arg2 = arg2;
+        args.arg3 = arg3;
+        return mH.obtainMessage(what, 0, 0, args);
+    }
+    
+    public Message obtainMessageIIII(int what, int arg1, int arg2,
+            int arg3, int arg4) {
+        SomeArgs args = obtainArgs();
+        args.argi1 = arg1;
+        args.argi2 = arg2;
+        args.argi3 = arg3;
+        args.argi4 = arg4;
+        return mH.obtainMessage(what, 0, 0, args);
+    }
+    
+    public Message obtainMessageIIIIO(int what, int arg1, int arg2,
+            int arg3, int arg4, Object arg5) {
+        SomeArgs args = obtainArgs();
+        args.arg1 = arg5;
+        args.argi1 = arg1;
+        args.argi2 = arg2;
+        args.argi3 = arg3;
+        args.argi4 = arg4;
+        return mH.obtainMessage(what, 0, 0, args);
+    }
+}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 566332b..631e7d8 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -210,7 +210,7 @@
             }
 
             pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
-                    parsedArgs.gids, parsedArgs.enableDebugger, rlimits);
+                    parsedArgs.gids, parsedArgs.debugFlags, rlimits);
         } catch (IllegalArgumentException ex) {
             logAndPrintError (newStderr, "Invalid zygote arguments", ex);
             pid = -1;
@@ -295,8 +295,8 @@
         /** from --peer-wait */
         boolean peerWait;
 
-        /** from --enable-debugger */
-        boolean enableDebugger;
+        /** from --enable-debugger, --enable-checkjni, --enable-assert */
+        int debugFlags;
 
         /** from --classpath */
         String classpath;
@@ -362,7 +362,11 @@
                     gid = Integer.parseInt(
                             arg.substring(arg.indexOf('=') + 1));
                 } else if (arg.equals("--enable-debugger")) {
-                    enableDebugger = true;
+                    debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+                } else if (arg.equals("--enable-checkjni")) {
+                    debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
+                } else if (arg.equals("--enable-assert")) {
+                    debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
                 } else if (arg.equals("--peer-wait")) {
                     peerWait = true;
                 } else if (arg.equals("--runtime-init")) {
@@ -567,7 +571,7 @@
      */
     private static void applyDebuggerSecurityPolicy(Arguments args) {
         if ("1".equals(SystemProperties.get("ro.debuggable"))) {
-            args.enableDebugger = true;
+            args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
         }
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5714b99..f21b62f 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -260,7 +260,7 @@
 
                 int count = 0;
                 String line;
-                boolean gotMissingClass = false;
+                String missingClasses = null;
                 while ((line = br.readLine()) != null) {
                     // Skip comments and blank lines.
                     line = line.trim();
@@ -285,14 +285,19 @@
                         count++;
                     } catch (ClassNotFoundException e) {
                         Log.e(TAG, "Class not found for preloading: " + line);
-                        gotMissingClass = true;
+                        if (missingClasses == null) {
+                            missingClasses = line;
+                        } else {
+                            missingClasses += " " + line;
+                        }
                     }
                 }
 
-                if (gotMissingClass &&
+                if (missingClasses != null &&
                         "1".equals(SystemProperties.get("persist.service.adb.enable"))) {
                     throw new IllegalStateException(
-                            "Missing class(es) for preloading, update preloaded-classes");
+                            "Missing class(es) for preloading, update preloaded-classes ["
+                            + missingClasses + "]");
                 }
 
                 Log.i(TAG, "...preloaded " + count + " classes in "
@@ -425,7 +430,7 @@
             "--setuid=1000",
             "--setgid=1000",
             "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
-            "--capabilities=88161312,88161312",
+            "--capabilities=121715744,121715744",
             "--runtime-init",
             "--nice-name=system_server",
             "com.android.server.SystemServer",
@@ -442,13 +447,14 @@
              * indicate it should be debuggable or the ro.debuggable system property
              * is set to "1"
              */
-            boolean debuggableBuild = "1".equals(SystemProperties.get("ro.debuggable"));
-            boolean enableDebugger = parsedArgs.enableDebugger || debuggableBuild;
+            int debugFlags = parsedArgs.debugFlags;
+            if ("1".equals(SystemProperties.get("ro.debuggable")))
+                debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
 
             /* Request to fork the system server process */
             pid = Zygote.forkSystemServer(
                     parsedArgs.uid, parsedArgs.gid,
-                    parsedArgs.gids, enableDebugger, null);
+                    parsedArgs.gids, debugFlags, null);
         } catch (IllegalArgumentException ex) {
             throw new RuntimeException(ex);
         } 
diff --git a/core/java/com/android/internal/provider/Settings.java b/core/java/com/android/internal/provider/Settings.java
deleted file mode 100644
index 85ef17e..0000000
--- a/core/java/com/android/internal/provider/Settings.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.provider;
-
-import android.provider.BaseColumns;
-import android.net.Uri;
-
-/**
- * Settings related utilities.
- */
-public class Settings {
-    /**
-     * Favorite intents
-     */
-    public static final class Favorites implements BaseColumns {
-        /**
-         * The content:// style URL for this table
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://" +
-                android.provider.Settings.AUTHORITY + "/favorites?notify=true");
-
-        /**
-         * The content:// style URL for this table. When this Uri is used, no notification is
-         * sent if the content changes.
-         */
-        public static final Uri CONTENT_URI_NO_NOTIFICATION =
-                Uri.parse("content://" + android.provider.Settings.AUTHORITY +
-                        "/favorites?notify=false");
-
-        /**
-         * The content:// style URL for a given row, identified by its id.
-         *
-         * @param id The row id.
-         * @param notify True to send a notification is the content changes.
-         *
-         * @return The unique content URL for the specified row.
-         */
-        public static Uri getContentUri(long id, boolean notify) {
-            return Uri.parse("content://" + android.provider.Settings.AUTHORITY +
-                    "/favorites/" + id + "?notify=" + notify);
-        }
-
-        /**
-         * The row ID.
-         * <p>Type: INTEGER</p>
-         */
-        public static final String ID = "_id";
-
-        /**
-         * Descriptive name of the favorite that can be displayed to the user.
-         * <P>Type: TEXT</P>
-         */
-        public static final String TITLE = "title";
-
-        /**
-         * The Intent URL of the favorite, describing what it points to.  This
-         * value is given to {@link android.content.Intent#getIntent} to create
-         * an Intent that can be launched.
-         * <P>Type: TEXT</P>
-         */
-        public static final String INTENT = "intent";
-
-        /**
-         * The container holding the favorite
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CONTAINER = "container";
-
-        /**
-         * The icon is a resource identified by a package name and an integer id.
-         */
-        public static final int CONTAINER_DESKTOP = -100;
-
-        /**
-         * The screen holding the favorite (if container is CONTAINER_DESKTOP)
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SCREEN = "screen";
-
-        /**
-         * The X coordinate of the cell holding the favorite
-         * (if container is CONTAINER_DESKTOP or CONTAINER_DOCK)
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CELLX = "cellX";
-
-        /**
-         * The Y coordinate of the cell holding the favorite
-         * (if container is CONTAINER_DESKTOP)
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CELLY = "cellY";
-
-        /**
-         * The X span of the cell holding the favorite
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SPANX = "spanX";
-
-        /**
-         * The Y span of the cell holding the favorite
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SPANY = "spanY";
-
-        /**
-         * The type of the favorite
-         *
-         * <P>Type: INTEGER</P>
-         */
-        public static final String ITEM_TYPE = "itemType";
-
-        /**
-         * The favorite is an application
-         */
-        public static final int ITEM_TYPE_APPLICATION = 0;
-
-        /**
-         * The favorite is an application created shortcut
-         */
-        public static final int ITEM_TYPE_SHORTCUT = 1;
-
-        /**
-         * The favorite is a user created folder
-         */
-        public static final int ITEM_TYPE_USER_FOLDER = 2;
-
-        /**
-         * The favorite is a clock
-         */
-        public static final int ITEM_TYPE_WIDGET_CLOCK = 1000;
-
-        /**
-         * The favorite is a search widget
-         */
-        public static final int ITEM_TYPE_WIDGET_SEARCH = 1001;
-
-        /**
-         * The favorite is a photo frame
-         */
-        public static final int ITEM_TYPE_WIDGET_PHOTO_FRAME = 1002;
-
-        /**
-         * Indicates whether this favorite is an application-created shortcut or not.
-         * If the value is 0, the favorite is not an application-created shortcut, if the
-         * value is 1, it is an application-created shortcut.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String IS_SHORTCUT = "isShortcut";
-
-        /**
-         * The icon type.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String ICON_TYPE = "iconType";
-
-        /**
-         * The icon is a resource identified by a package name and an integer id.
-         */
-        public static final int ICON_TYPE_RESOURCE = 0;
-
-        /**
-         * The icon is a bitmap.
-         */
-        public static final int ICON_TYPE_BITMAP = 1;
-
-        /**
-         * The icon package name, if icon type is ICON_TYPE_RESOURCE.
-         * <P>Type: TEXT</P>
-         */
-        public static final String ICON_PACKAGE = "iconPackage";
-
-        /**
-         * The icon resource id, if icon type is ICON_TYPE_RESOURCE.
-         * <P>Type: TEXT</P>
-         */
-        public static final String ICON_RESOURCE = "iconResource";
-
-        /**
-         * The custom icon bitmap, if icon type is ICON_TYPE_BITMAP.
-         * <P>Type: BLOB</P>
-         */
-        public static final String ICON = "icon";
-    }
-}
diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java
index b4dae94..592a8fa 100644
--- a/core/java/com/android/internal/util/FastXmlSerializer.java
+++ b/core/java/com/android/internal/util/FastXmlSerializer.java
@@ -125,7 +125,7 @@
             String escape = escapes[c];
             if (escape == null) continue;
             if (lastPos < pos) append(string, lastPos, pos-lastPos);
-            lastPos = pos;
+            lastPos = pos + 1;
             append(escape);
         }
         if (lastPos < pos) append(string, lastPos, pos-lastPos);
@@ -143,7 +143,7 @@
             String escape = escapes[c];
             if (escape == null) continue;
             if (lastPos < pos) append(buf, lastPos, pos-lastPos);
-            lastPos = pos;
+            lastPos = pos + 1;
             append(escape);
         }
         if (lastPos < pos) append(buf, lastPos, pos-lastPos);
diff --git a/core/java/com/android/internal/view/IInputConnectionCallback.aidl b/core/java/com/android/internal/view/IInputConnectionCallback.aidl
new file mode 100644
index 0000000..5b5b3df
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputConnectionCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import android.graphics.Rect;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.inputmethod.TextBoxAttribute;
+import com.android.internal.view.IInputContext;
+import android.os.IBinder;
+
+/**
+ * {@hide}
+ */
+oneway interface IInputMethodCallback {
+    void finishedEvent(int seq, boolean handled);
+}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
new file mode 100644
index 0000000..c5966ee
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -0,0 +1,252 @@
+package com.android.internal.view;
+
+import com.android.internal.view.IInputContext;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
+
+public class IInputConnectionWrapper extends IInputContext.Stub {
+    static final String TAG = "IInputConnectionWrapper";
+    
+    private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
+    private static final int DO_GET_TEXT_BEFORE_CURSOR = 20;
+    private static final int DO_GET_CURSOR_CAPS_MODE = 30;
+    private static final int DO_GET_EXTRACTED_TEXT = 40;
+    private static final int DO_COMMIT_TEXT = 50;
+    private static final int DO_COMMIT_COMPLETION = 55;
+    private static final int DO_SET_COMPOSING_TEXT = 60;
+    private static final int DO_SEND_KEY_EVENT = 70;
+    private static final int DO_DELETE_SURROUNDING_TEXT = 80;
+    private static final int DO_HIDE_STATUS_ICON = 100;
+    private static final int DO_SHOW_STATUS_ICON = 110;
+    private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
+    private static final int DO_CLEAR_META_KEY_STATES = 130;
+        
+    private InputConnection mInputConnection;
+
+    private Looper mMainLooper;
+    private Handler mH;
+
+    static class SomeArgs {
+        Object arg1;
+        Object arg2;
+        IInputContextCallback callback;
+        int seq;
+    }
+    
+    class MyHandler extends Handler {
+        MyHandler(Looper looper) {
+            super(looper);
+        }
+        
+        @Override
+        public void handleMessage(Message msg) {
+            executeMessage(msg);
+        }
+    }
+    
+    public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
+        mInputConnection = conn;
+        mMainLooper = mainLooper;
+        mH = new MyHandler(mMainLooper);
+    }
+
+    public void getTextAfterCursor(int length, int seq, IInputContextCallback callback) {
+        dispatchMessage(obtainMessageISC(DO_GET_TEXT_AFTER_CURSOR, length, seq, callback));
+    }
+    
+    public void getTextBeforeCursor(int length, int seq, IInputContextCallback callback) {
+        dispatchMessage(obtainMessageISC(DO_GET_TEXT_BEFORE_CURSOR, length, seq, callback));
+    }
+
+    public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
+        dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback));
+    }
+
+    public void getExtractedText(ExtractedTextRequest request,
+            int flags, int seq, IInputContextCallback callback) {
+        dispatchMessage(obtainMessageIOSC(DO_GET_EXTRACTED_TEXT, flags,
+                request, seq, callback));
+    }
+    
+    public void commitText(CharSequence text, int newCursorPosition) {
+        dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
+    }
+
+    public void commitCompletion(CompletionInfo text) {
+        dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
+    }
+
+    public void setComposingText(CharSequence text, int newCursorPosition) {
+        dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
+    }
+
+    public void sendKeyEvent(KeyEvent event) {
+        dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
+    }
+
+    public void clearMetaKeyStates(int states) {
+        dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
+    }
+
+    public void deleteSurroundingText(int leftLength, int rightLength) {
+        dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
+            leftLength, rightLength));
+    }
+
+    public void hideStatusIcon() {
+        dispatchMessage(obtainMessage(DO_HIDE_STATUS_ICON));
+    }
+
+    public void showStatusIcon(String packageName, int resId) {
+        dispatchMessage(obtainMessageIO(DO_SHOW_STATUS_ICON, resId, packageName));
+    }
+
+    public void performPrivateCommand(String action, Bundle data) {
+        dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
+    }
+    
+    void dispatchMessage(Message msg) {
+        // If we are calling this from the main thread, then we can call
+        // right through.  Otherwise, we need to send the message to the
+        // main thread.
+        if (Looper.myLooper() == mMainLooper) {
+            executeMessage(msg);
+            msg.recycle();
+            return;
+        }
+        
+        mH.sendMessage(msg);
+    }
+    
+    void executeMessage(Message msg) {
+        switch (msg.what) {
+            case DO_GET_TEXT_AFTER_CURSOR: {
+                SomeArgs args = (SomeArgs)msg.obj;
+                try {
+                    args.callback.setTextAfterCursor(mInputConnection.getTextAfterCursor(msg.arg1),
+                            args.seq);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e);
+                }
+                return;
+            }
+            case DO_GET_TEXT_BEFORE_CURSOR: {
+                SomeArgs args = (SomeArgs)msg.obj;
+                try {
+                    args.callback.setTextBeforeCursor(mInputConnection.getTextBeforeCursor(msg.arg1),
+                            args.seq);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e);
+                }
+                return;
+            }
+            case DO_GET_CURSOR_CAPS_MODE: {
+                SomeArgs args = (SomeArgs)msg.obj;
+                try {
+                    args.callback.setCursorCapsMode(mInputConnection.getCursorCapsMode(msg.arg1),
+                            args.seq);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e);
+                }
+                return;
+            }
+            case DO_GET_EXTRACTED_TEXT: {
+                SomeArgs args = (SomeArgs)msg.obj;
+                try {
+                    args.callback.setExtractedText(mInputConnection.getExtractedText(
+                            (ExtractedTextRequest)args.arg1, msg.arg1), args.seq);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Got RemoteException calling setExtractedText", e);
+                }
+                return;
+            }
+            case DO_COMMIT_TEXT: {
+                mInputConnection.commitText((CharSequence)msg.obj, msg.arg1);
+                return;
+            }
+            case DO_COMMIT_COMPLETION: {
+                mInputConnection.commitCompletion((CompletionInfo)msg.obj);
+                return;
+            }
+            case DO_SET_COMPOSING_TEXT: {
+                mInputConnection.setComposingText((CharSequence)msg.obj, msg.arg1);
+                return;
+            }
+            case DO_SEND_KEY_EVENT: {
+                mInputConnection.sendKeyEvent((KeyEvent)msg.obj);
+                return;
+            }
+            case DO_CLEAR_META_KEY_STATES: {
+                mInputConnection.clearMetaKeyStates(msg.arg1);
+                return;
+            }
+            case DO_DELETE_SURROUNDING_TEXT: {
+                mInputConnection.deleteSurroundingText(msg.arg1, msg.arg2);
+                return;
+            }
+            case DO_HIDE_STATUS_ICON: {
+                mInputConnection.hideStatusIcon();
+                return;
+            }
+            case DO_SHOW_STATUS_ICON: {
+                mInputConnection.showStatusIcon((String)msg.obj, msg.arg1);
+                return;
+            }
+            case DO_PERFORM_PRIVATE_COMMAND: {
+                SomeArgs args = (SomeArgs)msg.obj;
+                mInputConnection.performPrivateCommand((String)args.arg1,
+                        (Bundle)args.arg2);
+                return;
+            }
+        }
+        Log.w(TAG, "Unhandled message code: " + msg.what);
+    }
+    
+    Message obtainMessage(int what) {
+        return mH.obtainMessage(what);
+    }
+    
+    Message obtainMessageII(int what, int arg1, int arg2) {
+        return mH.obtainMessage(what, arg1, arg2);
+    }
+    
+    Message obtainMessageO(int what, Object arg1) {
+        return mH.obtainMessage(what, 0, 0, arg1);
+    }
+    
+    Message obtainMessageISC(int what, int arg1, int seq, IInputContextCallback callback) {
+        SomeArgs args = new SomeArgs();
+        args.callback = callback;
+        args.seq = seq;
+        return mH.obtainMessage(what, arg1, 0, args);
+    }
+    
+    Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
+            IInputContextCallback callback) {
+        SomeArgs args = new SomeArgs();
+        args.arg1 = arg2;
+        args.callback = callback;
+        args.seq = seq;
+        return mH.obtainMessage(what, arg1, 0, args);
+    }
+    
+    Message obtainMessageIO(int what, int arg1, Object arg2) {
+        return mH.obtainMessage(what, arg1, 0, arg2);
+    }
+    
+    Message obtainMessageOO(int what, Object arg1, Object arg2) {
+        SomeArgs args = new SomeArgs();
+        args.arg1 = arg1;
+        args.arg2 = arg2;
+        return mH.obtainMessage(what, 0, 0, args);
+    }
+}
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
new file mode 100644
index 0000000..7ea65a0
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.ExtractedTextRequest;
+
+import com.android.internal.view.IInputContextCallback;
+
+/**
+ * Interface from an input method to the application, allowing it to perform
+ * edits on the current input field and other interactions with the application.
+ * {@hide}
+ */
+ oneway interface IInputContext {
+    void getTextBeforeCursor(int length, int seq, IInputContextCallback callback); 
+
+    void getTextAfterCursor(int length, int seq, IInputContextCallback callback);
+    
+    void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback);
+    
+    void getExtractedText(in ExtractedTextRequest request, int flags, int seq,
+            IInputContextCallback callback);
+    
+    void deleteSurroundingText(int leftLength, int rightLength);
+
+    void setComposingText(CharSequence text, int newCursorPosition);
+
+    void commitText(CharSequence text, int newCursorPosition);
+
+    void commitCompletion(in CompletionInfo completion);
+
+    void sendKeyEvent(in KeyEvent event);
+    
+    void clearMetaKeyStates(int states);
+    
+    void performPrivateCommand(String action, in Bundle data);
+    
+    void showStatusIcon(String packageName, int resId);
+
+    void hideStatusIcon();
+}
diff --git a/core/java/com/android/internal/view/IInputContextCallback.aidl b/core/java/com/android/internal/view/IInputContextCallback.aidl
new file mode 100644
index 0000000..9b8c43c
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputContextCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.internal.view;
+
+import android.view.inputmethod.ExtractedText;
+
+/**
+ * {@hide}
+ */
+oneway interface IInputContextCallback {
+    void setTextBeforeCursor(CharSequence textBeforeCursor, int seq);
+    void setTextAfterCursor(CharSequence textAfterCursor, int seq);
+    void setCursorCapsMode(int capsMode, int seq);
+    void setExtractedText(in ExtractedText extractedText, int seq);
+}
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
new file mode 100644
index 0000000..87bf473
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodCallback;
+import com.android.internal.view.IInputMethodSession;
+
+/**
+ * Top-level interface to an input method component (implemented in a
+ * Service).
+ * {@hide}
+ */
+oneway interface IInputMethod {
+    void attachToken(IBinder token);
+    
+    void bindInput(in InputBinding binding);
+    
+    void unbindInput();
+
+    void startInput(in EditorInfo attribute);
+
+    void restartInput(in EditorInfo attribute);
+
+    void createSession(IInputMethodCallback callback);
+    
+    void setSessionEnabled(IInputMethodSession session, boolean enabled);
+    
+    void revokeSession(IInputMethodSession session);
+    
+    void showSoftInput();
+    
+    void hideSoftInput();
+}
diff --git a/core/java/com/android/internal/view/IInputMethodCallback.aidl b/core/java/com/android/internal/view/IInputMethodCallback.aidl
new file mode 100644
index 0000000..480cc0e
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputMethodCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.internal.view;
+
+import android.graphics.Rect;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+import android.os.IBinder;
+
+/**
+ * Helper interface for IInputMethod to allow the input method to call back
+ * to its client with results from incoming calls.
+ * {@hide}
+ */
+oneway interface IInputMethodCallback {
+    void finishedEvent(int seq, boolean handled);
+    void sessionCreated(IInputMethodSession session);
+}
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
new file mode 100644
index 0000000..ce4312d
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import com.android.internal.view.InputBindResult;
+
+/**
+ * Interface a client of the IInputMethodManager implements, to identify
+ * itself and receive information about changes to the global manager state.
+ */
+oneway interface IInputMethodClient {
+    void setUsingInputMethod(boolean state);
+    void onBindMethod(in InputBindResult res);
+    void onUnbindMethod(int sequence);
+    void setActive(boolean active);
+}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
new file mode 100644
index 0000000..b4cfe26
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.EditorInfo;
+import com.android.internal.view.InputBindResult;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodClient;
+
+/**
+ * Public interface to the global input method manager, used by all client
+ * applications.
+ */
+interface IInputMethodManager {
+    List<InputMethodInfo> getInputMethodList();
+    List<InputMethodInfo> getEnabledInputMethodList();
+    
+    void addClient(in IInputMethodClient client,
+            in IInputContext inputContext, int uid, int pid);
+    void removeClient(in IInputMethodClient client);
+            
+    InputBindResult startInput(in IInputMethodClient client,
+            in EditorInfo attribute, boolean initial, boolean needResult);
+    void finishInput(in IInputMethodClient client);
+    void showSoftInput(in IInputMethodClient client);
+    void hideSoftInput(in IInputMethodClient client);
+    void windowGainedFocus(in IInputMethodClient client,
+            boolean viewHasFocus, int softInputMode, boolean first,
+            int windowFlags);
+            
+    void showInputMethodPickerFromClient(in IInputMethodClient client);
+    void setInputMethod(in IBinder token, String id);
+    void hideMySoftInput(in IBinder token);
+    void updateStatusIcon(int iconId, String iconPackage);
+}
+
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
new file mode 100644
index 0000000..4f28593
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -0,0 +1,48 @@
+/*
+ * 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.internal.view;
+
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.ExtractedText;
+import com.android.internal.view.IInputMethodCallback;
+
+/**
+ * Sub-interface of IInputMethod which is safe to give to client applications.
+ * {@hide}
+ */
+oneway interface IInputMethodSession {
+    void finishInput();
+
+    void updateExtractedText(int token, in ExtractedText text);
+    
+    void updateSelection(int oldSelStart, int oldSelEnd,
+            int newSelStart, int newSelEnd);
+    
+    void updateCursor(in Rect newCursor);
+    
+    void displayCompletions(in CompletionInfo[] completions);
+    
+    void dispatchKeyEvent(int seq, in KeyEvent event, IInputMethodCallback callback);
+
+    void dispatchTrackballEvent(int seq, in MotionEvent event, IInputMethodCallback callback);
+
+    void appPrivateCommand(String action, in Bundle data);
+}
diff --git a/core/java/com/android/internal/view/InputBindResult.aidl b/core/java/com/android/internal/view/InputBindResult.aidl
new file mode 100644
index 0000000..7ff5c4e
--- /dev/null
+++ b/core/java/com/android/internal/view/InputBindResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.internal.view;
+
+parcelable InputBindResult;
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
new file mode 100644
index 0000000..658f098
--- /dev/null
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007-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.internal.view;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Bundle of information returned by input method manager about a successful
+ * binding to an input method.
+ */
+public final class InputBindResult implements Parcelable {
+    static final String TAG = "InputBindResult";
+    
+    /**
+     * The input method service.
+     */
+    public final IInputMethodSession method;
+    
+    /**
+     * The ID for this input method, as found in InputMethodInfo; null if
+     * no input method will be bound.
+     */
+    public final String id;
+    
+    /**
+     * Sequence number of this binding.
+     */
+    public final int sequence;
+    
+    public InputBindResult(IInputMethodSession _method, String _id, int _sequence) {
+        method = _method;
+        id = _id;
+        sequence = _sequence;
+    }
+    
+    InputBindResult(Parcel source) {
+        method = IInputMethodSession.Stub.asInterface(source.readStrongBinder());
+        id = source.readString();
+        sequence = source.readInt();
+    }
+    
+    @Override
+    public String toString() {
+        return "InputBindResult{" + method + " " + id
+                + " #" + sequence + "}";
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     * 
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongInterface(method);
+        dest.writeString(id);
+        dest.writeInt(sequence);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<InputBindResult> CREATOR = new Parcelable.Creator<InputBindResult>() {
+        public InputBindResult createFromParcel(Parcel source) {
+            return new InputBindResult(source);
+        }
+
+        public InputBindResult[] newArray(int size) {
+            return new InputBindResult[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
new file mode 100644
index 0000000..5bfcfe9
--- /dev/null
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -0,0 +1,306 @@
+package com.android.internal.view;
+
+import com.android.internal.view.IInputContext;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
+
+public class InputConnectionWrapper implements InputConnection {
+    private static final int MAX_WAIT_TIME_MILLIS = 2000;
+    private final IInputContext mIInputContext;
+    
+    static class InputContextCallback extends IInputContextCallback.Stub {
+        private static final String TAG = "InputConnectionWrapper.ICC";
+        public int mSeq;
+        public boolean mHaveValue;
+        public CharSequence mTextBeforeCursor;
+        public CharSequence mTextAfterCursor;
+        public ExtractedText mExtractedText;
+        public int mCursorCapsMode;
+        
+        // A 'pool' of one InputContextCallback.  Each ICW request will attempt to gain
+        // exclusive access to this object.
+        private static InputContextCallback sInstance = new InputContextCallback();
+        private static int sSequenceNumber = 1;
+        
+        /**
+         * Returns an InputContextCallback object that is guaranteed not to be in use by
+         * any other thread.  The returned object's 'have value' flag is cleared and its expected
+         * sequence number is set to a new integer.  We use a sequence number so that replies that
+         * occur after a timeout has expired are not interpreted as replies to a later request.
+         */
+        private static InputContextCallback getInstance() {
+            synchronized (InputContextCallback.class) {
+                // Return sInstance if it's non-null, otherwise construct a new callback
+                InputContextCallback callback;
+                if (sInstance != null) {
+                    callback = sInstance;
+                    sInstance = null;
+                    
+                    // Reset the callback
+                    callback.mHaveValue = false;
+                } else {
+                    callback = new InputContextCallback();
+                }
+                
+                // Set the sequence number
+                callback.mSeq = sSequenceNumber++;
+                return callback;
+            }
+        }
+        
+        /**
+         * Makes the given InputContextCallback available for use in the future.
+         */
+        private void dispose() {
+            synchronized (InputContextCallback.class) {
+                // If sInstance is non-null, just let this object be garbage-collected
+                if (sInstance == null) {
+                    // Allow any objects being held to be gc'ed
+                    mTextAfterCursor = null;
+                    mTextBeforeCursor = null;
+                    mExtractedText = null;
+                    sInstance = this;
+                }
+            }
+        }
+        
+        public void setTextBeforeCursor(CharSequence textBeforeCursor, int seq) {
+            synchronized (this) {
+                if (seq == mSeq) {
+                    mTextBeforeCursor = textBeforeCursor;
+                    mHaveValue = true;
+                    notifyAll();
+                } else {
+                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
+                            + ") in setTextBeforeCursor, ignoring.");
+                }
+            }
+        }
+
+        public void setTextAfterCursor(CharSequence textAfterCursor, int seq) {
+            synchronized (this) {
+                if (seq == mSeq) {
+                    mTextAfterCursor = textAfterCursor;
+                    mHaveValue = true;
+                    notifyAll();
+                } else {
+                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
+                            + ") in setTextAfterCursor, ignoring.");
+                }
+            }
+        }
+
+        public void setCursorCapsMode(int capsMode, int seq) {
+            synchronized (this) {
+                if (seq == mSeq) {
+                    mCursorCapsMode = capsMode; 
+                    mHaveValue = true;  
+                    notifyAll();
+                } else {
+                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
+                            + ") in setCursorCapsMode, ignoring.");
+                }
+            }
+        }
+
+        public void setExtractedText(ExtractedText extractedText, int seq) {
+            synchronized (this) {
+                if (seq == mSeq) {
+                    mExtractedText = extractedText;
+                    mHaveValue = true;
+                    notifyAll();
+                } else {
+                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
+                            + ") in setExtractedText, ignoring.");
+                }
+            }
+        }
+        
+        /**
+         * Waits for a result for up to {@link #MAX_WAIT_TIME_MILLIS} milliseconds.
+         * 
+         * <p>The caller must be synchronized on this callback object.
+         */
+        void waitForResultLocked() {
+            long startTime = SystemClock.uptimeMillis();
+            long endTime = startTime + MAX_WAIT_TIME_MILLIS;
+
+            while (!mHaveValue) {
+                long remainingTime = endTime - SystemClock.uptimeMillis();
+                if (remainingTime <= 0) {
+                    Log.w(TAG, "Timed out waiting on IInputContextCallback");
+                    return;
+                }
+                try {
+                    wait(remainingTime);
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+    }
+
+    public InputConnectionWrapper(IInputContext inputContext) {
+        mIInputContext = inputContext;
+    }
+
+    public CharSequence getTextAfterCursor(int length) {
+        CharSequence value = null;
+        try {
+            InputContextCallback callback = InputContextCallback.getInstance();
+            mIInputContext.getTextAfterCursor(length, callback.mSeq, callback);
+            synchronized (callback) {
+                callback.waitForResultLocked();
+                if (callback.mHaveValue) {
+                    value = callback.mTextAfterCursor;
+                }
+            }
+            callback.dispose();
+        } catch (RemoteException e) {
+            return null;
+        }
+        return value;
+    }
+    
+    public CharSequence getTextBeforeCursor(int length) {
+        CharSequence value = null;
+        try {
+            InputContextCallback callback = InputContextCallback.getInstance();
+            mIInputContext.getTextBeforeCursor(length, callback.mSeq, callback);
+            synchronized (callback) {
+                callback.waitForResultLocked();
+                if (callback.mHaveValue) {
+                    value = callback.mTextBeforeCursor;
+                }
+            }
+            callback.dispose();
+        } catch (RemoteException e) {
+            return null;
+        }
+        return value;
+    }
+    
+    public int getCursorCapsMode(int reqModes) {
+        int value = 0;
+        try {
+            InputContextCallback callback = InputContextCallback.getInstance();
+            mIInputContext.getCursorCapsMode(reqModes, callback.mSeq, callback);
+            synchronized (callback) {
+                callback.waitForResultLocked();
+                if (callback.mHaveValue) {
+                    value = callback.mCursorCapsMode;
+                }
+            }
+            callback.dispose();
+        } catch (RemoteException e) {
+            return 0;
+        }
+        return value;
+    }
+    
+    public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
+        ExtractedText value = null;
+        try {
+            InputContextCallback callback = InputContextCallback.getInstance();
+            mIInputContext.getExtractedText(request, flags, callback.mSeq, callback);
+            synchronized (callback) {
+                callback.waitForResultLocked();
+                if (callback.mHaveValue) {
+                    value = callback.mExtractedText;
+                }
+            }
+            callback.dispose();
+        } catch (RemoteException e) {
+            return null;
+        }
+        return value;
+    }
+    
+    public boolean commitText(CharSequence text, int newCursorPosition) {
+        try {
+            mIInputContext.commitText(text, newCursorPosition);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    public boolean commitCompletion(CompletionInfo text) {
+        try {
+            mIInputContext.commitCompletion(text);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    public boolean setComposingText(CharSequence text, int newCursorPosition) {
+        try {
+            mIInputContext.setComposingText(text, newCursorPosition);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    public boolean sendKeyEvent(KeyEvent event) {
+        try {
+            mIInputContext.sendKeyEvent(event);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    public boolean clearMetaKeyStates(int states) {
+        try {
+            mIInputContext.clearMetaKeyStates(states);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+    
+    public boolean deleteSurroundingText(int leftLength, int rightLength) {
+        try {
+            mIInputContext.deleteSurroundingText(leftLength, rightLength);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    public boolean hideStatusIcon() {
+        try {
+            mIInputContext.showStatusIcon(null, 0);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    public boolean showStatusIcon(String packageName, int resId) {
+        try {
+            mIInputContext.showStatusIcon(packageName, resId);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    public boolean performPrivateCommand(String action, Bundle data) {
+        try {
+            mIInputContext.performPrivateCommand(action, data);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java
index 156e20a..3b11a64 100644
--- a/core/java/com/android/internal/view/menu/IconMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java
@@ -26,6 +26,7 @@
 import android.view.Gravity;
 import android.view.SoundEffectConstants;
 import android.view.View;
+import android.view.ViewDebug;
 import android.widget.TextView;
 
 /**
@@ -176,6 +177,9 @@
             
             // Set the compound drawables
             setCompoundDrawables(null, icon, null, null);
+            
+            // When there is an icon, make sure the text is at the bottom
+            setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
 
             /*
              * Request a layout to reposition the icon. The positioning of icon
@@ -185,13 +189,17 @@
             requestLayout();
         } else {
             setCompoundDrawables(null, null, null, null);
+            
+            // When there is no icon, make sure the text is centered vertically
+            setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
         }
     }
 
     public void setItemInvoker(ItemInvoker itemInvoker) {
         mItemInvoker = itemInvoker;
     }
-
+    
+    @ViewDebug.CapturedViewProperty(retrieveReturn = true)
     public MenuItemImpl getItemData() {
         return mItemData;
     }
diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java
index fc76a04..781c608 100644
--- a/core/java/com/android/internal/view/menu/IconMenuView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuView.java
@@ -26,6 +26,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.Layout;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.View;
@@ -57,6 +58,8 @@
     private int mRowHeight;
     /** Maximum number of rows to be shown */ 
     private int mMaxRows;
+    /** Maximum number of items to show in the icon menu. */
+    private int mMaxItems;
     /** Maximum number of items per row */
     private int mMaxItemsPerRow;
     /** Actual number of items (the 'More' view does not count as an item) shown */
@@ -76,15 +79,15 @@
     /** Set of vertical divider positions where the vertical divider will be drawn */
     private ArrayList<Rect> mVerticalDividerRects;
     
+    /** Icon for the 'More' button */
+    private Drawable mMoreIcon;
+    
     /** Item view for the 'More' button */
     private IconMenuItemView mMoreItemView;
     
     /** Background of each item (should contain the selected and focused states) */
     private Drawable mItemBackground;
 
-    /** Icon for the 'More' button */
-    private Drawable mMoreIcon;
-    
     /** Default animations for this menu */
     private int mAnimations;
     
@@ -108,6 +111,20 @@
      * we broadcasted to children.
      */
     private boolean mLastChildrenCaptionMode;
+
+    /**
+     * The layout to use for menu items. Each index is the row number (0 is the
+     * top-most). Each value contains the number of items in that row.
+     * <p>
+     * The length of this array should not be used to get the number of rows in
+     * the current layout, instead use {@link #mLayoutNumRows}.
+     */
+    private int[] mLayout;
+
+    /**
+     * The number of rows in the current layout. 
+     */
+    private int mLayoutNumRows;
     
     /**
      * Instantiates the IconMenuView that is linked with the provided MenuBuilder.
@@ -119,6 +136,7 @@
             context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.IconMenuView, 0, 0);
         mRowHeight = a.getDimensionPixelSize(com.android.internal.R.styleable.IconMenuView_rowHeight, 64);
         mMaxRows = a.getInt(com.android.internal.R.styleable.IconMenuView_maxRows, 2);
+        mMaxItems = a.getInt(com.android.internal.R.styleable.IconMenuView_maxItems, 6);
         mMaxItemsPerRow = a.getInt(com.android.internal.R.styleable.IconMenuView_maxItemsPerRow, 3);
         mMoreIcon = a.getDrawable(com.android.internal.R.styleable.IconMenuView_moreIcon);
         a.recycle();
@@ -144,6 +162,8 @@
             if (mVerticalDividerWidth == -1) mVerticalDividerWidth = 1;
         }
         
+        mLayout = new int[mMaxRows];
+        
         // This view will be drawing the dividers        
         setWillNotDraw(false);
         
@@ -152,13 +172,106 @@
         // This is so our children can still be arrow-key focused
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
     }
-    
+
     /**
-     * Calculates the minimum number of rows needed to the items to be shown.
-     * @return the minimum number of rows
+     * Figures out the layout for the menu items.
+     * 
+     * @param width The available width for the icon menu.
      */
-    private int calculateNumberOfRows() {
-        return Math.min((int) Math.ceil(getChildCount() / (double) mMaxItemsPerRow), mMaxRows);
+    private void layoutItems(int width) {
+        int numItems = getChildCount();
+        
+        // Start with the least possible number of rows
+        int curNumRows =
+                Math.min((int) Math.ceil(numItems / (float) mMaxItemsPerRow), mMaxRows);
+        
+        /*
+         * Increase the number of rows until we find a configuration that fits
+         * all of the items' titles. Worst case, we use mMaxRows.
+         */
+        for (; curNumRows <= mMaxRows; curNumRows++) {
+            layoutItemsUsingGravity(curNumRows, numItems);
+            
+            if (curNumRows >= numItems) {
+                // Can't have more rows than items
+                break;
+            }
+            
+            if (doItemsFit()) {
+                // All the items fit, so this is a good configuration
+                break;
+            }
+        }
+    }
+
+    /**
+     * Figures out the layout for the menu items by equally distributing, and
+     * adding any excess items equally to lower rows.
+     * 
+     * @param numRows The total number of rows for the menu view
+     * @param numItems The total number of items (across all rows) contained in
+     *            the menu view
+     * @return int[] Where the value of index i contains the number of items for row i
+     */
+    private void layoutItemsUsingGravity(int numRows, int numItems) {
+        int numBaseItemsPerRow = numItems / numRows;
+        int numLeftoverItems = numItems % numRows;
+        /**
+         * The bottom rows will each get a leftover item. Rows (indexed at 0)
+         * that are >= this get a leftover item. Note: if there are 0 leftover
+         * items, no rows will get them since this value will be greater than
+         * the last row.
+         */
+        int rowsThatGetALeftoverItem = numRows - numLeftoverItems;
+        
+        int[] layout = mLayout;
+        for (int i = 0; i < numRows; i++) {
+            layout[i] = numBaseItemsPerRow;
+
+            // Fill the bottom rows with a leftover item each
+            if (i >= rowsThatGetALeftoverItem) {
+                layout[i]++;
+            }
+        }
+        
+        mLayoutNumRows = numRows;
+    }
+
+    /**
+     * Checks whether each item's title is fully visible using the current
+     * layout.
+     * 
+     * @return True if the items fit (each item's text is fully visible), false
+     *         otherwise.
+     */
+    private boolean doItemsFit() {
+        int itemPos = 0;
+        
+        int[] layout = mLayout;
+        int numRows = mLayoutNumRows;
+        for (int row = 0; row < numRows; row++) {
+            int numItemsOnRow = layout[row];
+
+            /*
+             * If there is only one item on this row, increasing the
+             * number of rows won't help.
+             */ 
+            if (numItemsOnRow == 1) {
+                itemPos++;
+                continue;
+            }
+            
+            for (int itemsOnRowCounter = numItemsOnRow; itemsOnRowCounter > 0;
+                    itemsOnRowCounter--) {
+                View child = getChildAt(itemPos++);
+                LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp.maxNumItemsOnRow < numItemsOnRow) {
+                    return false;
+                }
+            }
+        }
+        
+        return true;
     }
 
     /**
@@ -166,7 +279,7 @@
      * @param itemView The item's view to add
      */
     private void addItemView(IconMenuItemView itemView) {
-        ViewGroup.LayoutParams lp = itemView.getLayoutParams();
+        LayoutParams lp = (LayoutParams) itemView.getLayoutParams();
         
         if (lp == null) {
             // Default layout parameters
@@ -182,6 +295,9 @@
         // This class is the invoker for all its item views 
         itemView.setItemInvoker(this);
         
+        // Set the desired width of item
+        lp.desiredWidth = (int) Layout.getDesiredWidth(itemView.getText(), itemView.getPaint());
+        
         addView(itemView, lp);
     }
 
@@ -228,7 +344,7 @@
         
         final ArrayList<MenuItemImpl> itemsToShow = mMenu.getVisibleItems();
         final int numItems = itemsToShow.size();
-        final int numItemsThatCanFit = mMaxItemsPerRow * mMaxRows;
+        final int numItemsThatCanFit = mMaxItems;
         // Minimum of the num that can fit and the num that we have
         final int minFitMinus1AndNumItems = Math.min(numItemsThatCanFit - 1, numItems);
         
@@ -263,30 +379,6 @@
     }
 
     /**
-     * Calculates the number of items that should go on each row of this menu view.
-     * @param numRows the total number of rows for the menu view
-     * @param numItems the total number of items (across all rows) contained in the menu view
-     * @return int[] where index i contains the number of items for row i
-     */
-    private int[] calculateNumberOfItemsPerRow(final int numRows, final int numItems) {
-        // TODO: get from theme?  or write a best-fit algorithm? either way, this hard-coding needs
-        // to be dropped (946635).  Right now, this is according to UI spec.
-        final int numItemsForRow[] = new int[numRows];
-        if (numRows == 2) {
-            if (numItems <= 5) {
-                numItemsForRow[0] = 2;
-                numItemsForRow[1] = numItems - 2;
-            } else {
-                numItemsForRow[0] = numItemsForRow[1] = mMaxItemsPerRow;
-            }
-        } else if (numRows == 1) {
-            numItemsForRow[0] = numItems;
-        }
-        
-        return numItemsForRow;
-    }
-    
-    /**
      * The positioning algorithm that gets called from onMeasure.  It
      * just computes positions for each child, and then stores them in the child's layout params.
      * @param menuWidth The width of this menu to assume for positioning
@@ -298,10 +390,9 @@
         if (mVerticalDivider != null) mVerticalDividerRects.clear();
 
         // Get the minimum number of rows needed
-        final int numRows = calculateNumberOfRows();
+        final int numRows = mLayoutNumRows;
         final int numRowsMinus1 = numRows - 1;
-        final int numItems = getChildCount();
-        final int numItemsForRow[] = calculateNumberOfItemsPerRow(numRows, numItems);
+        final int numItemsForRow[] = mLayout;
         
         // The item position across all rows
         int itemPos = 0;
@@ -382,13 +473,17 @@
             updateChildren(false);
         }
         
+        int measuredWidth = resolveSize(Integer.MAX_VALUE, widthMeasureSpec);
+        calculateItemFittingMetadata(measuredWidth);
+        layoutItems(measuredWidth);
+        
         // Get the desired height of the icon menu view (last row of items does
         // not have a divider below)
-        final int desiredHeight = (mRowHeight + mHorizontalDividerHeight) * calculateNumberOfRows()
-                - mHorizontalDividerHeight;
+        final int desiredHeight = (mRowHeight + mHorizontalDividerHeight) *
+                mLayoutNumRows - mHorizontalDividerHeight;
         
         // Maximum possible width and desired height
-        setMeasuredDimension(resolveSize(Integer.MAX_VALUE, widthMeasureSpec),
+        setMeasuredDimension(measuredWidth,
                 resolveSize(desiredHeight, heightMeasureSpec));
 
         // Position the children
@@ -472,6 +567,32 @@
         return mAnimations;
     }
 
+    /**
+     * Returns the number of items per row.
+     * <p>
+     * This should only be used for testing.
+     * 
+     * @return The length of the array is the number of rows. A value at a
+     *         position is the number of items in that row.
+     * @hide
+     */
+    public int[] getLayout() {
+        return mLayout;
+    }
+    
+    /**
+     * Returns the number of rows in the layout.
+     * <p>
+     * This should only be used for testing.
+     * 
+     * @return The length of the array is the number of rows. A value at a
+     *         position is the number of items in that row.
+     * @hide
+     */
+    public int getLayoutNumRows() {
+        return mLayoutNumRows;
+    }
+    
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
 
@@ -499,6 +620,13 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        
+        requestFocus();
+    }
+
+    @Override
     protected void onDetachedFromWindow() {
         setCycleShortcutCaptionMode(false);
         super.onDetachedFromWindow();
@@ -580,6 +708,31 @@
             ((IconMenuItemView) getChildAt(i)).setCaptionMode(shortcut);
         }
     }
+
+    /**
+     * For each item, calculates the most dense row that fully shows the item's
+     * title.
+     * 
+     * @param width The available width of the icon menu.
+     */
+    private void calculateItemFittingMetadata(int width) {
+        int maxNumItemsPerRow = mMaxItemsPerRow;
+        int numItems = getChildCount();
+        for (int i = 0; i < numItems; i++) {
+            LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
+            // Start with 1, since that case does not get covered in the loop below
+            lp.maxNumItemsOnRow = 1;
+            for (int curNumItemsPerRow = maxNumItemsPerRow; curNumItemsPerRow > 0;
+                    curNumItemsPerRow--) {
+                // Check whether this item can fit into a row containing curNumItemsPerRow
+                if (lp.desiredWidth < width / curNumItemsPerRow) {
+                    // It can, mark this value as the most dense row it can fit into
+                    lp.maxNumItemsOnRow = curNumItemsPerRow;
+                    break;
+                }
+            }
+        }
+    }
     
     @Override
     protected Parcelable onSaveInstanceState() {
@@ -655,6 +808,8 @@
     public static class LayoutParams extends ViewGroup.MarginLayoutParams
     {
         int left, top, right, bottom;
+        int desiredWidth;
+        int maxNumItemsOnRow;
         
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 835e4a9..2987602 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -432,8 +432,9 @@
             rintent.setComponent(new ComponentName(
                     ri.activityInfo.applicationInfo.packageName,
                     ri.activityInfo.name));
-            final MenuItem item = add(group, id, categoryOrder, ri.loadLabel(pm));
-            item.setIntent(rintent);
+            final MenuItem item = add(group, id, categoryOrder, ri.loadLabel(pm))
+                    .setIcon(ri.loadIcon(pm))
+                    .setIntent(rintent);
             if (outSpecificItems != null && ri.specificIndex >= 0) {
                 outSpecificItems[ri.specificIndex] = item;
             }
@@ -624,7 +625,8 @@
         return mItems.size();
     }
 
-    public MenuItem get(int index) {
+    /** {@inheritDoc} */
+    public MenuItem getItem(int index) {
         return mItems.get(index);
     }
 
@@ -773,7 +775,8 @@
                         (shortcutAlphaChar != 0) &&
                         (shortcutAlphaChar == possibleChars.meta[0]
                          || shortcutAlphaChar == possibleChars.meta[2]
-                         || (shortcutAlphaChar == '\b' && keyCode == KeyEvent.KEYCODE_DEL))) {
+                         || (shortcutAlphaChar == '\b' && keyCode == KeyEvent.KEYCODE_DEL)) &&
+                        item.isEnabled()) {
                     return item;
                 }
             } else {
@@ -781,7 +784,8 @@
                 if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) &&
                         (shortcutNumericChar != 0) &&
                         (shortcutNumericChar == possibleChars.meta[0]
-                            || shortcutNumericChar == possibleChars.meta[2])) {
+                            || shortcutNumericChar == possibleChars.meta[2]) &&
+                        item.isEnabled()) {
                     return item;
                 }
             }
@@ -829,13 +833,18 @@
      *            sub menu is about to be shown, <var>allMenusAreClosing</var>
      *            is false.
      */
-    public final void close(boolean allMenusAreClosing) {
+    final void close(boolean allMenusAreClosing) {
         Callback callback = getCallback();
         if (callback != null) {
             callback.onCloseMenu(this, allMenusAreClosing);
         }
     }
 
+    /** {@inheritDoc} */
+    public void close() {
+        close(true);
+    }
+
     /**
      * Called when an item is added or removed.
      * 
diff --git a/core/java/com/android/internal/view/menu/MenuDialogHelper.java b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
index 6dfc7a2e..bc51cf3 100644
--- a/core/java/com/android/internal/view/menu/MenuDialogHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
@@ -72,10 +72,11 @@
         mDialog = builder.create();
         
         WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes();
-        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
         if (windowToken != null) {
             lp.token = windowToken;
         }
+        lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         
         mDialog.show();
     }
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index c89f2e9..43dba6f 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -24,6 +24,7 @@
 import android.view.MenuItem;
 import android.view.SubMenu;
 import android.view.View;
+import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.ContextMenu.ContextMenuInfo;
 
@@ -183,6 +184,7 @@
         return mGroup;
     }
 
+    @ViewDebug.CapturedViewProperty
     public int getItemId() {
         return mId;
     }
@@ -353,6 +355,7 @@
         subMenu.setHeaderTitle(getTitle());
     }
     
+    @ViewDebug.CapturedViewProperty
     public CharSequence getTitle() {
         return mTitle;
     }
diff --git a/core/java/com/android/internal/view/package.html b/core/java/com/android/internal/view/package.html
new file mode 100644
index 0000000..783d0a1
--- /dev/null
+++ b/core/java/com/android/internal/view/package.html
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java
new file mode 100644
index 0000000..2eef0b6
--- /dev/null
+++ b/core/java/com/android/internal/widget/DialogTitle.java
@@ -0,0 +1,71 @@
+/* 
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.text.Layout;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.widget.TextView;
+
+/**
+ * Used by dialogs to change the font size and number of lines to try to fit
+ * the text to the available space.
+ */
+public class DialogTitle extends TextView {
+    
+    public DialogTitle(Context context, AttributeSet attrs,
+            int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public DialogTitle(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public DialogTitle(Context context) {
+        super(context);
+    }
+    
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        final Layout layout = getLayout();
+        if (layout != null) {
+            final int lineCount = layout.getLineCount();
+            if (lineCount > 0) {
+                final int ellipsisCount = layout.getEllipsisCount(lineCount - 1);
+                if (ellipsisCount > 0) {
+                    setSingleLine(false);
+                    
+                    TypedArray a = mContext.obtainStyledAttributes(
+                            android.R.style.TextAppearance_Medium,
+                            android.R.styleable.TextAppearance);
+                    final int textSize = a.getDimensionPixelSize(
+                            android.R.styleable.TextAppearance_textSize, 20);
+
+                    setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);
+                    setMaxLines(2);
+                    super.onMeasure(widthMeasureSpec, heightMeasureSpec);      
+                }
+            }
+        }
+    }
+   
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
new file mode 100644
index 0000000..efe15f3
--- /dev/null
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2007-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.internal.widget;
+
+import android.content.res.TypedArray;
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.method.KeyListener;
+import android.util.Log;
+import android.util.LogPrinter;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.widget.TextView;
+
+class ComposingText {
+}
+
+public class EditableInputConnection extends BaseInputConnection {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "EditableInputConnection";
+
+    public static final Object COMPOSING = new ComposingText();
+    
+    private final TextView mTextView;
+    private final Handler mUiHandler;
+
+    private Object[] mDefaultComposingSpans;
+    
+    public EditableInputConnection(TextView textview) {
+        super(textview);
+        mTextView = textview;
+        mUiHandler = textview.getHandler();
+    }
+
+    public boolean setComposingText(CharSequence text, int newCursorPosition) {
+        if (DEBUG) Log.v(TAG, "setComposingText " + text);
+        replaceText(text, newCursorPosition, true);
+        return true;
+    }
+
+    public boolean commitText(CharSequence text, int newCursorPosition) {
+        if (DEBUG) Log.v(TAG, "commitText " + text);
+        replaceText(text, newCursorPosition, false);
+        return true;
+    }
+
+    public boolean commitCompletion(CompletionInfo text) {
+        if (DEBUG) Log.v(TAG, "commitCompletion " + text);
+        mTextView.onCommitCompletion(text);
+        return true;
+    }
+
+    public CharSequence getTextBeforeCursor(int length) {
+        final Editable content = getEditable();
+        if (content == null) return null;
+
+        int a = Selection.getSelectionStart(content);
+        int b = Selection.getSelectionEnd(content);
+
+        if (a > b) {
+            int tmp = a;
+            a = b;
+            b = tmp;
+        }
+
+        if (length > a) {
+            length = a;
+        }
+
+        return content.subSequence(a - length, a);
+    }
+
+    public CharSequence getTextAfterCursor(int length) {
+        final Editable content = getEditable();
+        if (content == null) return null;
+
+        int a = Selection.getSelectionStart(content);
+        int b = Selection.getSelectionEnd(content);
+
+        if (a > b) {
+            int tmp = a;
+            a = b;
+            b = tmp;
+        }
+
+        if (b + length > content.length()) {
+            length = content.length() - b;
+        }
+
+        return content.subSequence(b, b + length);
+    }
+
+    public int getCursorCapsMode(int reqModes) {
+        final Editable content = getEditable();
+        if (content == null) return 0;
+        
+        int a = Selection.getSelectionStart(content);
+        int b = Selection.getSelectionEnd(content);
+
+        if (a > b) {
+            int tmp = a;
+            a = b;
+            b = tmp;
+        }
+
+        return TextUtils.getCapsMode(content, a, reqModes);
+    }
+    
+    public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
+        if (mTextView != null) {
+            ExtractedText et = new ExtractedText();
+            if (mTextView.extractText(request, et)) {
+                if ((flags&EXTRACTED_TEXT_MONITOR) != 0) {
+                    mTextView.setExtracting(request);
+                }
+                return et;
+            }
+        }
+        return null;
+    }
+    
+    public boolean deleteSurroundingText(int leftLength, int rightLength) {
+        if (DEBUG) Log.v(TAG, "deleteSurroundingText " + leftLength
+                + " / " + rightLength);
+        final Editable content = getEditable();
+        if (content == null) return false;
+
+        int a = Selection.getSelectionStart(content);
+        int b = Selection.getSelectionEnd(content);
+
+        if (a > b) {
+            int tmp = a;
+            a = b;
+            b = tmp;
+        }
+
+        // ignore the composing text.
+        int ca = content.getSpanStart(COMPOSING);
+        int cb = content.getSpanEnd(COMPOSING);
+        if (cb < ca) {
+            int tmp = ca;
+            ca = cb;
+            cb = tmp;
+        }
+        if (ca != -1 && cb != -1) {
+            if (ca < a) a = ca;
+            if (cb > b) b = cb;
+        }
+
+        int deleted = 0;
+
+        if (leftLength > 0) {
+            int start = a - leftLength;
+            if (start < 0) start = 0;
+            content.delete(start, a);
+            deleted = a - start;
+        }
+
+        if (rightLength > 0) {
+            b = b - deleted;
+
+            int end = b + rightLength;
+            if (end > content.length()) end = content.length();
+
+            content.delete(b, end);
+        }
+        
+        return true;
+    }
+
+    public boolean clearMetaKeyStates(int states) {
+        final Editable content = getEditable();
+        if (content == null) return false;
+        KeyListener kl = mTextView.getKeyListener();
+        if (kl != null) kl.clearMetaKeyState(mTextView, content, states);
+        return true;
+    }
+    
+    public boolean performPrivateCommand(String action, Bundle data) {
+        if (mTextView == null) return false;
+        mTextView.onPrivateIMECommand(action, data);
+        return true;
+    }
+    
+    private Editable getEditable() {
+        TextView tv = mTextView;
+        if (tv != null) {
+            return tv.getEditableText();
+        }
+        return null;
+    }
+    
+    public static void setComposingSpans(Spannable text) {
+        final Object[] sps = text.getSpans(0, text.length(), Object.class);
+        if (sps != null) {
+            for (int i=sps.length-1; i>=0; i--) {
+                final Object o = sps[i];
+                if (o == COMPOSING) {
+                    text.removeSpan(o);
+                    continue;
+                }
+                final int fl = text.getSpanFlags(o);
+                if ((fl&(Spanned.SPAN_COMPOSING|Spanned.SPAN_POINT_MARK_MASK)) 
+                        != (Spanned.SPAN_COMPOSING|Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)) {
+                    text.setSpan(o, text.getSpanStart(o), text.getSpanEnd(o),
+                            (fl&Spanned.SPAN_POINT_MARK_MASK)
+                                    | Spanned.SPAN_COMPOSING
+                                    | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+            }
+        }
+        
+        text.setSpan(COMPOSING, 0, text.length(),
+                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
+    }
+    
+    public static final void removeComposingSpans(Spannable text) {
+        text.removeSpan(COMPOSING);
+        Object[] sps = text.getSpans(0, text.length(), Object.class);
+        if (sps != null) {
+            for (int i=sps.length-1; i>=0; i--) {
+                Object o = sps[i];
+                if ((text.getSpanFlags(o)&Spanned.SPAN_COMPOSING) != 0) {
+                    text.removeSpan(o);
+                }
+            }
+        }
+    }
+    
+    private void replaceText(CharSequence text, int newCursorPosition,
+            boolean composing) {
+        final Editable content = getEditable();
+        
+        // delete composing text set previously.
+        int a = content.getSpanStart(COMPOSING);
+        int b = content.getSpanEnd(COMPOSING);
+
+        if (DEBUG) Log.v(TAG, "Composing span: " + a + " to " + b);
+        
+        if (b < a) {
+            int tmp = a;
+            a = b;
+            b = tmp;
+        }
+
+        if (a != -1 && b != -1) {
+            removeComposingSpans(content);
+        } else {
+            a = Selection.getSelectionStart(content);
+            b = Selection.getSelectionEnd(content);
+            if (a >=0 && b>= 0 && a != b) {
+                if (b < a) {
+                    int tmp = a;
+                    a = b;
+                    b = tmp;
+                }
+            }
+        }
+
+        if (composing) {
+            Spannable sp = null;
+            if (!(text instanceof Spannable)) {
+                sp = new SpannableStringBuilder(text);
+                text = sp;
+                if (mDefaultComposingSpans == null) {
+                    TypedArray ta = mTextView.getContext().getTheme()
+                            .obtainStyledAttributes(new int[] {
+                                    com.android.internal.R.attr.candidatesTextStyleSpans
+                            });
+                    CharSequence style = ta.getText(0);
+                    ta.recycle();
+                    if (style != null && style instanceof Spanned) {
+                        mDefaultComposingSpans = ((Spanned)style).getSpans(
+                                0, style.length(), Object.class);
+                    }
+                }
+                if (mDefaultComposingSpans != null) {
+                    for (int i = 0; i < mDefaultComposingSpans.length; ++i) {
+                        sp.setSpan(mDefaultComposingSpans[i], 0, sp.length(),
+                                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    }
+                }
+            } else {
+                sp = (Spannable)text;
+            }
+            setComposingSpans(sp);
+        }
+        
+        // Adjust newCursorPosition to be relative the start of the text.
+        newCursorPosition += a;
+
+        if (DEBUG) Log.v(TAG, "Replacing from " + a + " to " + b + " with \""
+                + text + "\", composing=" + composing
+                + ", type=" + text.getClass().getCanonicalName());
+        
+        if (DEBUG) {
+            LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG);
+            lp.println("Current text:");
+            TextUtils.dumpSpans(content, lp, "  ");
+            lp.println("Composing text:");
+            TextUtils.dumpSpans(text, lp, "  ");
+        }
+        
+        content.replace(a, b, text);
+        if (newCursorPosition < 0) newCursorPosition = 0;
+        if (newCursorPosition > content.length())
+            newCursorPosition = content.length();
+        Selection.setSelection(content, newCursorPosition);
+        
+        if (DEBUG) {
+            LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG);
+            lp.println("Final text:");
+            TextUtils.dumpSpans(content, lp, "  ");
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 1c75daa..ed1cd58 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -256,6 +256,20 @@
     }
 
     /**
+     * @return Whether tactile feedback for the pattern is enabled.
+     */
+    public boolean isTactileFeedbackEnabled() {
+        return getBoolean(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
+    }
+
+    /**
+     * Set whether tactile feedback for the pattern is enabled.
+     */
+    public void setTactileFeedbackEnabled(boolean enabled) {
+        setBoolean(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED, enabled);
+    }
+
+    /**
      * Store the lockout deadline, meaning the user can't attempt his/her unlock
      * pattern until the deadline has passed.  Does not persist across reboots.
      * @param deadline The elapsed real time in millis in future.
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index bf00eff..7f99ac8 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -32,6 +32,7 @@
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.os.Debug;
+import android.os.Vibrator;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -48,6 +49,9 @@
  * "correct" states.
  */
 public class LockPatternView extends View {
+    // Vibrator pattern for creating a tactile bump
+    private static final long[] VIBE_PATTERN = {0, 1, 40, 41};
+
     private static final boolean PROFILE_DRAWING = false;
     private boolean mDrawingProfilingStarted = false;
 
@@ -88,6 +92,7 @@
     private DisplayMode mPatternDisplayMode = DisplayMode.Correct;
     private boolean mInputEnabled = true;
     private boolean mInStealthMode = false;
+    private boolean mTactileFeedbackEnabled = true;
     private boolean mPatternInProgress = false;
 
     private float mDiameterFactor = 0.5f;
@@ -112,6 +117,8 @@
     private int mBitmapHeight;
    
 
+    private Vibrator vibe; // Vibrator for creating tactile feedback
+
     /**
      * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
      */
@@ -219,6 +226,7 @@
 
     public LockPatternView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        vibe = new Vibrator();
 
         setClickable(true);
 
@@ -257,6 +265,13 @@
     }
 
     /**
+     * @return Whether the view has tactile feedback enabled.
+     */
+    public boolean isTactileFeedbackEnabled() {
+        return mTactileFeedbackEnabled;
+    }
+
+    /**
      * Set whether the view is in stealth mode.  If true, there will be no
      * visible feedback as the user enters the pattern.
      *
@@ -267,6 +282,16 @@
     }
 
     /**
+     * Set whether the view will use tactile feedback.  If true, there will be
+     * tactile feedback as the user enters the pattern.
+     *
+     * @param tactileFeedbackEnabled Whether tactile feedback is enabled
+     */
+    public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) {
+        mTactileFeedbackEnabled = tactileFeedbackEnabled;
+    }
+
+    /**
      * Set the call back for pattern detection.
      * @param onPatternListener The call back.
      */
@@ -420,6 +445,9 @@
                 addCellToPattern(fillInGapCell);
             }
             addCellToPattern(cell);
+            if (mTactileFeedbackEnabled){
+                vibe.vibrate(VIBE_PATTERN, -1); // Generate tactile feedback
+            }
             return cell;
         }
         return null;
@@ -900,7 +928,7 @@
         return new SavedState(superState,
                 LockPatternUtils.patternToString(mPattern),
                 mPatternDisplayMode.ordinal(),
-                mInputEnabled, mInStealthMode);
+                mInputEnabled, mInStealthMode, mTactileFeedbackEnabled);
     }
 
     @Override
@@ -913,6 +941,7 @@
         mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];
         mInputEnabled = ss.isInputEnabled();
         mInStealthMode = ss.isInStealthMode();
+        mTactileFeedbackEnabled = ss.isTactileFeedbackEnabled();
     }
 
     /**
@@ -924,17 +953,19 @@
         private final int mDisplayMode;
         private final boolean mInputEnabled;
         private final boolean mInStealthMode;
+        private final boolean mTactileFeedbackEnabled;
 
         /**
          * Constructor called from {@link LockPatternView#onSaveInstanceState()}
          */
         private SavedState(Parcelable superState, String serializedPattern, int displayMode,
-                boolean inputEnabled, boolean inStealthMode) {
+                boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) {
             super(superState);
             mSerializedPattern = serializedPattern;
             mDisplayMode = displayMode;
             mInputEnabled = inputEnabled;
             mInStealthMode = inStealthMode;
+            mTactileFeedbackEnabled = tactileFeedbackEnabled;
         }
 
         /**
@@ -946,6 +977,7 @@
             mDisplayMode = in.readInt();
             mInputEnabled = (Boolean) in.readValue(null);
             mInStealthMode = (Boolean) in.readValue(null);
+            mTactileFeedbackEnabled = (Boolean) in.readValue(null);
         }
         
         public String getSerializedPattern() {
@@ -964,6 +996,10 @@
             return mInStealthMode;
         }
 
+        public boolean isTactileFeedbackEnabled(){
+            return mTactileFeedbackEnabled;
+        }
+
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             super.writeToParcel(dest, flags);
@@ -971,6 +1007,7 @@
             dest.writeInt(mDisplayMode);
             dest.writeValue(mInputEnabled);
             dest.writeValue(mInStealthMode);
+            dest.writeValue(mTactileFeedbackEnabled);
         }
 
         public static final Parcelable.Creator<SavedState> CREATOR =
diff --git a/core/java/com/android/internal/widget/NumberPicker.java b/core/java/com/android/internal/widget/NumberPicker.java
index 5a7ddcb..5590f1a 100644
--- a/core/java/com/android/internal/widget/NumberPicker.java
+++ b/core/java/com/android/internal/widget/NumberPicker.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.Handler;
 import android.text.InputFilter;
+import android.text.InputType;
 import android.text.Spanned;
 import android.text.method.NumberKeyListener;
 import android.util.AttributeSet;
@@ -359,6 +360,12 @@
     
     private class NumberRangeKeyListener extends NumberKeyListener {
 
+        // XXX This doesn't allow for range limits when controlled by a
+        // soft input method!
+        public int getInputType() {
+            return InputType.TYPE_CLASS_NUMBER;
+        }
+        
         @Override
         protected char[] getAcceptedChars() {
             return DIGIT_CHARACTERS;
@@ -421,4 +428,10 @@
         return mStart;
     }
 
-}
+    /**
+     * @return the current value.
+     */
+    public int getCurrent() {
+        return mCurrent;
+    }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/SlidingDrawer.java b/core/java/com/android/internal/widget/SlidingDrawer.java
index 90a548a..a4045d5 100644
--- a/core/java/com/android/internal/widget/SlidingDrawer.java
+++ b/core/java/com/android/internal/widget/SlidingDrawer.java
@@ -74,6 +74,7 @@
  * @attr ref com.android.internal.R.styleable#SlidingDrawer_topOffset
  * @attr ref com.android.internal.R.styleable#SlidingDrawer_bottomOffset
  * @attr ref com.android.internal.R.styleable#SlidingDrawer_orientation
+ * @attr ref com.android.internal.R.styleable#SlidingDrawer_allowSingleTap
  * @attr ref com.android.internal.R.styleable#SlidingDrawer_animateOnClick
  */
 public class SlidingDrawer extends ViewGroup {
@@ -124,6 +125,7 @@
     private long mCurrentAnimationTime;
     private int mTouchDelta;
     private boolean mAnimating;
+    private boolean mAllowSingleTap;
     private boolean mAnimateOnClick;
 
     /**
@@ -186,6 +188,7 @@
         mVertical = orientation == ORIENTATION_VERTICAL;
         mBottomOffset = (int) a.getDimension(R.styleable.SlidingDrawer_bottomOffset, 0.0f);
         mTopOffset = (int) a.getDimension(R.styleable.SlidingDrawer_topOffset, 0.0f);
+        mAllowSingleTap = a.getBoolean(R.styleable.SlidingDrawer_allowSingleTap, true);
         mAnimateOnClick = a.getBoolean(R.styleable.SlidingDrawer_animateOnClick, true);
 
         int handleId = a.getResourceId(R.styleable.SlidingDrawer_handle, 0);
@@ -241,11 +244,11 @@
         measureChild(handle, widthMeasureSpec, heightMeasureSpec);
 
         if (mVertical) {
-            int height = heightSpecSize - handle.getMeasuredHeight();
+            int height = heightSpecSize - handle.getMeasuredHeight() - mTopOffset;
             mContent.measure(MeasureSpec.makeMeasureSpec(widthSpecSize, MeasureSpec.EXACTLY),
                     MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
         } else {
-            int width = widthSpecSize - handle.getMeasuredWidth();
+            int width = widthSpecSize - handle.getMeasuredWidth() - mTopOffset;
             mContent.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                     MeasureSpec.makeMeasureSpec(heightSpecSize, MeasureSpec.EXACTLY));
         }
@@ -269,6 +272,12 @@
                 } else {
                     canvas.drawBitmap(cache, handle.getRight(), 0, null);                    
                 }
+            } else {
+                canvas.save();
+                canvas.translate(isVertical ? 0 : handle.getLeft() - mTopOffset,
+                        isVertical ? handle.getTop() - mTopOffset : 0);
+                drawChild(canvas, mContent, drawingTime);
+                canvas.restore();
             }
         } else if (mExpanded) {
             drawChild(canvas, mContent, drawingTime);
@@ -415,12 +424,14 @@
                                 (!mExpanded && left > mBottomOffset + mRight - mLeft -
                                         mHandleWidth - TAP_THRESHOLD)) {
 
-                            playSoundEffect(SoundEffectConstants.CLICK);
+                            if (mAllowSingleTap) {
+                                playSoundEffect(SoundEffectConstants.CLICK);
 
-                            if (mExpanded) {
-                                animateClose(vertical ? top : left);
-                            } else {
-                                animateOpen(vertical ? top : left);
+                                if (mExpanded) {
+                                    animateClose(vertical ? top : left);
+                                } else {
+                                    animateOpen(vertical ? top : left);
+                                }
                             }
 
                         } else {
@@ -889,6 +900,9 @@
             if (mLocked) {
                 return;
             }
+            // mAllowSingleTap isn't relevant here; you're *always*
+            // allowed to open/close the drawer by clicking with the
+            // trackball.
 
             if (mAnimateOnClick) {
                 animateToggle();
diff --git a/core/java/com/google/android/mms/pdu/PduComposer.java b/core/java/com/google/android/mms/pdu/PduComposer.java
index acece47..094e992 100644
--- a/core/java/com/google/android/mms/pdu/PduComposer.java
+++ b/core/java/com/google/android/mms/pdu/PduComposer.java
@@ -24,7 +24,6 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 import java.util.HashMap;
 
@@ -461,7 +460,7 @@
 
                 int version = mPduHeader.getOctet(field);
                 if (0 == version) {
-                    appendShortInteger(PduHeaders.MMS_VERSION_1_3);
+                    appendShortInteger(PduHeaders.CURRENT_MMS_VERSION);
                 } else {
                     appendShortInteger(version);
                 }
@@ -952,7 +951,7 @@
                     appendQuotedString("<" + new String(contentId) + ">");
                 }
             }
-            
+
             // content-location
             byte[] contentLocation = part.getContentLocation();
             if (null != contentLocation) {
diff --git a/core/java/com/google/android/mms/pdu/PduHeaders.java b/core/java/com/google/android/mms/pdu/PduHeaders.java
index 3769349..4313815 100644
--- a/core/java/com/google/android/mms/pdu/PduHeaders.java
+++ b/core/java/com/google/android/mms/pdu/PduHeaders.java
@@ -150,13 +150,14 @@
     /**
      * X-Mms-MMS-Version field types.
      */
-    // Current version is 1.3.
     public static final int MMS_VERSION_1_3                 = ((1 << 4) | 3);
-
     public static final int MMS_VERSION_1_2                 = ((1 << 4) | 2);
     public static final int MMS_VERSION_1_1                 = ((1 << 4) | 1);
     public static final int MMS_VERSION_1_0                 = ((1 << 4) | 0);
 
+    // Current version is 1.2.
+    public static final int CURRENT_MMS_VERSION             = MMS_VERSION_1_2;
+
     /**
      *  From field type components.
      */
@@ -475,7 +476,7 @@
                 break;
             case MMS_VERSION:
                 if ((value < MMS_VERSION_1_0)|| (value > MMS_VERSION_1_3)) {
-                    value = MMS_VERSION_1_3; //1.3 is the default version.
+                    value = CURRENT_MMS_VERSION; // Current version is the default value.
                 }
                 break;
             case MESSAGE_TYPE:
diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java
index 4089c58..d2a41f1 100644
--- a/core/java/com/google/android/mms/pdu/PduPersister.java
+++ b/core/java/com/google/android/mms/pdu/PduPersister.java
@@ -729,36 +729,13 @@
                 }
                 is = mContentResolver.openInputStream(dataUri);
                 
-                boolean fakeRawAmr = contentType.equals("audio/amr");
-
                 if (LOCAL_LOGV) {
                     Log.v(TAG, "Saving data to: " + uri);
                 }
 
                 byte[] buffer = new byte[256];
                 for (int len = 0; (len = is.read(buffer)) != -1; ) {
-                    if (fakeRawAmr && len > 32) {
-                        // This is a Gross Hack. We can only record audio to amr format in a 3gpp container.
-                        // Millions of handsets out there only support what is essentially raw AMR.
-                        // We work around this issue by extracting the AMR data out of the 3gpp container
-                        // (in a really stupid and non-portable way), prepending a little header, and then
-                        // using that as the attachment.
-                        // This also requires some cooperation from the SoundRecorder, which ends up saving
-                        // a "recording.amr" file with mime type audio/amr, even though it's a 3gpp file.
-                        if (buffer[4] ==  0x66 &&       // f
-                                buffer[5] == 0x74 &&    // t
-                                buffer[6] == 0x79 &&    // y
-                                buffer[7] == 0x70) {    // p
-                            byte [] amrHeader = new byte [] { 0x23, 0x21, 0x41, 0x4d, 0x52, 0x0a };
-                            os.write(amrHeader);
-                            os.write(buffer, 32, len - 32);
-                        } else {
-                            os.write(buffer, 0, len);
-                        }
-                        fakeRawAmr = false;
-                    } else {
-                        os.write(buffer, 0, len);
-                    }
+                    os.write(buffer, 0, len);
                 }
             } else {
                 if (LOCAL_LOGV) {
diff --git a/core/java/com/google/android/mms/pdu/SendReq.java b/core/java/com/google/android/mms/pdu/SendReq.java
index e2f1101..9081b0c 100644
--- a/core/java/com/google/android/mms/pdu/SendReq.java
+++ b/core/java/com/google/android/mms/pdu/SendReq.java
@@ -29,7 +29,7 @@
 
         try {
             setMessageType(PduHeaders.MESSAGE_TYPE_SEND_REQ);
-            setMmsVersion(PduHeaders.MMS_VERSION_1_3);
+            setMmsVersion(PduHeaders.CURRENT_MMS_VERSION);
             // FIXME: Content-type must be decided according to whether
             // SMIL part present.
             setContentType("application/vnd.wap.multipart.related".getBytes());
diff --git a/core/java/com/google/android/net/ParentalControl.java b/core/java/com/google/android/net/ParentalControl.java
index 368b885..71a3958 100644
--- a/core/java/com/google/android/net/ParentalControl.java
+++ b/core/java/com/google/android/net/ParentalControl.java
@@ -23,7 +23,13 @@
 import android.util.Log;
 
 public class ParentalControl {
-    
+    /**
+     * Strings to identify your app. To enable parental control checking for
+     * new apps, please add it here, and configure GServices accordingly.
+     */
+    public static final String VENDING = "vending";
+    public static final String YOUTUBE = "youtube";
+
     /**
      * This interface is supplied to getParentalControlState and is callback upon with
      * the state of parental control.
@@ -36,28 +42,29 @@
          */
         void onResult(ParentalControlState state);
     }
-    
+
     private static class RemoteCallback extends IParentalControlCallback.Stub {
         private Callback mCallback;
-        
+
         public RemoteCallback(Callback callback) {
             mCallback = callback;
         }
-        
+
         public void onResult(ParentalControlState state) {
             if (mCallback != null) {
                 mCallback.onResult(state);
             }
         }
     };
-    
-    public static void getParentalControlState(Callback callback) {
+
+    public static void getParentalControlState(Callback callback,
+                                               String requestingApp) {
         ICheckinService service =
           ICheckinService.Stub.asInterface(ServiceManager.getService("checkin"));
-        
+
         RemoteCallback remoteCallback = new RemoteCallback(callback);
         try {
-            service.getParentalControlState(remoteCallback);
+            service.getParentalControlState(remoteCallback, requestingApp);
         } catch (RemoteException e) {
             // This should never happen.
             Log.e("ParentalControl", "Failed to talk to the checkin service.");
diff --git a/core/java/com/google/android/util/GoogleWebContentHelper.java b/core/java/com/google/android/util/GoogleWebContentHelper.java
index 57095222..7500ec3 100644
--- a/core/java/com/google/android/util/GoogleWebContentHelper.java
+++ b/core/java/com/google/android/util/GoogleWebContentHelper.java
@@ -22,6 +22,7 @@
 import android.os.Message;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -81,10 +82,26 @@
      */
     public GoogleWebContentHelper setUrlsFromGservices(String secureSetting, String prettySetting) {
         ContentResolver contentResolver = mContext.getContentResolver();
-        mSecureUrl = fillUrl(Settings.Gservices.getString(contentResolver, secureSetting));
-        mPrettyUrl = fillUrl(Settings.Gservices.getString(contentResolver, prettySetting));
+        mSecureUrl = fillUrl(Settings.Gservices.getString(contentResolver, secureSetting),
+                mContext);
+        mPrettyUrl = fillUrl(Settings.Gservices.getString(contentResolver, prettySetting), 
+                mContext);
         return this;
     }
+    
+    /**
+     * Fetch directly from provided urls.
+     * 
+     * @param secureUrl The HTTPS URL.
+     * @param prettyUrl The pretty URL.
+     * @return This {@link GoogleWebContentHelper} so methods can be chained.
+     */
+    public GoogleWebContentHelper setUrls(String secureUrl, String prettyUrl) {
+        mSecureUrl = fillUrl(secureUrl, mContext);
+        mPrettyUrl = fillUrl(prettyUrl, mContext);
+        return this;
+    }
+    
 
     /**
      * Sets the message that will be shown if we are unable to load the page.
@@ -113,6 +130,22 @@
         mWebView.loadUrl(mSecureUrl);
         return this;
     }
+    
+    /**
+     * Helper to handle the back key. Returns true if the back key was handled, 
+     * otherwise returns false.
+     * @param event the key event sent to {@link Activity#dispatchKeyEvent()}
+     */
+    public boolean handleKey(KeyEvent event) {
+        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK 
+                && event.getAction() == KeyEvent.ACTION_DOWN) {
+            if (mWebView.canGoBack()) {
+                mWebView.goBack();
+                return true;
+            }
+        }
+        return false;
+    }
 
     /**
      * Returns the layout containing the web view, progress bar, and text view.
@@ -138,12 +171,23 @@
      * @param url The URL in Formatter style for the extra info to be filled in.
      * @return The filled URL.
      */
-    private static String fillUrl(String url) {
+    private static String fillUrl(String url, Context context) {
         
         if (TextUtils.isEmpty(url)) {
             return "";
         }
-        
+
+        /* We add another layer of indirection here to allow mcc's to fill
+         * in Locales for TOS.  TODO - REMOVE when needed locales supported
+         * natively (when not shipping devices to country X without support
+         * for their locale).
+         */
+        String localeReplacement = context.
+                getString(com.android.internal.R.string.locale_replacement);
+        if (localeReplacement != null && localeReplacement.length() != 0) {
+            url = String.format(url, localeReplacement);
+        }
+
         Locale locale = Locale.getDefault();
         String tmp = locale.getLanguage() + "_" + locale.getCountry().toLowerCase();
         return String.format(url, tmp);
diff --git a/core/java/jarjar-rules.txt b/core/java/jarjar-rules.txt
new file mode 100644
index 0000000..5fdb022
--- /dev/null
+++ b/core/java/jarjar-rules.txt
@@ -0,0 +1,2 @@
+rule org.apache.commons com.android.internal.apache.commons
+
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index e9009e6..2c74ab7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -11,6 +11,10 @@
 	LOCAL_CFLAGS += -DPACKED=""
 endif
 
+ifneq ($(USE_CUSTOM_RUNTIME_HEAP_MAX),)
+  LOCAL_CFLAGS += -DCUSTOM_RUNTIME_HEAP_MAX=$(USE_CUSTOM_RUNTIME_HEAP_MAX)
+endif
+
 LOCAL_SRC_FILES:= \
 	ActivityManager.cpp \
 	AndroidRuntime.cpp \
@@ -45,7 +49,7 @@
 	android_net_wifi_Wifi.cpp \
 	android_nio_utils.cpp \
 	android_pim_EventRecurrence.cpp \
-	android_pim_Time.cpp \
+	android_text_format_Time.cpp \
 	android_security_Md5MessageDigest.cpp \
 	android_util_AssetManager.cpp \
 	android_util_Binder.cpp \
@@ -84,7 +88,9 @@
 	android/graphics/Shader.cpp \
 	android/graphics/Typeface.cpp \
 	android/graphics/Xfermode.cpp \
+	android_media_AudioRecord.cpp \
 	android_media_AudioSystem.cpp \
+	android_media_AudioTrack.cpp \
 	android_media_ToneGenerator.cpp \
 	android_hardware_Camera.cpp \
 	android_hardware_SensorManager.cpp \
@@ -100,6 +106,7 @@
 	android_bluetooth_ScoSocket.cpp \
 	android_server_BluetoothDeviceService.cpp \
 	android_server_BluetoothEventLoop.cpp \
+	android_server_BluetoothA2dpService.cpp \
 	android_message_digest_sha1.cpp \
 	android_ddm_DdmHandleNativeHeap.cpp \
 	android_location_GpsLocationProvider.cpp \
@@ -109,7 +116,7 @@
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
 	$(LOCAL_PATH)/android/graphics \
-	$(call include-path-for, corecg graphics) \
+	$(call include-path-for, bluedroid corecg graphics) \
 	$(call include-path-for, libhardware)/hardware \
 	$(LOCAL_PATH)/../../include/ui \
 	$(LOCAL_PATH)/../../include/utils \
@@ -128,6 +135,7 @@
 	libutils \
 	libnetutils \
 	libui \
+	libskiagl \
 	libsgl \
 	libcorecg \
 	libsqlite \
@@ -151,15 +159,15 @@
 LOCAL_SHARED_LIBRARIES += libbluedroid libdbus
 endif
 
-ifeq ($(TARGET_ARCH),arm)
+ifneq ($(TARGET_SIMULATOR),true)
 LOCAL_SHARED_LIBRARIES += \
 	libdl
 endif
 
 LOCAL_LDLIBS += -lpthread -ldl
 
-ifeq ($(TARGET_OS),linux)
-ifeq ($(TARGET_ARCH),x86)
+ifeq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
 LOCAL_LDLIBS += -lrt
 endif
 endif
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 2a1184f..f85f7d5 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -71,7 +71,9 @@
 
 extern int register_android_hardware_SensorManager(JNIEnv *env);
 
+extern int register_android_media_AudioRecord(JNIEnv *env);
 extern int register_android_media_AudioSystem(JNIEnv *env);
+extern int register_android_media_AudioTrack(JNIEnv *env);
 extern int register_android_media_ToneGenerator(JNIEnv *env);
 
 extern int register_android_message_digest_sha1(JNIEnv *env);
@@ -114,7 +116,7 @@
 extern int register_android_debug_JNITest(JNIEnv* env);
 extern int register_android_nio_utils(JNIEnv* env);
 extern int register_android_pim_EventRecurrence(JNIEnv* env);
-extern int register_android_pim_Time(JNIEnv* env);
+extern int register_android_text_format_Time(JNIEnv* env);
 extern int register_android_os_Debug(JNIEnv* env);
 extern int register_android_os_ParcelFileDescriptor(JNIEnv *env);
 extern int register_android_os_Power(JNIEnv *env);
@@ -142,6 +144,7 @@
 extern int register_android_bluetooth_ScoSocket(JNIEnv *env);
 extern int register_android_server_BluetoothDeviceService(JNIEnv* env);
 extern int register_android_server_BluetoothEventLoop(JNIEnv *env);
+extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
 extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
 extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
 extern int register_android_util_Base64(JNIEnv* env);
@@ -471,42 +474,21 @@
 }
 
 /*
- * Read the persistent locale from file.
+ * Read the persistent locale.
  */
 static void readLocale(char* language, char* region)
 {
-    char path[512];
     char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX];
-    char *dataDir = getenv("ANDROID_DATA");
-    bool found = false;
-    if (dataDir && strlen(dataDir) < 500) {
-        strcpy(path, dataDir);
-    } else {
-        strcpy(path, "/data");
-    }
-    strcat(path, "/locale");
     
-    FILE* localeFile = fopen(path, "r");
-    if (localeFile) {
-        char line[10];
-        char *got = fgets(line, 10, localeFile);
-        /* Locale code is ll_rr */
-        if (got != NULL && strlen(line) >= 5) {
-            strncat(language, line, 2);
-            strncat(region, line + 3, 2);
-            found = true;
-        } 
-        fclose(localeFile);
-    }
-
-    if (!found) {
+    property_get("persist.sys.language", propLang, "");
+    property_get("persist.sys.country", propRegn, "");
+    if (*propLang == 0 && *propRegn == 0) {
         /* Set to ro properties, default is en_US */
         property_get("ro.product.locale.language", propLang, "en");
         property_get("ro.product.locale.region", propRegn, "US");
-        strncat(language, propLang, 2);
-        strncat(region, propRegn, 2);
     }
-    
+    strncat(language, propLang, 2);
+    strncat(region, propRegn, 2);
     //LOGD("language=%s region=%s\n", language, region);
 }
 
@@ -518,8 +500,9 @@
     JavaVMInitArgs initArgs;
     JavaVMOption opt;
     char propBuf[PROPERTY_VALUE_MAX];
-    char enableAssertBuf[4 + PROPERTY_VALUE_MAX];
     char stackTraceFileBuf[PROPERTY_VALUE_MAX];
+    char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
+    char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
     char* stackTraceFile = NULL;
     char* slashClassName = NULL;
     char* cp;
@@ -578,6 +561,9 @@
     strcpy(enableAssertBuf, "-ea:");
     property_get("dalvik.vm.enableassertions", enableAssertBuf+4, "");
 
+    strcpy(jniOptsBuf, "-Xjniopts:");
+    property_get("dalvik.vm.jniopts", jniOptsBuf+10, "");
+
     const char* rootDir = getenv("ANDROID_ROOT");
     if (rootDir == NULL) {
         rootDir = "/system";
@@ -609,20 +595,23 @@
     mOptions.add(opt);
     //options[curOpt++].optionString = "-verbose:class";
 
+#ifdef CUSTOM_RUNTIME_HEAP_MAX
+#define __make_max_heap_opt(val) #val
+#define _make_max_heap_opt(val) "-Xmx" __make_max_heap_opt(val)
+    opt.optionString = _make_max_heap_opt(CUSTOM_RUNTIME_HEAP_MAX);
+#undef __make_max_heap_opt
+#undef _make_max_heap_opt
+#else
     /* limit memory use to 16MB */
     opt.optionString = "-Xmx16m";
+#endif
     mOptions.add(opt);
 
-    /* enable Java "assert" statements in all non-system code */
-    //options[curOpt++].optionString = "-ea";
-
     /*
-     * Enable or disable bytecode verification.  We currently force optimization
-     * to be enabled when the verifier is off; this is a bad idea, but
-     * useful while we fiddle with the verifier.
+     * Enable or disable bytecode verification.
      *
-     * This should be coordinated with:
-     * //device/dalvik/libcore/android/src/main/native/dalvik_system_TouchDex.cpp
+     * We don't optimize classes that haven't been verified, but that only
+     * matters if we do "just-in-time" DEX optimization.
      */
     if (verifyJava) {
         opt.optionString = "-Xverify:all";
@@ -632,7 +621,6 @@
     } else {
         opt.optionString = "-Xverify:none";
         mOptions.add(opt);
-        //opt.optionString = "-Xdexopt:all";
         opt.optionString = "-Xdexopt:verified";
         mOptions.add(opt);
     }
@@ -697,6 +685,12 @@
         LOGV("Assertions disabled\n");
     }
 
+    if (jniOptsBuf[10] != '\0') {
+        LOGI("JNI options: '%s'\n", jniOptsBuf);
+        opt.optionString = jniOptsBuf;
+        mOptions.add(opt);
+    }
+
     if (stackTraceFileBuf[0] != '\0') {
         static const char* stfOptName = "-Xstacktracefile:";
 
@@ -1008,7 +1002,7 @@
     REG_JNI(register_android_util_EventLog),
     REG_JNI(register_android_util_Log),
     REG_JNI(register_android_util_FloatMath),
-    REG_JNI(register_android_pim_Time),
+    REG_JNI(register_android_text_format_Time),
     REG_JNI(register_android_pim_EventRecurrence),
     REG_JNI(register_android_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
@@ -1076,7 +1070,9 @@
     REG_JNI(register_com_android_internal_os_ZygoteInit),
     REG_JNI(register_android_hardware_Camera),
     REG_JNI(register_android_hardware_SensorManager),
+    REG_JNI(register_android_media_AudioRecord),
     REG_JNI(register_android_media_AudioSystem),
+    REG_JNI(register_android_media_AudioTrack),
     REG_JNI(register_android_media_ToneGenerator),
 
     REG_JNI(register_android_opengl_classes),
@@ -1087,6 +1083,7 @@
     REG_JNI(register_android_bluetooth_ScoSocket),
     REG_JNI(register_android_server_BluetoothDeviceService),
     REG_JNI(register_android_server_BluetoothEventLoop),
+    REG_JNI(register_android_server_BluetoothA2dpService),
     REG_JNI(register_android_message_digest_sha1),
     REG_JNI(register_android_ddm_DdmHandleNativeHeap),
     REG_JNI(register_android_util_Base64),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 8628ec0..27a6349 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,573 +1,561 @@
-#include "SkBitmap.h"
-#include "SkImageDecoder.h"
-#include "SkColorPriv.h"
-#include "GraphicsJNI.h"
-#include "SkDither.h"
-
-#include "Parcel.h"
-#include "android_util_Binder.h"
-#include "android_nio_utils.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-
-#include <jni.h>
-
-#if 0
-    #define TRACE_BITMAP(code)  code
-#else
-    #define TRACE_BITMAP(code)
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// Conversions to/from SkColor, for get/setPixels, and the create method, which
-// is basically like setPixels
-
-typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
-                              int x, int y);
-
-static void FromColor_D32(void* dst, const SkColor src[], int width,
-                          int, int) {
-    SkPMColor* d = (SkPMColor*)dst;
-    
-    for (int i = 0; i < width; i++) {
-        *d++ = SkPreMultiplyColor(*src++);
-    }
-}
-
-static void FromColor_D565(void* dst, const SkColor src[], int width,
-                           int x, int y) {
-    uint16_t* d = (uint16_t*)dst;
-    
-    DITHER_565_SCAN(y);
-    for (int stop = x + width; x < stop; x++) {
-        SkColor c = *src++;
-        *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
-                                DITHER_VALUE(x));
-    }
-}
-
-static void FromColor_D4444(void* dst, const SkColor src[], int width,
-                            int x, int y) {
-    SkPMColor16* d = (SkPMColor16*)dst;
-    
-    DITHER_4444_SCAN(y);
-    for (int stop = x + width; x < stop; x++) {
-        SkPMColor c = SkPreMultiplyColor(*src++);
-        *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x));
-//        *d++ = SkPixel32ToPixel4444(c);
-    }
-}
-
-// can return NULL
-static FromColorProc ChooseFromColorProc(SkBitmap::Config config) {
-    switch (config) {
-        case SkBitmap::kARGB_8888_Config:
-            return FromColor_D32;
-        case SkBitmap::kARGB_4444_Config:
-            return FromColor_D4444;
-        case SkBitmap::kRGB_565_Config:
-            return FromColor_D565;
-        default:
-            break;
-    }
-    return NULL;
-}
-
-bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors,
-                            int srcOffset, int srcStride,
-                            int x, int y, int width, int height,
-                            const SkBitmap& dstBitmap) {
-    SkAutoLockPixels alp(dstBitmap);
-    void* dst = dstBitmap.getPixels();
-    FromColorProc proc = ChooseFromColorProc(dstBitmap.config());
-    
-    if (NULL == dst || NULL == proc) {
-        return false;
-    }
-    
-    jint* array = env->GetIntArrayElements(srcColors, NULL);
-    const SkColor* src = (const SkColor*)array + srcOffset;
-    
-    // reset to to actual choice from caller
-    dst = dstBitmap.getAddr(x, y);
-    // now copy/convert each scanline
-    for (int y = 0; y < height; y++) {
-        proc(dst, src, width, x, y);
-        src += srcStride;
-        dst = (char*)dst + dstBitmap.rowBytes();
-    }
-    
-    env->ReleaseIntArrayElements(srcColors, array, 0);
-    return true;
-}
-
-//////////////////// ToColor procs
-
-typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
-                            SkColorTable*);
-
-static inline SkColor pmcolorToColor(SkPMColor c) {
-    if (0 == c) {
-        return 0;
-    }
-
-    unsigned a = SkGetPackedA32(c);
-    unsigned r = SkGetPackedR32(c);
-    unsigned g = SkGetPackedG32(c);
-    unsigned b = SkGetPackedB32(c);
-
-    if (a < 255) {
-        SkFixed scale = SK_Fixed1 / a;
-        r = SkFixedRound(r * scale);
-        g = SkFixedRound(g * scale);
-        b = SkFixedRound(b * scale);
-        SkASSERT(r <= 0xFF);
-        SkASSERT(g <= 0xFF);
-        SkASSERT(b <= 0xFF);
-    }
-
-    return SkColorSetARGB(a, r, g, b);
-}
-
-static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
-                              SkColorTable*) {
-    SkASSERT(width > 0);
-    const SkPMColor* s = (const SkPMColor*)src;
-    do {
-        *dst++ = pmcolorToColor(*s++);
-    } while (--width != 0);
-}
-
-static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
-                               SkColorTable*) {
-    SkASSERT(width > 0);
-    const SkPMColor* s = (const SkPMColor*)src;
-    do {
-        SkPMColor c = *s++;
-        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
-                               SkGetPackedB32(c));
-    } while (--width != 0);
-}
-
-static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
-                                SkColorTable*) {
-    SkASSERT(width > 0);
-    const SkPMColor16* s = (const SkPMColor16*)src;
-    do {
-        *dst++ = pmcolorToColor(SkPixel4444ToPixel32(*s++));
-    } while (--width != 0);
-}
-
-static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
-                                 SkColorTable*) {
-    SkASSERT(width > 0);
-    const SkPMColor* s = (const SkPMColor*)src;
-    do {
-        SkPMColor c = SkPixel4444ToPixel32(*s++);
-        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
-                               SkGetPackedB32(c));
-    } while (--width != 0);
-}
-
-static void ToColor_S565(SkColor dst[], const void* src, int width,
-                         SkColorTable*) {
-    SkASSERT(width > 0);
-    const uint16_t* s = (const uint16_t*)src;
-    do {
-        uint16_t c = *s++;
-        *dst++ =  SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
-                                SkPacked16ToB32(c));
-    } while (--width != 0);
-}
-
-static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
-                              SkColorTable* ctable) {
-    SkASSERT(width > 0);
-    const uint8_t* s = (const uint8_t*)src;
-    const SkPMColor* colors = ctable->lockColors();
-    do {
-        *dst++ = pmcolorToColor(colors[*s++]);
-    } while (--width != 0);
-    ctable->unlockColors(false);
-}
-
-static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
-                               SkColorTable* ctable) {
-    SkASSERT(width > 0);
-    const uint8_t* s = (const uint8_t*)src;
-    const SkPMColor* colors = ctable->lockColors();
-    do {
-        SkPMColor c = colors[*s++];
-        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
-                               SkGetPackedB32(c));
-    } while (--width != 0);
-    ctable->unlockColors(false);
-}
-
-// can return NULL
-static ToColorProc ChooseToColorProc(const SkBitmap& src) {
-    switch (src.config()) {
-        case SkBitmap::kARGB_8888_Config:
-            return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha;
-        case SkBitmap::kARGB_4444_Config:
-            return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha;
-        case SkBitmap::kRGB_565_Config:
-            return ToColor_S565;
-        case SkBitmap::kIndex8_Config:
-            if (src.getColorTable() == NULL) {
-                return NULL;
-            }
-            return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha;
-        default:
-            break;
-    }
-    return NULL;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
-                              int offset, int stride, int width, int height,
-                              SkBitmap::Config config, jboolean isMutable) {
-    if (width <= 0 || height <= 0) {
-        doThrowIAE(env, "width and height must be > 0");
-        return NULL;
-    }
-    
-    if (NULL != jColors) {
-        size_t n = env->GetArrayLength(jColors);
-        if (n < SkAbs32(stride) * (size_t)height) {
-            doThrowAIOOBE(env);
-            return NULL;
-        }
-    }
-
-    SkBitmap bitmap;
-    
-    bitmap.setConfig(config, width, height);
-    if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) {
-        return NULL;
-    }
-
-    if (jColors != NULL) {
-        GraphicsJNI::SetPixels(env, jColors, offset, stride,
-                               0, 0, width, height, bitmap);
-    }
-    
-    return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), isMutable,
-                                     NULL);
-}
-
-static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
-                           SkBitmap::Config dstConfig, jboolean isMutable) {
-    SkBitmap            result;
-    JavaPixelAllocator  allocator(env);
-
-    if (!src->copyTo(&result, dstConfig, &allocator)) {
-        return NULL;
-    }
-    
-    return GraphicsJNI::createBitmap(env, new SkBitmap(result), isMutable,
-                                     NULL);
-}
-
-static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {
-    delete bitmap;
-}
-
-static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {
-    bitmap->setPixels(NULL, NULL);
-}
-
-// These must match the int values in Bitmap.java
-enum JavaEncodeFormat {
-    kJPEG_JavaEncodeFormat = 0,
-    kPNG_JavaEncodeFormat = 1
-};
-
-static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap,
-                            int format, int quality,
-                            jobject jstream, jbyteArray jstorage) {
-    SkImageEncoder::Type fm;
-
-    switch (format) {
-    case kJPEG_JavaEncodeFormat:
-        fm = SkImageEncoder::kJPEG_Type;
-        break;
-    case kPNG_JavaEncodeFormat:
-        fm = SkImageEncoder::kPNG_Type;
-        break;
-    default:
-        return false;
-    }
-
-    bool success = false;
-    SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
-    if (NULL != strm) {
-        SkImageEncoder* encoder = SkImageEncoder::Create(fm);
-        if (NULL != encoder) {
-            success = encoder->encodeStream(strm, *bitmap, quality);
-            delete encoder;
-        }
-        delete strm;
-    }
-    return success;
-}
-
-static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) {
-    bitmap->eraseColor(color);
-}
-
-static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) {
-    return bitmap->width();
-}
-
-static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) {
-    return bitmap->height();
-}
-
-static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) {
-    return bitmap->rowBytes();
-}
-
-static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) {
-    return bitmap->config();
-}
-
-static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {
-    return !bitmap->isOpaque();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
-    if (parcel == NULL) {
-        SkDebugf("-------- unparcel parcel is NULL\n");
-        return NULL;
-    }
-    
-    android::Parcel* p = android::parcelForJavaObject(env, parcel);
-    
-    const bool              isMutable = p->readInt32() != 0;
-    const SkBitmap::Config  config = (SkBitmap::Config)p->readInt32();
-    const int               width = p->readInt32();
-    const int               height = p->readInt32();
-    const int               rowBytes = p->readInt32();
-    
-    if (SkBitmap::kARGB_8888_Config != config &&
-            SkBitmap::kRGB_565_Config != config &&
-            SkBitmap::kARGB_4444_Config != config &&
-            SkBitmap::kIndex8_Config != config &&
-            SkBitmap::kA8_Config != config) {
-        SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
-        return NULL;
-    }
-
-    SkBitmap* bitmap = new SkBitmap;
-
-    bitmap->setConfig(config, width, height, rowBytes);
-
-    SkColorTable* ctable = NULL;
-    if (config == SkBitmap::kIndex8_Config) {
-        int count = p->readInt32();
-        if (count > 0) {
-            size_t size = count * sizeof(SkPMColor);
-            const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
-            ctable = new SkColorTable(src, count);
-        }
-    }
-    
-    if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) {
-        ctable->safeUnref();
-        delete bitmap;
-        return NULL;
-    }
-
-    ctable->safeUnref();
-
-    size_t size = bitmap->getSize();
-    bitmap->lockPixels();
-    memcpy(bitmap->getPixels(), p->readInplace(size), size);
-    bitmap->unlockPixels();
-    
-    return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL);
-}
-
-static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
-                                     const SkBitmap* bitmap,
-                                     jboolean isMutable, jobject parcel) {
-    if (parcel == NULL) {
-        SkDebugf("------- writeToParcel null parcel\n");
-        return false;
-    }
-
-    android::Parcel* p = android::parcelForJavaObject(env, parcel);
-    
-    p->writeInt32(isMutable);
-    p->writeInt32(bitmap->config());
-    p->writeInt32(bitmap->width());
-    p->writeInt32(bitmap->height());
-    p->writeInt32(bitmap->rowBytes());
-
-    if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {
-        SkColorTable* ctable = bitmap->getColorTable();
-        if (ctable != NULL) {
-            int count = ctable->count();
-            p->writeInt32(count);
-            memcpy(p->writeInplace(count * sizeof(SkPMColor)),
-                   ctable->lockColors(), count * sizeof(SkPMColor));
-            ctable->unlockColors(false);
-        } else {
-            p->writeInt32(0);   // indicate no ctable
-        }
-    }
-
-    size_t size = bitmap->getSize();
-    bitmap->lockPixels();
-    memcpy(p->writeInplace(size), bitmap->getPixels(), size);
-    bitmap->unlockPixels();
-    return true;
-}
-
-static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
-                                   const SkBitmap* src, const SkPaint* paint,
-                                   jintArray offsetXY) {
-    SkIPoint  offset;
-    SkBitmap* dst = new SkBitmap;
-    
-    src->extractAlpha(dst, paint, &offset);
-    if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
-        int* array = env->GetIntArrayElements(offsetXY, NULL);
-        array[0] = offset.fX;
-        array[1] = offset.fY;
-        env->ReleaseIntArrayElements(offsetXY, array, 0);
-    }
-    
-    return GraphicsJNI::createBitmap(env, dst, true, NULL);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
-                           int x, int y) {
-    SkAutoLockPixels alp(*bitmap);
-
-    ToColorProc proc = ChooseToColorProc(*bitmap);
-    if (NULL == proc) {
-        return 0;
-    }
-    const void* src = bitmap->getAddr(x, y);
-    if (NULL == src) {
-        return 0;
-    }
-    
-    SkColor dst[1];
-    proc(dst, src, 1, bitmap->getColorTable());
-    return dst[0];
-}
-
-static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
-                             jintArray pixelArray, int offset, int stride,
-                             int x, int y, int width, int height) {
-    SkAutoLockPixels alp(*bitmap);
-    
-    ToColorProc proc = ChooseToColorProc(*bitmap);
-    if (NULL == proc) {
-        return;
-    }
-    const void* src = bitmap->getAddr(x, y);
-    if (NULL == src) {
-        return;
-    }
-
-    SkColorTable* ctable = bitmap->getColorTable();
-    jint* dst = env->GetIntArrayElements(pixelArray, NULL);
-    SkColor* d = (SkColor*)dst + offset;
-    while (--height >= 0) {
-        proc(d, src, width, ctable);
-        d += stride;
-        src = (void*)((const char*)src + bitmap->rowBytes());
-    }
-    env->ReleaseIntArrayElements(pixelArray, dst, 0);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
-                            int x, int y, SkColor color) {
-    SkAutoLockPixels alp(*bitmap);
-    if (NULL == bitmap->getPixels()) {
-        return;
-    }
-
-    FromColorProc proc = ChooseFromColorProc(bitmap->config());
-    if (NULL == proc) {
-        return;
-    }
-
-    proc(bitmap->getAddr(x, y), &color, 1, x, y);
-}
-
-static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
-                             jintArray pixelArray, int offset, int stride,
-                             int x, int y, int width, int height) {
-    GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
-                           x, y, width, height, *bitmap);
-}
-
-static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
-                                      const SkBitmap* bitmap, jobject jbuffer) {
-    SkAutoLockPixels alp(*bitmap);
-    const void* src = bitmap->getPixels();
-    
-    if (NULL != src) {
-        android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
-
-        // the java side has already checked that buffer is large enough
-        memcpy(abp.pointer(), src, bitmap->getSize());
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include <android_runtime/AndroidRuntime.h>
-
-static JNINativeMethod gBitmapMethods[] = {
-    {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
-        (void*)Bitmap_creator },
-    {   "nativeCopy",               "(IIZ)Landroid/graphics/Bitmap;",
-        (void*)Bitmap_copy },
-    {   "nativeDestructor",         "(I)V", (void*)Bitmap_destructor },
-    {   "nativeRecycle",            "(I)V", (void*)Bitmap_recycle },
-    {   "nativeCompress",           "(IIILjava/io/OutputStream;[B)Z",
-        (void*)Bitmap_compress },
-    {   "nativeErase",              "(II)V", (void*)Bitmap_erase },
-    {   "nativeWidth",              "(I)I", (void*)Bitmap_width },
-    {   "nativeHeight",             "(I)I", (void*)Bitmap_height },
-    {   "nativeRowBytes",           "(I)I", (void*)Bitmap_rowBytes },
-    {   "nativeConfig",             "(I)I", (void*)Bitmap_config },
-    {   "nativeHasAlpha",           "(I)Z", (void*)Bitmap_hasAlpha },
-    {   "nativeCreateFromParcel",
-        "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
-        (void*)Bitmap_createFromParcel },
-    {   "nativeWriteToParcel",      "(IZLandroid/os/Parcel;)Z",
-        (void*)Bitmap_writeToParcel },
-    {   "nativeExtractAlpha",       "(II[I)Landroid/graphics/Bitmap;",
-        (void*)Bitmap_extractAlpha },
-    {   "nativeGetPixel",           "(III)I", (void*)Bitmap_getPixel },
-    {   "nativeGetPixels",          "(I[IIIIIII)V", (void*)Bitmap_getPixels },
-    {   "nativeSetPixel",           "(IIII)V", (void*)Bitmap_setPixel },
-    {   "nativeSetPixels",          "(I[IIIIIII)V", (void*)Bitmap_setPixels },
-    {   "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",
-                                        (void*)Bitmap_copyPixelsToBuffer }
-};
-
-#define kClassPathName  "android/graphics/Bitmap"
-
-int register_android_graphics_Bitmap(JNIEnv* env);
-int register_android_graphics_Bitmap(JNIEnv* env)
-{
-    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
-                                gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
-}
-
+#include "SkBitmap.h"

+#include "SkImageDecoder.h"

+#include "SkColorPriv.h"

+#include "GraphicsJNI.h"

+#include "SkDither.h"

+#include "SkUnPreMultiply.h"

+

+#include "Parcel.h"

+#include "android_util_Binder.h"

+#include "android_nio_utils.h"

+#include "CreateJavaOutputStreamAdaptor.h"

+

+#include <jni.h>

+

+#if 0

+    #define TRACE_BITMAP(code)  code

+#else

+    #define TRACE_BITMAP(code)

+#endif

+

+///////////////////////////////////////////////////////////////////////////////

+// Conversions to/from SkColor, for get/setPixels, and the create method, which

+// is basically like setPixels

+

+typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,

+                              int x, int y);

+

+static void FromColor_D32(void* dst, const SkColor src[], int width,

+                          int, int) {

+    SkPMColor* d = (SkPMColor*)dst;

+    

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

+        *d++ = SkPreMultiplyColor(*src++);

+    }

+}

+

+static void FromColor_D565(void* dst, const SkColor src[], int width,

+                           int x, int y) {

+    uint16_t* d = (uint16_t*)dst;

+    

+    DITHER_565_SCAN(y);

+    for (int stop = x + width; x < stop; x++) {

+        SkColor c = *src++;

+        *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),

+                                DITHER_VALUE(x));

+    }

+}

+

+static void FromColor_D4444(void* dst, const SkColor src[], int width,

+                            int x, int y) {

+    SkPMColor16* d = (SkPMColor16*)dst;

+    

+    DITHER_4444_SCAN(y);

+    for (int stop = x + width; x < stop; x++) {

+        SkPMColor c = SkPreMultiplyColor(*src++);

+        *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x));

+//        *d++ = SkPixel32ToPixel4444(c);

+    }

+}

+

+// can return NULL

+static FromColorProc ChooseFromColorProc(SkBitmap::Config config) {

+    switch (config) {

+        case SkBitmap::kARGB_8888_Config:

+            return FromColor_D32;

+        case SkBitmap::kARGB_4444_Config:

+            return FromColor_D4444;

+        case SkBitmap::kRGB_565_Config:

+            return FromColor_D565;

+        default:

+            break;

+    }

+    return NULL;

+}

+

+bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors,

+                            int srcOffset, int srcStride,

+                            int x, int y, int width, int height,

+                            const SkBitmap& dstBitmap) {

+    SkAutoLockPixels alp(dstBitmap);

+    void* dst = dstBitmap.getPixels();

+    FromColorProc proc = ChooseFromColorProc(dstBitmap.config());

+    

+    if (NULL == dst || NULL == proc) {

+        return false;

+    }

+    

+    const jint* array = env->GetIntArrayElements(srcColors, NULL);

+    const SkColor* src = (const SkColor*)array + srcOffset;

+    

+    // reset to to actual choice from caller

+    dst = dstBitmap.getAddr(x, y);

+    // now copy/convert each scanline

+    for (int y = 0; y < height; y++) {

+        proc(dst, src, width, x, y);

+        src += srcStride;

+        dst = (char*)dst + dstBitmap.rowBytes();

+    }

+    

+    env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),

+                                 JNI_ABORT);

+    return true;

+}

+

+//////////////////// ToColor procs

+

+typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,

+                            SkColorTable*);

+

+static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,

+                              SkColorTable*) {

+    SkASSERT(width > 0);

+    const SkPMColor* s = (const SkPMColor*)src;

+    do {

+        *dst++ = SkUnPreMultiply::PMColorToColor(*s++);

+    } while (--width != 0);

+}

+

+static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,

+                               SkColorTable*) {

+    SkASSERT(width > 0);

+    const SkPMColor* s = (const SkPMColor*)src;

+    do {

+        SkPMColor c = *s++;

+        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),

+                               SkGetPackedB32(c));

+    } while (--width != 0);

+}

+

+static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,

+                                SkColorTable*) {

+    SkASSERT(width > 0);

+    const SkPMColor16* s = (const SkPMColor16*)src;

+    do {

+        *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));

+    } while (--width != 0);

+}

+

+static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,

+                                 SkColorTable*) {

+    SkASSERT(width > 0);

+    const SkPMColor* s = (const SkPMColor*)src;

+    do {

+        SkPMColor c = SkPixel4444ToPixel32(*s++);

+        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),

+                               SkGetPackedB32(c));

+    } while (--width != 0);

+}

+

+static void ToColor_S565(SkColor dst[], const void* src, int width,

+                         SkColorTable*) {

+    SkASSERT(width > 0);

+    const uint16_t* s = (const uint16_t*)src;

+    do {

+        uint16_t c = *s++;

+        *dst++ =  SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),

+                                SkPacked16ToB32(c));

+    } while (--width != 0);

+}

+

+static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,

+                              SkColorTable* ctable) {

+    SkASSERT(width > 0);

+    const uint8_t* s = (const uint8_t*)src;

+    const SkPMColor* colors = ctable->lockColors();

+    do {

+        *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);

+    } while (--width != 0);

+    ctable->unlockColors(false);

+}

+

+static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,

+                               SkColorTable* ctable) {

+    SkASSERT(width > 0);

+    const uint8_t* s = (const uint8_t*)src;

+    const SkPMColor* colors = ctable->lockColors();

+    do {

+        SkPMColor c = colors[*s++];

+        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),

+                               SkGetPackedB32(c));

+    } while (--width != 0);

+    ctable->unlockColors(false);

+}

+

+// can return NULL

+static ToColorProc ChooseToColorProc(const SkBitmap& src) {

+    switch (src.config()) {

+        case SkBitmap::kARGB_8888_Config:

+            return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha;

+        case SkBitmap::kARGB_4444_Config:

+            return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha;

+        case SkBitmap::kRGB_565_Config:

+            return ToColor_S565;

+        case SkBitmap::kIndex8_Config:

+            if (src.getColorTable() == NULL) {

+                return NULL;

+            }

+            return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha;

+        default:

+            break;

+    }

+    return NULL;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+///////////////////////////////////////////////////////////////////////////////

+

+static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,

+                              int offset, int stride, int width, int height,

+                              SkBitmap::Config config, jboolean isMutable) {

+    if (width <= 0 || height <= 0) {

+        doThrowIAE(env, "width and height must be > 0");

+        return NULL;

+    }

+    

+    if (NULL != jColors) {

+        size_t n = env->GetArrayLength(jColors);

+        if (n < SkAbs32(stride) * (size_t)height) {

+            doThrowAIOOBE(env);

+            return NULL;

+        }

+    }

+

+    SkBitmap bitmap;

+    

+    bitmap.setConfig(config, width, height);

+    if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) {

+        return NULL;

+    }

+

+    if (jColors != NULL) {

+        GraphicsJNI::SetPixels(env, jColors, offset, stride,

+                               0, 0, width, height, bitmap);

+    }

+    

+    return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), isMutable,

+                                     NULL);

+}

+

+static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,

+                           SkBitmap::Config dstConfig, jboolean isMutable) {

+    SkBitmap            result;

+    JavaPixelAllocator  allocator(env);

+

+    if (!src->copyTo(&result, dstConfig, &allocator)) {

+        return NULL;

+    }

+    

+    return GraphicsJNI::createBitmap(env, new SkBitmap(result), isMutable,

+                                     NULL);

+}

+

+static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {

+    delete bitmap;

+}

+

+static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {

+    bitmap->setPixels(NULL, NULL);

+}

+

+// These must match the int values in Bitmap.java

+enum JavaEncodeFormat {

+    kJPEG_JavaEncodeFormat = 0,

+    kPNG_JavaEncodeFormat = 1

+};

+

+static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap,

+                            int format, int quality,

+                            jobject jstream, jbyteArray jstorage) {

+    SkImageEncoder::Type fm;

+

+    switch (format) {

+    case kJPEG_JavaEncodeFormat:

+        fm = SkImageEncoder::kJPEG_Type;

+        break;

+    case kPNG_JavaEncodeFormat:

+        fm = SkImageEncoder::kPNG_Type;

+        break;

+    default:

+        return false;

+    }

+

+    bool success = false;

+    SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);

+    if (NULL != strm) {

+        SkImageEncoder* encoder = SkImageEncoder::Create(fm);

+        if (NULL != encoder) {

+            success = encoder->encodeStream(strm, *bitmap, quality);

+            delete encoder;

+        }

+        delete strm;

+    }

+    return success;

+}

+

+static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) {

+    bitmap->eraseColor(color);

+}

+

+static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) {

+    return bitmap->width();

+}

+

+static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) {

+    return bitmap->height();

+}

+

+static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) {

+    return bitmap->rowBytes();

+}

+

+static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) {

+    return bitmap->config();

+}

+

+static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {

+    return !bitmap->isOpaque();

+}

+

+///////////////////////////////////////////////////////////////////////////////

+

+static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {

+    if (parcel == NULL) {

+        SkDebugf("-------- unparcel parcel is NULL\n");

+        return NULL;

+    }

+    

+    android::Parcel* p = android::parcelForJavaObject(env, parcel);

+    

+    const bool              isMutable = p->readInt32() != 0;

+    const SkBitmap::Config  config = (SkBitmap::Config)p->readInt32();

+    const int               width = p->readInt32();

+    const int               height = p->readInt32();

+    const int               rowBytes = p->readInt32();

+    

+    if (SkBitmap::kARGB_8888_Config != config &&

+            SkBitmap::kRGB_565_Config != config &&

+            SkBitmap::kARGB_4444_Config != config &&

+            SkBitmap::kIndex8_Config != config &&

+            SkBitmap::kA8_Config != config) {

+        SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);

+        return NULL;

+    }

+

+    SkBitmap* bitmap = new SkBitmap;

+

+    bitmap->setConfig(config, width, height, rowBytes);

+

+    SkColorTable* ctable = NULL;

+    if (config == SkBitmap::kIndex8_Config) {

+        int count = p->readInt32();

+        if (count > 0) {

+            size_t size = count * sizeof(SkPMColor);

+            const SkPMColor* src = (const SkPMColor*)p->readInplace(size);

+            ctable = new SkColorTable(src, count);

+        }

+    }

+    

+    if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) {

+        ctable->safeUnref();

+        delete bitmap;

+        return NULL;

+    }

+

+    ctable->safeUnref();

+

+    size_t size = bitmap->getSize();

+    bitmap->lockPixels();

+    memcpy(bitmap->getPixels(), p->readInplace(size), size);

+    bitmap->unlockPixels();

+    

+    return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL);

+}

+

+static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,

+                                     const SkBitmap* bitmap,

+                                     jboolean isMutable, jobject parcel) {

+    if (parcel == NULL) {

+        SkDebugf("------- writeToParcel null parcel\n");

+        return false;

+    }

+

+    android::Parcel* p = android::parcelForJavaObject(env, parcel);

+    

+    p->writeInt32(isMutable);

+    p->writeInt32(bitmap->config());

+    p->writeInt32(bitmap->width());

+    p->writeInt32(bitmap->height());

+    p->writeInt32(bitmap->rowBytes());

+

+    if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {

+        SkColorTable* ctable = bitmap->getColorTable();

+        if (ctable != NULL) {

+            int count = ctable->count();

+            p->writeInt32(count);

+            memcpy(p->writeInplace(count * sizeof(SkPMColor)),

+                   ctable->lockColors(), count * sizeof(SkPMColor));

+            ctable->unlockColors(false);

+        } else {

+            p->writeInt32(0);   // indicate no ctable

+        }

+    }

+

+    size_t size = bitmap->getSize();

+    bitmap->lockPixels();

+    memcpy(p->writeInplace(size), bitmap->getPixels(), size);

+    bitmap->unlockPixels();

+    return true;

+}

+

+static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,

+                                   const SkBitmap* src, const SkPaint* paint,

+                                   jintArray offsetXY) {

+    SkIPoint  offset;

+    SkBitmap* dst = new SkBitmap;

+    

+    src->extractAlpha(dst, paint, &offset);

+    if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {

+        int* array = env->GetIntArrayElements(offsetXY, NULL);

+        array[0] = offset.fX;

+        array[1] = offset.fY;

+        env->ReleaseIntArrayElements(offsetXY, array, 0);

+    }

+    

+    return GraphicsJNI::createBitmap(env, dst, true, NULL);

+}

+

+///////////////////////////////////////////////////////////////////////////////

+

+static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,

+                           int x, int y) {

+    SkAutoLockPixels alp(*bitmap);

+

+    ToColorProc proc = ChooseToColorProc(*bitmap);

+    if (NULL == proc) {

+        return 0;

+    }

+    const void* src = bitmap->getAddr(x, y);

+    if (NULL == src) {

+        return 0;

+    }

+    

+    SkColor dst[1];

+    proc(dst, src, 1, bitmap->getColorTable());

+    return dst[0];

+}

+

+static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,

+                             jintArray pixelArray, int offset, int stride,

+                             int x, int y, int width, int height) {

+    SkAutoLockPixels alp(*bitmap);

+    

+    ToColorProc proc = ChooseToColorProc(*bitmap);

+    if (NULL == proc) {

+        return;

+    }

+    const void* src = bitmap->getAddr(x, y);

+    if (NULL == src) {

+        return;

+    }

+

+    SkColorTable* ctable = bitmap->getColorTable();

+    jint* dst = env->GetIntArrayElements(pixelArray, NULL);

+    SkColor* d = (SkColor*)dst + offset;

+    while (--height >= 0) {

+        proc(d, src, width, ctable);

+        d += stride;

+        src = (void*)((const char*)src + bitmap->rowBytes());

+    }

+    env->ReleaseIntArrayElements(pixelArray, dst, 0);

+}

+

+///////////////////////////////////////////////////////////////////////////////

+

+static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,

+                            int x, int y, SkColor color) {

+    SkAutoLockPixels alp(*bitmap);

+    if (NULL == bitmap->getPixels()) {

+        return;

+    }

+

+    FromColorProc proc = ChooseFromColorProc(bitmap->config());

+    if (NULL == proc) {

+        return;

+    }

+

+    proc(bitmap->getAddr(x, y), &color, 1, x, y);

+}

+

+static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,

+                             jintArray pixelArray, int offset, int stride,

+                             int x, int y, int width, int height) {

+    GraphicsJNI::SetPixels(env, pixelArray, offset, stride,

+                           x, y, width, height, *bitmap);

+}

+

+static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,

+                                      const SkBitmap* bitmap, jobject jbuffer) {

+    SkAutoLockPixels alp(*bitmap);

+    const void* src = bitmap->getPixels();

+    

+    if (NULL != src) {

+        android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);

+

+        // the java side has already checked that buffer is large enough

+        memcpy(abp.pointer(), src, bitmap->getSize());

+    }

+}

+

+///////////////////////////////////////////////////////////////////////////////

+

+#include <android_runtime/AndroidRuntime.h>

+

+static JNINativeMethod gBitmapMethods[] = {

+    {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",

+        (void*)Bitmap_creator },

+    {   "nativeCopy",               "(IIZ)Landroid/graphics/Bitmap;",

+        (void*)Bitmap_copy },

+    {   "nativeDestructor",         "(I)V", (void*)Bitmap_destructor },

+    {   "nativeRecycle",            "(I)V", (void*)Bitmap_recycle },

+    {   "nativeCompress",           "(IIILjava/io/OutputStream;[B)Z",

+        (void*)Bitmap_compress },

+    {   "nativeErase",              "(II)V", (void*)Bitmap_erase },

+    {   "nativeWidth",              "(I)I", (void*)Bitmap_width },

+    {   "nativeHeight",             "(I)I", (void*)Bitmap_height },

+    {   "nativeRowBytes",           "(I)I", (void*)Bitmap_rowBytes },

+    {   "nativeConfig",             "(I)I", (void*)Bitmap_config },

+    {   "nativeHasAlpha",           "(I)Z", (void*)Bitmap_hasAlpha },

+    {   "nativeCreateFromParcel",

+        "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",

+        (void*)Bitmap_createFromParcel },

+    {   "nativeWriteToParcel",      "(IZLandroid/os/Parcel;)Z",

+        (void*)Bitmap_writeToParcel },

+    {   "nativeExtractAlpha",       "(II[I)Landroid/graphics/Bitmap;",

+        (void*)Bitmap_extractAlpha },

+    {   "nativeGetPixel",           "(III)I", (void*)Bitmap_getPixel },

+    {   "nativeGetPixels",          "(I[IIIIIII)V", (void*)Bitmap_getPixels },

+    {   "nativeSetPixel",           "(IIII)V", (void*)Bitmap_setPixel },

+    {   "nativeSetPixels",          "(I[IIIIIII)V", (void*)Bitmap_setPixels },

+    {   "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",

+                                        (void*)Bitmap_copyPixelsToBuffer }

+};

+

+#define kClassPathName  "android/graphics/Bitmap"

+

+int register_android_graphics_Bitmap(JNIEnv* env);

+int register_android_graphics_Bitmap(JNIEnv* env)

+{

+#if 1

+    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,

+                                gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));

+#else

+    short n = 0;

+    int limit = (char*)env - (char*)0;

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

+        n += i*i;

+    }

+    return n;

+#endif

+}

+

diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 90822a1..be8526d 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -43,57 +43,74 @@
     
 private:
     AutoDecoderCancel*  fNext;
+    AutoDecoderCancel*  fPrev;
     jobject             fJOptions;  // java options object
     SkImageDecoder*     fDecoder;
+    
+#ifdef SK_DEBUG
+    static void Validate();
+#else
+    static void Validate() {}
+#endif
 };
 
 static SkMutex  gAutoDecoderCancelMutex;
 static AutoDecoderCancel* gAutoDecoderCancel;
+#ifdef SK_DEBUG
+    static int gAutoDecoderCancelCount;
+#endif
 
 AutoDecoderCancel::AutoDecoderCancel(jobject joptions,
                                        SkImageDecoder* decoder) {
     fJOptions = joptions;
     fDecoder = decoder;
 
-    // only need to be in the list if we have options
     if (NULL != joptions) {
         SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
-        
+
+        // Add us as the head of the list
+        fPrev = NULL;
         fNext = gAutoDecoderCancel;
+        if (gAutoDecoderCancel) {
+            gAutoDecoderCancel->fPrev = this;
+        }
         gAutoDecoderCancel = this;
+        
+        SkDEBUGCODE(gAutoDecoderCancelCount += 1;)
+        Validate();
     }
 }
 
 AutoDecoderCancel::~AutoDecoderCancel() {
-    const jobject joptions = fJOptions;
-    
-    if (NULL != joptions) {
+    if (NULL != fJOptions) {
         SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
         
-        // remove us
-        AutoDecoderCancel* pair = gAutoDecoderCancel;
-        AutoDecoderCancel* prev = NULL;
-        while (pair != NULL) {
-            AutoDecoderCancel* next = pair->fNext;
-            if (pair->fJOptions == joptions) {
-                SkASSERT(pair->fDecoder == fDecoder);
-                if (prev) {
-                    prev->fNext = next;
-                } else {
-                    gAutoDecoderCancel = next;
-                }
-                return;
-            }
-            pair = next;
+        // take us out of the dllist
+        AutoDecoderCancel* prev = fPrev;
+        AutoDecoderCancel* next = fNext;
+        
+        if (prev) {
+            SkASSERT(prev->fNext == this);
+            prev->fNext = next;
+        } else {
+            SkASSERT(gAutoDecoderCancel == this);
+            gAutoDecoderCancel = next;
         }
-        SkDebugf("xxxxxxxxxxxxxxxxxxxxxxx not found in pair list %p %p\n",
-                 fJOptions, fDecoder);
+        if (next) {
+            SkASSERT(next->fPrev == this);
+            next->fPrev = prev;
+        }
+
+        SkDEBUGCODE(gAutoDecoderCancelCount -= 1;)
+        Validate();
     }
 }
 
 bool AutoDecoderCancel::RequestCancel(jobject joptions) {
     SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
 
+    Validate();
+
     AutoDecoderCancel* pair = gAutoDecoderCancel;
     while (pair != NULL) {
         if (pair->fJOptions == joptions) {
@@ -105,6 +122,37 @@
     return false;
 }
 
+#ifdef SK_DEBUG
+// can only call this inside a lock on gAutoDecoderCancelMutex 
+void AutoDecoderCancel::Validate() {
+    const int gCount = gAutoDecoderCancelCount;
+
+    if (gCount == 0) {
+        SkASSERT(gAutoDecoderCancel == NULL);
+    } else {
+        SkASSERT(gCount > 0);
+        
+        AutoDecoderCancel* curr = gAutoDecoderCancel;
+        SkASSERT(curr);
+        SkASSERT(curr->fPrev == NULL);
+
+        int count = 0;
+        while (curr) {
+            count += 1;
+            SkASSERT(count <= gCount);
+            if (curr->fPrev) {
+                SkASSERT(curr->fPrev->fNext == curr);
+            }
+            if (curr->fNext) {
+                SkASSERT(curr->fNext->fPrev == curr);
+            }
+            curr = curr->fNext;
+        }
+        SkASSERT(count == gCount);
+    }
+}
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 
 using namespace android;
@@ -132,6 +180,7 @@
             // You have to copy the data because it is owned by the png reader
             Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize);
             memcpy(patchNew, patch, patchSize);
+            // this relies on deserialization being done in place
             Res_png_9patch::deserialize(patchNew);
             patchNew->fileToDevice();
             if (fPatchIsValid) {
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 002fdf9..65c2326 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -28,66 +28,39 @@
         if (env->ExceptionCheck()) {
             env->ExceptionDescribe();
             env->ExceptionClear();
-            printf("------- reset threw an exception\n");
+            SkDebugf("------- reset threw an exception\n");
             return false;
         }
         return true;
     }
     
-	virtual size_t read(void* buffer, size_t size) {
+    size_t doRead(void* buffer, size_t size) {
         JNIEnv* env = fEnv;
-        
-        if (buffer == NULL && size == 0) {
-            jint avail = env->CallIntMethod(fJavaInputStream,
-                                            gInputStream_availableMethodID);
-            if (env->ExceptionCheck()) {
-                env->ExceptionDescribe();
-                env->ExceptionClear();
-                printf("------- available threw an exception\n");
-                avail = 0;
-            }
-            return avail;
-        }
-
         size_t bytesRead = 0;
-
-        if (buffer == NULL) { // skip
-            jlong skipped = env->CallLongMethod(fJavaInputStream,
-                                        gInputStream_skipMethodID, (jlong)size);
-            if (env->ExceptionCheck()) {
-                env->ExceptionDescribe();
-                env->ExceptionClear();
-                printf("------- available threw an exception\n");
-                return 0;
-            }
-            if (skipped < 0) {
-                return 0;
-            }
-            return (size_t)skipped;
-        }
-
         // read the bytes
         do {
             size_t requested = size;
             if (requested > fCapacity)
                 requested = fCapacity;
-
+            
             jint n = env->CallIntMethod(fJavaInputStream,
-                    gInputStream_readMethodID, fJavaByteArray, 0, requested);
+                                        gInputStream_readMethodID, fJavaByteArray, 0, requested);
             if (env->ExceptionCheck()) {
                 env->ExceptionDescribe();
                 env->ExceptionClear();
-                printf("---- read threw an exception\n");
+                SkDebugf("---- read threw an exception\n");
                 return 0;
             }
-
+            
             if (n <= 0) {
                 break;  // eof
             }
-
-            jbyte* array = env->GetByteArrayElements(fJavaByteArray, NULL);
+            
+            const jbyte* array = env->GetByteArrayElements(fJavaByteArray,
+                                                           NULL);
             memcpy(buffer, array, n);
-            env->ReleaseByteArrayElements(fJavaByteArray, array, 0);
+            env->ReleaseByteArrayElements(fJavaByteArray,
+                                          const_cast<jbyte*>(array), JNI_ABORT);
             
             buffer = (void*)((char*)buffer + n);
             bytesRead += n;
@@ -98,6 +71,64 @@
         return bytesRead;
     }
     
+    size_t doSkip(size_t size) {
+        JNIEnv* env = fEnv;
+        jlong skipped = env->CallLongMethod(fJavaInputStream,
+                                            gInputStream_skipMethodID, (jlong)size);
+        if (env->ExceptionCheck()) {
+            env->ExceptionDescribe();
+            env->ExceptionClear();
+            SkDebugf("------- available threw an exception\n");
+            return 0;
+        }
+        if (skipped < 0) {
+            skipped = 0;
+        }
+        return (size_t)skipped;
+    }
+    
+    size_t doSize() {
+        JNIEnv* env = fEnv;
+        jint avail = env->CallIntMethod(fJavaInputStream,
+                                        gInputStream_availableMethodID);
+        if (env->ExceptionCheck()) {
+            env->ExceptionDescribe();
+            env->ExceptionClear();
+            SkDebugf("------- available threw an exception\n");
+            avail = 0;
+        }
+        return avail;
+    }
+    
+	virtual size_t read(void* buffer, size_t size) {
+        JNIEnv* env = fEnv;
+        if (NULL == buffer) {
+            if (0 == size) {
+                return this->doSize();
+            } else {
+                /*  InputStream.skip(n) can return <=0 but still not be at EOF
+                    If we see that value, we need to call read(), which will
+                    block if waiting for more data, or return -1 at EOF
+                 */
+                size_t amountSkipped = 0;
+                do {
+                    size_t amount = this->doSkip(size);
+                    if (0 == amount) {
+                        char tmp;
+                        amount = this->doRead(&tmp, 1);
+                        if (0 == amount) {
+                            // if read returned 0, we're at EOF
+                            break;
+                        }
+                    }
+                    amountSkipped += amount;
+                } while (amountSkipped < size);
+                return amountSkipped;
+            }
+        }
+        return this->doRead(buffer, size);
+    }
+    
 private:
     JNIEnv*     fEnv;
     jobject     fJavaInputStream;   // the caller owns this object
@@ -167,7 +198,7 @@
             if (env->ExceptionCheck()) {
                 env->ExceptionDescribe();
                 env->ExceptionClear();
-                printf("------- write threw an exception\n");
+                SkDebugf("------- write threw an exception\n");
                 return false;
             }
             
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index f8ccf72..44113e5 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -265,8 +265,8 @@
 {
     SkASSERT(env->IsInstanceOf(obj, gPoint_class));
 
-    env->SetIntField(obj, gPointF_xFieldID, ir.fX);
-    env->SetIntField(obj, gPointF_yFieldID, ir.fY);
+    env->SetIntField(obj, gPoint_xFieldID, ir.fX);
+    env->SetIntField(obj, gPoint_yFieldID, ir.fY);
 }
 
 SkPoint* GraphicsJNI::jpointf_to_point(JNIEnv* env, jobject obj, SkPoint* point)
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 5c48077..de18f9f 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -106,7 +106,7 @@
 
     int totalLength = env->GetArrayLength(byteArray);
     if ((offset | length) < 0 || offset + length > totalLength) {
-        doThrow(env, "java/lang/ArrayIndexException");
+        doThrow(env, "java/lang/ArrayIndexOutOfBoundsException");
         return 0;
     }
 
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index a098d89..9e943f3 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -21,13 +21,14 @@
         if (env->GetArrayLength(obj) < (int)sizeof(Res_png_9patch)) {
             return false;
         }
-        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(obj, 0);
-        if (array != NULL)
-        {
-            Res_png_9patch* chunk = (Res_png_9patch*)array;
-            int8_t numXDivs = chunk->numXDivs;
-            env->ReleasePrimitiveArrayCritical(obj, array, 0);
-            return array[0] != -1;
+        const jbyte* array = env->GetByteArrayElements(obj, 0);
+        if (array != NULL) {
+            const Res_png_9patch* chunk =
+                                reinterpret_cast<const Res_png_9patch*>(array);
+            int8_t wasDeserialized = chunk->wasDeserialized;
+            env->ReleaseByteArrayElements(obj, const_cast<jbyte*>(array),
+                                          JNI_ABORT);
+            return wasDeserialized != -1;
         }
         return false;
     }
@@ -46,17 +47,19 @@
     static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds,
                       const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
     {
-        jbyte* array = env->GetByteArrayElements(chunkObj, 0);
-        if (array != NULL)
-        {
+        const jbyte* array = env->GetByteArrayElements(chunkObj, 0);
+        if (array != NULL) {
             size_t chunkSize = env->GetArrayLength(chunkObj);
-            void* deserializedArray = alloca(chunkSize);
-            Res_png_9patch* chunk = (Res_png_9patch*) deserializedArray;
-            assert(chunkSize == ((Res_png_9patch*) array)->serializedSize());
+            // need to deserialize the chunk
+            void* storage = alloca(chunkSize);
+            Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
             memcpy(chunk, array, chunkSize);
+            assert(chunkSize == chunk->serializedSize());
+            // this relies on deserialization being done in place
             Res_png_9patch::deserialize(chunk);            
             NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
-            env->ReleaseByteArrayElements(chunkObj, array, 0);
+            env->ReleaseByteArrayElements(chunkObj, const_cast<jbyte*>(array),
+                                          JNI_ABORT);
         }
     } 
 
@@ -99,18 +102,20 @@
         
         SkRect      bounds;
         GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
-        jbyte* array = (jbyte*)env->GetByteArrayElements(chunkObj, 0);
-        if (array != NULL)
-        {
+        const jbyte* array = (jbyte*)env->GetByteArrayElements(chunkObj, 0);
+        if (array != NULL) {
             size_t chunkSize = env->GetArrayLength(chunkObj);
-            void* deserializedArray = alloca(chunkSize);
-            Res_png_9patch* chunk = (Res_png_9patch*) deserializedArray;
-            assert(chunkSize == ((Res_png_9patch*) array)->serializedSize());
+            // need to deserialize the chunk
+            void* storage = alloca(chunkSize);
+            Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
             memcpy(chunk, array, chunkSize);
+            assert(chunkSize == chunk->serializedSize());
+            // this relies on deserialization being done in place
             Res_png_9patch::deserialize(chunk);
             SkRegion* region = NULL;
             NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);
-            env->ReleaseByteArrayElements(chunkObj, array, 0);
+            env->ReleaseByteArrayElements(chunkObj, const_cast<jbyte*>(array),
+                                          JNI_ABORT);
             return (jint)region;
         }
         
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index ba63ae4..f82053c 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -103,6 +103,10 @@
 void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
                        const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
                        const SkPaint* paint, SkRegion** outRegion) {
+    if (canvas && canvas->quickReject(bounds, SkCanvas::kBW_EdgeType)) {
+        return;
+    }
+    
     // if our canvas is GL, draw this as a mesh, which will be faster than
     // in parts (which is faster for raster)
     if (canvas && canvas->getViewport(NULL)) {
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 05830de..76e6f02 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -313,18 +313,21 @@
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
-        SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);        
-        jchar* textArray = env->GetCharArrayElements(text, NULL);
         size_t textLength = env->GetArrayLength(text);
-    
+        
         if ((index | count) < 0 || (size_t)(index + count) > textLength) {
-            doThrow(env, "ArrayIndexOutOfBoundsException");
+            doThrow(env, "java/lang/ArrayIndexOutOfBoundsException");
             return 0;
         }
 
-        jfloat width = SkScalarToFloat(paint->measureText(textArray + index, count << 1));
-        env->ReleaseCharArrayElements(text, textArray, 0);
-        return width;
+        const SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);        
+        const jchar* textArray = env->GetCharArrayElements(text, NULL);
+        // we double count, since measureText wants a byteLength
+        SkScalar width = paint->measureText(textArray + index, count << 1);
+        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
+                                      JNI_ABORT);
+
+        return SkScalarToFloat(width);
     }
  
     static jfloat measureText_StringII(JNIEnv* env, jobject jpaint, jstring text, int start, int end) {
@@ -337,7 +340,7 @@
         
         int count = end - start;
         if ((start | count) < 0 || (size_t)count > textLength) {
-            doThrow(env, "IndexOutOfBoundsException");
+            doThrow(env, "java/lang/IndexOutOfBoundsException");
             return 0;
         }
         
@@ -372,9 +375,10 @@
     }
     
     static int getTextWidths___CII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloatArray widths) {
-        jchar* textArray = env->GetCharArrayElements(text, NULL);
+        const jchar* textArray = env->GetCharArrayElements(text, NULL);
         count = dotextwidths(env, paint, textArray + index, count, widths);
-        env->ReleaseCharArrayElements(text, textArray, 0);        
+        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
+                                      JNI_ABORT);        
         return count;
     }
  
@@ -386,9 +390,10 @@
     }
     
     static void getTextPath___CIIFFPath(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
-        jchar* textArray = env->GetCharArrayElements(text, NULL);
+        const jchar* textArray = env->GetCharArrayElements(text, NULL);
         paint->getTextPath(textArray + index, count << 1, SkFloatToScalar(x), SkFloatToScalar(y), path);
-        env->ReleaseCharArrayElements(text, textArray, 0);
+        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
+                                      JNI_ABORT);
     }
  
     static void getTextPath__StringIIFFPath(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
@@ -451,10 +456,11 @@
         }
 
         SkPaint*     paint = GraphicsJNI::getNativePaint(env, jpaint);
-        jchar* text = env->GetCharArrayElements(jtext, NULL);
+        const jchar* text = env->GetCharArrayElements(jtext, NULL);
         count = breakText(env, *paint, text + index, count, maxWidth,
                           jmeasuredWidth, tbd);
-        env->ReleaseCharArrayElements(jtext, text, 0);
+        env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
+                                      JNI_ABORT);
         return count;
     }
 
@@ -498,9 +504,10 @@
     static void getCharArrayBounds(JNIEnv* env, jobject, const SkPaint* paint,
                         jcharArray text, int index, int count, jobject bounds)
     {
-        jchar* textArray = env->GetCharArrayElements(text, NULL);
+        const jchar* textArray = env->GetCharArrayElements(text, NULL);
         doTextBounds(env, textArray + index, count, bounds, *paint);
-        env->ReleaseCharArrayElements(text, textArray, 0);
+        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
+                                      JNI_ABORT);
     }
     
 };
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 71dc875..eef8bb2 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -8,6 +8,12 @@
 #include "SkTemplates.h"
 #include "SkXfermode.h"
 
+static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
+    if (NULL == ptr) {
+        doThrowIAE(env);
+    }
+}
+
 static void Color_RGBToHSV(JNIEnv* env, jobject, int red, int green, int blue, jfloatArray hsvArray)
 {
     SkScalar hsv[3];
@@ -64,9 +70,11 @@
 static SkShader* BitmapShader_constructor(JNIEnv* env, jobject, const SkBitmap* bitmap,
                                           int tileModeX, int tileModeY)
 {
-    return SkShader::CreateBitmapShader(*bitmap,
+    SkShader* s = SkShader::CreateBitmapShader(*bitmap,
                                         (SkShader::TileMode)tileModeX,
                                         (SkShader::TileMode)tileModeY);
+    ThrowIAE_IfNull(env, s);
+    return s;
 }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -79,8 +87,8 @@
     pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
     pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
 
-    size_t  count = env->GetArrayLength(colorArray);
-    int*    colorValues = env->GetIntArrayElements(colorArray, NULL);
+    size_t      count = env->GetArrayLength(colorArray);
+    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
 
     SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
     SkScalar*                   pos = NULL;
@@ -93,9 +101,13 @@
             pos[i] = SkFloatToScalar(posValues[i]);
     }
 
-    SkShader* shader = SkGradientShader::CreateLinear(pts, (const SkColor*)colorValues,
-                                                      pos, count, (SkShader::TileMode)tileMode);
-    env->ReleaseIntArrayElements(colorArray, colorValues, 0);
+    SkShader* shader = SkGradientShader::CreateLinear(pts,
+                                reinterpret_cast<const SkColor*>(colorValues),
+                                pos, count,
+                                static_cast<SkShader::TileMode>(tileMode));
+    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
+                                 JNI_ABORT);
+    ThrowIAE_IfNull(env, shader);
     return shader;
 }
 
@@ -111,7 +123,9 @@
     colors[0] = color0;
     colors[1] = color1;
 
-    return SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
+    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
+    ThrowIAE_IfNull(env, s);
+    return s;
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -123,8 +137,8 @@
     SkPoint center;
     center.set(SkFloatToScalar(x), SkFloatToScalar(y));
 
-    size_t  count = env->GetArrayLength(colorArray);
-    int*    colorValues = env->GetIntArrayElements(colorArray, NULL);
+    size_t      count = env->GetArrayLength(colorArray);
+    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
 
     SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
     SkScalar*                   pos = NULL;
@@ -137,10 +151,15 @@
             pos[i] = SkFloatToScalar(posValues[i]);
     }
 
-    SkShader* shader = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius),
-                                                      (const SkColor*)colorValues, pos,
-                                                      count, (SkShader::TileMode)tileMode);
-    env->ReleaseIntArrayElements(colorArray, colorValues, 0);
+    SkShader* shader = SkGradientShader::CreateRadial(center,
+                                SkFloatToScalar(radius),
+                                reinterpret_cast<const SkColor*>(colorValues),
+                                pos, count,
+                                static_cast<SkShader::TileMode>(tileMode));
+    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
+                                 JNI_ABORT);
+
+    ThrowIAE_IfNull(env, shader);
     return shader;
 }
 
@@ -155,8 +174,10 @@
     colors[0] = color0;
     colors[1] = color1;
 
-    return SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
+    SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
                                           2, (SkShader::TileMode)tileMode);
+    ThrowIAE_IfNull(env, s);
+    return s;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -164,8 +185,8 @@
 static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
                                     jintArray jcolors, jfloatArray jpositions)
 {
-    size_t  count = env->GetArrayLength(jcolors);
-    int*    colors = env->GetIntArrayElements(jcolors, NULL);
+    size_t      count = env->GetArrayLength(jcolors);
+    const jint* colors = env->GetIntArrayElements(jcolors, NULL);
     
     SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
     SkScalar*                   pos = NULL;
@@ -174,15 +195,18 @@
         AutoJavaFloatArray autoPos(env, jpositions, count);
         const float* posValues = autoPos.ptr();
         pos = (SkScalar*)storage.get();
-        for (size_t i = 0; i < count; i++)
+        for (size_t i = 0; i < count; i++) {
             pos[i] = SkFloatToScalar(posValues[i]);
+        }
     }
 
     SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x),
-                                                     SkFloatToScalar(y),
-                                                     (const SkColor*)colors,
-                                                     pos, count);
-    env->ReleaseIntArrayElements(jcolors, colors, 0);
+                                     SkFloatToScalar(y),
+                                     reinterpret_cast<const SkColor*>(colors),
+                                     pos, count);
+    env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
+                                 JNI_ABORT);
+    ThrowIAE_IfNull(env, shader);
     return shader;
 }
 
@@ -192,8 +216,10 @@
     SkColor colors[2];
     colors[0] = color0;
     colors[1] = color1;
-    return SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
+    SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
                                          colors, NULL, 2);
+    ThrowIAE_IfNull(env, s);
+    return s;
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h
index e77cd30..c30ba22 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -61,6 +61,15 @@
         (err)->name, (err)->message); \
         dbus_error_free((err)); }
 
+struct event_loop_native_data_t {
+    DBusConnection *conn;
+    /* These variables are set in waitForAndDispatchEventNative() and are
+       valid only within the scope of this function.  At any other time, they
+       are NULL. */
+    jobject me;
+    JNIEnv *env;
+};
+
 dbus_bool_t dbus_func_args_async_valist(JNIEnv *env,
                                         DBusConnection *conn,
                                         int timeout_ms,
diff --git a/core/jni/android_database_SQLiteProgram.cpp b/core/jni/android_database_SQLiteProgram.cpp
index 54e7de2..7bda004 100644
--- a/core/jni/android_database_SQLiteProgram.cpp
+++ b/core/jni/android_database_SQLiteProgram.cpp
@@ -172,7 +172,7 @@
 
     if (err != SQLITE_OK) {
         char buf[32];
-        sprintf(buf, "handle %p", statement);
+        sprintf(buf, "statement %p", statement);
         throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
         return;
     }
diff --git a/core/jni/android_database_SQLiteQuery.cpp b/core/jni/android_database_SQLiteQuery.cpp
index 9458433..44271683 100644
--- a/core/jni/android_database_SQLiteQuery.cpp
+++ b/core/jni/android_database_SQLiteQuery.cpp
@@ -106,11 +106,12 @@
 }
 
 static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow,
-                               jint startPos, jint offsetParam)
+                               jint startPos, jint offsetParam, jint maxRead, jint lastPos)
 {
     int err;
     sqlite3_stmt * statement = GET_STATEMENT(env, object);
-    int numRows = 0;
+    int numRows = lastPos;
+    maxRead += lastPos;
     int numColumns;
     int retryCount;
     int boundParams;
@@ -168,7 +169,7 @@
         }
     } 
     
-    while(true) {
+    while(startPos != 0 || numRows < maxRead) {
         err = sqlite3_step(statement);
         if (err == SQLITE_ROW) {
             LOG_WINDOW("\nStepped statement %p to row %d", statement, startPos + numRows);
@@ -274,6 +275,7 @@
 
             if (i < numColumns) {
                 // Not all the fields fit in the window
+                // Unknown data error happened
                 break;
             }
 
@@ -305,8 +307,12 @@
     LOG_WINDOW("Resetting statement %p after fetching %d rows in %d bytes\n\n\n\n", statement,
             numRows, window->size() - window->freeSpace());
 //    LOGI("Filled window with %d rows in %d bytes", numRows, window->size() - window->freeSpace());
-    sqlite3_reset(statement);
-    return startPos + numRows;
+    if (err == SQLITE_ROW) {
+        return -1;
+    } else {
+        sqlite3_reset(statement);
+        return startPos + numRows;
+    }
 }
 
 static jint native_column_count(JNIEnv* env, jobject object)
@@ -330,7 +336,7 @@
 static JNINativeMethod sMethods[] =
 {
      /* name, signature, funcPtr */
-    {"native_fill_window", "(Landroid/database/CursorWindow;II)I", (void *)native_fill_window},
+    {"native_fill_window", "(Landroid/database/CursorWindow;IIII)I", (void *)native_fill_window},
     {"native_column_count", "()I", (void*)native_column_count},
     {"native_column_name", "(I)Ljava/lang/String;", (void *)native_column_name},
 };
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index a29c27b..4b126a6 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -2,16 +2,16 @@
 **
 ** 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 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -50,15 +50,17 @@
 };
 
 static fields_t fields;
+static Mutex sLock;
 
 struct callback_cookie {
     jclass      camera_class;
     jobject     camera_ref;
 };
 
-static Camera *get_native_camera(JNIEnv *env, jobject thiz)
+sp<Camera> get_native_camera(JNIEnv *env, jobject thiz)
 {
-    Camera *c = reinterpret_cast<Camera*>(env->GetIntField(thiz, fields.context));
+    Mutex::Autolock _l(sLock);
+    sp<Camera> c = reinterpret_cast<Camera*>(env->GetIntField(thiz, fields.context));
     if (c == 0)
         jniThrowException(env, "java/lang/RuntimeException", "Method called after release()");
 
@@ -80,7 +82,7 @@
         break;
     }
     LOGV("err_callback: camera_ref=%x, cookie=%x", (int)c->camera_ref, (int)cookie);
-    
+
     env->CallStaticVoidMethod(c->camera_class, fields.post_event,
                               c->camera_ref, kErrorCallback, error, 0, NULL);
 }
@@ -117,34 +119,38 @@
     env->SetIntField(thiz, fields.listener_context, (int)cookie);
 
     LOGV("native_setup: camera_ref=%x, camera_obj=%x, cookie=%x", (int)cookie->camera_ref, (int)thiz, (int)cookie);
-    
+
     // save camera object in opaque field
     env->SetIntField(thiz, fields.context, reinterpret_cast<int>(c.get()));
 
     c->setErrorCallback(err_callback, cookie);
-    
-    // hold a strong reference so this doesn't go away while the app is still running
+
+    // hold a strong reference so the camera doesn't go away while the app is still running
     c->incStrong(thiz);
 }
 
 // disconnect from camera service
 static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
 {
+    Mutex::Autolock _l(sLock);
     sp<Camera> c = reinterpret_cast<Camera*>(env->GetIntField(thiz, fields.context));
     // It's okay to call this when the native camera context is already null.
     // This handles the case where the user has called release() and the
     // finalizer is invoked later.
     if (c != 0) {
+        // Make sure that we do not attempt to deliver an eror callback on a deleted
+        // Java object.
+        c->setErrorCallback(NULL, NULL);
         c->disconnect();
 
         // remove our strong reference created in native setup
         c->decStrong(thiz);
         env->SetIntField(thiz, fields.context, 0);
-        
+
         callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
 
         LOGV("release: camera_ref=%x, camera_obj=%x, cookie=%x", (int)cookie->camera_ref, (int)thiz, (int)cookie);
-      
+
         if (cookie) {
             env->DeleteGlobalRef(cookie->camera_ref);
             env->DeleteGlobalRef(cookie->camera_class);
@@ -156,7 +162,7 @@
 
 static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject surface)
 {
-    Camera *c = get_native_camera(env, thiz);
+    sp<Camera> c = get_native_camera(env, thiz);
     if (c == 0)
         return;
 
@@ -183,6 +189,7 @@
     jbyteArray array = env->NewByteArray(size);
     if (array == NULL) {
         LOGE("Couldn't allocate byte array for YUV data");
+        env->ExceptionClear();
         return;
     }
 
@@ -199,10 +206,10 @@
 
 static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
 {
-    Camera *c = get_native_camera(env, thiz);
+    sp<Camera> c = get_native_camera(env, thiz);
     if (c == 0)
         return;
-    
+
     if (c->startPreview() != NO_ERROR) {
         jniThrowException(env, "java/io/IOException", "startPreview failed");
         return;
@@ -211,7 +218,7 @@
 
 static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz)
 {
-    Camera *c = get_native_camera(env, thiz);
+    sp<Camera> c = get_native_camera(env, thiz);
     if (c == 0)
         return;
 
@@ -220,7 +227,7 @@
 
 static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed)
 {
-    Camera *c = get_native_camera(env, thiz);
+    sp<Camera> c = get_native_camera(env, thiz);
     if (c == 0)
         return;
 
@@ -228,7 +235,10 @@
     // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
     // each preview frame for nothing.
     callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
-    c->setFrameCallback(installed ? preview_callback : NULL, cookie);
+
+    c->setFrameCallback(installed ? preview_callback : NULL,
+            cookie,
+            installed ? FRAME_CALLBACK_FLAG_CAMERA: FRAME_CALLBACK_FLAG_NOOP);
 }
 
 static void autofocus_callback_impl(bool success, void *cookie)
@@ -236,7 +246,7 @@
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     callback_cookie *c = (callback_cookie *)cookie;
     env->CallStaticVoidMethod(c->camera_class, fields.post_event,
-                              c->camera_ref, kAutoFocusCallback, 
+                              c->camera_ref, kAutoFocusCallback,
                               success, 0, NULL);
 }
 
@@ -244,7 +254,7 @@
 
 static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
 {
-    Camera *c = get_native_camera(env, thiz);
+    sp<Camera> c = get_native_camera(env, thiz);
     if (c == 0)
         return;
     callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
@@ -282,6 +292,7 @@
     jbyteArray array = env->NewByteArray(size);
     if (array == NULL) {
         LOGE("Couldn't allocate byte array for JPEG data");
+        env->ExceptionClear();
         return;
     }
 
@@ -315,7 +326,7 @@
 
 static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
 {
-    Camera *c = get_native_camera(env, thiz);
+    sp<Camera> c = get_native_camera(env, thiz);
     if (c == 0)
         return;
 
@@ -334,7 +345,7 @@
 
 static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
 {
-    Camera *c = get_native_camera(env, thiz);
+    sp<Camera> c = get_native_camera(env, thiz);
     if (c == 0)
         return;
 
@@ -345,20 +356,32 @@
         env->ReleaseStringCritical(params, str);
     }
     if (c->setParameters(params8) != NO_ERROR) {
-        jniThrowException(env, "java/io/IllegalArgumentException", "setParameters failed");
+        jniThrowException(env, "java/lang/IllegalArgumentException", "setParameters failed");
         return;
     }
 }
 
 static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz)
 {
-    Camera *c = get_native_camera(env, thiz);
+    sp<Camera> c = get_native_camera(env, thiz);
     if (c == 0)
         return 0;
 
     return env->NewStringUTF(c->getParameters().string());
 }
 
+static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz)
+{
+    sp<Camera> c = get_native_camera(env, thiz);
+    if (c == 0)
+        return;
+
+    if (c->reconnect() != NO_ERROR) {
+        jniThrowException(env, "java/io/IOException", "reconnect failed");
+        return;
+    }
+}
+
 //-------------------------------------------------
 
 static JNINativeMethod camMethods[] = {
@@ -391,7 +414,10 @@
     (void *)android_hardware_Camera_setParameters },
   { "native_getParameters",
     "()Ljava/lang/String;",
-    (void *)android_hardware_Camera_getParameters }
+    (void *)android_hardware_Camera_getParameters },
+  { "reconnect",
+    "()V",
+    (void*)android_hardware_Camera_reconnect },
 };
 
 struct field {
@@ -442,7 +468,7 @@
         LOGE("Can't find android/hardware/Camera.postEventFromNative");
         return -1;
     }
- 
+
 
     // Register native functions
     return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index e8dcd71..75aa458 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -24,51 +24,142 @@
 
 namespace android {
 
+struct SensorOffsets
+{
+    jfieldID    name;
+    jfieldID    vendor;
+    jfieldID    version;
+    jfieldID    handle;
+    jfieldID    type;
+    jfieldID    range;
+    jfieldID    resolution;
+    jfieldID    power;
+} gSensorOffsets;
+
 /*
  * The method below are not thread-safe and not intended to be
  */
 
+static sensors_module_t* sSensorModule = 0;
+static sensors_data_device_t* sSensorDevice = 0;
+
 static jint
-android_data_open(JNIEnv *env, jclass clazz, jobject fdo)
+sensors_module_init(JNIEnv *env, jclass clazz)
+{
+    int err = 0;
+    sensors_module_t const* module;
+    err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t **)&module);
+    if (err == 0)
+        sSensorModule = (sensors_module_t*)module;
+    return err;
+}
+
+static jint
+sensors_module_get_next_sensor(JNIEnv *env, jobject clazz, jobject sensor, jint next)
+{
+    if (sSensorModule == NULL)
+        return 0;
+
+    SensorOffsets& sensorOffsets = gSensorOffsets;
+    const struct sensor_t* list;
+    int count = sSensorModule->get_sensors_list(sSensorModule, &list);
+    if (next >= count)
+        return -1;
+    
+    list += next;
+
+    jstring name = env->NewStringUTF(list->name);
+    jstring vendor = env->NewStringUTF(list->vendor);
+    env->SetObjectField(sensor, sensorOffsets.name,      name);
+    env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
+    env->SetIntField(sensor, sensorOffsets.version,      list->version);
+    env->SetIntField(sensor, sensorOffsets.handle,       list->handle);
+    env->SetIntField(sensor, sensorOffsets.type,         list->type);
+    env->SetFloatField(sensor, sensorOffsets.range,      list->maxRange);
+    env->SetFloatField(sensor, sensorOffsets.resolution, list->resolution);
+    env->SetFloatField(sensor, sensorOffsets.power,      list->power);
+    
+    next++;
+    return next<count ? next : 0;
+}
+
+//----------------------------------------------------------------------------
+static jint
+sensors_data_init(JNIEnv *env, jclass clazz)
+{
+    if (sSensorModule == NULL)
+        return -1;
+    int err = sensors_data_open(&sSensorModule->common, &sSensorDevice);
+    return err;
+}
+
+static jint
+sensors_data_uninit(JNIEnv *env, jclass clazz)
+{
+    int err = 0;
+    if (sSensorDevice) {
+        err = sensors_data_close(sSensorDevice);
+        if (err == 0)
+            sSensorDevice = 0;
+    }
+    return err;
+}
+
+static jint
+sensors_data_open(JNIEnv *env, jclass clazz, jobject fdo)
 {
     jclass FileDescriptor = env->FindClass("java/io/FileDescriptor");
     jfieldID offset = env->GetFieldID(FileDescriptor, "descriptor", "I");
     int fd = env->GetIntField(fdo, offset);
-    return sensors_data_open(fd); // doesn't take ownership of fd
+    return sSensorDevice->data_open(sSensorDevice, fd); // doesn't take ownership of fd
 }
 
 static jint
-android_data_close(JNIEnv *env, jclass clazz)
+sensors_data_close(JNIEnv *env, jclass clazz)
 {
-    return sensors_data_close();
+    return sSensorDevice->data_close(sSensorDevice);
 }
 
 static jint
-android_data_poll(JNIEnv *env, jclass clazz, jfloatArray values, jint sensors)
+sensors_data_poll(JNIEnv *env, jclass clazz, 
+        jfloatArray values, jintArray status, jlongArray timestamp)
 {
     sensors_data_t data;
-    int res = sensors_data_poll(&data, sensors);
-    if (res) {
+    int res = sSensorDevice->poll(sSensorDevice, &data);
+    if (res >= 0) {
+        jint accuracy = data.vector.status;
         env->SetFloatArrayRegion(values, 0, 3, data.vector.v);
-        // return the sensor's number
-        res = 31 - __builtin_clz(res);
-        // and its status in the top 4 bits
-        res |= data.vector.status << 28;
+        env->SetIntArrayRegion(status, 0, 1, &accuracy);
+        env->SetLongArrayRegion(timestamp, 0, 1, &data.time);
     }
     return res;
 }
 
-static jint
-android_data_get_sensors(JNIEnv *env, jclass clazz)
+static void
+nativeClassInit (JNIEnv *_env, jclass _this)
 {
-    return sensors_data_get_sensors();
+    jclass sensorClass = _env->FindClass("android/hardware/Sensor");
+    SensorOffsets& sensorOffsets = gSensorOffsets;
+    sensorOffsets.name        = _env->GetFieldID(sensorClass, "mName",      "Ljava/lang/String;");
+    sensorOffsets.vendor      = _env->GetFieldID(sensorClass, "mVendor",    "Ljava/lang/String;");
+    sensorOffsets.version     = _env->GetFieldID(sensorClass, "mVersion",   "I");
+    sensorOffsets.handle      = _env->GetFieldID(sensorClass, "mHandle",    "I");
+    sensorOffsets.type        = _env->GetFieldID(sensorClass, "mType",      "I");
+    sensorOffsets.range       = _env->GetFieldID(sensorClass, "mMaxRange",  "F");
+    sensorOffsets.resolution  = _env->GetFieldID(sensorClass, "mResolution","F");
+    sensorOffsets.power       = _env->GetFieldID(sensorClass, "mPower",     "F");
 }
 
 static JNINativeMethod gMethods[] = {
-    {"_sensors_data_open",  "(Ljava/io/FileDescriptor;)I",  (void*) android_data_open },
-    {"_sensors_data_close", "()I",   (void*) android_data_close },
-    {"_sensors_data_poll",  "([FI)I", (void*) android_data_poll },
-    {"_sensors_data_get_sensors","()I",   (void*) android_data_get_sensors },
+    {"nativeClassInit", "()V",              (void*)nativeClassInit },
+    {"sensors_module_init","()I",           (void*)sensors_module_init },
+    {"sensors_module_get_next_sensor","(Landroid/hardware/Sensor;I)I",
+                                            (void*)sensors_module_get_next_sensor },
+    {"sensors_data_init", "()I",            (void*)sensors_data_init },
+    {"sensors_data_uninit", "()I",          (void*)sensors_data_uninit },
+    {"sensors_data_open",  "(Ljava/io/FileDescriptor;)I",  (void*)sensors_data_open },
+    {"sensors_data_close", "()I",           (void*)sensors_data_close },
+    {"sensors_data_poll",  "([F[I[J)I",     (void*)sensors_data_poll },
 };
 
 }; // namespace android
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
new file mode 100644
index 0000000..e4586d9
--- /dev/null
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "AudioRecord-JNI"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include "utils/Log.h"
+#include "media/AudioSystem.h"
+#include "media/AudioRecord.h"
+
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+static const char* const kClassPathName = "android/media/AudioRecord";
+
+struct fields_t {
+    // these fields provide access from C++ to the...
+    jclass    audioRecordClass;      //... AudioRecord class
+    jmethodID postNativeEventInJava; //... event post callback method
+    int       PCM16;                 //...  format constants
+    int       PCM8;                  //...  format constants
+    int       SOURCE_DEFAULT;        //...  record source constants
+    int       SOURCE_MIC;            //...  record source constants
+    jfieldID  nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
+    jfieldID  nativeCallbackCookie;    // provides access to the AudioRecord callback data
+};
+static fields_t javaAudioRecordFields;
+
+struct audiorecord_callback_cookie {
+    jclass      audioRecord_class;
+    jobject     audioRecord_ref;
+ };
+
+// ----------------------------------------------------------------------------
+
+#define AUDIORECORD_SUCCESS                         0
+#define AUDIORECORD_ERROR                           -1
+#define AUDIORECORD_ERROR_BAD_VALUE                 -2
+#define AUDIORECORD_ERROR_INVALID_OPERATION         -3
+#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      -4
+#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT -5
+#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       -6
+#define AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE   -7
+#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    -8
+
+jint android_media_translateRecorderErrorCode(int code) {
+    switch(code) {
+    case NO_ERROR:
+        return AUDIORECORD_SUCCESS;
+    case BAD_VALUE:
+        return AUDIORECORD_ERROR_BAD_VALUE;
+    case INVALID_OPERATION:
+        return AUDIORECORD_ERROR_INVALID_OPERATION;
+    default:
+        return AUDIORECORD_ERROR;
+    }   
+}
+
+
+// ----------------------------------------------------------------------------
+static void recorderCallback(int event, void* user, void *info) {
+    if (event == AudioRecord::EVENT_MORE_DATA) {
+        // set size to 0 to signal we're not using the callback to read more data
+        AudioRecord::Buffer* pBuff = (AudioRecord::Buffer*)info;
+        pBuff->size = 0;  
+    
+    } else if (event == AudioRecord::EVENT_MARKER) {
+        audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
+        JNIEnv *env = AndroidRuntime::getJNIEnv();
+        if (user && env) {
+            env->CallStaticVoidMethod(
+                callbackInfo->audioRecord_class, 
+                javaAudioRecordFields.postNativeEventInJava,
+                callbackInfo->audioRecord_ref, event, 0,0, NULL);
+            if (env->ExceptionCheck()) {
+                env->ExceptionDescribe();
+                env->ExceptionClear();
+            }
+        }
+
+    } else if (event == AudioRecord::EVENT_NEW_POS) {
+        audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
+        JNIEnv *env = AndroidRuntime::getJNIEnv();
+        if (user && env) {
+            env->CallStaticVoidMethod(
+                callbackInfo->audioRecord_class, 
+                javaAudioRecordFields.postNativeEventInJava,
+                callbackInfo->audioRecord_ref, event, 0,0, NULL);
+            if (env->ExceptionCheck()) {
+                env->ExceptionDescribe();
+                env->ExceptionClear();
+            }
+        }
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static int
+android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
+        jint source, jint sampleRateInHertz, jint nbChannels, 
+        jint audioFormat, jint buffSizeInBytes)
+{
+    //LOGV(">> Entering android_media_AudioRecord_setup");
+    //LOGV("sampleRate=%d, audioFormat=%d, nbChannels=%d, buffSizeInBytes=%d",
+    //     sampleRateInHertz, audioFormat, nbChannels,     buffSizeInBytes);
+
+    if ((nbChannels == 0) || (nbChannels > 2)) {
+        LOGE("Error creating AudioRecord: channel count is not 1 or 2.");
+        return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT;
+    }
+
+    // compare the format against the Java constants
+    if ((audioFormat != javaAudioRecordFields.PCM16) 
+        && (audioFormat != javaAudioRecordFields.PCM8)) {
+        LOGE("Error creating AudioRecord: unsupported audio format.");
+        return AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
+    }
+
+    int bytesPerSample = audioFormat==javaAudioRecordFields.PCM16 ? 2 : 1;
+    int format = audioFormat==javaAudioRecordFields.PCM16 ? 
+            AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
+
+    if (buffSizeInBytes == 0) {
+         LOGE("Error creating AudioRecord: frameCount is 0.");
+        return AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
+    }
+    int frameSize = nbChannels * bytesPerSample;
+    size_t frameCount = buffSizeInBytes / frameSize;
+    
+    // compare the source against the Java constants
+    AudioRecord::stream_type arSource;
+    if (source == javaAudioRecordFields.SOURCE_DEFAULT) {
+        arSource = AudioRecord::DEFAULT_INPUT;
+    } else if (source == javaAudioRecordFields.SOURCE_MIC) {
+        arSource = AudioRecord::MIC_INPUT;
+    } else {
+        LOGE("Error creating AudioRecord: unknown source.");
+        return AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE;
+    }
+     
+    audiorecord_callback_cookie *lpCallbackData = NULL;
+    AudioRecord* lpRecorder = NULL;
+
+    // create an uninitialized AudioRecord object
+    lpRecorder = new AudioRecord();
+        if(lpRecorder == NULL) {
+        LOGE("Error creating AudioRecord instance.");
+        return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
+    }
+    
+    // create the callback information:
+    // this data will be passed with every AudioRecord callback
+    jclass clazz = env->GetObjectClass(thiz);
+    if (clazz == NULL) {
+        LOGE("Can't find %s when setting up callback.", kClassPathName);
+        goto native_track_failure;
+    }
+    lpCallbackData = new audiorecord_callback_cookie;
+    lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
+    // we use a weak reference so the AudioRecord object can be garbage collected.
+    lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
+    
+    lpRecorder->set(arSource,
+        sampleRateInHertz,
+        format,        // word length, PCM
+        nbChannels,
+        frameCount,
+        0,             // flags
+        recorderCallback,// callback_t
+        lpCallbackData,// void* user
+        0,             // notificationFrames,
+        true);         // threadCanCallJava)
+
+    if(lpRecorder->initCheck() != NO_ERROR) {
+        LOGE("Error creating AudioRecord instance: initialization check failed.");
+        goto native_init_failure;
+    }
+
+    // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field 
+    // of the Java object
+    env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (int)lpRecorder);
+    
+    // save our newly created callback information in the "nativeCallbackCookie" field
+    // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
+    env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, (int)lpCallbackData);
+    
+    return AUDIORECORD_SUCCESS;
+    
+    // failure:
+native_init_failure:
+    delete lpCallbackData;
+    
+native_track_failure:
+    delete lpRecorder;
+
+    env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0);
+    env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
+    
+    return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
+}
+
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioRecord_start(JNIEnv *env, jobject thiz)
+{
+    AudioRecord *lpRecorder = 
+            (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+    if (lpRecorder == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+    
+    lpRecorder->start();
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
+{
+    AudioRecord *lpRecorder = 
+            (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+    if (lpRecorder == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    lpRecorder->stop();
+    //LOGV("Called lpRecorder->stop()");
+}
+
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioRecord_finalize(JNIEnv *env,  jobject thiz) {
+    
+    // delete the AudioRecord object
+    AudioRecord *lpRecorder = 
+            (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+
+    if (lpRecorder) {
+        //LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
+        lpRecorder->stop();
+        delete lpRecorder;
+    }
+    
+    // delete the callback information
+    audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetIntField(
+        thiz, javaAudioRecordFields.nativeCallbackCookie);
+    if (lpCookie) {
+        LOGV("deleting lpCookie: %x\n", (int)lpCookie);
+        delete lpCookie;
+    }
+
+}
+
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioRecord_release(JNIEnv *env,  jobject thiz) {
+       
+    // do everything a call to finalize would
+    android_media_AudioRecord_finalize(env, thiz);
+    // + reset the native resources in the Java object so any attempt to access
+    // them after a call to release fails.
+    env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0);
+    env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_readInByteArray(JNIEnv *env,  jobject thiz,
+                                                        jbyteArray javaAudioData,
+                                                        jint offsetInBytes, jint sizeInBytes) {
+    jbyte* recordBuff = NULL;
+    AudioRecord *lpRecorder = NULL;
+
+    // get the audio recorder from which we'll read new audio samples
+    lpRecorder = 
+            (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+    if (lpRecorder == NULL) {
+        LOGE("Unable to retrieve AudioRecord object, can't record");
+        return 0;
+    }
+
+    if (!javaAudioData) {
+        LOGE("Invalid Java array to store recorded audio, can't record");
+        return 0;
+    }
+
+    // get the pointer to where we'll record the audio
+    recordBuff = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
+
+    if (recordBuff == NULL) {
+        LOGE("Error retrieving destination for recorded audio data, can't record");
+        return 0;
+    }
+
+    // read the new audio data from the native AudioRecord object
+    ssize_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize();
+    ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes, 
+                                        sizeInBytes > (jint)recorderBuffSize ? 
+                                            (jint)recorderBuffSize : sizeInBytes );
+    env->ReleasePrimitiveArrayCritical(javaAudioData, recordBuff, 0);
+
+    return (jint) readSize;
+}
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_readInShortArray(JNIEnv *env,  jobject thiz,
+                                                        jshortArray javaAudioData,
+                                                        jint offsetInShorts, jint sizeInShorts) {
+
+    return (android_media_AudioRecord_readInByteArray(env, thiz,
+                                                        (jbyteArray) javaAudioData,
+                                                        offsetInShorts*2, sizeInShorts*2)
+            / 2);
+}
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env,  jobject thiz,
+                                                  jobject jBuffer, jint sizeInBytes) {
+    AudioRecord *lpRecorder = NULL;
+    //LOGV("Entering android_media_AudioRecord_readInBuffer");
+
+    // get the audio recorder from which we'll read new audio samples
+    lpRecorder = 
+        (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+    if(lpRecorder==NULL)
+        return 0;
+
+    // direct buffer and direct access supported?
+    long capacity = env->GetDirectBufferCapacity(jBuffer);
+    if(capacity == -1) {
+        // buffer direct access is not supported
+        LOGE("Buffer direct access is not supported, can't record");
+        return 0;
+    }
+    //LOGV("capacity = %ld", capacity);
+    jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer);
+    if(nativeFromJavaBuf==NULL) {
+        LOGE("Buffer direct access is not supported, can't record");
+        return 0;
+    } 
+
+    // read new data from the recorder
+    return (jint) lpRecorder->read(nativeFromJavaBuf, 
+                                   capacity < sizeInBytes ? capacity : sizeInBytes);
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env,  jobject thiz, 
+        jint markerPos) {
+            
+    AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
+                thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+                
+    if (lpRecorder) {
+        return 
+            android_media_translateRecorderErrorCode( lpRecorder->setMarkerPosition(markerPos) );   
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for setMarkerPosition()");
+        return AUDIORECORD_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env,  jobject thiz) {
+    
+    AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
+                thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+    uint32_t markerPos = 0;
+                
+    if (lpRecorder) {
+        lpRecorder->getMarkerPosition(&markerPos);
+        return (jint)markerPos;
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for getMarkerPosition()");
+        return AUDIORECORD_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env,  jobject thiz,
+        jint period) {
+            
+    AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
+                thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+                
+    if (lpRecorder) {
+        return 
+            android_media_translateRecorderErrorCode( lpRecorder->setPositionUpdatePeriod(period) );   
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
+        return AUDIORECORD_ERROR;
+    }            
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env,  jobject thiz) {
+    
+    AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
+                thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+    uint32_t period = 0;
+                
+    if (lpRecorder) {
+        lpRecorder->getPositionUpdatePeriod(&period);
+        return (jint)period;
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
+        return AUDIORECORD_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+static JNINativeMethod gMethods[] = {
+    // name,               signature,  funcPtr
+    {"native_start",         "()V",    (void *)android_media_AudioRecord_start},
+    {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
+    {"native_setup",         "(Ljava/lang/Object;IIIII)I",
+                                       (void *)android_media_AudioRecord_setup},
+    {"native_finalize",      "()V",    (void *)android_media_AudioRecord_finalize},
+    {"native_release",       "()V",    (void *)android_media_AudioRecord_release},
+    {"native_read_in_byte_array", 
+                             "([BII)I", (void *)android_media_AudioRecord_readInByteArray},
+    {"native_read_in_short_array",
+                             "([SII)I", (void *)android_media_AudioRecord_readInShortArray},
+    {"native_read_in_direct_buffer","(Ljava/lang/Object;I)I",
+                                       (void *)android_media_AudioRecord_readInDirectBuffer},
+    {"native_set_marker_pos","(I)I",   (void *)android_media_AudioRecord_set_marker_pos},
+    {"native_get_marker_pos","()I",    (void *)android_media_AudioRecord_get_marker_pos},
+    {"native_set_pos_update_period",
+                             "(I)I",   (void *)android_media_AudioRecord_set_pos_update_period},
+    {"native_get_pos_update_period",
+                             "()I",    (void *)android_media_AudioRecord_get_pos_update_period},
+};
+
+// field names found in android/media/AudioRecord.java
+#define JAVA_POSTEVENT_CALLBACK_NAME  "postEventFromNative"
+#define JAVA_CONST_PCM16_NAME         "ENCODING_PCM_16BIT"
+#define JAVA_CONST_PCM8_NAME          "ENCODING_PCM_8BIT"
+#define JAVA_CONST_SOURCEDEFAULT_NAME "SOURCE_DEFAULT"
+#define JAVA_CONST_SOURCEMIC_NAME     "SOURCE_MIC"
+#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME  "mNativeRecorderInJavaObj"
+#define JAVA_NATIVECALLBACKINFO_FIELD_NAME       "mNativeCallbackCookie"
+
+#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat"
+
+// ----------------------------------------------------------------------------
+
+extern bool android_media_getIntConstantFromClass(JNIEnv* pEnv, 
+                jclass theClass, const char* className, const char* constName, int* constVal);
+
+// ----------------------------------------------------------------------------
+int register_android_media_AudioRecord(JNIEnv *env)
+{
+    javaAudioRecordFields.audioRecordClass = NULL;
+    javaAudioRecordFields.postNativeEventInJava = NULL;
+    javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
+    javaAudioRecordFields.nativeCallbackCookie = NULL;
+    
+
+    // Get the AudioRecord class
+    javaAudioRecordFields.audioRecordClass = env->FindClass(kClassPathName);
+    if (javaAudioRecordFields.audioRecordClass == NULL) {
+        LOGE("Can't find %s", kClassPathName);
+        return -1;
+    }
+    
+    // Get the postEvent method
+    javaAudioRecordFields.postNativeEventInJava = env->GetStaticMethodID(
+            javaAudioRecordFields.audioRecordClass,
+            JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+    if (javaAudioRecordFields.postNativeEventInJava == NULL) {
+        LOGE("Can't find AudioRecord.%s", JAVA_POSTEVENT_CALLBACK_NAME);
+        return -1;
+    }
+
+    // Get the variables
+    //    mNativeRecorderInJavaObj
+    javaAudioRecordFields.nativeRecorderInJavaObj = 
+        env->GetFieldID(javaAudioRecordFields.audioRecordClass,
+                        JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "I");
+    if (javaAudioRecordFields.nativeRecorderInJavaObj == NULL) {
+        LOGE("Can't find AudioRecord.%s", JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME);
+        return -1;
+    }
+    //     mNativeCallbackCookie
+    javaAudioRecordFields.nativeCallbackCookie = env->GetFieldID(
+            javaAudioRecordFields.audioRecordClass,
+            JAVA_NATIVECALLBACKINFO_FIELD_NAME, "I");
+    if (javaAudioRecordFields.nativeCallbackCookie == NULL) {
+        LOGE("Can't find AudioRecord.%s", JAVA_NATIVECALLBACKINFO_FIELD_NAME);
+        return -1;
+    }
+
+    // Get the format constants from the AudioFormat class
+    jclass audioFormatClass = NULL;
+    audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME);
+    if (audioFormatClass == NULL) {
+        LOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME);
+        return -1;
+    }
+    if ( !android_media_getIntConstantFromClass(env, audioFormatClass, 
+                JAVA_AUDIOFORMAT_CLASS_NAME, 
+                JAVA_CONST_PCM16_NAME, &(javaAudioRecordFields.PCM16))
+           || !android_media_getIntConstantFromClass(env, audioFormatClass, 
+                JAVA_AUDIOFORMAT_CLASS_NAME, 
+                JAVA_CONST_PCM8_NAME, &(javaAudioRecordFields.PCM8)) ) {
+        // error log performed in getIntConstantFromClass() 
+        return -1;
+    }
+
+    // Get the recording source constants from the AudioRecord class
+    if ( !android_media_getIntConstantFromClass(env, javaAudioRecordFields.audioRecordClass, 
+                kClassPathName,
+                JAVA_CONST_SOURCEDEFAULT_NAME, &(javaAudioRecordFields.SOURCE_DEFAULT))
+        || !android_media_getIntConstantFromClass(env, javaAudioRecordFields.audioRecordClass, 
+                kClassPathName,
+                JAVA_CONST_SOURCEMIC_NAME, &(javaAudioRecordFields.SOURCE_MIC)) ) {
+        // error log performed in getIntConstantFromClass() 
+        return -1;
+    }
+
+    return AndroidRuntime::registerNativeMethods(env,
+            kClassPathName, gMethods, NELEM(gMethods));
+}
+
+// ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
new file mode 100644
index 0000000..4a98fcc
--- /dev/null
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "AudioTrack-JNI"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include "utils/Log.h"
+#include "media/AudioSystem.h"
+#include "media/AudioTrack.h"
+
+#include <utils/MemoryHeapBase.h>
+#include <utils/MemoryBase.h>
+
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+static const char* const kClassPathName = "android/media/AudioTrack";
+
+struct fields_t {
+    // these fields provide access from C++ to the...
+    jclass    audioTrackClass;       //... AudioTrack class
+    jmethodID postNativeEventInJava; //... event post callback method
+    int       PCM16;                 //...  format constants
+    int       PCM8;                  //...  format constants
+    int       STREAM_VOICE_CALL;     //...  stream type constants
+    int       STREAM_SYSTEM;         //...  stream type constants
+    int       STREAM_RING;           //...  stream type constants
+    int       STREAM_MUSIC;          //...  stream type constants
+    int       STREAM_ALARM;          //...  stream type constants
+    int       MODE_STREAM;           //...  memory mode
+    int       MODE_STATIC;           //...  memory mode
+    jfieldID  nativeTrackInJavaObj; // stores in Java the native AudioTrack object
+    jfieldID  jniData;      // stores in Java additional resources used by the native AudioTrack
+};
+static fields_t javaAudioTrackFields;
+
+struct audiotrack_callback_cookie {
+    jclass      audioTrack_class;
+    jobject     audioTrack_ref;
+ };
+
+// ----------------------------------------------------------------------------
+class AudioTrackJniStorage {
+    public:
+        sp<MemoryHeapBase>         mMemHeap;
+        sp<MemoryBase>             mMemBase;
+        audiotrack_callback_cookie mCallbackData;
+
+    AudioTrackJniStorage() {
+    }
+
+    ~AudioTrackJniStorage() {
+        mMemBase.clear();
+        mMemHeap.clear();
+    }
+
+    bool allocSharedMem(int sizeInBytes) {
+        mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
+        if (mMemHeap->getHeapID() < 0) {
+            return false;
+        }
+        mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
+        return true;
+    }
+};
+
+// ----------------------------------------------------------------------------
+#define DEFAULT_OUTPUT_SAMPLE_RATE   44100
+
+#define AUDIOTRACK_SUCCESS                         0
+#define AUDIOTRACK_ERROR                           -1
+#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM         -2
+#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT -3
+#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT       -4
+#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE   -5
+#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED    -6
+#define AUDIOTRACK_ERROR_BAD_VALUE                 -7
+#define AUDIOTRACK_ERROR_INVALID_OPERATION         -8
+
+
+jint android_media_translateErrorCode(int code) {
+    switch(code) {
+    case NO_ERROR:
+        return AUDIOTRACK_SUCCESS;
+    case BAD_VALUE:
+        return AUDIOTRACK_ERROR_BAD_VALUE;
+    case INVALID_OPERATION:
+        return AUDIOTRACK_ERROR_INVALID_OPERATION;
+    default:
+        return AUDIOTRACK_ERROR;
+    }   
+}
+
+
+// ----------------------------------------------------------------------------
+static void audioCallback(int event, void* user, void *info) {
+    if (event == AudioTrack::EVENT_MORE_DATA) {
+        // set size to 0 to signal we're not using the callback to write more data
+        AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info;
+        pBuff->size = 0;  
+    
+    } else if (event == AudioTrack::EVENT_MARKER) {
+        audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
+        JNIEnv *env = AndroidRuntime::getJNIEnv();
+        if (user && env) {
+            env->CallStaticVoidMethod(
+                callbackInfo->audioTrack_class, 
+                javaAudioTrackFields.postNativeEventInJava,
+                callbackInfo->audioTrack_ref, event, 0,0, NULL);
+            if (env->ExceptionCheck()) {
+                env->ExceptionDescribe();
+                env->ExceptionClear();
+            }
+        }
+
+    } else if (event == AudioTrack::EVENT_NEW_POS) {
+        audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
+        JNIEnv *env = AndroidRuntime::getJNIEnv();
+        if (user && env) {
+            env->CallStaticVoidMethod(
+                callbackInfo->audioTrack_class, 
+                javaAudioTrackFields.postNativeEventInJava,
+                callbackInfo->audioTrack_ref, event, 0,0, NULL);
+            if (env->ExceptionCheck()) {
+                env->ExceptionDescribe();
+                env->ExceptionClear();
+            }
+        }
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static int
+android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
+        jint streamType, jint sampleRateInHertz, jint nbChannels, 
+        jint audioFormat, jint buffSizeInBytes, jint memoryMode)
+{
+    //LOGV("sampleRate=%d, audioFormat(from Java)=%d, nbChannels=%d, buffSize=%d", 
+    //    sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+    int afSampleRate;
+    int afFrameCount;
+
+    if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+        LOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");
+        return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
+    }
+    if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+        LOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");
+        return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
+    }
+
+    if ((nbChannels == 0) || (nbChannels > 2)) {
+        LOGE("Error creating AudioTrack: channel count is not 1 or 2.");
+        return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT;
+    }
+    
+    // check the stream type
+    AudioTrack::stream_type atStreamType;
+    if (streamType == javaAudioTrackFields.STREAM_VOICE_CALL) {
+        atStreamType = AudioTrack::VOICE_CALL;
+    } else if (streamType == javaAudioTrackFields.STREAM_SYSTEM) {
+        atStreamType = AudioTrack::SYSTEM;
+    } else if (streamType == javaAudioTrackFields.STREAM_RING) {
+        atStreamType = AudioTrack::RING;
+    } else if (streamType == javaAudioTrackFields.STREAM_MUSIC) {
+        atStreamType = AudioTrack::MUSIC;
+    } else if (streamType == javaAudioTrackFields.STREAM_ALARM) {
+        atStreamType = AudioTrack::ALARM;
+    } else {
+        LOGE("Error creating AudioTrack: unknown stream type.");
+        return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
+     }
+
+    // check the format.
+    // This function was called from Java, so we compare the format against the Java constants
+    if ((audioFormat != javaAudioTrackFields.PCM16) && (audioFormat != javaAudioTrackFields.PCM8)) {
+        LOGE("Error creating AudioTrack: unsupported audio format.");
+        return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
+    }
+    
+    // compute the frame count
+    int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
+    int format = audioFormat == javaAudioTrackFields.PCM16 ? 
+            AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
+    int frameCount;
+    if (buffSizeInBytes == -1) {
+        // compute the frame count based on the system's output frame count 
+        // and the native sample rate
+        frameCount = (sampleRateInHertz*afFrameCount)/afSampleRate;
+    } else {
+        // compute the frame count based on the specified buffer size
+        frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
+    }
+    
+    AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
+    
+    // initialize the callback information:
+    // this data will be passed with every AudioTrack callback
+    jclass clazz = env->GetObjectClass(thiz);
+    if (clazz == NULL) {
+        LOGE("Can't find %s when setting up callback.", kClassPathName);
+        delete lpJniStorage;
+        return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
+    }
+    lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
+    // we use a weak reference so the AudioTrack object can be garbage collected.
+    lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
+    
+    // create the native AudioTrack object
+    AudioTrack* lpTrack = new AudioTrack();
+    if (lpTrack == NULL) {
+        LOGE("Error creating uninitialized AudioTrack");
+        goto native_track_failure;
+    }
+    
+    // initialize the native AudioTrack object
+    if (memoryMode == javaAudioTrackFields.MODE_STREAM) {
+
+        lpTrack->set(
+            atStreamType,// stream type
+            sampleRateInHertz,
+            format,// word length, PCM
+            nbChannels,
+            frameCount,
+            0,// flags
+            audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
+            0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
+            0,// shared mem
+            true);// thread can call Java
+            
+    } else if (memoryMode == javaAudioTrackFields.MODE_STATIC) {
+        // AudioTrack is using shared memory
+        
+        if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
+            LOGE("Error creating AudioTrack in static mode: error creating mem heap base");
+            goto native_init_failure;
+        }
+        
+        lpTrack->set(
+            atStreamType,// stream type
+            sampleRateInHertz,
+            format,// word length, PCM
+            nbChannels,
+            frameCount,
+            0,// flags
+            audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
+            0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack 
+            lpJniStorage->mMemBase,// shared mem
+            true);// thread can call Java 
+    }
+
+    if (lpTrack->initCheck() != NO_ERROR) {
+        LOGE("Error initializing AudioTrack");
+        goto native_init_failure;
+    }
+
+    // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field 
+    // of the Java object (in mNativeTrackInJavaObj)
+    env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (int)lpTrack);
+    
+    // save the JNI resources so we can free them later
+    //LOGV("storing lpJniStorage: %x\n", (int)lpJniStorage);
+    env->SetIntField(thiz, javaAudioTrackFields.jniData, (int)lpJniStorage);
+
+    return AUDIOTRACK_SUCCESS;
+    
+    // failures:
+native_init_failure:
+    delete lpTrack;
+    env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
+    
+native_track_failure:
+    delete lpJniStorage;
+    env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
+    return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
+    
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
+{
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+        thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    if (lpTrack == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for start()");
+    }
+    
+    lpTrack->start();
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
+{
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+        thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    if (lpTrack == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for stop()");
+    }
+
+    lpTrack->stop();
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
+{
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+        thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    if (lpTrack == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for pause()");
+    }
+
+    lpTrack->pause();
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
+{
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+        thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    if (lpTrack == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for flush()");
+    }
+
+    lpTrack->flush();
+}
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
+{
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+        thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    if (lpTrack == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for setVolume()");
+    }
+
+    lpTrack->setVolume(leftVol, rightVol);
+}
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioTrack_native_finalize(JNIEnv *env,  jobject thiz) {
+    LOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz);
+       
+    // delete the AudioTrack object
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+        thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    if (lpTrack) {
+        LOGV("deleting lpTrack: %x\n", (int)lpTrack);
+        lpTrack->stop();
+        delete lpTrack;
+    }
+    
+    // delete the JNI data
+    AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetIntField(
+        thiz, javaAudioTrackFields.jniData);
+    if (pJniStorage) {
+        LOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
+        delete pJniStorage;
+    }
+}
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioTrack_native_release(JNIEnv *env,  jobject thiz) {
+       
+    // do everything a call to finalize would
+    android_media_AudioTrack_native_finalize(env, thiz);
+    // + reset the native resources in the Java object so any attempt to access
+    // them after a call to release fails.
+    env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
+    env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_native_write(JNIEnv *env,  jobject thiz,
+                                                  jbyteArray javaAudioData,
+                                                  jint offsetInBytes, jint sizeInBytes) {
+    jbyte* cAudioData = NULL;
+    AudioTrack *lpTrack = NULL;
+    //LOGV("android_media_AudioTrack_native_write(offset=%d, sizeInBytes=%d) called",
+    //    offsetInBytes, sizeInBytes);
+    
+    // get the audio track to load with samples
+    lpTrack = (AudioTrack *)env->GetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    if (lpTrack == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for write()");
+    }
+
+    // get the pointer for the audio data from the java array
+    if (javaAudioData) {
+        cAudioData = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
+        if (cAudioData == NULL) {
+            LOGE("Error retrieving source of audio data to play, can't play");
+            return 0; // out of memory or no data to load
+        }
+    } else {
+        LOGE("NULL java array of audio data to play, can't play");
+        return 0;
+    }
+
+    // give the data to the native AudioTrack object (the data starts at the offset)
+    ssize_t written = 0;
+    // regular write() or copy the data to the AudioTrack's shared memory?
+    if (lpTrack->sharedBuffer() == 0) {
+        written = lpTrack->write(cAudioData + offsetInBytes, sizeInBytes);
+    } else {
+        memcpy(lpTrack->sharedBuffer()->pointer(), cAudioData + offsetInBytes, sizeInBytes);
+        written = sizeInBytes;
+    }
+
+    env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0);
+
+    //LOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
+    //     (int)written, (int)(sizeInBytes), (int)offsetInBytes);
+    return (int)written;
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_native_write_short(JNIEnv *env,  jobject thiz,
+                                                  jshortArray javaAudioData,
+                                                  jint offsetInShorts, jint sizeInShorts) {
+    return (android_media_AudioTrack_native_write(env, thiz,
+                                                 (jbyteArray) javaAudioData,
+                                                 offsetInShorts*2, sizeInShorts*2)
+            / 2);
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env,  jobject thiz) {
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+        thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+
+    if (lpTrack) {
+        return lpTrack->frameCount();
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for frameCount()");
+        return AUDIOTRACK_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioTrack_set_playback_rate(JNIEnv *env,  jobject thiz,
+        jint sampleRateInHz) {
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+
+    if (lpTrack) {
+        lpTrack->setSampleRate(sampleRateInHz);   
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for setSampleRate()");
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env,  jobject thiz) {
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+
+    if (lpTrack) {
+        return (jint) lpTrack->getSampleRate();   
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for getSampleRate()");
+        return AUDIOTRACK_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env,  jobject thiz, 
+        jint markerPos) {
+            
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+                
+    if (lpTrack) {
+        return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );   
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
+        return AUDIOTRACK_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env,  jobject thiz) {
+    
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    uint32_t markerPos = 0;
+                
+    if (lpTrack) {
+        lpTrack->getMarkerPosition(&markerPos);
+        return (jint)markerPos;
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
+        return AUDIOTRACK_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env,  jobject thiz,
+        jint period) {
+            
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+                
+    if (lpTrack) {
+        return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );   
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
+        return AUDIOTRACK_ERROR;
+    }            
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env,  jobject thiz) {
+    
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    uint32_t period = 0;
+                
+    if (lpTrack) {
+        lpTrack->getPositionUpdatePeriod(&period);
+        return (jint)period;
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
+        return AUDIOTRACK_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_set_position(JNIEnv *env,  jobject thiz, 
+        jint position) {
+            
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+                
+    if (lpTrack) {
+        return android_media_translateErrorCode( lpTrack->setPosition(position) );
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for setPosition()");
+        return AUDIOTRACK_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_position(JNIEnv *env,  jobject thiz) {
+    
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    uint32_t position = 0;
+                
+    if (lpTrack) {
+        lpTrack->getPosition(&position);
+        return (jint)position;
+    }  else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for getPosition()");
+        return AUDIOTRACK_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_set_loop(JNIEnv *env,  jobject thiz,
+        jint loopStart, jint loopEnd, jint loopCount) {
+
+     AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+     if (lpTrack) {
+        return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
+     }  else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for setLoop()");
+        return AUDIOTRACK_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_reload(JNIEnv *env,  jobject thiz) {
+
+     AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+     if (lpTrack) {
+        return android_media_translateErrorCode( lpTrack->reload() );
+     } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for reload()");
+        return AUDIOTRACK_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env,  jobject thiz) {
+    int afSamplingRate;
+    if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
+        return DEFAULT_OUTPUT_SAMPLE_RATE;
+    } else {
+        return afSamplingRate;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+static JNINativeMethod gMethods[] = {
+    // name,              signature,     funcPtr
+    {"native_start",         "()V",      (void *)android_media_AudioTrack_start},
+    {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},
+    {"native_pause",         "()V",      (void *)android_media_AudioTrack_pause},
+    {"native_flush",         "()V",      (void *)android_media_AudioTrack_flush},
+    {"native_setup",         "(Ljava/lang/Object;IIIIII)I", 
+                                         (void *)android_media_AudioTrack_native_setup},
+    {"native_finalize",      "()V",      (void *)android_media_AudioTrack_native_finalize},
+    {"native_release",       "()V",      (void *)android_media_AudioTrack_native_release},
+    {"native_write_byte",    "([BII)I",  (void *)android_media_AudioTrack_native_write},
+    {"native_write_short",   "([SII)I",  (void *)android_media_AudioTrack_native_write_short},
+    {"native_setVolume",     "(FF)V",    (void *)android_media_AudioTrack_set_volume},
+    {"native_get_native_frame_count",
+                             "()I",      (void *)android_media_AudioTrack_get_native_frame_count},
+    {"native_set_playback_rate",
+                             "(I)V",     (void *)android_media_AudioTrack_set_playback_rate},
+    {"native_get_playback_rate",
+                             "()I",      (void *)android_media_AudioTrack_get_playback_rate},
+    {"native_set_marker_pos","(I)I",     (void *)android_media_AudioTrack_set_marker_pos},
+    {"native_get_marker_pos","()I",      (void *)android_media_AudioTrack_get_marker_pos},
+    {"native_set_pos_update_period",
+                             "(I)I",     (void *)android_media_AudioTrack_set_pos_update_period},
+    {"native_get_pos_update_period",
+                             "()I",      (void *)android_media_AudioTrack_get_pos_update_period},
+    {"native_set_position",  "(I)I",     (void *)android_media_AudioTrack_set_position},
+    {"native_get_position",  "()I",      (void *)android_media_AudioTrack_get_position},
+    {"native_set_loop",      "(III)I",   (void *)android_media_AudioTrack_set_loop},
+    {"native_reload_static", "()I",      (void *)android_media_AudioTrack_reload},
+    {"native_get_output_sample_rate",
+                             "()I",      (void *)android_media_AudioTrack_get_output_sample_rate},
+};
+
+
+// field names found in android/media/AudioTrack.java
+#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
+#define JAVA_CONST_PCM16_NAME        "ENCODING_PCM_16BIT"
+#define JAVA_CONST_PCM8_NAME         "ENCODING_PCM_8BIT"
+#define JAVA_CONST_BUFFER_COUNT_NAME "BUFFER_COUNT"
+#define JAVA_CONST_STREAM_VOICE_CALL_NAME "STREAM_VOICE_CALL"
+#define JAVA_CONST_STREAM_SYSTEM_NAME     "STREAM_SYSTEM"
+#define JAVA_CONST_STREAM_RING_NAME       "STREAM_RING"
+#define JAVA_CONST_STREAM_MUSIC_NAME      "STREAM_MUSIC"
+#define JAVA_CONST_STREAM_ALARM_NAME      "STREAM_ALARM"
+#define JAVA_CONST_MODE_STREAM_NAME       "MODE_STREAM"
+#define JAVA_CONST_MODE_STATIC_NAME       "MODE_STATIC"
+#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
+#define JAVA_JNIDATA_FIELD_NAME              "mJniData"
+
+#define JAVA_AUDIOFORMAT_CLASS_NAME  "android/media/AudioFormat"
+#define JAVA_AUDIOMANAGER_CLASS_NAME "android/media/AudioManager"
+
+// ----------------------------------------------------------------------------
+// preconditions:
+//    theClass is valid
+bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
+                             const char* constName, int* constVal) {
+    jfieldID javaConst = NULL;
+    javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
+    if (javaConst != NULL) {
+        *constVal = pEnv->GetStaticIntField(theClass, javaConst);
+        return true;
+    } else {
+        LOGE("Can't find %s.%s", className, constName);
+        return false;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+int register_android_media_AudioTrack(JNIEnv *env)
+{
+    javaAudioTrackFields.audioTrackClass = NULL;
+    javaAudioTrackFields.nativeTrackInJavaObj = NULL;
+    javaAudioTrackFields.postNativeEventInJava = NULL;
+
+    // Get the AudioTrack class
+    javaAudioTrackFields.audioTrackClass = env->FindClass(kClassPathName);
+    if (javaAudioTrackFields.audioTrackClass == NULL) {
+        LOGE("Can't find %s", kClassPathName);
+        return -1;
+    }
+
+    // Get the postEvent method
+    javaAudioTrackFields.postNativeEventInJava = env->GetStaticMethodID(
+            javaAudioTrackFields.audioTrackClass,
+            JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+    if (javaAudioTrackFields.postNativeEventInJava == NULL) {
+        LOGE("Can't find AudioTrack.%s", JAVA_POSTEVENT_CALLBACK_NAME);
+        return -1;
+    }
+
+    // Get the variables fields
+    //      nativeTrackInJavaObj
+    javaAudioTrackFields.nativeTrackInJavaObj = env->GetFieldID(
+            javaAudioTrackFields.audioTrackClass,
+            JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "I");
+    if (javaAudioTrackFields.nativeTrackInJavaObj == NULL) {
+        LOGE("Can't find AudioTrack.%s", JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME);
+        return -1;
+    }
+    //      jniData;
+    javaAudioTrackFields.jniData = env->GetFieldID(
+            javaAudioTrackFields.audioTrackClass,
+            JAVA_JNIDATA_FIELD_NAME, "I");
+    if (javaAudioTrackFields.jniData == NULL) {
+        LOGE("Can't find AudioTrack.%s", JAVA_JNIDATA_FIELD_NAME);
+        return -1;
+    }
+
+    // Get the memory mode constants
+    if ( !android_media_getIntConstantFromClass(env, javaAudioTrackFields.audioTrackClass,
+               kClassPathName, 
+               JAVA_CONST_MODE_STATIC_NAME, &(javaAudioTrackFields.MODE_STATIC))
+         || !android_media_getIntConstantFromClass(env, javaAudioTrackFields.audioTrackClass,
+               kClassPathName, 
+               JAVA_CONST_MODE_STREAM_NAME, &(javaAudioTrackFields.MODE_STREAM)) ) {
+        // error log performed in android_media_getIntConstantFromClass() 
+        return -1;
+    }
+
+    // Get the format constants from the AudioFormat class
+    jclass audioFormatClass = NULL;
+    audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME);
+    if (audioFormatClass == NULL) {
+        LOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME);
+        return -1;
+    }
+    if ( !android_media_getIntConstantFromClass(env, audioFormatClass, 
+                JAVA_AUDIOFORMAT_CLASS_NAME, 
+                JAVA_CONST_PCM16_NAME, &(javaAudioTrackFields.PCM16))
+           || !android_media_getIntConstantFromClass(env, audioFormatClass, 
+                JAVA_AUDIOFORMAT_CLASS_NAME, 
+                JAVA_CONST_PCM8_NAME, &(javaAudioTrackFields.PCM8)) ) {
+        // error log performed in android_media_getIntConstantFromClass() 
+        return -1;
+    }
+ 
+    // Get the stream types from the AudioManager class
+    jclass audioManagerClass = NULL;
+    audioManagerClass = env->FindClass(JAVA_AUDIOMANAGER_CLASS_NAME);
+    if (audioManagerClass == NULL) {
+       LOGE("Can't find %s", JAVA_AUDIOMANAGER_CLASS_NAME);
+       return -1;
+    }
+    if ( !android_media_getIntConstantFromClass(env, audioManagerClass, 
+               JAVA_AUDIOMANAGER_CLASS_NAME, 
+               JAVA_CONST_STREAM_VOICE_CALL_NAME, &(javaAudioTrackFields.STREAM_VOICE_CALL))
+          || !android_media_getIntConstantFromClass(env, audioManagerClass, 
+               JAVA_AUDIOMANAGER_CLASS_NAME, 
+               JAVA_CONST_STREAM_MUSIC_NAME, &(javaAudioTrackFields.STREAM_MUSIC))
+          || !android_media_getIntConstantFromClass(env, audioManagerClass, 
+               JAVA_AUDIOMANAGER_CLASS_NAME, 
+               JAVA_CONST_STREAM_SYSTEM_NAME, &(javaAudioTrackFields.STREAM_SYSTEM))
+          || !android_media_getIntConstantFromClass(env, audioManagerClass, 
+               JAVA_AUDIOMANAGER_CLASS_NAME, 
+               JAVA_CONST_STREAM_RING_NAME, &(javaAudioTrackFields.STREAM_RING))
+          || !android_media_getIntConstantFromClass(env, audioManagerClass,
+               JAVA_AUDIOMANAGER_CLASS_NAME, 
+               JAVA_CONST_STREAM_ALARM_NAME, &(javaAudioTrackFields.STREAM_ALARM)) ) {
+       // error log performed in android_media_getIntConstantFromClass()
+       return -1;
+    }
+ 
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+
+// ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 73c1283..a4388de 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -87,7 +87,7 @@
 
     if (lpToneGen == NULL) {
         LOGE("ToneGenerator creation failed \n");
-        jniThrowException(env, "java/lang/OutOfMemoryException", NULL);
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
         return;
     }
     LOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen);
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index abd0961..f14b9fa 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -700,7 +700,7 @@
     }
 
     if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
-        jniThrowException(env, "java/lang/ArrayIndexOutOfBounds", NULL);
+        jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
         return (jint)-1;
     }
 
@@ -767,7 +767,7 @@
     }
 
     if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
-        jniThrowException(env, "java/lang/ArrayIndexOutOfBounds", NULL);
+        jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
         return;
     }
 
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 417ce54..8383deb 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -41,6 +41,7 @@
                     in_addr_t *server,
                     uint32_t  *lease);
 int dhcp_stop(const char *ifname);
+int dhcp_release_lease(const char *ifname);
 char *dhcp_get_errmsg();
 }
 
@@ -157,7 +158,7 @@
     return (jboolean)(result == 0);
 }
 
-static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
 {
     int result;
 
@@ -167,6 +168,16 @@
     return (jboolean)(result == 0);
 }
 
+static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
+{
+    int result;
+
+    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+    result = ::dhcp_release_lease(nameStr);
+    env->ReleaseStringUTFChars(ifname, nameStr);
+    return (jboolean)(result == 0);
+}
+
 static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
 {
     return env->NewStringUTF(::dhcp_get_errmsg());
@@ -207,6 +218,7 @@
     { "resetConnections", "(Ljava/lang/String;)I",  (void *)android_net_utils_resetConnections },
     { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z",  (void *)android_net_utils_runDhcp },
     { "stopDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_stopDhcp },
+    { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
     { "configureNative", "(Ljava/lang/String;IIIII)Z",  (void *)android_net_utils_configureInterface },
     { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
 };
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 48af99e..722b5b8 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -343,6 +343,32 @@
     return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
 }
 
+static jboolean android_net_wifi_setNumAllowedChannelsCommand(JNIEnv* env, jobject clazz, jint numChannels)
+{
+    char cmdstr[256];
+
+    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER SCAN-CHANNELS %u", numChannels);
+    int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
+
+    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
+static jint android_net_wifi_getNumAllowedChannelsCommand(JNIEnv* env, jobject clazz)
+{
+    char reply[256];
+    int numChannels;
+
+    if (doCommand("DRIVER SCAN-CHANNELS", reply, sizeof(reply)) != 0) {
+        return -1;
+    }
+    // reply comes back in the form "Scan-Channels = X" where X is the
+    // number of channels
+    if (sscanf(reply, "%*s = %u", &numChannels) == 1)
+        return numChannels;
+    else
+        return -1;
+}
+
 static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject clazz, jint mode)
 {
     char cmdstr[256];
@@ -382,7 +408,7 @@
 
     const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
 
-    int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "BLACKLIST %s", bssidStr) >= sizeof(cmdstr);
+    int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "BLACKLIST %s", bssidStr) >= (int)sizeof(cmdstr);
 
     env->ReleaseStringUTFChars(bssid, bssidStr);
 
@@ -453,6 +479,8 @@
     { "startDriverCommand", "()Z", (void*) android_net_wifi_startDriverCommand },
     { "stopDriverCommand", "()Z", (void*) android_net_wifi_stopDriverCommand },
     { "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand },
+    { "setNumAllowedChannelsCommand", "(I)Z", (void*) android_net_wifi_setNumAllowedChannelsCommand },
+    { "getNumAllowedChannelsCommand", "()I", (void*) android_net_wifi_getNumAllowedChannelsCommand },
     { "setBluetoothCoexistenceModeCommand", "(I)Z",
     		(void*) android_net_wifi_setBluetoothCoexistenceModeCommand },
     { "getRssiCommand", "()I", (void*) android_net_wifi_getRssiCommand },
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
new file mode 100644
index 0000000..19ed39f
--- /dev/null
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -0,0 +1,417 @@
+/*
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "BluetoothA2dpService.cpp"
+
+#include "android_bluetooth_common.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static jmethodID method_onHeadsetCreated;
+static jmethodID method_onHeadsetRemoved;
+static jmethodID method_onSinkConnected;
+static jmethodID method_onSinkDisconnected;
+static jmethodID method_onSinkPlaying;
+static jmethodID method_onSinkStopped;
+
+typedef struct {
+    JNIEnv *env;
+    DBusConnection *conn;
+    jobject me;  // for callbacks to java
+} native_data_t;
+
+static native_data_t *nat = NULL;  // global native data
+
+extern event_loop_native_data_t *event_loop_nat;  // for the event loop JNIEnv
+#endif
+
+#ifdef HAVE_BLUETOOTH
+static void onConnectSinkResult(DBusMessage *msg, void *user);
+static void onDisconnectSinkResult(DBusMessage *msg, void *user);
+#endif
+
+/* Returns true on success (even if adapter is present but disabled).
+ * Return false if dbus is down, or another serious error (out of memory)
+*/
+static bool initNative(JNIEnv* env, jobject object) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+    if (NULL == nat) {
+        LOGE("%s: out of memory!", __FUNCTION__);
+        return false;
+    }
+    nat->env = env;
+    nat->me = env->NewGlobalRef(object);
+
+    DBusError err;
+    dbus_error_init(&err);
+    dbus_threads_init_default();
+    nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+    if (dbus_error_is_set(&err)) {
+        LOGE("Could not get onto the system bus: %s", err.message);
+        dbus_error_free(&err);
+        return false;
+    }
+#endif  /*HAVE_BLUETOOTH*/
+    return true;
+}
+
+static void cleanupNative(JNIEnv* env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        dbus_connection_close(nat->conn);
+        env->DeleteGlobalRef(nat->me);
+        free(nat);
+        nat = NULL;
+    }
+#endif
+}
+static jobjectArray listHeadsetsNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        DBusMessage *reply =
+            dbus_func_args(env, nat->conn, "/org/bluez/audio",
+                           "org.bluez.audio.Manager", "ListHeadsets",
+                           DBUS_TYPE_INVALID);
+        return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
+    }
+#endif
+    return NULL;
+}
+
+static jstring createHeadsetNative(JNIEnv *env, jobject object,
+                                     jstring address) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        const char *c_address = env->GetStringUTFChars(address, NULL);
+        LOGV("... address = %s\n", c_address);
+        DBusMessage *reply =
+            dbus_func_args(env, nat->conn, "/org/bluez/audio",
+                           "org.bluez.audio.Manager", "CreateHeadset",
+                           DBUS_TYPE_STRING, &c_address,
+                           DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(address, c_address);
+        return reply ? dbus_returns_string(env, reply) : NULL;
+    }
+#endif
+    return NULL;
+}
+
+static jstring removeHeadsetNative(JNIEnv *env, jobject object, jstring path) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        const char *c_path = env->GetStringUTFChars(path, NULL);
+        DBusMessage *reply =
+            dbus_func_args(env, nat->conn, "/org/bluez/audio",
+                           "org.bluez.audio.Manager", "RemoveHeadset",
+                           DBUS_TYPE_STRING, &c_path,
+                           DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(path, c_path);
+        return reply ? dbus_returns_string(env, reply) : NULL;
+    }
+#endif
+    return NULL;
+}
+
+static jstring getAddressNative(JNIEnv *env, jobject object, jstring path) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        const char *c_path = env->GetStringUTFChars(path, NULL);
+        DBusMessage *reply =
+            dbus_func_args(env, nat->conn, c_path,
+                           "org.bluez.audio.Device", "GetAddress",
+                           DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(path, c_path);
+        return reply ? dbus_returns_string(env, reply) : NULL;
+    }
+#endif
+    return NULL;
+}
+
+static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        const char *c_path = env->GetStringUTFChars(path, NULL);
+        size_t path_sz = env->GetStringUTFLength(path) + 1;
+        char *c_path_copy = (char *)malloc(path_sz);  // callback data
+        strncpy(c_path_copy, c_path, path_sz);
+
+        bool ret =
+            dbus_func_args_async(env, nat->conn, -1,
+                           onConnectSinkResult, (void *)c_path_copy, c_path,
+                           "org.bluez.audio.Sink", "Connect",
+                           DBUS_TYPE_INVALID);
+
+        env->ReleaseStringUTFChars(path, c_path);
+        if (!ret) {
+            free(c_path_copy);
+            return JNI_FALSE;
+        }
+        return JNI_TRUE;
+    }
+#endif
+    return JNI_FALSE;
+}
+
+static jboolean disconnectSinkNative(JNIEnv *env, jobject object,
+                                     jstring path) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        const char *c_path = env->GetStringUTFChars(path, NULL);
+        size_t path_sz = env->GetStringUTFLength(path) + 1;
+        char *c_path_copy = (char *)malloc(path_sz);  // callback data
+        strncpy(c_path_copy, c_path, path_sz);
+
+        bool ret =
+            dbus_func_args_async(env, nat->conn, -1,
+                           onDisconnectSinkResult, (void *)c_path_copy, c_path,
+                           "org.bluez.audio.Sink", "Disconnect",
+                           DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(path, c_path);
+        if (!ret) {
+            free(c_path_copy);
+            return JNI_FALSE;
+        }
+        return JNI_TRUE;
+    }
+#endif
+    return JNI_FALSE;
+}
+
+static jboolean isSinkConnectedNative(JNIEnv *env, jobject object, jstring path) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        const char *c_path = env->GetStringUTFChars(path, NULL);
+        DBusMessage *reply =
+            dbus_func_args(env, nat->conn, c_path,
+                           "org.bluez.audio.Sink", "IsConnected",
+                           DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(path, c_path);
+        return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
+    }
+#endif
+    return JNI_FALSE;
+}
+
+#ifdef HAVE_BLUETOOTH
+static void onConnectSinkResult(DBusMessage *msg, void *user) {
+    LOGV(__FUNCTION__);
+
+    char *c_path = (char *)user;
+    DBusError err;
+    dbus_error_init(&err);
+    JNIEnv *env = event_loop_nat->env;
+
+    LOGV("... path = %s", c_path);
+    if (dbus_set_error_from_message(&err, msg)) {
+        /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
+        LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+        dbus_error_free(&err);
+        env->CallVoidMethod(nat->me,
+                            method_onSinkDisconnected,
+                            env->NewStringUTF(c_path));
+        if (env->ExceptionCheck()) {
+            LOGE("VM Exception occurred in native function %s (%s:%d)",
+                 __FUNCTION__, __FILE__, __LINE__);
+        }
+    } // else Java callback is triggered by signal in a2dp_event_filter
+
+    free(c_path);
+}
+
+static void onDisconnectSinkResult(DBusMessage *msg, void *user) {
+    LOGV(__FUNCTION__);
+
+    char *c_path = (char *)user;
+    DBusError err;
+    dbus_error_init(&err);
+    JNIEnv *env = event_loop_nat->env;
+
+    LOGV("... path = %s", c_path);
+    if (dbus_set_error_from_message(&err, msg)) {
+        /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
+        LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+        dbus_error_free(&err);
+        // Assume it is still connected
+        env->CallVoidMethod(nat->me,
+                            method_onSinkConnected,
+                            env->NewStringUTF(c_path));
+        if (env->ExceptionCheck()) {
+            LOGE("VM Exception occurred in native function %s (%s:%d)",
+                 __FUNCTION__, __FILE__, __LINE__);
+        }
+    } // else Java callback is triggered by signal in a2dp_event_filter
+
+    free(c_path);
+}
+
+DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
+    DBusError err;
+
+    if (!nat) {
+        LOGV("... skipping %s\n", __FUNCTION__);
+        LOGV("... ignored\n");
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+    dbus_error_init(&err);
+
+    if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) {
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+    DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    if (dbus_message_is_signal(msg,
+                               "org.bluez.audio.Manager",
+                               "HeadsetCreated")) {
+        char *c_path;
+        if (dbus_message_get_args(msg, &err,
+                                  DBUS_TYPE_STRING, &c_path,
+                                  DBUS_TYPE_INVALID)) {
+            LOGV("... path = %s", c_path);
+            env->CallVoidMethod(nat->me,
+                                method_onHeadsetCreated,
+                                env->NewStringUTF(c_path));
+        } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+        result = DBUS_HANDLER_RESULT_HANDLED;
+    } else if (dbus_message_is_signal(msg,
+                                      "org.bluez.audio.Manager",
+                                      "HeadsetRemoved")) {
+        char *c_path;
+        if (dbus_message_get_args(msg, &err,
+                                  DBUS_TYPE_STRING, &c_path,
+                                  DBUS_TYPE_INVALID)) {
+            LOGV("... path = %s", c_path);
+            env->CallVoidMethod(nat->me,
+                                method_onHeadsetRemoved,
+                                env->NewStringUTF(c_path));
+        } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+        result = DBUS_HANDLER_RESULT_HANDLED;
+    } else if (dbus_message_is_signal(msg,
+                                      "org.bluez.audio.Sink",
+                                      "Connected")) {
+        const char *c_path = dbus_message_get_path(msg);
+        LOGV("... path = %s", c_path);
+        env->CallVoidMethod(nat->me,
+                            method_onSinkConnected,
+                            env->NewStringUTF(c_path));
+        result = DBUS_HANDLER_RESULT_HANDLED;
+    } else if (dbus_message_is_signal(msg,
+                                      "org.bluez.audio.Sink",
+                                      "Disconnected")) {
+        const char *c_path = dbus_message_get_path(msg);
+        LOGV("... path = %s", c_path);
+        env->CallVoidMethod(nat->me,
+                            method_onSinkDisconnected,
+                            env->NewStringUTF(c_path));
+        result = DBUS_HANDLER_RESULT_HANDLED;
+    } else if (dbus_message_is_signal(msg,
+                                      "org.bluez.audio.Sink",
+                                      "Playing")) {
+        const char *c_path = dbus_message_get_path(msg);
+        LOGV("... path = %s", c_path);
+        env->CallVoidMethod(nat->me,
+                            method_onSinkPlaying,
+                            env->NewStringUTF(c_path));
+        result = DBUS_HANDLER_RESULT_HANDLED;
+    } else if (dbus_message_is_signal(msg,
+                                      "org.bluez.audio.Sink",
+                                      "Stopped")) {
+        const char *c_path = dbus_message_get_path(msg);
+        LOGV("... path = %s", c_path);
+        env->CallVoidMethod(nat->me,
+                            method_onSinkStopped,
+                            env->NewStringUTF(c_path));
+        result = DBUS_HANDLER_RESULT_HANDLED;
+    }
+
+    if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) {
+        LOGV("... ignored");
+    }
+    if (env->ExceptionCheck()) {
+        LOGE("VM Exception occurred while handling %s.%s (%s) in %s,"
+             " leaving for VM",
+             dbus_message_get_interface(msg), dbus_message_get_member(msg),
+             dbus_message_get_path(msg), __FUNCTION__);
+    }
+
+    return result;
+}
+#endif
+
+
+static JNINativeMethod sMethods[] = {
+    {"initNative", "()Z", (void *)initNative},
+    {"cleanupNative", "()V", (void *)cleanupNative},
+
+    /* Bluez audio 3.36 API */
+    {"listHeadsetsNative", "()[Ljava/lang/String;", (void*)listHeadsetsNative},
+    {"createHeadsetNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)createHeadsetNative},
+    {"removeHeadsetNative", "(Ljava/lang/String;)Z", (void*)removeHeadsetNative},
+    {"getAddressNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getAddressNative},
+    {"connectSinkNative", "(Ljava/lang/String;)Z", (void*)connectSinkNative},
+    {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void*)disconnectSinkNative},
+    {"isSinkConnectedNative", "(Ljava/lang/String;)Z", (void*)isSinkConnectedNative},
+};
+
+int register_android_server_BluetoothA2dpService(JNIEnv *env) {
+    jclass clazz = env->FindClass("android/server/BluetoothA2dpService");
+    if (clazz == NULL) {
+        LOGE("Can't find android/server/BluetoothA2dpService");
+        return -1;
+    }
+
+#ifdef HAVE_BLUETOOTH
+    method_onHeadsetCreated = env->GetMethodID(clazz, "onHeadsetCreated", "(Ljava/lang/String;)V");
+    method_onHeadsetRemoved = env->GetMethodID(clazz, "onHeadsetRemoved", "(Ljava/lang/String;)V");
+    method_onSinkConnected = env->GetMethodID(clazz, "onSinkConnected", "(Ljava/lang/String;)V");
+    method_onSinkDisconnected = env->GetMethodID(clazz, "onSinkDisconnected", "(Ljava/lang/String;)V");
+    method_onSinkPlaying = env->GetMethodID(clazz, "onSinkPlaying", "(Ljava/lang/String;)V");
+    method_onSinkStopped = env->GetMethodID(clazz, "onSinkStopped", "(Ljava/lang/String;)V");
+#endif
+
+    return AndroidRuntime::registerNativeMethods(env,
+                "android/server/BluetoothA2dpService", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 395a45c..1aef138 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -39,6 +39,7 @@
 static jfieldID field_mNativeData;
 
 static jmethodID method_onModeChanged;
+static jmethodID method_onNameChanged;
 static jmethodID method_onDiscoveryStarted;
 static jmethodID method_onDiscoveryCompleted;
 static jmethodID method_onRemoteDeviceFound;
@@ -60,17 +61,10 @@
 static jmethodID method_onPasskeyAgentRequest;
 static jmethodID method_onPasskeyAgentCancel;
 
-struct native_data_t {
-    DBusConnection *conn;
-    /* These variables are set in waitForAndDispatchEventNative() and are
-       valid only within the scope of this function.  At any other time, they
-       are NULL. */
-    jobject me;
-    JNIEnv *env;
-};
+typedef event_loop_native_data_t native_data_t;
 
 // Only valid during waitForAndDispatchEventNative()
-static native_data_t *event_loop_nat;
+native_data_t *event_loop_nat;
 
 static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
     return (native_data_t *)(env->GetIntField(object,
@@ -83,6 +77,7 @@
 
 #ifdef HAVE_BLUETOOTH
     method_onModeChanged = env->GetMethodID(clazz, "onModeChanged", "(Ljava/lang/String;)V");
+    method_onNameChanged = env->GetMethodID(clazz, "onNameChanged", "(Ljava/lang/String;)V");
     method_onDiscoveryStarted = env->GetMethodID(clazz, "onDiscoveryStarted", "()V");
     method_onDiscoveryCompleted = env->GetMethodID(clazz, "onDiscoveryCompleted", "()V");
     method_onRemoteDeviceFound = env->GetMethodID(clazz, "onRemoteDeviceFound", "(Ljava/lang/String;IS)V");
@@ -142,8 +137,6 @@
 }
 
 #ifdef HAVE_BLUETOOTH
-static jboolean add_adapter_event_match(JNIEnv *env, native_data_t *nat);
-static void remove_adapter_event_match(JNIEnv *env, native_data_t *nat);
 static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
                                       void *data);
 static DBusHandlerResult passkey_agent_event_filter(DBusConnection *conn,
@@ -160,15 +153,46 @@
     LOGV(__FUNCTION__);
     dbus_threads_init_default();
     native_data_t *nat = get_native_data(env, object);
+    DBusError err;
+    dbus_error_init(&err);
+
     if (nat != NULL && nat->conn != NULL) {
+        // Add a filter for all incoming messages
         if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
             return JNI_FALSE;
         }
 
-        if (add_adapter_event_match(env, nat) != JNI_TRUE) {
+        // Set which messages will be processed by this dbus connection
+        dbus_bus_add_match(nat->conn,
+                "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
+                &err);
+        if (dbus_error_is_set(&err)) {
+            LOG_AND_FREE_DBUS_ERROR(&err);
+            return JNI_FALSE;
+        }
+        dbus_bus_add_match(nat->conn,
+                "type='signal',interface='org.bluez.audio.Manager'",
+                &err);
+        if (dbus_error_is_set(&err)) {
+            LOG_AND_FREE_DBUS_ERROR(&err);
+            return JNI_FALSE;
+        }
+        dbus_bus_add_match(nat->conn,
+                "type='signal',interface='org.bluez.audio.Device'",
+                &err);
+        if (dbus_error_is_set(&err)) {
+            LOG_AND_FREE_DBUS_ERROR(&err);
+            return JNI_FALSE;
+        }
+        dbus_bus_add_match(nat->conn,
+                "type='signal',interface='org.bluez.audio.Sink'",
+                &err);
+        if (dbus_error_is_set(&err)) {
+            LOG_AND_FREE_DBUS_ERROR(&err);
             return JNI_FALSE;
         }
 
+        // Add an object handler for passkey agent method calls
         const char *path = "/android/bluetooth/PasskeyAgent";
         if (!dbus_connection_register_object_path(nat->conn, path,
                                                   &passkey_agent_vtable, NULL)) {
@@ -177,9 +201,6 @@
             return JNI_FALSE;
         }
 
-        DBusError err;
-        dbus_error_init(&err);
-
         // RegisterDefaultPasskeyAgent() will fail until hcid is up, so keep
         // trying for 10 seconds.
         int attempt;
@@ -219,6 +240,9 @@
     native_data_t *nat = get_native_data(env, object);
     if (nat != NULL && nat->conn != NULL) {
 
+        DBusError err;
+        dbus_error_init(&err);
+
         const char *path = "/android/bluetooth/PasskeyAgent";
         DBusMessage *reply =
             dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH,
@@ -227,50 +251,40 @@
                            DBUS_TYPE_INVALID);
         if (reply) dbus_message_unref(reply);
 
-        DBusError err;
-        dbus_error_init(&err);
-        (void)dbus_connection_remove_filter(nat->conn,
-                                            event_filter,
-                                            nat);
-
         dbus_connection_unregister_object_path(nat->conn, path);
 
-        remove_adapter_event_match(env, nat);
+        dbus_bus_remove_match(nat->conn,
+                "type='signal',interface='org.bluez.audio.Sink'",
+                &err);
+        if (dbus_error_is_set(&err)) {
+            LOG_AND_FREE_DBUS_ERROR(&err);
+        }
+        dbus_bus_remove_match(nat->conn,
+                "type='signal',interface='org.bluez.audio.Device'",
+                &err);
+        if (dbus_error_is_set(&err)) {
+            LOG_AND_FREE_DBUS_ERROR(&err);
+        }
+        dbus_bus_remove_match(nat->conn,
+                "type='signal',interface='org.bluez.audio.Manager'",
+                &err);
+        if (dbus_error_is_set(&err)) {
+            LOG_AND_FREE_DBUS_ERROR(&err);
+        }
+        dbus_bus_remove_match(nat->conn,
+                "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
+                &err);
+        if (dbus_error_is_set(&err)) {
+            LOG_AND_FREE_DBUS_ERROR(&err);
+        }
+
+        dbus_connection_remove_filter(nat->conn, event_filter, nat);
     }
 #endif
 }
 
 #ifdef HAVE_BLUETOOTH
-static const char *const adapter_event_match =
-    "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'";
-
-static jboolean add_adapter_event_match(JNIEnv *env, native_data_t *nat) {
-    if (nat == NULL || nat->conn == NULL) {
-        LOGE("%s: Not connected to d-bus!", __FUNCTION__);
-        return JNI_FALSE;
-    }
-    DBusError err;
-    dbus_error_init(&err);
-    dbus_bus_add_match(nat->conn, adapter_event_match, &err);
-    if (dbus_error_is_set(&err)) {
-        LOG_AND_FREE_DBUS_ERROR(&err);
-        return JNI_FALSE;
-    }
-    return JNI_TRUE;
-}
-
-static void remove_adapter_event_match(JNIEnv *env, native_data_t *nat) {
-    if (nat->conn == NULL) {
-        LOGE("%s: Not connected to d-bus!", __FUNCTION__);
-        return;
-    }
-    DBusError err;
-    dbus_error_init(&err);
-    dbus_bus_remove_match(nat->conn, adapter_event_match, &err);
-    if (dbus_error_is_set(&err)) {
-        LOG_AND_FREE_DBUS_ERROR(&err);
-    }
-}
+extern DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env);
 
 // Called by dbus during WaitForAndDispatchEventNative()
 static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
@@ -288,8 +302,9 @@
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
-    LOGV("%s: Received signal %s:%s", __FUNCTION__,
-         dbus_message_get_interface(msg), dbus_message_get_member(msg));
+    LOGV("%s: Received signal %s:%s from %s", __FUNCTION__,
+         dbus_message_get_interface(msg), dbus_message_get_member(msg),
+         dbus_message_get_path(msg));
 
     if (dbus_message_is_signal(msg,
                                "org.bluez.Adapter",
@@ -471,11 +486,35 @@
                                 env->NewStringUTF(c_address));
         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
         return DBUS_HANDLER_RESULT_HANDLED;
-    } else {
-        LOGV("... ignored");
+    } else if (dbus_message_is_signal(msg,
+                                      "org.bluez.Adapter",
+                                      "ModeChanged")) {
+        char *c_mode;
+        if (dbus_message_get_args(msg, &err,
+                                  DBUS_TYPE_STRING, &c_mode,
+                                  DBUS_TYPE_INVALID)) {
+            LOGV("... mode = %s", c_mode);
+            env->CallVoidMethod(nat->me,
+                                method_onModeChanged,
+                                env->NewStringUTF(c_mode));
+        } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+        return DBUS_HANDLER_RESULT_HANDLED;
+    } else if (dbus_message_is_signal(msg,
+                                      "org.bluez.Adapter",
+                                      "NameChanged")) {
+        char *c_name;
+        if (dbus_message_get_args(msg, &err,
+                                  DBUS_TYPE_STRING, &c_name,
+                                  DBUS_TYPE_INVALID)) {
+            LOGV("... name = %s", c_name);
+            env->CallVoidMethod(nat->me,
+                                method_onNameChanged,
+                                env->NewStringUTF(c_name));
+        } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+        return DBUS_HANDLER_RESULT_HANDLED;
     }
 
-    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    return a2dp_event_filter(msg, env);
 }
 
 // Called by dbus during WaitForAndDispatchEventNative()
@@ -557,9 +596,9 @@
         nat->me = object;
         nat->env = env;
         event_loop_nat = nat;
-        ret = dbus_connection_read_write_dispatch(nat->conn,
-                                                  timeout_ms) == TRUE ?
-            JNI_TRUE : JNI_FALSE;
+        ret = dbus_connection_read_write_dispatch_greedy(nat->conn,
+                                                         timeout_ms) == TRUE ?
+              JNI_TRUE : JNI_FALSE;
         event_loop_nat = NULL;
         nat->me = NULL;
         nat->env = NULL;
@@ -604,7 +643,7 @@
     JNIEnv *env = event_loop_nat->env;
     jint channel = -2;
 
-    LOGV("... address = %s", context->address);
+    LOGV("... address = %s", address);
 
     if (dbus_set_error_from_message(&err, msg) ||
         !dbus_message_get_args(msg, &err,
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 97daed3..450cee2 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -43,7 +43,7 @@
     }
 
     if (env->GetArrayLength(srcArray) < count || env->GetArrayLength(destArray) < count) {
-        jniThrowException(env, "java/lang/ArrayIndexException", NULL);
+        jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
         goto DIRECTION_END;
     }
 
@@ -81,7 +81,7 @@
     }
 
     if (start > start + count || env->GetArrayLength(charArray) < count) {
-        jniThrowException(env, "java/lang/ArrayIndexException", NULL);
+        jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
         goto MIRROR_END;
     }
 
diff --git a/core/jni/android_pim_Time.cpp b/core/jni/android_text_format_Time.cpp
similarity index 68%
rename from core/jni/android_pim_Time.cpp
rename to core/jni/android_text_format_Time.cpp
index c1dd499..8e41ec7 100644
--- a/core/jni/android_pim_Time.cpp
+++ b/core/jni/android_text_format_Time.cpp
@@ -25,6 +25,7 @@
 #include "android_runtime/AndroidRuntime.h"
 #include <utils/TimeUtils.h>
 #include <nativehelper/JNIHelp.h>
+#include <cutils/tztime.h>
 
 namespace android {
 
@@ -41,6 +42,17 @@
 static jfieldID g_gmtoffField = 0;
 static jfieldID g_timezoneField = 0;
 
+static jfieldID g_shortMonthsField = 0;
+static jfieldID g_longMonthsField = 0;
+static jfieldID g_shortWeekdaysField = 0;
+static jfieldID g_longWeekdaysField = 0;
+static jfieldID g_timeOnlyFormatField = 0;
+static jfieldID g_dateOnlyFormatField = 0;
+static jfieldID g_dateTimeFormatField = 0;
+static jfieldID g_amField = 0;
+static jfieldID g_pmField = 0;
+static jfieldID g_dateCommandField = 0;
+
 static inline bool java2time(JNIEnv* env, Time* t, jobject o)
 {
     t->t.tm_sec = env->GetIntField(o, g_secField);
@@ -89,7 +101,7 @@
 
 // ============================================================================
 
-static jlong android_pim_Time_normalize(JNIEnv* env, jobject This,
+static jlong android_text_format_Time_normalize(JNIEnv* env, jobject This,
                                            jboolean ignoreDst)
 {
     Time t;
@@ -104,7 +116,7 @@
     return result;
 }
 
-static void android_pim_Time_switchTimezone(JNIEnv* env, jobject This,
+static void android_text_format_Time_switchTimezone(JNIEnv* env, jobject This,
                             jstring timezoneObject)
 {
     Time t;
@@ -123,7 +135,7 @@
     env->SetObjectField(This, g_timezoneField, timezoneObject);
 }
 
-static jint android_pim_Time_compare(JNIEnv* env, jobject clazz,
+static jint android_text_format_Time_compare(JNIEnv* env, jobject clazz,
                             jobject aObject, jobject bObject)
 {
     Time a, b;
@@ -142,7 +154,7 @@
     return result;
 }
 
-static jstring android_pim_Time_format2445(JNIEnv* env, jobject This)
+static jstring android_text_format_Time_format2445(JNIEnv* env, jobject This)
 {
     Time t;
     if (!java2time(env, &t, This)) return env->NewStringUTF("");
@@ -168,25 +180,91 @@
     }
 }
 
-static jstring android_pim_Time_format(JNIEnv* env, jobject This,
+static jstring android_text_format_Time_format(JNIEnv* env, jobject This,
                             jstring formatObject)
 {
     Time t;
+    struct strftime_locale locale;
+    jclass timeClass = env->FindClass("android/text/format/Time");
+    jstring js_mon[12], js_month[12], js_wday[7], js_weekday[7];
+    jstring js_X_fmt, js_x_fmt, js_c_fmt, js_am, js_pm, js_date_fmt;
+    jobjectArray ja;
+
     if (!java2time(env, &t, This)) return env->NewStringUTF("");
+
+    ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortMonthsField);
+    for (int i = 0; i < 12; i++) {
+        js_mon[i] = (jstring) env->GetObjectArrayElement(ja, i);
+        locale.mon[i] = env->GetStringUTFChars(js_mon[i], NULL);
+    }
+
+    ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longMonthsField);
+    for (int i = 0; i < 12; i++) {
+        js_month[i] = (jstring) env->GetObjectArrayElement(ja, i);
+        locale.month[i] = env->GetStringUTFChars(js_month[i], NULL);
+    }
+
+    ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortWeekdaysField);
+    for (int i = 0; i < 7; i++) {
+        js_wday[i] = (jstring) env->GetObjectArrayElement(ja, i);
+        locale.wday[i] = env->GetStringUTFChars(js_wday[i], NULL);
+    }
+
+    ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longWeekdaysField);
+    for (int i = 0; i < 7; i++) {
+        js_weekday[i] = (jstring) env->GetObjectArrayElement(ja, i);
+        locale.weekday[i] = env->GetStringUTFChars(js_weekday[i], NULL);
+    }
+
+    js_X_fmt = (jstring) env->GetStaticObjectField(timeClass, g_timeOnlyFormatField);
+    locale.X_fmt = env->GetStringUTFChars(js_X_fmt, NULL);
+
+    js_x_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateOnlyFormatField);
+    locale.x_fmt = env->GetStringUTFChars(js_x_fmt, NULL);
+
+    js_c_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateTimeFormatField);
+    locale.c_fmt = env->GetStringUTFChars(js_c_fmt, NULL);
+
+    js_am = (jstring) env->GetStaticObjectField(timeClass, g_amField);
+    locale.am = env->GetStringUTFChars(js_am, NULL);
+
+    js_pm = (jstring) env->GetStaticObjectField(timeClass, g_pmField);
+    locale.pm = env->GetStringUTFChars(js_pm, NULL);
+
+    js_date_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateCommandField);
+    locale.date_fmt = env->GetStringUTFChars(js_date_fmt, NULL);
+
     ACQUIRE_TIMEZONE(This, t)
 
     const char* format = env->GetStringUTFChars(formatObject, NULL);
 
-    String8 r = t.format(format);
+    String8 r = t.format(format, &locale);
 
     env->ReleaseStringUTFChars(formatObject, format);
     RELEASE_TIMEZONE(This, t)
 
+    for (int i = 0; i < 12; i++) {
+        env->ReleaseStringUTFChars(js_mon[i], locale.mon[i]);
+        env->ReleaseStringUTFChars(js_month[i], locale.month[i]);
+    }
+
+    for (int i = 0; i < 7; i++) {
+        env->ReleaseStringUTFChars(js_wday[i], locale.wday[i]);
+        env->ReleaseStringUTFChars(js_weekday[i], locale.weekday[i]);
+    }
+
+    env->ReleaseStringUTFChars(js_X_fmt, locale.X_fmt);
+    env->ReleaseStringUTFChars(js_x_fmt, locale.x_fmt);
+    env->ReleaseStringUTFChars(js_c_fmt, locale.c_fmt);
+    env->ReleaseStringUTFChars(js_am, locale.am);
+    env->ReleaseStringUTFChars(js_pm, locale.pm);
+    env->ReleaseStringUTFChars(js_date_fmt, locale.date_fmt);
+
     return env->NewStringUTF(r.string());
 }
 
 
-static jstring android_pim_Time_toString(JNIEnv* env, jobject This)
+static jstring android_text_format_Time_toString(JNIEnv* env, jobject This)
 {
     Time t;
     if (!java2time(env, &t, This)) return env->NewStringUTF("");;
@@ -199,7 +277,7 @@
     return env->NewStringUTF(r.string());
 }
 
-static void android_pim_Time_setToNow(JNIEnv* env, jobject This)
+static void android_text_format_Time_setToNow(JNIEnv* env, jobject This)
 {
     env->SetBooleanField(This, g_allDayField, JNI_FALSE);
     Time t;
@@ -211,7 +289,7 @@
     RELEASE_TIMEZONE(This, t)
 }
 
-static jlong android_pim_Time_toMillis(JNIEnv* env, jobject This,
+static jlong android_text_format_Time_toMillis(JNIEnv* env, jobject This,
                                         jboolean ignoreDst)
 {
     Time t;
@@ -225,7 +303,7 @@
     return result;
 }
 
-static void android_pim_Time_set(JNIEnv* env, jobject This, jlong millis)
+static void android_text_format_Time_set(JNIEnv* env, jobject This, jlong millis)
 {
     env->SetBooleanField(This, g_allDayField, JNI_FALSE);
     Time t;
@@ -271,65 +349,7 @@
 }
 
 
-static void android_pim_Time_parse(JNIEnv* env, jobject This, jstring strObj)
-{
-    jsize len = env->GetStringLength(strObj);
-    const jchar *s = env->GetStringChars(strObj, NULL);
-
-    bool thrown = false;
-    int n;
-
-    n = get_char(env, s, 0, 1000, &thrown);
-    n += get_char(env, s, 1, 100, &thrown);
-    n += get_char(env, s, 2, 10, &thrown);
-    n += get_char(env, s, 3, 1, &thrown);
-    if (thrown) return;
-    env->SetIntField(This, g_yearField, n);
-
-    n = get_char(env, s, 4, 10, &thrown);
-    n += get_char(env, s, 5, 1, &thrown);
-    n--;
-    if (thrown) return;
-    env->SetIntField(This, g_monField, n);
-
-    n = get_char(env, s, 6, 10, &thrown);
-    n += get_char(env, s, 7, 1, &thrown);
-    if (thrown) return;
-    env->SetIntField(This, g_mdayField, n);
-
-    if (len >= 15) {
-        env->SetBooleanField(This, g_allDayField, JNI_FALSE);
-        n = get_char(env, s, 9, 10, &thrown);
-        n += get_char(env, s, 10, 1, &thrown);
-        if (thrown) return;
-        env->SetIntField(This, g_hourField, n);
-
-        n = get_char(env, s, 11, 10, &thrown);
-        n += get_char(env, s, 12, 1, &thrown);
-        if (thrown) return;
-        env->SetIntField(This, g_minField, n);
-
-        n = get_char(env, s, 13, 10, &thrown);
-        n += get_char(env, s, 14, 1, &thrown);
-        if (thrown) return;
-        env->SetIntField(This, g_secField, n);
-    } else {
-        env->SetBooleanField(This, g_allDayField, JNI_TRUE);
-        env->SetIntField(This, g_hourField, 0);
-        env->SetIntField(This, g_minField, 0);
-        env->SetIntField(This, g_secField, 0);
-    }
-
-    env->SetIntField(This, g_wdayField, 0);
-    env->SetIntField(This, g_ydayField, 0);
-    env->SetIntField(This, g_isdstField, -1);
-    env->SetLongField(This, g_gmtoffField, 0);
-    
-    env->ReleaseStringChars(strObj, s);
-}
-
-static jboolean android_pim_Time_parse2445(JNIEnv* env, jobject This, 
-					    jstring strObj)
+static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstring strObj)
 {
     jsize len = env->GetStringLength(strObj);
     const jchar *s = env->GetStringChars(strObj, NULL);
@@ -337,7 +357,7 @@
     bool thrown = false;
     int n;
     jboolean inUtc = false;
-    
+
     if (len < 8) {
         char msg[100];
         sprintf(msg, "String too short -- expected at least 8 characters.");
@@ -367,39 +387,38 @@
     env->SetIntField(This, g_mdayField, n);
 
     if (len > 8) {
-      // T
-      if (!check_char(env, s, 8, 'T')) return false;
-      env->SetBooleanField(This, g_allDayField, JNI_FALSE);
+        // T
+        if (!check_char(env, s, 8, 'T')) return false;
+        env->SetBooleanField(This, g_allDayField, JNI_FALSE);
 
-      // hour
-      n = get_char(env, s, 9, 10, &thrown);
-      n += get_char(env, s, 10, 1, &thrown);
-      if (thrown) return false;
-      env->SetIntField(This, g_hourField, n);
+        // hour
+        n = get_char(env, s, 9, 10, &thrown);
+        n += get_char(env, s, 10, 1, &thrown);
+        if (thrown) return false;
+        env->SetIntField(This, g_hourField, n);
 
-      // min
-      n = get_char(env, s, 11, 10, &thrown);
-      n += get_char(env, s, 12, 1, &thrown);
-      if (thrown) return false;
-      env->SetIntField(This, g_minField, n);
-    
-      // sec
-      n = get_char(env, s, 13, 10, &thrown);
-      n += get_char(env, s, 14, 1, &thrown);
-      if (thrown) return false;
-      env->SetIntField(This, g_secField, n);
+        // min
+        n = get_char(env, s, 11, 10, &thrown);
+        n += get_char(env, s, 12, 1, &thrown);
+        if (thrown) return false;
+        env->SetIntField(This, g_minField, n);
 
-      if (len > 15) {
-        // Z
-        if (!check_char(env, s, 15, 'Z')) return false;
-	inUtc = true;
-      }
+        // sec
+        n = get_char(env, s, 13, 10, &thrown);
+        n += get_char(env, s, 14, 1, &thrown);
+        if (thrown) return false;
+        env->SetIntField(This, g_secField, n);
+
+        if (len > 15) {
+            // Z
+            if (!check_char(env, s, 15, 'Z')) return false;
+	    inUtc = true;
+        }
     } else {
-      // all day
-      env->SetBooleanField(This, g_allDayField, JNI_TRUE);
-      env->SetIntField(This, g_hourField, 0);
-      env->SetIntField(This, g_minField, 0);
-      env->SetIntField(This, g_secField, 0);
+        env->SetBooleanField(This, g_allDayField, JNI_TRUE);
+        env->SetIntField(This, g_hourField, 0);
+        env->SetIntField(This, g_minField, 0);
+        env->SetIntField(This, g_secField, 0);
     }
 
     env->SetIntField(This, g_wdayField, 0);
@@ -411,7 +430,7 @@
     return inUtc;
 }
 
-static jboolean android_pim_Time_parse3339(JNIEnv* env, 
+static jboolean android_text_format_Time_parse3339(JNIEnv* env, 
                                            jobject This, 
                                            jstring strObj)
 {
@@ -531,7 +550,7 @@
 
 	if (offset != 0) {
 	    // we need to normalize after applying the hour and minute offsets
-	    android_pim_Time_normalize(env, This, false /* use isdst */);
+	    android_text_format_Time_normalize(env, This, false /* use isdst */);
 	    // The timezone is set to UTC in the calling Java code.
 	}
     } else {
@@ -556,23 +575,22 @@
  */
 static JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
-    { "normalize",               "(Z)J",                                        (void*)android_pim_Time_normalize },
-    { "switchTimezone",          "(Ljava/lang/String;)V",                       (void*)android_pim_Time_switchTimezone },
-    { "compare",                 "(Landroid/pim/Time;Landroid/pim/Time;)I",     (void*)android_pim_Time_compare },
-    { "format",                  "(Ljava/lang/String;)Ljava/lang/String;",      (void*)android_pim_Time_format },
-    { "format2445",              "()Ljava/lang/String;",                        (void*)android_pim_Time_format2445 },
-    { "toString",                "()Ljava/lang/String;",                        (void*)android_pim_Time_toString },
-    { "parse",                   "(Ljava/lang/String;)V",                       (void*)android_pim_Time_parse },
-    { "nativeParse2445",         "(Ljava/lang/String;)Z",                       (void*)android_pim_Time_parse2445 },
-    { "nativeParse3339",         "(Ljava/lang/String;)Z",                       (void*)android_pim_Time_parse3339 },
-    { "setToNow",                "()V",                                         (void*)android_pim_Time_setToNow },
-    { "toMillis",                "(Z)J",                                        (void*)android_pim_Time_toMillis },
-    { "set",                     "(J)V",                                        (void*)android_pim_Time_set }
+    { "normalize",               "(Z)J",                                        (void*)android_text_format_Time_normalize },
+    { "switchTimezone",          "(Ljava/lang/String;)V",                       (void*)android_text_format_Time_switchTimezone },
+    { "compare",                 "(Landroid/text/format/Time;Landroid/text/format/Time;)I",     (void*)android_text_format_Time_compare },
+    { "format1",                 "(Ljava/lang/String;)Ljava/lang/String;",      (void*)android_text_format_Time_format },
+    { "format2445",              "()Ljava/lang/String;",                        (void*)android_text_format_Time_format2445 },
+    { "toString",                "()Ljava/lang/String;",                        (void*)android_text_format_Time_toString },
+    { "nativeParse",             "(Ljava/lang/String;)Z",                       (void*)android_text_format_Time_parse },
+    { "nativeParse3339",         "(Ljava/lang/String;)Z",                       (void*)android_text_format_Time_parse3339 },
+    { "setToNow",                "()V",                                         (void*)android_text_format_Time_setToNow },
+    { "toMillis",                "(Z)J",                                        (void*)android_text_format_Time_toMillis },
+    { "set",                     "(J)V",                                        (void*)android_text_format_Time_set }
 };
 
-int register_android_pim_Time(JNIEnv* env)
+int register_android_text_format_Time(JNIEnv* env)
 {
-    jclass timeClass = env->FindClass("android/pim/Time");
+    jclass timeClass = env->FindClass("android/text/format/Time");
 
     g_allDayField = env->GetFieldID(timeClass, "allDay", "Z");
     g_secField = env->GetFieldID(timeClass, "second", "I");
@@ -587,7 +605,18 @@
     g_gmtoffField = env->GetFieldID(timeClass, "gmtoff", "J");
     g_timezoneField = env->GetFieldID(timeClass, "timezone", "Ljava/lang/String;");
 
-    return AndroidRuntime::registerNativeMethods(env, "android/pim/Time", gMethods, NELEM(gMethods));
+    g_shortMonthsField = env->GetStaticFieldID(timeClass, "sShortMonths", "[Ljava/lang/String;");
+    g_longMonthsField = env->GetStaticFieldID(timeClass, "sLongMonths", "[Ljava/lang/String;");
+    g_shortWeekdaysField = env->GetStaticFieldID(timeClass, "sShortWeekdays", "[Ljava/lang/String;");
+    g_longWeekdaysField = env->GetStaticFieldID(timeClass, "sLongWeekdays", "[Ljava/lang/String;");
+    g_timeOnlyFormatField = env->GetStaticFieldID(timeClass, "sTimeOnlyFormat", "Ljava/lang/String;");
+    g_dateOnlyFormatField = env->GetStaticFieldID(timeClass, "sDateOnlyFormat", "Ljava/lang/String;");
+    g_dateTimeFormatField = env->GetStaticFieldID(timeClass, "sDateTimeFormat", "Ljava/lang/String;");
+    g_amField = env->GetStaticFieldID(timeClass, "sAm", "Ljava/lang/String;");
+    g_pmField = env->GetStaticFieldID(timeClass, "sPm", "Ljava/lang/String;");
+    g_dateCommandField = env->GetStaticFieldID(timeClass, "sDateCommand", "Ljava/lang/String;");
+
+    return AndroidRuntime::registerNativeMethods(env, "android/text/format/Time", gMethods, NELEM(gMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 8a62159..add1080 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -901,7 +901,8 @@
         return JNI_FALSE;
     }
 
-    jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    jint* dest = baseDest;
     if (dest == NULL) {
         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
         doThrow(env, "java/lang/OutOfMemoryError");
@@ -1074,7 +1075,7 @@
         indices[0] = indicesIdx;
         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
     }
-    env->ReleasePrimitiveArrayCritical(outValues, dest, 0);
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
 
     return JNI_TRUE;
@@ -1112,7 +1113,8 @@
         return JNI_FALSE;
     }
     
-    jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    jint* dest = baseDest;
     if (dest == NULL) {
         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
         doThrow(env, "java/lang/OutOfMemoryError");
@@ -1201,7 +1203,7 @@
         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
     }
     
-    env->ReleasePrimitiveArrayCritical(outValues, dest, 0);
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
     
     return JNI_TRUE;
@@ -1243,7 +1245,8 @@
     
     const jsize NV = env->GetArrayLength(outValues);
     
-    jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    jint* dest = baseDest;
     if (dest == NULL) {
         doThrow(env, "java/lang/OutOfMemoryError");
         return JNI_FALSE;
@@ -1295,7 +1298,7 @@
     
     res.unlock();
     
-    env->ReleasePrimitiveArrayCritical(outValues, dest, 0);
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
     
     return i;
 }
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 08c4f1c..3feccde 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -88,6 +88,11 @@
     return getpid();
 }
 
+jint android_os_Process_myUid(JNIEnv* env, jobject clazz)
+{
+    return getuid();
+}
+
 jint android_os_Process_myTid(JNIEnv* env, jobject clazz)
 {
 #ifdef HAVE_GETTID
@@ -707,6 +712,7 @@
 static const JNINativeMethod methods[] = {
     {"myPid",       "()I", (void*)android_os_Process_myPid},
     {"myTid",       "()I", (void*)android_os_Process_myTid},
+    {"myUid",       "()I", (void*)android_os_Process_myUid},
     {"getUidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
     {"getGidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
     {"setThreadPriority",   "(II)V", (void*)android_os_Process_setThreadPriority},
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index af03016..a985c24 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -332,12 +332,8 @@
 
     if (success && configs) {
         for (int i=0 ; i<num ; i++) {
-            jobject obj = _env->GetObjectArrayElement(configs, i);
-            if (obj == NULL) {
-                doThrow(_env, "java/lang/NullPointerException");
-                break;
-            }
-            _env->SetIntField(obj, gConfig_EGLConfigFieldID, (jint)nativeConfigs[i]);
+            jobject obj = _env->NewObject(gConfig_class, gConfig_ctorID, (jint)nativeConfigs[i]);
+            _env->SetObjectArrayElement(configs, i, obj);
         }
     }
     return success;
@@ -396,8 +392,7 @@
 jstring jni_eglQueryString(JNIEnv *_env, jobject _this, jobject display, jint name) {
     EGLDisplay dpy = getDisplay(_env, display);
     const char* chars = eglQueryString(dpy, name);
-    return _env->NewString((const jchar *)chars,
-                            (jsize)strlen((const char *)chars));
+    return _env->NewStringUTF(chars);
 }
 
 jboolean jni_eglSwapBuffers(JNIEnv *_env, jobject _this, jobject display, jobject surface) {
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index 1cd23b0..9b09c9b 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -35,6 +35,7 @@
 static jclass OOMEClass;
 static jclass UOEClass;
 static jclass IAEClass;
+static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -78,10 +79,13 @@
          _env->FindClass("java/lang/OutOfMemoryError");
     jclass UOEClassLocal =
          _env->FindClass("java/lang/UnsupportedOperationException");
+    jclass AIOOBEClassLocal =
+         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
 
     IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
     OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
     UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
+    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
 }
 
 static void *
@@ -526,12 +530,18 @@
     GLvoid *indices = (GLvoid *) 0;
 
     indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining);
+    if (_remaining < count) {
+        _env->ThrowNew(AIOOBEClass, "remaining() < count");
+        goto exit;
+    }
     glDrawElements(
         (GLenum)mode,
         (GLsizei)count,
         (GLenum)type,
         (GLvoid *)indices
     );
+
+exit:
     if (_array) {
         releasePointer(_env, _array, indices, JNI_FALSE);
     }
@@ -1647,20 +1657,8 @@
 jstring
 android_glGetString
   (JNIEnv *_env, jobject _this, jint name) {
-    const GLubyte * chars = glGetString((GLenum)name);
-
-    int len = strlen((const char *)chars);
-    jchar * wchars = (jchar *)malloc(len * sizeof(jchar));
-    if (wchars == (jchar*) 0) {
-        _env->ThrowNew(OOMEClass, "No space for glGetString output");
-        return (jstring) 0;
-    }
-    // Copy bytes -> chars, including trailing '\0'
-    for (int i = 0; i <= len; i++) {
-        wchars[i] = (jchar) chars[i];
-    }
-    jstring output = _env->NewString(wchars, (jsize) len);
-    free(wchars);
+    const char * chars = (const char *)glGetString((GLenum)name);
+    jstring output = _env->NewStringUTF(chars);
     return output;
 }
 /* void glHint ( GLenum target, GLenum mode ) */
diff --git a/core/jni/server/Android.mk b/core/jni/server/Android.mk
index d108330..bd08da3 100644
--- a/core/jni/server/Android.mk
+++ b/core/jni/server/Android.mk
@@ -21,11 +21,13 @@
 	libutils \
 	libui
 
+ifeq ($(TARGET_SIMULATOR),true)
 ifeq ($(TARGET_OS),linux)
 ifeq ($(TARGET_ARCH),x86)
 LOCAL_LDLIBS += -lpthread -ldl -lrt
 endif
 endif
+endif
 
 ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
 	LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
diff --git a/core/jni/server/com_android_server_AlarmManagerService.cpp b/core/jni/server/com_android_server_AlarmManagerService.cpp
index a81a0ff4..0f37921 100644
--- a/core/jni/server/com_android_server_AlarmManagerService.cpp
+++ b/core/jni/server/com_android_server_AlarmManagerService.cpp
@@ -44,6 +44,23 @@
 
 namespace android {
 
+static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest)
+{
+#if HAVE_ANDROID_OS
+    struct timezone tz;
+
+    tz.tz_minuteswest = minswest;
+    tz.tz_dsttime = 0;
+
+    int result = ioctl(fd, ANDROID_ALARM_SET_TIMEZONE, &tz);
+    if (result < 0) {
+        LOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
+        return -1;
+    }
+    return 0;
+#endif
+}
+
 static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj)
 {
 #if HAVE_ANDROID_OS
@@ -101,6 +118,7 @@
 	{"close", "(I)V", (void*)android_server_AlarmManagerService_close},
 	{"set", "(IIJ)V", (void*)android_server_AlarmManagerService_set},
     {"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm},
+    {"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
 };
 
 int register_android_server_AlarmManagerService(JNIEnv* env)
diff --git a/core/jni/server/com_android_server_SensorService.cpp b/core/jni/server/com_android_server_SensorService.cpp
index 37f6231..695a8a3 100644
--- a/core/jni/server/com_android_server_SensorService.cpp
+++ b/core/jni/server/com_android_server_SensorService.cpp
@@ -23,7 +23,6 @@
 
 namespace android {
 
-
 static struct file_descriptor_offsets_t
 {
     jclass mClass;
@@ -41,16 +40,26 @@
  * The method below are not thread-safe and not intended to be 
  */
 
+static sensors_control_device_t* sSensorDevice = 0;
+
 static jint
 android_init(JNIEnv *env, jclass clazz)
 {
-    return sensors_control_init();
+    sensors_module_t* module;
+    if (hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {
+        if (sensors_control_open(&module->common, &sSensorDevice) == 0) {
+            const struct sensor_t* list;
+            int count = module->get_sensors_list(module, &list);
+            return count;
+        }
+    }
+    return 0;
 }
 
 static jobject
 android_open(JNIEnv *env, jclass clazz)
 {
-    int fd = sensors_control_open();
+    int fd = sSensorDevice->open_data_source(sSensorDevice);
     // new FileDescriptor()
     jobject filedescriptor = env->NewObject(
             gFileDescriptorOffsets.mClass, 
@@ -70,20 +79,29 @@
 static jboolean
 android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate)
 {
-    uint32_t active = sensors_control_activate(activate ? sensor : 0, sensor);
-    return (activate && !active) ? false : true;
+    int active = sSensorDevice->activate(sSensorDevice, sensor, activate);
+    return (active<0) ? false : true;
 }
 
 static jint
 android_set_delay(JNIEnv *env, jclass clazz, jint ms)
 {
-    return sensors_control_delay(ms);
+    return sSensorDevice->set_delay(sSensorDevice, ms);
 }
 
+static jint
+android_data_wake(JNIEnv *env, jclass clazz)
+{
+    int res = sSensorDevice->wake(sSensorDevice);
+    return res;
+}
+
+
 static JNINativeMethod gMethods[] = {
     {"_sensors_control_init",     "()I",   (void*) android_init },
     {"_sensors_control_open",     "()Landroid/os/ParcelFileDescriptor;",  (void*) android_open },
     {"_sensors_control_activate", "(IZ)Z", (void*) android_activate },
+    {"_sensors_control_wake",     "()I", (void*) android_data_wake },
     {"_sensors_control_set_delay","(I)I", (void*) android_set_delay },
 };
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 104ba88..2e04885 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -367,6 +367,12 @@
         android:label="@string/permlab_writeSettings"
         android:description="@string/permdesc_writeSettings" />
 
+    <!-- Allows an application to read or write the secure system settings. -->
+    <permission android:name="android.permission.WRITE_SECURE_SETTINGS"
+        android:protectionLevel="signatureOrSystem"
+        android:label="@string/permlab_writeSecureSettings"
+        android:description="@string/permdesc_writeSecureSettings" />
+
     <!-- Allows an application to modify the Google service map. -->
     <permission android:name="android.permission.WRITE_GSERVICES"
         android:protectionLevel="signature"
@@ -746,6 +752,13 @@
         android:description="@string/permdesc_readInputState"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by input method services, to ensure that only the
+         system can bind to them. -->
+    <permission android:name="android.permission.BIND_INPUT_METHOD"
+        android:label="@string/permlab_bindInputMethod"
+        android:description="@string/permdesc_bindInputMethod"
+        android:protectionLevel="signature" />
+
     <!-- Allows low-level access to setting the orientation (actually
          rotation) of the screen.  Not for use by normal applications. -->
     <permission android:name="android.permission.SET_ORIENTATION"
@@ -830,6 +843,20 @@
         android:description="@string/permdesc_broadcastPackageRemoved"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to broadcast an SMS receipt notification -->
+    <permission android:name="android.permission.BROADCAST_SMS"
+        android:permissionGroup="android.permission-group.MESSAGES"
+        android:label="@string/permlab_broadcastSmsReceived"
+        android:description="@string/permdesc_broadcastSmsReceived"
+        android:protectionLevel="signature" />
+
+    <!-- Allows an application to broadcast a WAP PUSH receipt notification -->
+    <permission android:name="android.permission.BROADCAST_WAP_PUSH"
+        android:permissionGroup="android.permission-group.MESSAGES"
+        android:label="@string/permlab_broadcastWapPush"
+        android:description="@string/permdesc_broadcastWapPush"
+        android:protectionLevel="signature" />
+
     <permission android:name="android.permission.MASTER_CLEAR"
         android:label="@string/permlab_masterClear"
         android:description="@string/permdesc_masterClear"
@@ -865,6 +892,7 @@
                  android:icon="@drawable/ic_launcher_android">
         <activity android:name="com.android.internal.app.ChooserActivity"
                 android:theme="@style/Theme.Dialog.Alert"
+                android:excludeFromRecents="true"
                 android:multiprocess="true">
             <intent-filter>
                 <action android:name="android.intent.action.CHOOSER" />
@@ -873,6 +901,7 @@
         </activity>
         <activity android:name="com.android.internal.app.RingtonePickerActivity"
                 android:theme="@style/Theme.Dialog.Alert"
+                android:excludeFromRecents="true"
                 android:multiprocess="true">
             <intent-filter>
                 <action android:name="android.intent.action.RINGTONE_PICKER" />
@@ -880,7 +909,8 @@
             </intent-filter>
         </activity>
         <activity android:name="com.android.internal.app.UsbStorageActivity"
-                android:theme="@style/Theme.Dialog.Alert">
+                android:theme="@style/Theme.Dialog.Alert"
+                android:excludeFromRecents="true">
         </activity>
         <provider android:name=".server.checkin.CheckinProvider"
                 android:authorities="android.server.checkin"
@@ -894,7 +924,7 @@
             android:name=".server.checkin.UpdateReceiver$DownloadCompletedBroadcastReceiver"
             android:exported="true" />
 
-        <receiver android:name=".server.checkin.SecretCodeReceiver">
+          <receiver android:name="com.google.android.server.checkin.SecretCodeReceiver">
             <intent-filter>
                 <action android:name="android.provider.Telephony.SECRET_CODE" />
                 <data android:scheme="android_secret_code"
diff --git a/core/res/assets/webkit/film.png b/core/res/assets/webkit/film.png
deleted file mode 100755
index f457f23..0000000
--- a/core/res/assets/webkit/film.png
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/webkit/play.png b/core/res/assets/webkit/play.png
new file mode 100644
index 0000000..26fe286
--- /dev/null
+++ b/core/res/assets/webkit/play.png
Binary files differ
diff --git a/core/res/assets/webkit/youtube.html b/core/res/assets/webkit/youtube.html
index 86e492a..5a40c1e 100644
--- a/core/res/assets/webkit/youtube.html
+++ b/core/res/assets/webkit/youtube.html
@@ -3,24 +3,57 @@
     <style type="text/css">
       body      { background-color: black; }
       a:hover   { text-decoration: none; }
-      a:link    { color: white; }
-      a:visited { color: white; }
+      a:link    { color: black; }
+      a:visited { color: black; }
+      #bg {
+        position: fixed;
+        margin: 0px;
+        border: 0px;
+        padding: 0px;
+        left: 0px;
+        top: 0px;
+        width: 100%;
+        height: 100%;
+        overflow: hidden;
+        z-index: 0;
+      }
+      #main {
+        position: absolute;
+        left: 0%;
+        top: 0%;
+        width: 100%;
+        height: 100%;
+        padding: 0%;
+        z-index: 10;
+      }
     </style>
   </head>
   <body>
-    <table height="100%" width="100%">
-      <tr>
-        <td align="center" valign="middle" height="100%">
-          <img src="film.png"/>
-          <br/>
-          <a id="url" href="" onClick="javascript:window.top.document.location='http://youtube.com/watch' +
-            document.location.search; return false" target="_top">Open YouTube player</a>
-        </td>
-      </tr>
-      <tr><td valign="bottom" align="right">
-          <img src="youtube.png" style="opacity:.7"/>
-        </td>
-      </tr>
-    </table>
+    <div id="bg">
+      <table height="100%" width="100%" border="0" cellpadding="0"
+        cellspacing="0">
+        <tr>
+          <td valign="middle">
+            <img src="http://img.youtube.com/vi/VIDEO_ID/0.jpg" width="100%"/>
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div id="main">
+      <table height="100%" width="100%">
+        <tr>
+          <td align="center" valign="middle" height="100%">
+            <a id="url" href="youtube:VIDEO_ID" target="_top">
+              <img src="play.png" style="border:0px"/>
+            </a>
+          </td>
+        </tr>
+        <tr>
+          <td valign="bottom" align="right">
+            <img src="youtube.png" style="opacity:.7"/>
+          </td>
+        </tr>
+      </table>
+    </div>
   </body>
 </html>
diff --git a/core/res/res/anim/dialog_enter.xml b/core/res/res/anim/dialog_enter.xml
new file mode 100644
index 0000000..fd08cd0
--- /dev/null
+++ b/core/res/res/anim/dialog_enter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/fade_in.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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator">
+    <scale android:fromXScale="0.5" android:toXScale="1.0"
+           android:fromYScale="0.5" android:toYScale="1.0"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="200" />
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+            android:duration="200" />
+</set>
diff --git a/core/res/res/anim/dialog_exit.xml b/core/res/res/anim/dialog_exit.xml
new file mode 100644
index 0000000..e1b7a77
--- /dev/null
+++ b/core/res/res/anim/dialog_exit.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/fade_out.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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/accelerate_interpolator">
+    <scale android:fromXScale="1.0" android:toXScale="0.5"
+           android:fromYScale="1.0" android:toYScale="0.5"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="200" />
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:duration="200"/>
+</set>
diff --git a/core/res/res/anim/input_method_enter.xml b/core/res/res/anim/input_method_enter.xml
new file mode 100644
index 0000000..5e8a084
--- /dev/null
+++ b/core/res/res/anim/input_method_enter.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/fade_in.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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator">
+    <!--
+    <scale android:fromXScale="2.0" android:toXScale="1.0"
+           android:fromYScale="2.0" android:toYScale="1.0"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="200" />
+    -->
+    <translate android:fromYDelta="100%" android:toYDelta="0" android:duration="200"/>
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+            android:duration="200" />
+</set>
diff --git a/core/res/res/anim/input_method_exit.xml b/core/res/res/anim/input_method_exit.xml
new file mode 100644
index 0000000..843cb18
--- /dev/null
+++ b/core/res/res/anim/input_method_exit.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/fade_out.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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/accelerate_interpolator">
+    <!--
+    <scale android:fromXScale="1.0" android:toXScale="2.0"
+           android:fromYScale="1.0" android:toYScale="2.0"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="200" />
+    -->
+    <translate android:fromYDelta="0" android:toYDelta="100%" android:duration="200"/>
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:duration="200"/>
+</set>
diff --git a/core/res/res/anim/search_bar_enter.xml b/core/res/res/anim/search_bar_enter.xml
new file mode 100644
index 0000000..ecb86c1
--- /dev/null
+++ b/core/res/res/anim/search_bar_enter.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_enter.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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
+	<translate android:fromYDelta="-25%" android:toYDelta="0" android:duration="75"/>
+	<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+</set>
diff --git a/core/res/res/anim/search_bar_exit.xml b/core/res/res/anim/search_bar_exit.xml
new file mode 100644
index 0000000..db7142e
--- /dev/null
+++ b/core/res/res/anim/search_bar_exit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator">
+	<translate android:fromYDelta="0" android:toYDelta="-50%" android:duration="50"/>
+	<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
+</set>
+
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index 7309656..48dc31a 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -20,5 +20,5 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator">
-	<translate android:fromXDelta="0%" android:toXDelta="50%" android:duration="200"/>
+	<translate android:fromXDelta="0%" android:toXDelta="33%" android:duration="200"/>
 </set>
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index ca8a7e6..e498c9d 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -20,5 +20,5 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator">
-	<translate android:fromXDelta="50%" android:toXDelta="0" android:duration="200"/>
+	<translate android:fromXDelta="33%" android:toXDelta="0" android:duration="200"/>
 </set>
diff --git a/core/res/res/drawable/btn_check_buttonless_off.png b/core/res/res/drawable/btn_check_buttonless_off.png
new file mode 100755
index 0000000..f8972fc
--- /dev/null
+++ b/core/res/res/drawable/btn_check_buttonless_off.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_buttonless_on.png b/core/res/res/drawable/btn_check_buttonless_on.png
new file mode 100755
index 0000000..a10a37a
--- /dev/null
+++ b/core/res/res/drawable/btn_check_buttonless_on.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off.png b/core/res/res/drawable/btn_check_off.png
index 47924a3..56d3861 100644
--- a/core/res/res/drawable/btn_check_off.png
+++ b/core/res/res/drawable/btn_check_off.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_disable.png b/core/res/res/drawable/btn_check_off_disable.png
index f131eea..6c065bd 100644
--- a/core/res/res/drawable/btn_check_off_disable.png
+++ b/core/res/res/drawable/btn_check_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_disable_focused.png b/core/res/res/drawable/btn_check_off_disable_focused.png
index 00ec08e..cf23690 100644
--- a/core/res/res/drawable/btn_check_off_disable_focused.png
+++ b/core/res/res/drawable/btn_check_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_longpress.png b/core/res/res/drawable/btn_check_off_longpress.png
index 2117113..c81e119 100644
--- a/core/res/res/drawable/btn_check_off_longpress.png
+++ b/core/res/res/drawable/btn_check_off_longpress.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_pressed.png b/core/res/res/drawable/btn_check_off_pressed.png
index 24793cd..47c1a46 100644
--- a/core/res/res/drawable/btn_check_off_pressed.png
+++ b/core/res/res/drawable/btn_check_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_selected.png b/core/res/res/drawable/btn_check_off_selected.png
index c2aa44da..cf53075 100644
--- a/core/res/res/drawable/btn_check_off_selected.png
+++ b/core/res/res/drawable/btn_check_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on.png b/core/res/res/drawable/btn_check_on.png
index 29764ec..791ac1d 100644
--- a/core/res/res/drawable/btn_check_on.png
+++ b/core/res/res/drawable/btn_check_on.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_disable.png b/core/res/res/drawable/btn_check_on_disable.png
index 9ff0072..8e9f633 100644
--- a/core/res/res/drawable/btn_check_on_disable.png
+++ b/core/res/res/drawable/btn_check_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_disable_focused.png b/core/res/res/drawable/btn_check_on_disable_focused.png
index 2b31a0e..0abb051 100644
--- a/core/res/res/drawable/btn_check_on_disable_focused.png
+++ b/core/res/res/drawable/btn_check_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_longpress.png b/core/res/res/drawable/btn_check_on_longpress.png
index 6337033..367760b 100644
--- a/core/res/res/drawable/btn_check_on_longpress.png
+++ b/core/res/res/drawable/btn_check_on_longpress.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_pressed.png b/core/res/res/drawable/btn_check_on_pressed.png
index 9c1f0eb..ee2175d 100644
--- a/core/res/res/drawable/btn_check_on_pressed.png
+++ b/core/res/res/drawable/btn_check_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_selected.png b/core/res/res/drawable/btn_check_on_selected.png
index 21745aa..9356456 100644
--- a/core/res/res/drawable/btn_check_on_selected.png
+++ b/core/res/res/drawable/btn_check_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_close.xml b/core/res/res/drawable/btn_close.xml
new file mode 100644
index 0000000..9d90e4b
--- /dev/null
+++ b/core/res/res/drawable/btn_close.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:state_pressed="false"
+        android:drawable="@android:drawable/btn_close_normal" />
+
+    <item android:state_pressed="true"
+        android:drawable="@android:drawable/btn_close_pressed" />
+
+</selector>
diff --git a/core/res/res/drawable/btn_close_normal.png b/core/res/res/drawable/btn_close_normal.png
new file mode 100644
index 0000000..ecc4dde
--- /dev/null
+++ b/core/res/res/drawable/btn_close_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_close_pressed.png b/core/res/res/drawable/btn_close_pressed.png
new file mode 100644
index 0000000..49223c5
--- /dev/null
+++ b/core/res/res/drawable/btn_close_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_longpress.9.png b/core/res/res/drawable/btn_default_longpress.9.png
index ba1a880..d42ae0b 100644
--- a/core/res/res/drawable/btn_default_longpress.9.png
+++ b/core/res/res/drawable/btn_default_longpress.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_normal.9.png b/core/res/res/drawable/btn_default_normal.9.png
index 6644ad0..ad1634a 100644
--- a/core/res/res/drawable/btn_default_normal.9.png
+++ b/core/res/res/drawable/btn_default_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_normal_disable.9.png b/core/res/res/drawable/btn_default_normal_disable.9.png
index 27d98a9..a89f37d 100644
--- a/core/res/res/drawable/btn_default_normal_disable.9.png
+++ b/core/res/res/drawable/btn_default_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_normal_disable_focused.9.png b/core/res/res/drawable/btn_default_normal_disable_focused.9.png
index b36b2d3..b71dae9 100644
--- a/core/res/res/drawable/btn_default_normal_disable_focused.9.png
+++ b/core/res/res/drawable/btn_default_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_pressed.9.png b/core/res/res/drawable/btn_default_pressed.9.png
index 0fca4d9..f496a86 100644
--- a/core/res/res/drawable/btn_default_pressed.9.png
+++ b/core/res/res/drawable/btn_default_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_selected.9.png b/core/res/res/drawable/btn_default_selected.9.png
index a3f756e..c9e7e64 100644
--- a/core/res/res/drawable/btn_default_selected.9.png
+++ b/core/res/res/drawable/btn_default_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_longpress.9.png b/core/res/res/drawable/btn_default_small_longpress.9.png
index 15df06f..63c28c0 100644
--- a/core/res/res/drawable/btn_default_small_longpress.9.png
+++ b/core/res/res/drawable/btn_default_small_longpress.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_normal.9.png b/core/res/res/drawable/btn_default_small_normal.9.png
index 6726b04..faac205 100644
--- a/core/res/res/drawable/btn_default_small_normal.9.png
+++ b/core/res/res/drawable/btn_default_small_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_normal_disable.9.png b/core/res/res/drawable/btn_default_small_normal_disable.9.png
index 2ead262..ce4fd28 100644
--- a/core/res/res/drawable/btn_default_small_normal_disable.9.png
+++ b/core/res/res/drawable/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png b/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png
index d60370b..1f04c18 100644
--- a/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png
+++ b/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_pressed.9.png b/core/res/res/drawable/btn_default_small_pressed.9.png
index 04cdc64..dab005b 100644
--- a/core/res/res/drawable/btn_default_small_pressed.9.png
+++ b/core/res/res/drawable/btn_default_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_selected.9.png b/core/res/res/drawable/btn_default_small_selected.9.png
index 0a2b9e9..5dec504 100644
--- a/core/res/res/drawable/btn_default_small_selected.9.png
+++ b/core/res/res/drawable/btn_default_small_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dropdown_disabled.9.png b/core/res/res/drawable/btn_dropdown_disabled.9.png
index dc6e679..529511a 100644
--- a/core/res/res/drawable/btn_dropdown_disabled.9.png
+++ b/core/res/res/drawable/btn_dropdown_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dropdown_normal.9.png b/core/res/res/drawable/btn_dropdown_normal.9.png
index 16edcec..f6e9a19 100644
--- a/core/res/res/drawable/btn_dropdown_normal.9.png
+++ b/core/res/res/drawable/btn_dropdown_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dropdown_pressed.9.png b/core/res/res/drawable/btn_dropdown_pressed.9.png
index 405a5e2..3bdf52d 100644
--- a/core/res/res/drawable/btn_dropdown_pressed.9.png
+++ b/core/res/res/drawable/btn_dropdown_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dropdown_selected.9.png b/core/res/res/drawable/btn_dropdown_selected.9.png
index 467ce8b..087956e 100644
--- a/core/res/res/drawable/btn_dropdown_selected.9.png
+++ b/core/res/res/drawable/btn_dropdown_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key.xml b/core/res/res/drawable/btn_keyboard_key.xml
new file mode 100644
index 0000000..45578e5
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- Toggle keys. Use checkable/checked state. -->
+    
+    <item android:state_checkable="true" android:state_checked="true" 
+          android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_pressed_on" />
+    <item android:state_checkable="true" android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_pressed_off" />
+    <item android:state_checkable="true" android:state_checked="true"
+          android:drawable="@drawable/btn_keyboard_key_normal_on" />
+    <item android:state_checkable="true"
+          android:drawable="@drawable/btn_keyboard_key_normal_off" />
+
+    <!-- Normal keys -->
+
+    <item android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_pressed" />
+    <item
+          android:drawable="@drawable/btn_keyboard_key_normal" />
+          
+</selector>
diff --git a/core/res/res/drawable/btn_keyboard_key_longpress.9.png b/core/res/res/drawable/btn_keyboard_key_longpress.9.png
new file mode 100644
index 0000000..a62a60d
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_longpress.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_longpress_off.9.png b/core/res/res/drawable/btn_keyboard_key_longpress_off.9.png
new file mode 100644
index 0000000..f03f29c
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_longpress_off.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_longpress_on.9.png b/core/res/res/drawable/btn_keyboard_key_longpress_on.9.png
new file mode 100644
index 0000000..90e572a
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_longpress_on.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_normal.9.png b/core/res/res/drawable/btn_keyboard_key_normal.9.png
new file mode 100644
index 0000000..5c8a945
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_normal_off.9.png b/core/res/res/drawable/btn_keyboard_key_normal_off.9.png
new file mode 100644
index 0000000..e6e640a
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_normal_off.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_normal_on.9.png b/core/res/res/drawable/btn_keyboard_key_normal_on.9.png
new file mode 100644
index 0000000..ce97a44
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_normal_on.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_pressed.9.png b/core/res/res/drawable/btn_keyboard_key_pressed.9.png
new file mode 100755
index 0000000..f2e9f04
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png b/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png
new file mode 100644
index 0000000..d541f95
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png b/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png
new file mode 100644
index 0000000..1cd6d45
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off.png b/core/res/res/drawable/btn_radio_off.png
index de865b6..407632b 100644
--- a/core/res/res/drawable/btn_radio_off.png
+++ b/core/res/res/drawable/btn_radio_off.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off_disable.png b/core/res/res/drawable/btn_radio_off_disable.png
index 7fa1609..166a9f3 100755
--- a/core/res/res/drawable/btn_radio_off_disable.png
+++ b/core/res/res/drawable/btn_radio_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off_disable_focused.png b/core/res/res/drawable/btn_radio_off_disable_focused.png
index 10eb731..cdec0c3 100755
--- a/core/res/res/drawable/btn_radio_off_disable_focused.png
+++ b/core/res/res/drawable/btn_radio_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off_longpress.png b/core/res/res/drawable/btn_radio_off_longpress.png
index 2ca7dda..8938ae4 100644
--- a/core/res/res/drawable/btn_radio_off_longpress.png
+++ b/core/res/res/drawable/btn_radio_off_longpress.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off_pressed.png b/core/res/res/drawable/btn_radio_off_pressed.png
index 3c92a24..41120ae 100644
--- a/core/res/res/drawable/btn_radio_off_pressed.png
+++ b/core/res/res/drawable/btn_radio_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off_selected.png b/core/res/res/drawable/btn_radio_off_selected.png
index 4c7f4f2..8b5535d 100644
--- a/core/res/res/drawable/btn_radio_off_selected.png
+++ b/core/res/res/drawable/btn_radio_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on.png b/core/res/res/drawable/btn_radio_on.png
index 01be1e3..7286b31 100644
--- a/core/res/res/drawable/btn_radio_on.png
+++ b/core/res/res/drawable/btn_radio_on.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on_disable.png b/core/res/res/drawable/btn_radio_on_disable.png
index f442674..26c75f8 100755
--- a/core/res/res/drawable/btn_radio_on_disable.png
+++ b/core/res/res/drawable/btn_radio_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on_disable_focused.png b/core/res/res/drawable/btn_radio_on_disable_focused.png
index b372b31..12b9b91 100755
--- a/core/res/res/drawable/btn_radio_on_disable_focused.png
+++ b/core/res/res/drawable/btn_radio_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on_longpress.png b/core/res/res/drawable/btn_radio_on_longpress.png
index e6d9f73..8588977 100644
--- a/core/res/res/drawable/btn_radio_on_longpress.png
+++ b/core/res/res/drawable/btn_radio_on_longpress.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on_pressed.png b/core/res/res/drawable/btn_radio_on_pressed.png
index 03779e4..20ce0ec 100644
--- a/core/res/res/drawable/btn_radio_on_pressed.png
+++ b/core/res/res/drawable/btn_radio_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on_selected.png b/core/res/res/drawable/btn_radio_on_selected.png
index ed866bd..ed53dc7 100644
--- a/core/res/res/drawable/btn_radio_on_selected.png
+++ b/core/res/res/drawable/btn_radio_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_buttonless_off.png b/core/res/res/drawable/btn_star_big_buttonless_off.png
new file mode 100755
index 0000000..5b9cd81
--- /dev/null
+++ b/core/res/res/drawable/btn_star_big_buttonless_off.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_buttonless_on.png b/core/res/res/drawable/btn_star_big_buttonless_on.png
new file mode 100755
index 0000000..5957c65
--- /dev/null
+++ b/core/res/res/drawable/btn_star_big_buttonless_on.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_buttonless.xml b/core/res/res/drawable/btn_star_buttonless.xml
new file mode 100644
index 0000000..8d60ed2
--- /dev/null
+++ b/core/res/res/drawable/btn_star_buttonless.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_checked="false" android:state_window_focused="false" 
+          android:drawable="@drawable/btn_star_big_buttonless_off" />
+    <item android:state_checked="true" android:state_window_focused="false" 
+          android:drawable="@drawable/btn_star_big_buttonless_on" />
+<!-- 
+    <item android:state_checked="true" android:state_window_focused="false" 
+          android:state_enabled="false" android:drawable="@drawable/btn_star_big_on_disable" />
+    <item android:state_checked="false" android:state_window_focused="false" 
+          android:state_enabled="false" android:drawable="@drawable/btn_star_big_off_disable" />
+          
+    <item android:state_checked="true" android:state_pressed="true"
+          android:drawable="@drawable/btn_star_big_on_pressed" />
+    <item android:state_checked="false" android:state_pressed="true"
+          android:drawable="@drawable/btn_star_big_off_pressed" />
+
+    <item android:state_checked="true" android:state_focused="true"
+          android:drawable="@drawable/btn_star_big_on_selected" />
+    <item android:state_checked="false" android:state_focused="true"
+          android:drawable="@drawable/btn_star_big_off_selected" />
+
+    <item android:state_checked="true" android:state_focused="true" android:state_enabled="false"
+          android:drawable="@drawable/btn_star_big_on_disable_focused" />
+    <item android:state_checked="true" android:state_focused="false" android:state_enabled="false"
+          android:drawable="@drawable/btn_star_big_on_disable" />
+          
+    <item android:state_checked="false" android:state_focused="true" android:state_enabled="false"
+          android:drawable="@drawable/btn_star_big_off_disable_focused" />
+    <item android:state_checked="false" android:state_focused="false" android:state_enabled="false"
+          android:drawable="@drawable/btn_star_big_off_disable" />
+-->
+          
+    <item android:state_checked="false" android:drawable="@drawable/btn_star_big_buttonless_off" />
+    <item android:state_checked="true" android:drawable="@drawable/btn_star_big_buttonless_on" />
+</selector>
diff --git a/core/res/res/drawable/ic_btn_search.png b/core/res/res/drawable/ic_btn_search.png
new file mode 100644
index 0000000..3f8913e
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_search.png
Binary files differ
diff --git a/core/res/res/drawable/ic_volume_bluetooth_ad2p.png b/core/res/res/drawable/ic_volume_bluetooth_ad2p.png
new file mode 100644
index 0000000..cf86ab3
--- /dev/null
+++ b/core/res/res/drawable/ic_volume_bluetooth_ad2p.png
Binary files differ
diff --git a/core/res/res/drawable/ic_volume_bluetooth_in_call.png b/core/res/res/drawable/ic_volume_bluetooth_in_call.png
new file mode 100644
index 0000000..94801fc
--- /dev/null
+++ b/core/res/res/drawable/ic_volume_bluetooth_in_call.png
Binary files differ
diff --git a/core/res/res/drawable/ime_qwerty.png b/core/res/res/drawable/ime_qwerty.png
new file mode 100644
index 0000000..e6e5cda
--- /dev/null
+++ b/core/res/res/drawable/ime_qwerty.png
Binary files differ
diff --git a/core/res/res/drawable/indicator_check_mark_dark.xml b/core/res/res/drawable/indicator_check_mark_dark.xml
index 9713cc4..f363a2d 100644
--- a/core/res/res/drawable/indicator_check_mark_dark.xml
+++ b/core/res/res/drawable/indicator_check_mark_dark.xml
@@ -17,12 +17,12 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
     <item android:state_checked="true"
-        android:drawable="@drawable/ic_check_mark_dark" />
+        android:drawable="@drawable/btn_check_buttonless_on" />
 
     <item android:state_checked="false"
-        android:drawable="@color/transparent" />
+        android:drawable="@drawable/btn_check_buttonless_off" />
         
-     <item
-        android:drawable="@drawable/ic_check_mark_dark" />
-        
+    <item
+        android:drawable="@drawable/btn_check_buttonless_off" />
+
 </selector>
diff --git a/core/res/res/drawable/indicator_check_mark_light.xml b/core/res/res/drawable/indicator_check_mark_light.xml
index e0129e9..3c8bb6c 100644
--- a/core/res/res/drawable/indicator_check_mark_light.xml
+++ b/core/res/res/drawable/indicator_check_mark_light.xml
@@ -17,12 +17,12 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
     <item android:state_checked="true"
-        android:drawable="@drawable/ic_check_mark_light" />
+        android:drawable="@drawable/btn_check_buttonless_on" />
 
     <item android:state_checked="false"
-        android:drawable="@color/transparent" />
-        
-     <item
-        android:drawable="@drawable/ic_check_mark_light" />
-        
+        android:drawable="@drawable/btn_check_buttonless_off" />
+
+    <item
+        android:drawable="@drawable/btn_check_buttonless_off" />
+
 </selector>
diff --git a/core/res/res/drawable/keyboard_background.9.png b/core/res/res/drawable/keyboard_background.9.png
new file mode 100644
index 0000000..595acc5
--- /dev/null
+++ b/core/res/res/drawable/keyboard_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_key_feedback.xml b/core/res/res/drawable/keyboard_key_feedback.xml
new file mode 100644
index 0000000..e55854d
--- /dev/null
+++ b/core/res/res/drawable/keyboard_key_feedback.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_long_pressable="true"
+            android:drawable="@android:drawable/keyboard_key_feedback_more_background" />
+
+    <item android:drawable="@android:drawable/keyboard_key_feedback_background" />
+</selector>
diff --git a/core/res/res/drawable/keyboard_key_feedback_background.9.png b/core/res/res/drawable/keyboard_key_feedback_background.9.png
new file mode 100644
index 0000000..2a80f09
--- /dev/null
+++ b/core/res/res/drawable/keyboard_key_feedback_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_key_feedback_more_background.9.png b/core/res/res/drawable/keyboard_key_feedback_more_background.9.png
new file mode 100755
index 0000000..29aa285
--- /dev/null
+++ b/core/res/res/drawable/keyboard_key_feedback_more_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_popup_panel_background.9.png b/core/res/res/drawable/keyboard_popup_panel_background.9.png
new file mode 100644
index 0000000..36d75df
--- /dev/null
+++ b/core/res/res/drawable/keyboard_popup_panel_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_dropdown_background_down.9.png b/core/res/res/drawable/spinner_dropdown_background_down.9.png
index 0a5e4c8..8fd22f4 100644
--- a/core/res/res/drawable/spinner_dropdown_background_down.9.png
+++ b/core/res/res/drawable/spinner_dropdown_background_down.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_dropdown_background_up.9.png b/core/res/res/drawable/spinner_dropdown_background_up.9.png
index 240a982..1354feb 100644
--- a/core/res/res/drawable/spinner_dropdown_background_up.9.png
+++ b/core/res/res/drawable/spinner_dropdown_background_up.9.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_calibrate_compass.png b/core/res/res/drawable/stat_notify_calibrate_compass.png
deleted file mode 100755
index 28bd386..0000000
--- a/core/res/res/drawable/stat_notify_calibrate_compass.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/layout-land/icon_menu_layout.xml b/core/res/res/layout-land/icon_menu_layout.xml
index 761f767..d1b25d91 100644
--- a/core/res/res/layout-land/icon_menu_layout.xml
+++ b/core/res/res/layout-land/icon_menu_layout.xml
@@ -19,5 +19,6 @@
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:rowHeight="65dip"
-    android:maxRows="1"
+    android:maxItems="6"
+    android:maxRows="2"
     android:maxItemsPerRow="6" />
diff --git a/core/res/res/layout-port/icon_menu_layout.xml b/core/res/res/layout-port/icon_menu_layout.xml
index 05ffe106..08edfcc 100644
--- a/core/res/res/layout-port/icon_menu_layout.xml
+++ b/core/res/res/layout-port/icon_menu_layout.xml
@@ -19,5 +19,6 @@
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:rowHeight="65dip"
-    android:maxRows="2"
+    android:maxItems="6"
+    android:maxRows="3"
     android:maxItemsPerRow="3" />
diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml
index e3de682..cf2de05 100644
--- a/core/res/res/layout/alert_dialog.xml
+++ b/core/res/res/layout/alert_dialog.xml
@@ -50,8 +50,10 @@
                 android:paddingTop="6dip"
                 android:paddingRight="10dip"
                 android:src="@drawable/ic_dialog_info" />
-            <TextView android:id="@+id/alertTitle" 
-                style="?android:attr/textAppearanceMedium"
+            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle" 
+                style="?android:attr/textAppearanceLarge"
+                android:singleLine="true"
+                android:ellipsize="end"
                 android:layout_width="fill_parent" 
                 android:layout_height="wrap_content" />
         </LinearLayout>
diff --git a/core/res/res/layout/always_use_checkbox.xml b/core/res/res/layout/always_use_checkbox.xml
index 90c9a44..20fc403 100644
--- a/core/res/res/layout/always_use_checkbox.xml
+++ b/core/res/res/layout/always_use_checkbox.xml
@@ -19,7 +19,9 @@
 <RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    android:paddingLeft="14dip"
+    android:paddingRight="15dip">
     
     <CheckBox
         android:id="@+id/alwaysUse"
@@ -30,22 +32,12 @@
         android:clickable="true" />
     
     <TextView 
-        android:id="@+id/useDefaultText"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:paddingLeft="6dip"
-        android:layout_toRightOf="@id/alwaysUse"
-        android:text="@string/alwaysUse" />
-
-    <TextView 
         android:id="@+id/clearDefaultHint"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textAppearance="?android:attr/textAppearanceSmall"
-        android:paddingLeft="6dip"
+        android:paddingLeft="36dip"
         android:visibility="gone"
-        android:layout_below="@id/useDefaultText"
-        android:layout_toRightOf="@id/alwaysUse"
+        android:layout_below="@id/alwaysUse"
         android:text="@string/clearDefaultHintMsg" />
 </RelativeLayout>
diff --git a/core/res/res/layout/icon_menu_item_layout.xml b/core/res/res/layout/icon_menu_item_layout.xml
index 06f6098..c6d9496 100644
--- a/core/res/res/layout/icon_menu_item_layout.xml
+++ b/core/res/res/layout/icon_menu_item_layout.xml
@@ -19,6 +19,8 @@
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:paddingBottom="1dip"
-    android:gravity="bottom|center_horizontal"
+    android:paddingLeft="3dip"
+    android:paddingRight="3dip"
     android:singleLine="true"
-    android:ellipsize="end" />
+    android:ellipsize="marquee"
+    android:fadingEdge="horizontal" />
diff --git a/core/res/res/layout/input_method.xml b/core/res/res/layout/input_method.xml
new file mode 100644
index 0000000..ec75cf1
--- /dev/null
+++ b/core/res/res/layout/input_method.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/alert_dialog.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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    >
+
+    <FrameLayout android:id="@android:id/extractArea"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:visibility="gone">
+    </FrameLayout>
+    
+    <FrameLayout android:id="@android:id/candidatesArea"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:visibility="invisible">
+    </FrameLayout>
+    
+    <FrameLayout android:id="@android:id/inputArea"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:visibility="gone">
+    </FrameLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/input_method_extract_view.xml b/core/res/res/layout/input_method_extract_view.xml
new file mode 100644
index 0000000..f8a4bde
--- /dev/null
+++ b/core/res/res/layout/input_method_extract_view.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/alert_dialog.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.
+*/
+-->
+
+<android.inputmethodservice.ExtractEditText
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/inputExtractEditText"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:inputType="text"
+    >
+</android.inputmethodservice.ExtractEditText>
diff --git a/core/res/res/layout/keyboard_key_preview.xml b/core/res/res/layout/keyboard_key_preview.xml
new file mode 100644
index 0000000..a6e096b
--- /dev/null
+++ b/core/res/res/layout/keyboard_key_preview.xml
@@ -0,0 +1,29 @@
+<?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.
+*/
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content" 
+    android:layout_height="80sp"
+    android:textSize="40sp"
+    android:textColor="?android:attr/textColorPrimaryInverse"
+    android:minWidth="32dip"
+    android:gravity="center"
+    android:background="@drawable/keyboard_key_feedback"
+    />
diff --git a/core/res/res/layout/keyboard_popup_keyboard.xml b/core/res/res/layout/keyboard_popup_keyboard.xml
new file mode 100644
index 0000000..0cdd9da
--- /dev/null
+++ b/core/res/res/layout/keyboard_popup_keyboard.xml
@@ -0,0 +1,47 @@
+<?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.
+*/
+-->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:background="@android:drawable/keyboard_popup_panel_background"
+        >
+        
+    <android.inputmethodservice.KeyboardView
+            android:id="@android:id/keyboardView"
+            android:background="@android:color/transparent"
+            android:layout_alignParentBottom="true"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:keyPreviewLayout="@layout/keyboard_key_preview"
+            android:popupLayout="@layout/keyboard_popup_keyboard"
+            android:keyTextSize="22sp"
+            />
+    <ImageButton android:id="@android:id/button_close"
+        android:background="@android:color/transparent"
+        android:src="@drawable/btn_close" 
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginLeft="8dp"
+        android:clickable="true"
+        />
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index f890643..175a3a5 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -100,6 +100,7 @@
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
                     android:textSize="14sp"
+                    android:visibility="invisible"
                     />
                 <Button android:id="@+id/emergencyCallTogether"
                     android:layout_width="fill_parent"
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index c888411..b591b10 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -110,6 +110,7 @@
                 android:layout_height="fill_parent"
                 android:layout_weight="1.0"
                 android:textSize="14sp"
+                android:visibility="invisible"
                 />
         </LinearLayout>
 
diff --git a/core/res/res/layout/list_menu_item_layout.xml b/core/res/res/layout/list_menu_item_layout.xml
index 3af1261..20c46a7 100644
--- a/core/res/res/layout/list_menu_item_layout.xml
+++ b/core/res/res/layout/list_menu_item_layout.xml
@@ -38,7 +38,9 @@
             android:layout_alignParentLeft="true"
             android:textAppearance="?android:attr/textAppearanceLargeInverse"
             android:singleLine="true"
-            android:duplicateParentState="true" />
+            android:duplicateParentState="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
 
         <TextView
             android:id="@+id/shortcut"
diff --git a/core/res/res/layout/preference.xml b/core/res/res/layout/preference.xml
index 3f589a4..ac6dd76 100644
--- a/core/res/res/layout/preference.xml
+++ b/core/res/res/layout/preference.xml
@@ -21,7 +21,8 @@
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:minHeight="?android:attr/listPreferredItemHeight"
-    android:gravity="center_vertical">
+    android:gravity="center_vertical"
+    android:paddingRight="?android:attr/scrollbarSize">
     
     <RelativeLayout
         android:layout_width="wrap_content"
@@ -36,7 +37,9 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceLarge" />
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
             
         <TextView android:id="@+android:id/summary"
             android:layout_width="wrap_content"
diff --git a/core/res/res/layout/preference_child.xml b/core/res/res/layout/preference_child.xml
index 26a1046..1d626b9 100644
--- a/core/res/res/layout/preference_child.xml
+++ b/core/res/res/layout/preference_child.xml
@@ -18,7 +18,8 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     android:layout_width="fill_parent"
     android:layout_height="?android:attr/listPreferredItemHeight"
-    android:gravity="center_vertical">
+    android:gravity="center_vertical"
+    android:paddingRight="?android:attr/scrollbarSize">
     
     <RelativeLayout
         android:layout_width="wrap_content"
@@ -46,6 +47,7 @@
     <!-- Preference should place its actual preference widget here. -->
     <LinearLayout android:id="@+android:id/widget_frame"
         android:layout_width="wrap_content"
-        android:layout_height="fill_parent" />
+        android:layout_height="fill_parent"
+         />
 
 </LinearLayout>
diff --git a/core/res/res/layout/preference_information.xml b/core/res/res/layout/preference_information.xml
index 0481857..8f05a8e 100644
--- a/core/res/res/layout/preference_information.xml
+++ b/core/res/res/layout/preference_information.xml
@@ -21,7 +21,8 @@
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:minHeight="?android:attr/listPreferredItemHeight"
-    android:gravity="center_vertical">
+    android:gravity="center_vertical"
+    android:paddingRight="?android:attr/scrollbarSize">
     
     <RelativeLayout
         android:layout_width="wrap_content"
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index eda1c73..da35e97 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -17,25 +17,37 @@
 ** limitations under the License.
 */
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical"
+    android:minHeight="?android:attr/listPreferredItemHeight"
     android:paddingLeft="14dip"
     android:paddingRight="15dip">
 
+
+    <!-- Activity icon when presenting dialog -->
     <ImageView android:id="@+id/icon"
         android:layout_width="@android:dimen/app_icon_size"
         android:layout_height="@android:dimen/app_icon_size"
-        android:layout_gravity="center_vertical"
+        android:layout_alignParentLeft="true"
         android:scaleType="fitCenter" />
 
+    <!-- Activity name -->
     <TextView android:id="@android:id/text1"
-        android:layout_width="fill_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:minHeight="?android:attr/listPreferredItemHeight"
         android:textAppearance="?android:attr/textAppearanceLargeInverse"
-        android:gravity="center_vertical"
-        android:paddingLeft="14dip" />
-</LinearLayout>
+        android:layout_toRightOf="@id/icon"
+        android:paddingLeft="6dip" />
+
+    <!-- Extended activity info to distinguish between duplicate activity names -->
+    <TextView android:id="@android:id/text2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMediumInverse"
+        android:layout_toRightOf="@id/icon"
+        android:layout_below="@id/text1"
+        android:paddingLeft="6dip" />
+</RelativeLayout>
 
diff --git a/core/res/res/layout/search_bar.xml b/core/res/res/layout/search_bar.xml
index f8c96cc..ac3777c9 100644
--- a/core/res/res/layout/search_bar.xml
+++ b/core/res/res/layout/search_bar.xml
@@ -76,14 +76,15 @@
                 android:layout_weight="1.0"
                 android:paddingLeft="8dip"
                 android:paddingRight="6dip"
-                android:singleLine="true" />
+                android:inputType="text|textAutoComplete" />
                 
-            <Button
-                android:id="@+id/search_go_btn"
-                android:text="@string/search_go"
+            <ImageButton android:id="@+id/search_go_btn"
+                android:layout_marginLeft="1dip"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_marginLeft="6dip" />
+                android:src="@android:drawable/ic_btn_search"
+            />
+
         </LinearLayout>
         
     </LinearLayout>
diff --git a/core/res/res/layout/select_dialog_item.xml b/core/res/res/layout/select_dialog_item.xml
index 3b607ca..0983b66 100644
--- a/core/res/res/layout/select_dialog_item.xml
+++ b/core/res/res/layout/select_dialog_item.xml
@@ -32,4 +32,5 @@
     android:gravity="center_vertical"
     android:paddingLeft="14dip"
     android:paddingRight="15dip"
+    android:ellipsize="marquee"
 />
diff --git a/core/res/res/layout/select_dialog_multichoice.xml b/core/res/res/layout/select_dialog_multichoice.xml
index eae4800..3bd1a48 100644
--- a/core/res/res/layout/select_dialog_multichoice.xml
+++ b/core/res/res/layout/select_dialog_multichoice.xml
@@ -24,5 +24,6 @@
     android:paddingLeft="12dip"
     android:paddingRight="7dip"
     android:checkMark="@android:drawable/btn_check"
+    android:ellipsize="marquee"
 />
 
diff --git a/core/res/res/layout/select_dialog_singlechoice.xml b/core/res/res/layout/select_dialog_singlechoice.xml
index 98f5dbd..ec97d7b 100644
--- a/core/res/res/layout/select_dialog_singlechoice.xml
+++ b/core/res/res/layout/select_dialog_singlechoice.xml
@@ -24,5 +24,5 @@
     android:paddingLeft="12dip"
     android:paddingRight="7dip"
     android:checkMark="@android:drawable/btn_radio"
+    android:ellipsize="marquee"
 />
-
diff --git a/core/res/res/layout/simple_dropdown_item_1line.xml b/core/res/res/layout/simple_dropdown_item_1line.xml
index 8994e8c..5745d15 100644
--- a/core/res/res/layout/simple_dropdown_item_1line.xml
+++ b/core/res/res/layout/simple_dropdown_item_1line.xml
@@ -23,4 +23,5 @@
     android:textAppearance="?android:attr/textAppearanceLargeInverse"
     android:singleLine="true"
     android:layout_width="fill_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight" />
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:ellipsize="marquee" />
diff --git a/core/res/res/layout/simple_spinner_dropdown_item.xml b/core/res/res/layout/simple_spinner_dropdown_item.xml
index 0881b9c..7006b09 100644
--- a/core/res/res/layout/simple_spinner_dropdown_item.xml
+++ b/core/res/res/layout/simple_spinner_dropdown_item.xml
@@ -22,4 +22,5 @@
     style="?android:attr/spinnerDropDownItemStyle"
     android:singleLine="true"
     android:layout_width="fill_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight" />
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:ellipsize="marquee" />
diff --git a/core/res/res/layout/simple_spinner_item.xml b/core/res/res/layout/simple_spinner_item.xml
index 1c51a48..4dd739fd5 100644
--- a/core/res/res/layout/simple_spinner_item.xml
+++ b/core/res/res/layout/simple_spinner_item.xml
@@ -18,8 +18,9 @@
 */
 -->
 <TextView xmlns:android="http://schemas.android.com/apk/res/android" 
- android:id="@android:id/text1"
+    android:id="@android:id/text1"
 	style="?android:attr/spinnerItemStyle"
-        android:singleLine="true"
+    android:singleLine="true"
     android:layout_width="fill_parent"
-    android:layout_height="wrap_content" />
+    android:layout_height="wrap_content"
+    android:ellipsize="marquee" />
diff --git a/core/res/res/layout/volume_adjust.xml b/core/res/res/layout/volume_adjust.xml
index 2d1bd5c..946ca7e 100644
--- a/core/res/res/layout/volume_adjust.xml
+++ b/core/res/res/layout/volume_adjust.xml
@@ -41,6 +41,12 @@
 
     </LinearLayout>
 
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/additional_message"
+        android:textAppearance="?android:attr/textAppearanceSmall" />
+
     <ImageView
         android:id="@+id/ringer_stream_icon"
         android:layout_width="wrap_content"
diff --git a/core/res/res/raw-de/loaderror.html b/core/res/res/raw-de/loaderror.html
new file mode 100644
index 0000000..bece2d7
--- /dev/null
+++ b/core/res/res/raw-de/loaderror.html
@@ -0,0 +1,18 @@
+<html>
+    <head>
+        <title>Webseite nicht verf&uuml;gbar</title>
+        <style type="text/css">
+            body { margin-top: 0px; padding-top: 0px; }
+            h2   { margin-top: 5px; padding-top: 0px; }
+        </style>
+
+        <body>
+
+            <img src="file:///android_asset/webkit/android-weberror.png" align="top" />
+            <h2>Webseite nicht verf&uuml;gbar</h2>
+            <p>Die Webseite unter <a href="%s">%s</a> konnte nicht geladen werden als:</p>
+            <!-- The %e is replaced by a localized error string -->
+            <p>%e</p>
+        </body>
+    </head>
+</html>
diff --git a/core/res/res/raw-de/nodomain.html b/core/res/res/raw-de/nodomain.html
new file mode 100644
index 0000000..9fd8094
--- /dev/null
+++ b/core/res/res/raw-de/nodomain.html
@@ -0,0 +1,24 @@
+<html>
+    <head>
+        <title>Webseite nicht verf&uuml;gbar</title>
+        <style type="text/css">
+            body { margin-top: 0px; padding-top: 0px; }
+            h2   { margin-top: 5px; padding-top: 0px; }
+        </style>
+
+        <body>
+
+            <img src="file:///android_asset/webkit/android-weberror.png" align="top" />
+            <h2>Webseite nicht verf&uuml;gbar</h2>
+            <p>Die Webseite unter <a href="%s">%s</a> ist m&ouml;glicherweise vor&uuml;bergehend deaktiviert oder dauerhaft an eine neue Webadresse verschoben worden.</p>
+
+            <p><b>Hier sind einige Vorschl&auml;ge:</b></p>
+            <ul>
+                <li>Stellen Sie sicher, dass Ihr Ger&auml;t ein Signal empf&auml;ngt und &uuml;ber eine Datenverbindung verf&uuml;gt.</li>
+                <li>Laden Sie die Webseite sp&auml;ter erneut.</li>
+                <li>Zeigen Sie eine im Cache gespeicherte Kopie der Webseite von Google an.</li>
+
+            </ul>
+        </body>
+    </head>
+</html>
diff --git a/core/res/assets/webkit/loaderror.html b/core/res/res/raw/loaderror.html
similarity index 100%
rename from core/res/assets/webkit/loaderror.html
rename to core/res/res/raw/loaderror.html
diff --git a/core/res/assets/webkit/nodomain.html b/core/res/res/raw/nodomain.html
similarity index 100%
rename from core/res/assets/webkit/nodomain.html
rename to core/res/res/raw/nodomain.html
diff --git a/core/res/res/values-cs-rCZ/strings.xml b/core/res/res/values-cs-rCZ/strings.xml
index a6d2c6b..e1eb3f4 100644
--- a/core/res/res/values-cs-rCZ/strings.xml
+++ b/core/res/res/values-cs-rCZ/strings.xml
@@ -1,274 +1,1112 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="day_labels">
-    <item>Ne</item>
-    <item>Po</item>
-    <item>Út</item>
-    <item>St</item>
-    <item>Čt</item>
-    <item>Pá</item>
-    <item>So</item>
-  </string-array>
+    <!-- no translation found for byteShort (2850097084724465606) -->
+    <skip />
+    <!-- no translation found for kilobyteShort (5865542430193761682) -->
+    <skip />
+    <!-- no translation found for megabyteShort (112984851085937882) -->
+    <skip />
+    <!-- no translation found for gigabyteShort (8586075069559273847) -->
+    <skip />
+    <!-- no translation found for terabyteShort (5828502357595687794) -->
+    <skip />
+    <!-- no translation found for petabyteShort (7523248732657962413) -->
+    <skip />
+    <string name="untitled">"&lt;bez názvu&gt;"</string>
+    <string name="ellipsis">"…"</string>
+    <string name="emptyPhoneNumber">"(žádné telefonní číslo)"</string>
+    <string name="unknownName">"(neznámý)"</string>
+    <string name="defaultVoiceMailAlphaTag">"Hlasová schránka"</string>
+    <string name="defaultMsisdnAlphaTag">"Msisdn1"</string>
+    <string name="mmiError">"Chyba sítě nebo neplatný kód MMI."</string>
+    <string name="serviceEnabled">"Služba povolena"</string>
+    <string name="serviceEnabledFor">"Služba povolena pro:"</string>
+    <string name="serviceDisabled">"Služba zakázána"</string>
+    <string name="serviceRegistered">"Registrace úspěšná"</string>
+    <string name="serviceErased">"Odstranění úspěšné"</string>
+    <string name="passwordIncorrect">"Nesprávné heslo."</string>
+    <string name="mmiComplete">"MMI dokončeno"</string>
+    <!-- no translation found for badPin (5103184589972647739) -->
+    <skip />
+    <!-- no translation found for badPuk (2200634943393540609) -->
+    <skip />
+    <!-- no translation found for mismatchPin (5055729703806180857) -->
+    <skip />
+    <!-- no translation found for invalidPin (6201854814319326475) -->
+    <skip />
+    <!-- no translation found for needPuk (4788728144863892764) -->
+    <skip />
+    <!-- no translation found for needPuk2 (7056908944942451033) -->
+    <skip />
+    <!-- no translation found for ClipMmi (5649729434121615509) -->
+    <skip />
+    <!-- no translation found for ClirMmi (5220979296096544477) -->
+    <skip />
+    <!-- no translation found for CfMmi (4998483717856803914) -->
+    <skip />
+    <!-- no translation found for CwMmi (5678103638951836350) -->
+    <skip />
+    <!-- no translation found for BaMmi (6030555200442855833) -->
+    <skip />
+    <!-- no translation found for PwdMmi (2549941247959366670) -->
+    <skip />
+    <!-- no translation found for PinMmi (2463353963837922189) -->
+    <skip />
+    <string name="CLIRDefaultOnNextCallOn">"Výchozí nastavení omezení ID - omezení. Další hovor: omezení"</string>
+    <string name="CLIRDefaultOnNextCallOff">"Výchozí nastavení omezení ID - omezení. Další hovor: bez omezení"</string>
+    <string name="CLIRDefaultOffNextCallOn">"Výchozí nastavení omezení ID - bez omezení. Další hovor: omezení"</string>
+    <string name="CLIRDefaultOffNextCallOff">"Výchozí nastavení omezení ID - bez omezení. Další hovor: bez omezení"</string>
+    <string name="serviceNotProvisioned">"Služba není poskytována."</string>
+    <string name="CLIRPermanent">"Omezení ID v trvalém režimu."</string>
+    <string name="serviceClassVoice">"Hlasový záznam"</string>
+    <string name="serviceClassData">"Data"</string>
+    <string name="serviceClassFAX">"FAX"</string>
+    <string name="serviceClassSMS">"SMS"</string>
+    <string name="serviceClassDataAsync">"Asynchronní"</string>
+    <string name="serviceClassDataSync">"Synchronizace"</string>
+    <string name="serviceClassPacket">"Pakety"</string>
+    <string name="serviceClassPAD">"PAD"</string>
+    <string name="cfTemplateNotForwarded">"{0}: Nepřesměrováno"</string>
+    <string name="cfTemplateForwarded">"{0}: {1}"</string>
+    <string name="cfTemplateForwardedTime">"{0}: {1} po {2} sekundách"</string>
+    <string name="cfTemplateRegistered">"{0}: Nepřesměrováno ({1})"</string>
+    <string name="cfTemplateRegisteredTime">"{0}: Nepřesměrováno ({1} po {2} sekundách)"</string>
+    <string name="httpErrorOk">"OK"</string>
+    <string name="httpError">"Neznámá chyba"</string>
+    <string name="httpErrorLookup">"Neznámý hostitel"</string>
+    <string name="httpErrorUnsupportedAuthScheme">"Nepodporované schéma ověření. Ověření se nezdařilo."</string>
+    <string name="httpErrorAuth">"Ověřování se nezdařilo"</string>
+    <string name="httpErrorProxyAuth">"Ověření serverem proxy se nezdařilo"</string>
+    <string name="httpErrorConnect">"Připojení k serveru se nezdařilo"</string>
+    <string name="httpErrorIO">"Čtení nebo zápis na server se nezdařil"</string>
+    <string name="httpErrorTimeout">"Časový limit připojení k serveru vypršel"</string>
+    <string name="httpErrorRedirectLoop">"Příliš mnoho přesměrování serverů"</string>
+    <string name="httpErrorUnsupportedScheme">"Nepodporovaný protokol"</string>
+    <string name="httpErrorFailedSslHandshake">"Navázání spojení typu SSL handshake se nezdařilo"</string>
+    <string name="httpErrorBadUrl">"Nepodařilo se analyzovat URL"</string>
+    <string name="httpErrorFile">"File error"</string>
+    <string name="httpErrorFileNotFound">"File not found"</string>
+    <!-- no translation found for httpErrorTooManyRequests (3764334538393544875) -->
+    <skip />
+    <string name="contentServiceSync">"Synchronizace"</string>
+    <string name="contentServiceSyncNotificationTitle">"Synchronizace"</string>
+    <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8477597194404210723) -->
+    <skip />
+    <!-- no translation found for low_memory (4191592786596642367) -->
+    <skip />
+    <!-- no translation found for me (4616693653158602117) -->
+    <skip />
+    <string name="power_dialog">"Možnosti napájení"</string>
+    <string name="silent_mode">"Tichý režim"</string>
+    <string name="turn_on_radio">"Zapnout rádio"</string>
+    <string name="turn_off_radio">"Vypnout rádio"</string>
+    <!-- no translation found for screen_lock (1560333453597081877) -->
+    <skip />
+    <string name="power_off">"Vypnuto"</string>
+    <!-- no translation found for shutdown_progress (3735034517335251808) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm (699224922526414097) -->
+    <skip />
+    <!-- no translation found for no_recent_tasks (1367712919998349373) -->
+    <skip />
+    <!-- no translation found for global_actions (8299888906525675157) -->
+    <skip />
+    <!-- no translation found for global_action_lock (5943677976245541105) -->
+    <skip />
+    <!-- no translation found for global_action_power_off (3143027278596694254) -->
+    <skip />
+    <!-- no translation found for global_action_toggle_silent_mode (5849335789367070450) -->
+    <skip />
+    <!-- no translation found for global_action_silent_mode_on_status (6053429980569202260) -->
+    <skip />
+    <!-- no translation found for global_action_silent_mode_off_status (1994514127029249081) -->
+    <skip />
+    <!-- no translation found for safeMode (3375134507868534320) -->
+    <skip />
+    <!-- no translation found for permgrouplab_costMoney (904087853776533085) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_costMoney (4662370555643969515) -->
+    <skip />
+    <!-- no translation found for permgrouplab_messages (2984053976424233925) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_messages (2129093134354989379) -->
+    <skip />
+    <!-- no translation found for permgrouplab_personalInfo (4548406335021507392) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_personalInfo (8499310823817958034) -->
+    <skip />
+    <!-- no translation found for permgrouplab_location (8535677827151907069) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_location (2341662219604651887) -->
+    <skip />
+    <!-- no translation found for permgrouplab_network (3597781730625751831) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_network (8332572695347918340) -->
+    <skip />
+    <!-- no translation found for permgrouplab_accounts (8631201594657951893) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_accounts (443982868906396781) -->
+    <skip />
+    <!-- no translation found for permgrouplab_hardwareControls (5074512938567152139) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_hardwareControls (8772503144945278440) -->
+    <skip />
+    <!-- no translation found for permgrouplab_phoneCalls (7096448531266882376) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_phoneCalls (6703873478653366233) -->
+    <skip />
+    <!-- no translation found for permgrouplab_systemTools (1840847965111633430) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_systemTools (2810337951496685271) -->
+    <skip />
+    <!-- no translation found for permgrouplab_developmentTools (692844635256963358) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_developmentTools (5253915519857796400) -->
+    <skip />
+    <!-- no translation found for permlab_statusBar (8789506912215455922) -->
+    <skip />
+    <!-- no translation found for permdesc_statusBar (5034247171231682403) -->
+    <skip />
+    <!-- no translation found for permlab_expandStatusBar (6382500803293284173) -->
+    <skip />
+    <!-- no translation found for permdesc_expandStatusBar (90953162060681436) -->
+    <skip />
+    <!-- no translation found for permlab_processOutgoingCalls (786316295241100144) -->
+    <skip />
+    <!-- no translation found for permdesc_processOutgoingCalls (1655242138991854396) -->
+    <skip />
+    <string name="permlab_receiveSms">"Příjem zpráv SMS"</string>
+    <string name="permdesc_receiveSms">"Umožňuje aplikacím přijímat a zpracovávat zprávy SMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."</string>
+    <string name="permlab_receiveMms">"Příjem zpráv MMS"</string>
+    <string name="permdesc_receiveMms">"Umožňuje aplikacím přijímat a zpracovávat zprávy MMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."</string>
+    <!-- no translation found for permlab_sendSms (4713837923748234081) -->
+    <skip />
+    <!-- no translation found for permdesc_sendSms (7126594387176704010) -->
+    <skip />
+    <!-- no translation found for permlab_readSms (4256004535185449429) -->
+    <skip />
+    <!-- no translation found for permdesc_readSms (4586480500886941902) -->
+    <skip />
+    <!-- no translation found for permlab_writeSms (8453452414726246828) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSms (1036408118901361812) -->
+    <skip />
+    <string name="permlab_receiveWapPush">"Příjem zpráv WAP"</string>
+    <string name="permdesc_receiveWapPush">"Umožňuje aplikacím přijímat a zpracovávat zprávy WAP. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."</string>
+    <string name="permlab_getTasks">"Získat informace o úkolech"</string>
+    <string name="permdesc_getTasks">"Umožňuje aplikacím načítat informace o aktuálně a naposledy spuštěných úkolech. Umožňuje škodlivým aplikacím zjišťovat soukromé informace o jiných aplikacích."</string>
+    <!-- no translation found for permlab_reorderTasks (4758862288285224517) -->
+    <skip />
+    <!-- no translation found for permdesc_reorderTasks (7507060843941912021) -->
+    <skip />
+    <!-- no translation found for permlab_setDebugApp (2973363275929449444) -->
+    <skip />
+    <!-- no translation found for permdesc_setDebugApp (5720449860498265972) -->
+    <skip />
+    <!-- no translation found for permlab_changeConfiguration (8581093564179818627) -->
+    <skip />
+    <!-- no translation found for permdesc_changeConfiguration (4055366453803187171) -->
+    <skip />
+    <!-- no translation found for permlab_restartPackages (5836367540766044606) -->
+    <skip />
+    <!-- no translation found for permdesc_restartPackages (1764965996765573321) -->
+    <skip />
+    <!-- no translation found for permlab_setProcessForeground (4860990420780868638) -->
+    <skip />
+    <!-- no translation found for permdesc_setProcessForeground (3795477299954784360) -->
+    <skip />
+    <!-- no translation found for permlab_forceBack (4737517869935566733) -->
+    <skip />
+    <!-- no translation found for permdesc_forceBack (5579316297001154697) -->
+    <skip />
+    <string name="permlab_dump">"Výpis stavu systému"</string>
+    <string name="permdesc_dump">"Umožňuje aplikacím načítat vnitřní stav systému. Škodlivé aplikace mohou načítat široký rozsah soukromých a důvěrných informací, jež by obvykle neměly nikdy vyžadovat."</string>
+    <string name="permlab_addSystemService">"Přidat systémovou službu"</string>
+    <string name="permdesc_addSystemService">"Umožňuje aplikacím vydávat vlastní systémové služby nižší úrovně. Škodlivé aplikace mohou napadnout systém a vykrást nebo poškodit jeho data."</string>
+    <string name="permlab_runSetActivityWatcher">"Nastavení sledování činností"</string>
+    <string name="permdesc_runSetActivityWatcher">"Umožňuje aplikacím sledovat a řídit spouštění činností systému. Škodlivé aplikace mohou zcela zničit systém. Toto oprávnění je nutné pouze pro vývoj, nikdy pro normální používání zařízení."</string>
+    <string name="permlab_broadcastPackageRemoved">"Sada vysílání odebrána"</string>
+    <string name="permdesc_broadcastPackageRemoved">"Umožňuje aplikacím vysílat oznámení o odebrání sady aplikací. Škodlivé aplikace toho mohou využít k likvidaci jiné spuštěné aplikace."</string>
+    <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
+    <skip />
+    <!-- no translation found for permlab_setProcessLimit (5190694306017260601) -->
+    <skip />
+    <!-- no translation found for permdesc_setProcessLimit (593938303319848578) -->
+    <skip />
+    <!-- no translation found for permlab_setAlwaysFinish (8745533365504920540) -->
+    <skip />
+    <!-- no translation found for permdesc_setAlwaysFinish (2437195869854312148) -->
+    <skip />
+    <string name="permlab_fotaUpdate">"Instalace aktualizace systému"</string>
+    <string name="permdesc_fotaUpdate">"Umožňuje aplikacím přijímat oznámení o aktualizacích systému čekajících na dokončení a spouštět jejich instalaci. Škodlivé aplikace toho mohou využít k poškození systému neautorizovanými aktualizacemi nebo obecně k zásahům do aktualizačního procesu."</string>
+    <!-- no translation found for permlab_batteryStats (1598947993704535568) -->
+    <skip />
+    <!-- no translation found for permdesc_batteryStats (6247598531831307989) -->
+    <skip />
+    <string name="permlab_internalSystemWindow">"Okno vnitřního systému"</string>
+    <string name="permdesc_internalSystemWindow">"Umožňuje vytváření oken určených k použití uživatelským rozhraním vnitřního systému . Není určeno k použití normálními aplikacemi."</string>
+    <string name="permlab_systemAlertWindow">"Okno systémových výstrah"</string>
+    <string name="permdesc_systemAlertWindow">"Umožňuje aplikacím zobrazovat okna systémových výstrah. Škodlivé aplikace mohou ovládnout celou obrazovku zařízení."</string>
+    <!-- no translation found for permlab_setAnimationScale (2419250686027992384) -->
+    <skip />
+    <!-- no translation found for permdesc_setAnimationScale (8518027785481727264) -->
+    <skip />
+    <!-- no translation found for permlab_manageAppTokens (1033424552444304594) -->
+    <skip />
+    <!-- no translation found for permdesc_manageAppTokens (7285840918912623550) -->
+    <skip />
+    <!-- no translation found for permlab_injectEvents (1383601196263145482) -->
+    <skip />
+    <!-- no translation found for permdesc_injectEvents (840097509341464737) -->
+    <skip />
+    <!-- no translation found for permlab_readInputState (2723668746963882102) -->
+    <skip />
+    <!-- no translation found for permdesc_readInputState (4651137638757852001) -->
+    <skip />
+    <!-- no translation found for permlab_setOrientation (1112555600323148680) -->
+    <skip />
+    <!-- no translation found for permdesc_setOrientation (1960269530378827858) -->
+    <skip />
+    <string name="permlab_signalPersistentProcesses">"Signálové trvalé procesy"</string>
+    <string name="permdesc_signalPersistentProcesses">"Umožňuje aplikacím vyžadovat, aby se přiváděný signál odesílal do všech trvalých procesů."</string>
+    <!-- no translation found for permlab_persistentActivity (8163108526929094627) -->
+    <skip />
+    <!-- no translation found for permdesc_persistentActivity (5258975883823299624) -->
+    <skip />
+    <string name="permlab_deletePackages">"Odstranit sady"</string>
+    <string name="permdesc_deletePackages">"Umožňuje aplikacím odstranit sady systému Android. Škodlivé aplikace toho mohou využít k odstranění důležitých aplikací."</string>
+    <!-- no translation found for permlab_clearAppUserData (3858185484601410171) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppUserData (7233537744753081136) -->
+    <skip />
+    <!-- no translation found for permlab_deleteCacheFiles (7362746182961997888) -->
+    <skip />
+    <!-- no translation found for permdesc_deleteCacheFiles (8293849509208181266) -->
+    <skip />
+    <!-- no translation found for permlab_getPackageSize (6743556676630447973) -->
+    <skip />
+    <!-- no translation found for permdesc_getPackageSize (2893996655828539776) -->
+    <skip />
+    <string name="permlab_installPackages">"Instalovat sady"</string>
+    <string name="permdesc_installPackages">"Umožňuje aplikacím instalovat nové nebo aktualizované sady systému Android. Škodlivé aplikace toho mohou využít k přidání nových aplikací s libovolně silnými oprávněními."</string>
+    <!-- no translation found for permlab_clearAppCache (7860214328511700776) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppCache (5203820862573167878) -->
+    <skip />
+    <!-- no translation found for permlab_readLogs (6653488552442991707) -->
+    <skip />
+    <!-- no translation found for permdesc_readLogs (356352685800884319) -->
+    <skip />
+    <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
+    <skip />
+    <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
+    <skip />
+    <string name="permlab_changeComponentState">"Povolit nebo zakázat součásti aplikací"</string>
+    <string name="permdesc_changeComponentState">"Umožňuje změnu aplikace bez ohledu na to, zda je součást další aplikace povolená nebo zakázaná. Škodlivá aplikace toho může využít k zakázání důležitých funkcí zařízení. Je třeba nakládat s oprávněními opatrně, protože se mohou součásti aplikace dostat do stavu nepoužitelnosti, nekonzistence nebo nestability."</string>
+    <string name="permlab_setPreferredApplications">"Nastavení upřednostňovaných aplikací"</string>
+    <string name="permdesc_setPreferredApplications">"Umožňuje aplikacím upravovat oblíbené aplikace. Škodlivé aplikace tak mohou bez upozornění měnit spouštěné aplikace a klamně využívat stávající aplikace ke shromažďování vašich soukromých dat."</string>
+    <string name="permlab_writeSettings">"Nastavení systému pro zápis"</string>
+    <string name="permdesc_writeSettings">"Umožňuje aplikacím upravovat data nastavení systému. Škodlivé aplikace mohou narušit systémovou konfiguraci."</string>
+    <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
+    <skip />
+    <!-- no translation found for permlab_writeGservices (296370685945777755) -->
+    <skip />
+    <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
+    <skip />
+    <string name="permlab_receiveBootCompleted">"Spustit při spouštění"</string>
+    <string name="permdesc_receiveBootCompleted">"Umožňuje aplikacím spouštět se po dokončení spuštění systému. Tím se může prodlužovat doba spouštění zařízení a aplikace může svým stálým spouštěním zpomalovat celé zařízení."</string>
+    <string name="permlab_broadcastSticky">"Vysílat lepivý obsah (sticky)"</string>
+    <string name="permdesc_broadcastSticky">"Umožňuje aplikacím odesílat tzv. lepivé (sticky) vysílání, které zůstává i po ukončení vysílání. Škodlivé aplikace mohou zpomalit zařízení nebo narušit jeho stabilitu vynucením využívání příliš velké části paměti."</string>
+    <string name="permlab_readContacts">"Čtení dat o kontaktech"</string>
+    <string name="permdesc_readContacts">"Umožňuje aplikacím číst všechna data o kontaktech (adresy) uložená v zařízení. Škodlivé aplikace toho mohou využívat k odesílání vašich dat jiným osobám."</string>
+    <string name="permlab_writeContacts">"Zápis dat o kontaktech"</string>
+    <string name="permdesc_writeContacts">"Umožňuje aplikacím upravovat data o kontaktech (adresy) uložená v zařízení. Škodlivé aplikace toho mohou využívat k vymazání nebo úpravě dat o kontaktech."</string>
+    <!-- no translation found for permlab_writeOwnerData (8036840529708535113) -->
+    <skip />
+    <!-- no translation found for permdesc_writeOwnerData (5873447528845878348) -->
+    <skip />
+    <!-- no translation found for permlab_readOwnerData (1847040178513733757) -->
+    <skip />
+    <!-- no translation found for permdesc_readOwnerData (7563299529149214764) -->
+    <skip />
+    <!-- no translation found for permlab_readCalendar (2111238731453410895) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (4408253940601239114) -->
+    <skip />
+    <!-- no translation found for permlab_writeCalendar (7518052789370653396) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCalendar (8057304232140147596) -->
+    <skip />
+    <!-- no translation found for permlab_accessMockLocation (321094551062270213) -->
+    <skip />
+    <!-- no translation found for permdesc_accessMockLocation (3651565866471419739) -->
+    <skip />
+    <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
+    <skip />
+    <string name="permlab_accessFineLocation">"Používat službu GPS"</string>
+    <string name="permdesc_accessFineLocation">"Technologii GPS v zařízení lze používat, pokud je k dispozici. Toto oprávnění vyžaduje oprávnění ACCESS_LOCATION. Škodlivé aplikace toho mohou využívat k určení vaší polohy a mohou spotřebovávat zbytečně energii baterie."</string>
+    <string name="permlab_accessCoarseLocation">"Používat službu Cell ID"</string>
+    <string name="permdesc_accessCoarseLocation">"Identifikátory pro technologii využívající polohu vysílačů mobilních sítí (je-li k dispozici) se používají k určení přibližné polohy zařízení. Toto oprávnění vyžaduje oprávnění ACCESS_LOCATION. Škodlivé aplikace toho mohou využívat k určení vaší přibližné polohy."</string>
+    <string name="permlab_accessSurfaceFlinger">"Používat službu SurfaceFlinger"</string>
+    <string name="permdesc_accessSurfaceFlinger">"Umožňuje aplikacím používat funkce nižší úrovně SurfaceFlinger."</string>
+    <string name="permlab_readFrameBuffer">"Čtení vyrovnávací paměti rámce"</string>
+    <string name="permdesc_readFrameBuffer">"Umožňuje aplikacím používat čtení obsahu vyrovnávací paměti rámce."</string>
+    <!-- no translation found for permlab_modifyAudioSettings (1587341813207960943) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyAudioSettings (1447143004892708149) -->
+    <skip />
+    <!-- no translation found for permlab_recordAudio (4447848534036991667) -->
+    <skip />
+    <!-- no translation found for permdesc_recordAudio (6936874682400894820) -->
+    <skip />
+    <!-- no translation found for permlab_camera (1944473855727060380) -->
+    <skip />
+    <!-- no translation found for permdesc_camera (5978058582323766022) -->
+    <skip />
+    <!-- no translation found for permlab_brick (4749832243303289777) -->
+    <skip />
+    <!-- no translation found for permdesc_brick (7428524578693695766) -->
+    <skip />
+    <!-- no translation found for permlab_reboot (8844650672567077423) -->
+    <skip />
+    <!-- no translation found for permdesc_reboot (4704919552870918328) -->
+    <skip />
+    <!-- no translation found for permlab_mount_unmount_filesystems (1009574821038043781) -->
+    <skip />
+    <!-- no translation found for permdesc_mount_unmount_filesystems (100792065894811109) -->
+    <skip />
+    <!-- no translation found for permlab_vibrate (61984555644467146) -->
+    <skip />
+    <!-- no translation found for permdesc_vibrate (7831723100758509238) -->
+    <skip />
+    <!-- no translation found for permlab_flashlight (9097145977808182652) -->
+    <skip />
+    <!-- no translation found for permdesc_flashlight (7851502731988978358) -->
+    <skip />
+    <!-- no translation found for permlab_hardware_test (4103324677866524254) -->
+    <skip />
+    <!-- no translation found for permdesc_hardware_test (7315242723603994769) -->
+    <skip />
+    <string name="permlab_callPhone">"Volat telefonní čísla"</string>
+    <string name="permdesc_callPhone">"Umožňuje aplikacím volat telefonní čísla bez vašeho zásahu. Škodlivé aplikace mohou přinést na váš telefonní účet neočekávané hovory."</string>
+    <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
+    <skip />
+    <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
+    <skip />
+    <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
+    <skip />
+    <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
+    <skip />
+    <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
+    <skip />
+    <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
+    <skip />
+    <!-- no translation found for permlab_modifyPhoneState (7791696535097912313) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyPhoneState (6352405226410454770) -->
+    <skip />
+    <!-- no translation found for permlab_readPhoneState (7320082586621086653) -->
+    <skip />
+    <!-- no translation found for permdesc_readPhoneState (8004450067066407969) -->
+    <skip />
+    <!-- no translation found for permlab_wakeLock (1591164750935072136) -->
+    <skip />
+    <!-- no translation found for permdesc_wakeLock (160471538196734936) -->
+    <skip />
+    <!-- no translation found for permlab_devicePower (9214865067086065548) -->
+    <skip />
+    <!-- no translation found for permdesc_devicePower (5608364066480036402) -->
+    <skip />
+    <!-- no translation found for permlab_factoryTest (7786199300637896247) -->
+    <skip />
+    <!-- no translation found for permdesc_factoryTest (3466066005210542042) -->
+    <skip />
+    <!-- no translation found for permlab_setWallpaper (2256730637138641725) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaper (3034653140208685093) -->
+    <skip />
+    <!-- no translation found for permlab_setWallpaperHints (4192438316932517807) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaperHints (738757439960921674) -->
+    <skip />
+    <!-- no translation found for permlab_masterClear (6155403967270586906) -->
+    <skip />
+    <!-- no translation found for permdesc_masterClear (4213553172342689754) -->
+    <skip />
+    <!-- no translation found for permlab_setTimeZone (477196167239548690) -->
+    <skip />
+    <!-- no translation found for permdesc_setTimeZone (8564892020460841198) -->
+    <skip />
+    <!-- no translation found for permlab_getAccounts (2764070033402295170) -->
+    <skip />
+    <!-- no translation found for permdesc_getAccounts (1203491378748649898) -->
+    <skip />
+    <!-- no translation found for permlab_accessNetworkState (2032916924886010827) -->
+    <skip />
+    <!-- no translation found for permdesc_accessNetworkState (7081329402551195933) -->
+    <skip />
+    <!-- no translation found for permlab_createNetworkSockets (4706698319966917864) -->
+    <skip />
+    <!-- no translation found for permdesc_createNetworkSockets (2580337178778551792) -->
+    <skip />
+    <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
+    <skip />
+    <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
+    <skip />
+    <!-- no translation found for permlab_changeNetworkState (2710779001260856872) -->
+    <skip />
+    <!-- no translation found for permdesc_changeNetworkState (8076109230787022270) -->
+    <skip />
+    <!-- no translation found for permlab_accessWifiState (3613679494230374297) -->
+    <skip />
+    <!-- no translation found for permdesc_accessWifiState (8226508433563326925) -->
+    <skip />
+    <!-- no translation found for permlab_changeWifiState (6043889338995432957) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWifiState (7829372845909567994) -->
+    <skip />
+    <!-- no translation found for permlab_bluetoothAdmin (5513286736585647334) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (1838208497914347365) -->
+    <skip />
+    <!-- no translation found for permlab_bluetooth (6378797624765639115) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetooth (8592386018922265273) -->
+    <skip />
+    <!-- no translation found for permlab_disableKeyguard (4574886811903233903) -->
+    <skip />
+    <!-- no translation found for permdesc_disableKeyguard (815972646344251271) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncSettings (8818819977141505127) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncSettings (8454705401908767847) -->
+    <skip />
+    <!-- no translation found for permlab_writeSyncSettings (4514911143753152941) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSyncSettings (7630627689635091836) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncStats (5748337739678952863) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncStats (582551457321957183) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
+    <skip />
+    <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
   <string-array name="emailAddressTypes">
-    <item>Výchozí</item>
-    <item>Zaměstnání</item>
-    <item>Primární</item>
-    <item>Vlastní\u2026</item>
-  </string-array>
-  <string-array name="phoneTypes">
-    <item>Výchozí</item>
-    <item>Mobil</item>
-    <item>Zaměstnání</item>
-    <item>Fax do zaměstnání</item>
-    <item>Fax domů</item>
-    <item>Operátor</item>
-    <item>Vlastní\u2026</item>
+    <item>"Výchozí"</item>
+    <item>"Zaměstnání"</item>
+    <item>"Primární"</item>
+    <item>"Vlastní…"</item>
   </string-array>
   <string-array name="postalAddressTypes">
-    <item>Poštovní</item>
-    <item>Výchozí</item>
-    <item>Zaměstnání</item>
-    <item>Vlastní\u2026</item>
+    <item>"Poštovní"</item>
+    <item>"Výchozí"</item>
+    <item>"Zaměstnání"</item>
+    <item>"Vlastní…"</item>
   </string-array>
-  <string name="CLIRDefaultOffNextCallOff">Výchozí nastavení omezení ID - bez omezení. Další hovor: bez omezení</string>
-  <string name="CLIRDefaultOffNextCallOn">Výchozí nastavení omezení ID - bez omezení. Další hovor: omezení</string>
-  <string name="CLIRDefaultOnNextCallOff">Výchozí nastavení omezení ID - omezení. Další hovor: bez omezení</string>
-  <string name="CLIRDefaultOnNextCallOn">Výchozí nastavení omezení ID - omezení. Další hovor: omezení</string>
-  <string name="CLIRPermanent">Omezení ID v trvalém režimu.</string>
-  <string name="activate_keyguard">Aktivovat zámek kláves</string>
-  <string name="ago">před</string>
-  <string name="am">dop.</string>
-  <string name="before">Před</string>
-  <string name="browserSavedFormData">Uložená data formuláře</string>
-  <string name="cfReasonBusy">Přesměrování hovorů - je-li obsazeno</string>
-  <string name="cfReasonNR">Přesměrování hovorů - je-li nedostupný</string>
-  <string name="cfReasonNRy">Přesměrování hovorů - neodpovídá-li</string>
-  <string name="cfReasonUnconditional">Přesměrování hovorů - bezpodmínečné</string>
-  <string name="cfTemplateForwarded">{0}: {1}</string>
-  <string name="cfTemplateForwardedTime">{0}: {1} po {2} sekundách</string>
-  <string name="cfTemplateNotForwarded">{0}: Nepřesměrováno</string>
-  <string name="cfTemplateRegistered">{0}: Nepřesměrováno ({1})</string>
-  <string name="cfTemplateRegisteredTime">{0}: Nepřesměrováno ({1} po {2} sekundách)</string>
-  <string name="contentServiceSync">Synchronizace</string>
-  <string name="contentServiceSyncNotificationDesc">Synchronizace</string>
-  <string name="contentServiceSyncNotificationTitle">Synchronizace</string>
-  <string name="contentServiceXmppAvailable">XMPP aktivní</string>
-  <string name="daily">Denně</string>
-  <string name="day">den</string>
-  <string name="days">dnů</string>
-  <string name="defaultMsisdnAlphaTag">Msisdn1</string>
-  <string name="defaultVoiceMailAlphaTag">Hlasová schránka</string>
-  <string name="ellipsis">\u2026</string>
-  <string name="emptyPhoneNumber">(žádné telefonní číslo)</string>
-  <string name="every_weekday">"Každý den v týdnu (Po\u2013Pá)"</string>
-  <string name="factorytest_failed">Výrobní test skončil chybou</string>
-  <string name="factorytest_no_action">Nebyla nalezena žádná sada, která zajišťuje
-        akci FACTORY_TEST.</string>
-  <string name="factorytest_not_system">Akce FACTORY_TEST
-        je podporována pouze pro sady instalované v adresáři /system/app.</string>
-  <string name="factorytest_reboot">Restartovat</string>
-  <string name="friday">Pátek</string>
-  <string name="hour">hodinu</string>
-  <string name="hours">hodin</string>
-  <string name="httpError">Neznámá chyba</string>
-  <string name="httpErrorAuth">Ověřování se nezdařilo</string>
-  <string name="httpErrorBadUrl">Nepodařilo se analyzovat URL</string>
-  <string name="httpErrorConnect">Připojení k serveru se nezdařilo</string>
-  <string name="httpErrorFailedSslHandshake">Navázání spojení typu SSL handshake se nezdařilo</string>
-  <string name="httpErrorIO">Čtení nebo zápis na server se nezdařil</string>
-  <string name="httpErrorLookup">Neznámý hostitel</string>
-  <string name="httpErrorOk">OK</string>
-  <string name="httpErrorProxyAuth">Ověření serverem proxy se nezdařilo</string>
-  <string name="httpErrorRedirectLoop">Příliš mnoho přesměrování serverů</string>
-  <string name="httpErrorTimeout">Časový limit připojení k serveru vypršel</string>
-  <string name="httpErrorUnsupportedAuthScheme">Nepodporované schéma ověření. Ověření se nezdařilo.</string>
-  <string name="httpErrorUnsupportedScheme">Nepodporovaný protokol</string>
-  <!-- generic file error --><string name="httpErrorFile">File error</string>
-  <!-- file not found error --><string name="httpErrorFileNotFound">File not found</string>
-  <string name="in">v</string>
-  <string name="keyguard_label_text">Telefon odemknete stisknutím tlačítka nabídky a poté 0.</string>
-  <string name="keyguard_password_emergency_instructions">Chcete-li provést tísňové volání, stiskněte tlačítko Odeslat.</string>
-  <string name="keyguard_password_instructions">Zadejte heslo nebo vytočte číslo tísňového volání.</string>
-  <string name="minute">minutu</string>
-  <string name="minutes">minut</string>
-  <string name="mmiComplete">MMI dokončeno</string>
-  <string name="mmiError">Chyba sítě nebo neplatný kód MMI.</string>
-  <string name="monday">Pondělí</string>
-  <string name="monthly">Měsíčně</string>
-  <string name="more_item_label">Další</string>
-  <string name="passwordIncorrect">Nesprávné heslo.</string>
-  <string name="permdesc_accessCoarseLocation">Identifikátory pro technologii využívající polohu vysílačů mobilních sítí (je-li k dispozici) se používají k určení přibližné polohy zařízení. Toto oprávnění vyžaduje oprávnění ACCESS_LOCATION. Škodlivé aplikace toho mohou využívat k určení vaší přibližné polohy.</string>
-  <string name="permdesc_accessFineLocation">Technologii GPS v zařízení lze používat, pokud je k dispozici. Toto oprávnění vyžaduje oprávnění ACCESS_LOCATION. Škodlivé aplikace toho mohou využívat k určení vaší polohy a mohou spotřebovávat zbytečně energii baterie.</string>
-  <string name="permdesc_accessSurfaceFlinger">Umožňuje aplikacím používat
-        funkce nižší úrovně SurfaceFlinger.</string>
-  <string name="permdesc_addSystemService">Umožňuje aplikacím vydávat
-        vlastní systémové služby nižší úrovně. Škodlivé aplikace mohou napadnout
-        systém a vykrást nebo poškodit jeho data.</string>
-  <string name="permdesc_broadcastPackageRemoved">Umožňuje aplikacím
-        vysílat oznámení o odebrání sady aplikací.
-        Škodlivé aplikace toho mohou využít k likvidaci jiné spuštěné
-        aplikace.</string>
-  <string name="permdesc_broadcastSticky">Umožňuje aplikacím odesílat
-        tzv. lepivé (sticky) vysílání, které zůstává i po ukončení vysílání.
-        Škodlivé aplikace mohou zpomalit zařízení nebo narušit jeho stabilitu
-        vynucením využívání příliš velké části paměti.</string>
-  <string name="permdesc_callPhone">Umožňuje aplikacím volat
-        telefonní čísla bez vašeho zásahu. Škodlivé aplikace mohou
-        přinést na váš telefonní účet neočekávané hovory.</string>
-  <string name="permdesc_changeComponentState">Umožňuje změnu aplikace bez ohledu na to, zda
-        je součást další aplikace povolená nebo zakázaná. Škodlivá aplikace toho může využít
-        k zakázání důležitých funkcí zařízení. Je třeba nakládat s oprávněními opatrně, protože
-        se mohou součásti aplikace dostat do stavu nepoužitelnosti, nekonzistence nebo nestability.
-    </string>
-  <string name="permdesc_deletePackages">Umožňuje aplikacím odstranit
-        sady systému Android. Škodlivé aplikace toho mohou využít k odstranění důležitých aplikací.</string>
-  <string name="permdesc_dump">Umožňuje aplikacím načítat
-        vnitřní stav systému. Škodlivé aplikace mohou načítat
-        široký rozsah soukromých a důvěrných informací, jež by
-        obvykle neměly nikdy vyžadovat.</string>
-  <string name="permdesc_fotaUpdate">Umožňuje aplikacím přijímat
-        oznámení o aktualizacích systému čekajících na dokončení a spouštět jejich
-        instalaci. Škodlivé aplikace toho mohou využít k poškození systému
-        neautorizovanými aktualizacemi nebo obecně k zásahům do aktualizačního
-        procesu.</string>
-  <string name="permdesc_getTasks">Umožňuje aplikacím načítat
-        informace o aktuálně a naposledy spuštěných úkolech. Umožňuje
-        škodlivým aplikacím
-        zjišťovat soukromé informace o jiných aplikacích.</string>
-  <string name="permdesc_installPackages">Umožňuje aplikacím instalovat nové nebo aktualizované
-        sady systému Android. Škodlivé aplikace toho mohou využít k přidání nových aplikací s libovolně
-        silnými oprávněními.</string>
-  <string name="permdesc_internalSystemWindow">Umožňuje vytváření
-        oken určených k použití uživatelským rozhraním vnitřního systému
-        . Není určeno k použití normálními aplikacemi.</string>
-  <string name="permdesc_raisedThreadPriority">Umožňuje aplikacím používat
-        vyšších priorit vláken, případně ovlivnit reagování uživatelského rozhraní
-        .</string>
-  <string name="permdesc_readContacts">Umožňuje aplikacím číst všechna
-        data o kontaktech (adresy) uložená v zařízení. Škodlivé aplikace
-        toho mohou využívat k odesílání vašich dat jiným osobám.</string>
-  <string name="permdesc_readFrameBuffer">Umožňuje aplikacím používat
-        čtení obsahu vyrovnávací paměti rámce.</string>
-  <string name="permdesc_receiveBootCompleted">Umožňuje aplikacím
-        spouštět se po dokončení spuštění systému.
-        Tím se může prodlužovat doba spouštění zařízení a
-        aplikace může svým stálým spouštěním zpomalovat celé zařízení.</string>
-  <string name="permdesc_receiveSms">Umožňuje aplikacím přijímat
-      a zpracovávat zprávy SMS. Škodlivé aplikace mohou sledovat
-      vaše zprávy nebo je odstraňovat, aniž by se zobrazily.</string>
-  <string name="permdesc_receiveMms">Umožňuje aplikacím přijímat
-      a zpracovávat zprávy MMS. Škodlivé aplikace mohou sledovat
-      vaše zprávy nebo je odstraňovat, aniž by se zobrazily.</string>
-  <string name="permdesc_receiveWapPush">Umožňuje aplikacím přijímat
-      a zpracovávat zprávy WAP. Škodlivé aplikace mohou sledovat
-      vaše zprávy nebo je odstraňovat, aniž by se zobrazily.</string>
-  <string name="permdesc_runInstrumentation">Umožňuje aplikacím
-        vložit kód vlastního nástroje do libovolné jiné aplikace.
-        Škodlivé aplikace mohou zcela zničit systém. Toto
-        oprávnění je nutné pouze pro vývoj, nikdy pro normální
-        používání zařízení.</string>
-  <string name="permdesc_runSetActivityWatcher">Umožňuje aplikacím
-        sledovat a řídit spouštění činností systému.
-        Škodlivé aplikace mohou zcela zničit systém. Toto
-        oprávnění je nutné pouze pro vývoj, nikdy pro normální
-        používání zařízení.</string>
-  <string name="permdesc_setPreferredApplications">Umožňuje aplikacím
-        upravovat oblíbené aplikace. Škodlivé aplikace tak mohou
-        bez upozornění měnit spouštěné aplikace a klamně využívat
-        stávající aplikace ke shromažďování vašich soukromých dat.</string>
-  <string name="permdesc_signalPersistentProcesses">Umožňuje aplikacím vyžadovat, aby
-        se přiváděný signál odesílal do všech trvalých procesů.</string>
-  <string name="permdesc_systemAlertWindow">Umožňuje aplikacím
-        zobrazovat okna systémových výstrah. Škodlivé aplikace mohou ovládnout
-        celou obrazovku zařízení.</string>
-  <string name="permdesc_writeContacts">Umožňuje aplikacím upravovat
-        data o kontaktech (adresy) uložená v zařízení. Škodlivé
-        aplikace toho mohou využívat k vymazání nebo úpravě dat o kontaktech.</string>
-  <string name="permdesc_writeSettings">Umožňuje aplikacím upravovat
-        data nastavení systému. Škodlivé aplikace mohou narušit systémovou
-        konfiguraci.</string>
-  <string name="permlab_accessCoarseLocation">Používat službu Cell ID</string>
-  <string name="permlab_accessFineLocation">Používat službu GPS</string>
-  <string name="permlab_accessSurfaceFlinger">Používat službu SurfaceFlinger</string>
-  <string name="permlab_addSystemService">Přidat systémovou službu</string>
-  <string name="permlab_broadcastPackageRemoved">Sada vysílání odebrána</string>
-  <string name="permlab_broadcastSticky">Vysílat lepivý obsah (sticky)</string>
-  <string name="permlab_callPhone">Volat telefonní čísla</string>
-  <string name="permlab_changeComponentState">Povolit nebo zakázat součásti aplikací</string>
-  <string name="permlab_deletePackages">Odstranit sady</string>
-  <string name="permlab_dump">Výpis stavu systému</string>
-  <string name="permlab_fotaUpdate">Instalace aktualizace systému</string>
-  <string name="permlab_getTasks">Získat informace o úkolech</string>
-  <string name="permlab_installPackages">Instalovat sady</string>
-  <string name="permlab_internalSystemWindow">Okno vnitřního systému</string>
-  <string name="permlab_raisedThreadPriority">Vyšší priority vláken</string>
-  <string name="permlab_readContacts">Čtení dat o kontaktech</string>
-  <string name="permlab_readFrameBuffer">Čtení vyrovnávací paměti rámce</string>
-  <string name="permlab_receiveBootCompleted">Spustit při spouštění</string>
-  <string name="permlab_receiveSms">Příjem zpráv SMS</string>
-  <string name="permlab_receiveMms">Příjem zpráv MMS</string>
-  <string name="permlab_receiveWapPush">Příjem zpráv WAP</string>
-  <string name="permlab_runInstrumentation">Spustit nástroje</string>
-  <string name="permlab_runSetActivityWatcher">Nastavení sledování činností</string>
-  <string name="permlab_setPreferredApplications">Nastavení upřednostňovaných aplikací</string>
-  <string name="permlab_signalPersistentProcesses">Signálové trvalé procesy</string>
-  <string name="permlab_systemAlertWindow">Okno systémových výstrah</string>
-  <string name="permlab_writeContacts">Zápis dat o kontaktech</string>
-  <string name="permlab_writeSettings">Nastavení systému pro zápis</string>
-  <string name="pm">odp.</string>
-  <string name="power_dialog">Možnosti napájení</string>
-  <string name="power_off">Vypnuto</string>
-  <string name="prepend_shortcut_label">Menu+</string>
-  <string name="primaryEmailAddressLabel">E-mail</string>
-  <string name="saturday">Sobota</string>
-  <string name="screen_progress">Pracuji...</string>
-  <string name="search_go">PŘEJÍT</string>
-  <string name="search_hint_placeholder">Zde zadejte hledaný text</string>
-  <string name="second">sekund</string>
-  <string name="seconds">sekund</string>
-  <string name="selectMenuLabel">Vybrat</string>
-  <string name="serviceClassData">Data</string>
-  <string name="serviceClassDataAsync">Asynchronní</string>
-  <string name="serviceClassDataSync">Synchronizace</string>
-  <string name="serviceClassFAX">FAX</string>
-  <string name="serviceClassPAD">PAD</string>
-  <string name="serviceClassPacket">Pakety</string>
-  <string name="serviceClassSMS">SMS</string>
-  <string name="serviceClassVoice">Hlasový záznam</string>
-  <string name="serviceDisabled">Služba zakázána</string>
-  <string name="serviceEnabled">Služba povolena</string>
-  <string name="serviceEnabledFor">Služba povolena pro:</string>
-  <string name="serviceErased">Odstranění úspěšné</string>
-  <string name="serviceNotProvisioned">Služba není poskytována.</string>
-  <string name="serviceRegistered">Registrace úspěšná</string>
-  <string name="silent_mode">Tichý režim</string>
-  <string name="simAbsentLabel">Chybí karta SIM nebo je nesprávně vložena</string>
-  <string name="simNetworkPersonalizationLabel">Tuto kartu SIM nelze v zařízení používat</string>
-  <string name="simPINLabel">Vyžadován kód PIN karty SIM (nyní nepodporován)</string>
-  <string name="simPUKLabel">Vyžadován kód PUK karty SIM (nyní nepodporován)</string>
-  <string name="status_bar_applications_label">Aplikace</string>
-  <string name="status_bar_close">Zavřít</string>
-  <string name="status_bar_latest_events_label">Poslední události</string>
-  <string name="status_bar_no_notifications">Neupozorňovat</string>
-  <string name="status_bar_ongoing_events_label">Probíhá</string>
-  <string name="sunday">Neděle</string>
-  <string name="thursday">Čtvrtek</string>
-  <string name="time_picker_ColonBetweenHourAndMinute_text">:</string>
-  <string name="time_picker_setButton_text">Nastavit</string>
-  <string name="today">Dnes</string>
-  <string name="tomorrow">Zítra</string>
-  <string name="tuesday">Úterý</string>
-  <string name="turn_off_radio">Vypnout rádio</string>
-  <string name="turn_on_radio">Zapnout rádio</string>
-  <string name="unknownName">(neznámý)</string>
-  <string name="untitled">&lt;bez názvu&gt;</string>
-  <string name="web_user_agent">Mozilla/5.0 (Linux; U; Android 0.5; en)
-        AppleWebKit/522+ (KHTML, like Gecko) Safari/419.3</string>
-  <string name="wednesday">Středa</string>
-  <string name="week">týden</string>
-  <string name="weekly">"Týdně (%s)"</string>
-  <string name="weeks">týdnů</string>
-  <string name="yearly">Ročně</string>
-  <string name="yesterday">Včera</string>
+    <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
+    <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
+    <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
+    <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
+    <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
+    <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
+    <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
+    <!-- no translation found for imProtocols:0 (3318725788774688043) -->
+    <!-- no translation found for imProtocols:1 (1787713387022932886) -->
+    <!-- no translation found for imProtocols:2 (6751174158442316516) -->
+    <!-- no translation found for imProtocols:3 (1151283347465052653) -->
+    <!-- no translation found for imProtocols:4 (2157980008878817934) -->
+    <!-- no translation found for imProtocols:5 (7836237460308230767) -->
+    <!-- no translation found for imProtocols:6 (1180789904462172516) -->
+    <!-- no translation found for imProtocols:7 (21955111672779862) -->
+    <!-- no translation found for keyguard_password_enter_pin_code (6779835451906812518) -->
+    <skip />
+    <!-- no translation found for keyguard_password_wrong_pin_code (230312338493035499) -->
+    <skip />
+    <string name="keyguard_label_text">"Telefon odemknete stisknutím tlačítka nabídky a poté 0."</string>
+    <!-- no translation found for emergency_call_dialog_number_for_display (6256361184251050511) -->
+    <skip />
+    <!-- no translation found for lockscreen_carrier_default (5222269885486229730) -->
+    <skip />
+    <!-- no translation found for lockscreen_screen_locked (1922273663462058967) -->
+    <skip />
+    <!-- no translation found for lockscreen_instructions_when_pattern_enabled (7535864145009679967) -->
+    <skip />
+    <!-- no translation found for lockscreen_instructions_when_pattern_disabled (6526504555912746785) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_instructions (8984964506352089877) -->
+    <skip />
+    <!-- no translation found for lockscreen_emergency_call (422835617844547383) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_correct (7104753084746383672) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_wrong (7517004470797680361) -->
+    <skip />
+    <!-- no translation found for lockscreen_plugged_in (8806977650003537118) -->
+    <skip />
+    <!-- no translation found for lockscreen_low_battery (9002637795199621345) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message_short (5051192587315492957) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message (8912914495901434841) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_instructions (8125847194365725429) -->
+    <skip />
+    <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_message (1005803622871256359) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_instructions (5033160098036646955) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_locked_message (7398401200962556379) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (5939537246164692076) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6709066241494622136) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (1569017295989454551) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_attempts_countdown (8823588000022797566) -->
+    <skip />
+    <!-- no translation found for lockscreen_forgot_pattern_button_text (4219994639843985488) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_too_many_attempts (7504679498838839295) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_instructions (6542400673357252011) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_username_hint (6378418320242015111) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_password_hint (3224230234042131153) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_submit_button (5562051040043760034) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
+    <skip />
+    <!-- no translation found for status_bar_time_format (2168573805413119180) -->
+    <skip />
+    <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
+    <skip />
+    <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
+    <skip />
+    <!-- no translation found for hour_ampm (7665432130905376251) -->
+    <skip />
+    <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
+    <skip />
+    <!-- no translation found for status_bar_clear_all_button (2202004591253243750) -->
+    <skip />
+    <!-- no translation found for status_bar_no_notifications_title (5123133188102094464) -->
+    <skip />
+    <!-- no translation found for status_bar_ongoing_events_title (799961521630569167) -->
+    <skip />
+    <!-- no translation found for status_bar_latest_events_title (5414094466807164279) -->
+    <skip />
+    <!-- no translation found for battery_status_text_percent_format (7391464609447031944) -->
+    <skip />
+    <!-- no translation found for battery_status_charging (5078780715755132756) -->
+    <skip />
+    <!-- no translation found for battery_low_title (3665400828395001695) -->
+    <skip />
+    <!-- no translation found for battery_low_subtitle (7537149915372180016) -->
+    <skip />
+    <!-- no translation found for battery_low_percent_format (8635359708781261154) -->
+    <skip />
+    <string name="factorytest_failed">"Výrobní test skončil chybou"</string>
+    <string name="factorytest_not_system">"Akce FACTORY_TEST je podporována pouze pro sady instalované v adresáři /system/app."</string>
+    <string name="factorytest_no_action">"Nebyla nalezena žádná sada, která zajišťuje akci FACTORY_TEST."</string>
+    <string name="factorytest_reboot">"Restartovat"</string>
+    <!-- no translation found for save_password_label (4129493019621348626) -->
+    <skip />
+    <!-- no translation found for save_password_message (7412617920202682045) -->
+    <skip />
+    <!-- no translation found for save_password_notnow (3887362423496820832) -->
+    <skip />
+    <!-- no translation found for save_password_remember (4319688896716308569) -->
+    <skip />
+    <!-- no translation found for save_password_never (1836981952883642377) -->
+    <skip />
+    <!-- no translation found for open_permission_deny (6408502671105717111) -->
+    <skip />
+    <!-- no translation found for text_copied (6106873823411904723) -->
+    <skip />
+    <string name="more_item_label">"Další"</string>
+    <string name="prepend_shortcut_label">"Menu+"</string>
+    <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
+    <skip />
+    <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
+    <skip />
+    <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
+    <skip />
+    <string name="search_go">"PŘEJÍT"</string>
+    <string name="today">"Dnes"</string>
+    <string name="yesterday">"Včera"</string>
+    <string name="tomorrow">"Zítra"</string>
+    <!-- no translation found for oneMonthDurationPast (3402179395240209557) -->
+    <skip />
+    <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
+    <skip />
+    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
+    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
+    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
+    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
+    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
+    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
+    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
+    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
+    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
+    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
+    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
+    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
+    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
+    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
+    <!-- no translation found for in_num_days:one (5608475533104443893) -->
+    <!-- no translation found for in_num_days:other (3827193006163842267) -->
+    <!-- no translation found for preposition_for_date (2689847983632851560) -->
+    <skip />
+    <!-- no translation found for preposition_for_time (2613388053493148013) -->
+    <skip />
+    <!-- no translation found for preposition_for_year (6968468294728152393) -->
+    <skip />
+    <string name="day">"den"</string>
+    <string name="days">"dnů"</string>
+    <string name="hour">"hodinu"</string>
+    <string name="hours">"hodin"</string>
+    <string name="minute">"minutu"</string>
+    <string name="minutes">"minut"</string>
+    <string name="second">"sekund"</string>
+    <string name="seconds">"sekund"</string>
+    <string name="week">"týden"</string>
+    <string name="weeks">"týdnů"</string>
+    <!-- no translation found for year (8024790425994085153) -->
+    <skip />
+    <!-- no translation found for years (8592090054773244417) -->
+    <skip />
+    <string name="sunday">"Neděle"</string>
+    <string name="monday">"Pondělí"</string>
+    <string name="tuesday">"Úterý"</string>
+    <string name="wednesday">"Středa"</string>
+    <string name="thursday">"Čtvrtek"</string>
+    <string name="friday">"Pátek"</string>
+    <string name="saturday">"Sobota"</string>
+    <string name="every_weekday">"Každý den v týdnu (Po–Pá)"</string>
+    <string name="daily">"Denně"</string>
+    <string name="weekly">"Týdně (%s)"</string>
+    <string name="monthly">"Měsíčně"</string>
+    <string name="yearly">"Ročně"</string>
+    <!-- no translation found for VideoView_error_title (1024334251681931859) -->
+    <skip />
+    <!-- no translation found for VideoView_error_text_unknown (3398417247398476771) -->
+    <skip />
+    <!-- no translation found for VideoView_error_button (3144127115413163445) -->
+    <skip />
+    <string name="am">"dop."</string>
+    <string name="pm">"odp."</string>
+    <!-- no translation found for numeric_date (5120078478872821100) -->
+    <skip />
+    <!-- no translation found for wday1_date1_time1_wday2_date2_time2 (7066878981949584861) -->
+    <skip />
+    <!-- no translation found for wday1_date1_wday2_date2 (8671068747172261907) -->
+    <skip />
+    <!-- no translation found for date1_time1_date2_time2 (3645498975775629615) -->
+    <skip />
+    <!-- no translation found for date1_date2 (377057563556488062) -->
+    <skip />
+    <!-- no translation found for time1_time2 (3173474242109288305) -->
+    <skip />
+    <!-- no translation found for time_wday_date (8928955562064570313) -->
+    <skip />
+    <!-- no translation found for wday_date (8794741400546136975) -->
+    <skip />
+    <!-- no translation found for time_date (1922644512833014496) -->
+    <skip />
+    <!-- no translation found for time_wday (1422050241301754712) -->
+    <skip />
+    <!-- no translation found for full_date_month_first (6011143962222283357) -->
+    <skip />
+    <!-- no translation found for full_date_day_first (8621594762705478189) -->
+    <skip />
+    <!-- no translation found for medium_date_month_first (48990963718825728) -->
+    <skip />
+    <!-- no translation found for medium_date_day_first (2898992016440387123) -->
+    <skip />
+    <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
+    <skip />
+    <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
+    <skip />
+    <!-- no translation found for noon (8390796001560682897) -->
+    <skip />
+    <!-- no translation found for Noon (7698941576181064429) -->
+    <skip />
+    <!-- no translation found for midnight (7773339795626486146) -->
+    <skip />
+    <!-- no translation found for Midnight (1260172107848123187) -->
+    <skip />
+    <!-- no translation found for month_day (3356633704511426364) -->
+    <skip />
+    <!-- no translation found for month (3017405760734206414) -->
+    <skip />
+    <!-- no translation found for month_day_year (2435948225709176752) -->
+    <skip />
+    <!-- no translation found for month_year (6228414124777343135) -->
+    <skip />
+    <!-- no translation found for time_of_day (8375993139317154157) -->
+    <skip />
+    <!-- no translation found for date_and_time (9197690194373107109) -->
+    <skip />
+    <!-- no translation found for same_year_md1_md2 (9199324363135981317) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_md1_wday2_md2 (6006392413355305178) -->
+    <skip />
+    <!-- no translation found for same_year_mdy1_mdy2 (1576657593937827090) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_mdy1_wday2_mdy2 (9135935796468891580) -->
+    <skip />
+    <!-- no translation found for same_year_md1_time1_md2_time2 (2172964106375558081) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_md1_time1_wday2_md2_time2 (1702879534101786310) -->
+    <skip />
+    <!-- no translation found for same_year_mdy1_time1_mdy2_time2 (2476443311723358767) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_mdy1_time1_wday2_mdy2_time2 (1564837340334069879) -->
+    <skip />
+    <!-- no translation found for numeric_md1_md2 (8908376522875100300) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_md1_wday2_md2 (3239690882018292077) -->
+    <skip />
+    <!-- no translation found for numeric_mdy1_mdy2 (8883797176939233525) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_mdy1_wday2_mdy2 (4150475769255828954) -->
+    <skip />
+    <!-- no translation found for numeric_md1_time1_md2_time2 (3624746590607741419) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_md1_time1_wday2_md2_time2 (4258040955467298134) -->
+    <skip />
+    <!-- no translation found for numeric_mdy1_time1_mdy2_time2 (3598215409314517987) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_mdy1_time1_wday2_mdy2_time2 (264076937155877259) -->
+    <skip />
+    <!-- no translation found for same_month_md1_md2 (2393563617438036111) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_md1_wday2_md2 (1208946773794057819) -->
+    <skip />
+    <!-- no translation found for same_month_mdy1_mdy2 (3713236637869030492) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_mdy1_wday2_mdy2 (389638922479870472) -->
+    <skip />
+    <!-- no translation found for same_month_md1_time1_md2_time2 (7477075526337542685) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_md1_time1_wday2_md2_time2 (3516978303779391173) -->
+    <skip />
+    <!-- no translation found for same_month_mdy1_time1_mdy2_time2 (7320410992514057310) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_mdy1_time1_wday2_mdy2_time2 (1332950588774239228) -->
+    <skip />
+    <!-- no translation found for abbrev_month_day_year (5767271534015320250) -->
+    <skip />
+    <!-- no translation found for abbrev_month_year (8058929633673942490) -->
+    <skip />
+    <!-- no translation found for abbrev_month_day (458867920693482757) -->
+    <skip />
+    <!-- no translation found for abbrev_month (1674509986330181349) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_sunday (9057662850446501884) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_monday (7358451993082888343) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_tuesday (2282901451170509613) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_wednesday (2100217950343286482) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_thursday (5475158963242863176) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_friday (4081018004819837155) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_saturday (1929694088305891795) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_sunday (6462580883948669820) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_monday (6960587654241349502) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_tuesday (7004462235990108936) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_wednesday (5688564741951314696) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_thursday (1784339868453982400) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_friday (4314577583604069357) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_saturday (70321191398427845) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_sunday (7403409454572591357) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_monday (5278358100012478239) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_tuesday (5121116040712487059) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_wednesday (1601079579293330319) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_thursday (5863422096017401812) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_friday (2916686031099723960) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_saturday (8521564973195542073) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_sunday (1650484495176707638) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_monday (9133193697786876074) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_tuesday (4012095408481489663) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_wednesday (6279056612496078470) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_thursday (2748599403545071011) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_friday (5037282109124849673) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_saturday (3208167155877833783) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_sunday (4683862964821549758) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_monday (6701142261471667000) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_tuesday (9098171980161292477) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_wednesday (655049238289460956) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_thursday (7816913627500884083) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_friday (903301878650619398) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_saturday (5359692489649817988) -->
+    <skip />
+    <!-- no translation found for month_long_january (7128497801440564337) -->
+    <skip />
+    <!-- no translation found for month_long_february (7808570514581190617) -->
+    <skip />
+    <!-- no translation found for month_long_march (2061328556983796034) -->
+    <skip />
+    <!-- no translation found for month_long_april (6575007959043269919) -->
+    <skip />
+    <!-- no translation found for month_long_may (8404051103463071121) -->
+    <skip />
+    <!-- no translation found for month_long_june (6255771619238859451) -->
+    <skip />
+    <!-- no translation found for month_long_july (4129177743136800884) -->
+    <skip />
+    <!-- no translation found for month_long_august (5494331003296804494) -->
+    <skip />
+    <!-- no translation found for month_long_september (2691137479752033087) -->
+    <skip />
+    <!-- no translation found for month_long_october (7501261567327243313) -->
+    <skip />
+    <!-- no translation found for month_long_november (8759690753068763664) -->
+    <skip />
+    <!-- no translation found for month_long_december (4505008719696569497) -->
+    <skip />
+    <!-- no translation found for month_medium_january (2315492772833932512) -->
+    <skip />
+    <!-- no translation found for month_medium_february (118412521324313430) -->
+    <skip />
+    <!-- no translation found for month_medium_march (5546835583839352358) -->
+    <skip />
+    <!-- no translation found for month_medium_april (7052559668687733702) -->
+    <skip />
+    <!-- no translation found for month_medium_may (2825303871720116018) -->
+    <skip />
+    <!-- no translation found for month_medium_june (829843667101495271) -->
+    <skip />
+    <!-- no translation found for month_medium_july (5029778226925324789) -->
+    <skip />
+    <!-- no translation found for month_medium_august (8851230594641162805) -->
+    <skip />
+    <!-- no translation found for month_medium_september (8420590486625304647) -->
+    <skip />
+    <!-- no translation found for month_medium_october (1787382806172930239) -->
+    <skip />
+    <!-- no translation found for month_medium_november (675513809622370603) -->
+    <skip />
+    <!-- no translation found for month_medium_december (2934948295928978783) -->
+    <skip />
+    <!-- no translation found for month_shortest_january (6070060405144675883) -->
+    <skip />
+    <!-- no translation found for month_shortest_february (5632605004902176653) -->
+    <skip />
+    <!-- no translation found for month_shortest_march (4304231552356086624) -->
+    <skip />
+    <!-- no translation found for month_shortest_april (1166434066469385532) -->
+    <skip />
+    <!-- no translation found for month_shortest_may (9131326028845529001) -->
+    <skip />
+    <!-- no translation found for month_shortest_june (1875723154506665289) -->
+    <skip />
+    <!-- no translation found for month_shortest_july (2003596275389810773) -->
+    <skip />
+    <!-- no translation found for month_shortest_august (9120245162625763214) -->
+    <skip />
+    <!-- no translation found for month_shortest_september (7980651111022693669) -->
+    <skip />
+    <!-- no translation found for month_shortest_october (3640405450427788312) -->
+    <skip />
+    <!-- no translation found for month_shortest_november (4002935318566146993) -->
+    <skip />
+    <!-- no translation found for month_shortest_december (6213739417171334040) -->
+    <skip />
+    <!-- no translation found for elapsed_time_short_format_mm_ss (1294409362352514646) -->
+    <skip />
+    <!-- no translation found for elapsed_time_short_format_h_mm_ss (2997059666628785039) -->
+    <skip />
+    <!-- no translation found for selectAll (691691810023908884) -->
+    <skip />
+    <!-- no translation found for cut (5845613239192595662) -->
+    <skip />
+    <!-- no translation found for cutAll (4474519683293791451) -->
+    <skip />
+    <!-- no translation found for copy (8603721575469529820) -->
+    <skip />
+    <!-- no translation found for copyAll (4777548804630476932) -->
+    <skip />
+    <!-- no translation found for paste (6458036735811828538) -->
+    <skip />
+    <!-- no translation found for copyUrl (5785708478767435812) -->
+    <skip />
+    <!-- no translation found for inputMethod (7911866729148111492) -->
+    <skip />
+    <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_title (5997772070488639934) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_text (2230118755295375293) -->
+    <skip />
+    <!-- no translation found for ok (4003878536083514869) -->
+    <skip />
+    <!-- no translation found for cancel (1527674037280267012) -->
+    <skip />
+    <!-- no translation found for yes (8185296114406773873) -->
+    <skip />
+    <!-- no translation found for no (2300685350903156262) -->
+    <skip />
+    <!-- no translation found for capital_on (8418242581217554942) -->
+    <skip />
+    <!-- no translation found for capital_off (8870368560477693851) -->
+    <skip />
+    <!-- no translation found for whichApplication (2828159696176255212) -->
+    <skip />
+    <!-- no translation found for alwaysUse (6433627451071144629) -->
+    <skip />
+    <!-- no translation found for clearDefaultHintMsg (5742432113023174321) -->
+    <skip />
+    <!-- no translation found for chooseActivity (7588691622928031978) -->
+    <skip />
+    <!-- no translation found for noApplications (4068560364116066745) -->
+    <skip />
+    <!-- no translation found for aerr_title (2654390351574026098) -->
+    <skip />
+    <!-- no translation found for aerr_application (4917288809565116720) -->
+    <skip />
+    <!-- no translation found for aerr_process (1273819861108073461) -->
+    <skip />
+    <!-- no translation found for anr_title (3305935690891435915) -->
+    <skip />
+    <!-- no translation found for anr_activity_application (1653036325679156678) -->
+    <skip />
+    <!-- no translation found for anr_activity_process (2674027618362070465) -->
+    <skip />
+    <!-- no translation found for anr_application_process (2163656674970221928) -->
+    <skip />
+    <!-- no translation found for anr_process (7747550780123472160) -->
+    <skip />
+    <!-- no translation found for force_close (9020954128872810669) -->
+    <skip />
+    <!-- no translation found for wait (7973775702304037058) -->
+    <skip />
+    <!-- no translation found for debug (857932504764728770) -->
+    <skip />
+    <!-- no translation found for sendText (6158329286172492543) -->
+    <skip />
+    <!-- no translation found for volume_ringtone (4121694816346562058) -->
+    <skip />
+    <!-- no translation found for volume_music (4869950240104717493) -->
+    <skip />
+    <!-- no translation found for volume_call (5723421277753250395) -->
+    <skip />
+    <!-- no translation found for volume_alarm (2752102730973081294) -->
+    <skip />
+    <!-- no translation found for volume_unknown (6908187627672375742) -->
+    <skip />
+    <!-- no translation found for ringtone_default (2873893375149093475) -->
+    <skip />
+    <!-- no translation found for ringtone_default_with_actual (5474076151665761913) -->
+    <skip />
+    <!-- no translation found for ringtone_silent (7477159279081654685) -->
+    <skip />
+    <!-- no translation found for ringtone_picker_title (7055241890764367884) -->
+    <skip />
+    <!-- no translation found for ringtone_unknown (6888219771401173795) -->
+    <skip />
+    <!-- no translation found for wifi_available:one (8168012881468888470) -->
+    <!-- no translation found for wifi_available:other (4666122955807117718) -->
+    <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
+    <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
+    <!-- no translation found for select_character (3735110139249491726) -->
+    <skip />
+    <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
+    <skip />
+    <!-- no translation found for sms_control_title (2742400596989418394) -->
+    <skip />
+    <!-- no translation found for sms_control_message (3447126217666595989) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (8839660939359273650) -->
+    <skip />
+    <!-- no translation found for sms_control_no (909756849988183801) -->
+    <skip />
+    <!-- no translation found for date_time_set (2495199891239480952) -->
+    <skip />
+    <!-- no translation found for default_permission_group (7742780381379652409) -->
+    <skip />
+    <!-- no translation found for no_permissions (85461124044682315) -->
+    <skip />
+    <!-- no translation found for perms_hide (4145325555929151849) -->
+    <skip />
+    <!-- no translation found for perms_show_all (6040194843455403173) -->
+    <skip />
+    <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
+    <skip />
+    <!-- no translation found for usb_storage_title (8699631567051394409) -->
+    <skip />
+    <!-- no translation found for usb_storage_message (5344039189213308733) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
+    <skip />
+    <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
+    <skip />
+    <!-- no translation found for select_input_method (2658280517827502015) -->
+    <skip />
+    <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
+    <skip />
+    <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
+    <skip />
+    <!-- no translation found for candidates_style (7738463880139922176) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de-rDE/strings.xml b/core/res/res/values-de-rDE/strings.xml
deleted file mode 100644
index aafe7e5..0000000
--- a/core/res/res/values-de-rDE/strings.xml
+++ /dev/null
@@ -1,767 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="BaMmi">Anrufsperre</string>
-  <string name="CLIRDefaultOffNextCallOff">Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt</string>
-  <string name="CLIRDefaultOffNextCallOn">Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Beschränkt</string>
-  <string name="CLIRDefaultOnNextCallOff">Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Nicht beschränkt</string>
-  <string name="CLIRDefaultOnNextCallOn">Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Beschränkt</string>
-  <string name="CLIRPermanent">Die Einstellung der Anrufer-ID kann nicht geändert werden.</string>
-  <string name="CfMmi">Rufumleitung</string>
-  <string name="ClipMmi">Anrufer-ID von eingehendem Anrufer</string>
-  <string name="ClirMmi">Anrufer-ID bei ausgehendem Anruf</string>
-  <string name="CwMmi">Anklopfen</string>
-  <string name="Midnight">"Mitternacht"</string>
-  <string name="Noon">"Mittag"</string>
-  <string name="PinMmi">PIN-Änderung</string>
-  <string name="PwdMmi">Kennwortänderung</string>
-  <string name="VideoView_error_button">OK</string>
-  <string name="VideoView_error_text_unknown">Dieses Video kann leider nicht abgespielt werden.</string>
-  <string name="VideoView_error_title">Video kann nicht abgespielt werden</string>
-  <string name="abbrev_month">"<xliff:g id="format">%b</xliff:g>"</string>
-  <string name="abbrev_month_day">"<xliff:g id="format">%b %-d</xliff:g>"</string>
-  <string name="abbrev_month_day_year">"<xliff:g id="format">%b %-d, %Y</xliff:g>"</string>
-  <string name="abbrev_month_year">"<xliff:g id="format">%b %Y</xliff:g>"</string>
-  <string name="activate_keyguard">Displaysperre</string>
-  <string name="aerr_application">Die Anwendung <xliff:g id="application">%1$s</xliff:g>
-        (Vorgang <xliff:g id="process">%2$s</xliff:g>) wurde unerwartet angehalten. Versuchen Sie es noch einmal.</string>
-  <string name="aerr_process">Der Vorgang <xliff:g id="process">%1$s</xliff:g> wurde
-        unerwartet angehalten. Versuchen Sie es noch einmal.</string>
-  <string name="aerr_title">Verzeihung!</string>
-  <string name="ago">zuvor</string>
-  <string name="alwaysUse">Standardmäßig für diese Aktion verwenden.</string>
-  <string name="am">"AM"</string>
-  <string name="anr_activity_application">Keine Reaktion bei Aktivität <xliff:g id="activity">%1$s</xliff:g> (in Anwendung <xliff:g id="application">%2$s</xliff:g>).</string>
-  <string name="anr_activity_process">Aktivität <xliff:g id="activity">%1$s</xliff:g> (in Vorgang <xliff:g id="process">%2$s</xliff:g>), keine Reaktion.</string>
-  <string name="anr_application_process">Keine Reaktion bei Anwendung <xliff:g id="application">%1$s</xliff:g> (in Vorgang <xliff:g id="process">%2$s</xliff:g>).</string>
-  <string name="anr_process">Vorgang <xliff:g id="process">%1$s</xliff:g>, keine Reaktion.</string>
-  <string name="anr_title">Keine Reaktion bei Anwendung</string>
-  <string name="badPin">Die alte PIN wurde falsch eingegeben.</string>
-  <string name="badPuk">Der PUK wurde falsch eingegeben.</string>
-  <string name="battery_low_percent_format">weniger als <xliff:g id="number">%d%%</xliff:g>
-    verbleiben.</string>
-  <string name="battery_low_subtitle">Die Akkuladung geht zur Neige:</string>
-  <string name="battery_low_title">Schließen Sie Ladegerät an</string>
-  <string name="battery_status_charging">Laden\u2026</string>
-  <string name="battery_status_text_percent_format"><xliff:g id="number">%d%%</xliff:g></string>
-  <string name="before">Vorher</string>
-  <string name="browserSavedFormData">Formulardaten gespeichert.</string>
-  <string name="byteShort">B</string>
-  <string name="cancel">Abbrechen</string>
-  <string name="capital_off">AUS</string>
-  <string name="capital_on">EIN</string>
-  <string name="cfReasonBusy">Rufumleitung - Wenn besetzt</string>
-  <string name="cfReasonNR">Rufumleitung - Wenn nicht erreichbar</string>
-  <string name="cfReasonNRy">Rufumleitung - Bei keiner Antwort</string>
-  <string name="cfReasonUnconditional">Rufumleitung - Immer</string>
-  <string name="cfTemplateForwarded">{0}: {1}</string>
-  <string name="cfTemplateForwardedTime">{0}: {1} nach {2} Sek.</string>
-  <string name="cfTemplateNotForwarded">{0}: Nicht umgeleitet</string>
-  <string name="cfTemplateRegistered">{0}: Nicht umgeleitet</string>
-  <string name="cfTemplateRegisteredTime">{0}: Nicht umgeleitet</string>
-  <string name="chooseActivity">Aktion auswählen</string>
-  <string name="clearDefaultHintMsg">Löschen Sie Standardeinstellung unter Startseiteneinstellungen &gt; Anwendungen &gt; Anwendungen verwalten.</string>
-  <string name="compass_accuracy_banner">Kompass erfordert Kalibration</string>
-  <string name="compass_accuracy_notificaction_body">Beschreiben Sie mit dem Telefon eine 8, um den Kompass zu kalibrieren.</string>
-  <string name="compass_accuracy_notificaction_title">Kompass kalibrieren</string>
-  <string name="contentServiceSync">Synchr.</string>
-  <string name="contentServiceSyncErrorNotificationDesc">Bei der Synchronisierung kommt es zu Problemen.</string>
-  <string name="contentServiceSyncNotificationDesc">Synchr.</string>
-  <string name="contentServiceSyncNotificationTitle">Synchr.</string>
-  <string name="contentServiceTooManyDeletesNotificationDesc">Zu viele %s Löschungen</string>
-  <string name="contentServiceXmppAvailable">XMPP Active</string>
-  <string name="copy">Kopieren</string>
-  <string name="copyAll">Alle kopieren</string>
-  <string name="copyUrl">URL kopieren</string>
-  <string name="cut">Ausschneiden</string>
-  <string name="cutAll">Alle ausschneiden</string>
-  <string name="daily">Täglich</string>
-  <string name="daily_format">h:mm aa</string>
-  <string name="date1_date2">"<xliff:g id="format">%2$s \u2013 %5$s</xliff:g>"</string>
-  <string name="date1_time1_date2_time2">"<xliff:g id="format">%2$s, %3$s \u2013 %5$s, %6$s</xliff:g>"</string>
-  <string name="date_picker_month">Monat</string>
-  <string name="date_picker_set">Einstellen</string>
-  <string name="date_range_separator">" \u2013 "</string>
-  <string name="date_time_set">Einstellen</string>
-  <string name="day">Tag</string>
-  <string name="day_of_week_long_friday">Freitag</string>
-  <string name="day_of_week_long_monday">Montag</string>
-  <string name="day_of_week_long_saturday">Samstag</string>
-  <string name="day_of_week_long_sunday">Sonntag</string>
-  <string name="day_of_week_long_thursday">Donnerstag</string>
-  <string name="day_of_week_long_tuesday">Dienstag</string>
-  <string name="day_of_week_long_wednesday">Mittwoch</string>
-  <string name="day_of_week_medium_friday">Fre.</string>
-  <string name="day_of_week_medium_monday">Mon.</string>
-  <string name="day_of_week_medium_saturday">Sam.</string>
-  <string name="day_of_week_medium_sunday">Son.</string>
-  <string name="day_of_week_medium_thursday">Don.</string>
-  <string name="day_of_week_medium_tuesday">Die.</string>
-  <string name="day_of_week_medium_wednesday">Mit.</string>
-  <string name="day_of_week_short_friday">Fr</string>
-  <string name="day_of_week_short_monday">Mo</string>
-  <string name="day_of_week_short_saturday">Sa</string>
-  <string name="day_of_week_short_sunday">So</string>
-  <string name="day_of_week_short_thursday">Do</string>
-  <string name="day_of_week_short_tuesday">Di</string>
-  <string name="day_of_week_short_wednesday">Mi</string>
-  <string name="day_of_week_shorter_friday">F</string>
-  <string name="day_of_week_shorter_monday">M</string>
-  <string name="day_of_week_shorter_saturday">Sa</string>
-  <string name="day_of_week_shorter_sunday">So</string>
-  <string name="day_of_week_shorter_thursday">Do</string>
-  <string name="day_of_week_shorter_tuesday">Di</string>
-  <string name="day_of_week_shorter_wednesday">M</string>
-  <string name="day_of_week_shortest_friday">F</string>
-  <string name="day_of_week_shortest_monday">M</string>
-  <string name="day_of_week_shortest_saturday">S</string>
-  <string name="day_of_week_shortest_sunday">S</string>
-  <string name="day_of_week_shortest_thursday">D</string>
-  <string name="day_of_week_shortest_tuesday">D</string>
-  <string name="day_of_week_shortest_wednesday">M</string>
-  <string name="days">Tage</string>
-  <string name="daysDurationFuturePlural">in <xliff:g id="days">%d</xliff:g> Tagen</string>
-  <string name="daysDurationPastPlural">vor <xliff:g id="days">%d</xliff:g> Tagen</string>
-  <string name="debug">Debug</string>
-  <string name="defaultMsisdnAlphaTag">MSISDN1</string>
-  <string name="defaultVoiceMailAlphaTag">Mailbox</string>
-  <string name="default_permission_group">Standard</string>
-  <string name="elapsed_time_short_format_h_mm_ss"><xliff:g id="format">%1$d:%2$02d:%3$02d</xliff:g></string>
-  <string name="elapsed_time_short_format_mm_ss"><xliff:g id="format">%1$02d:%2$02d</xliff:g></string>
-  <string name="ellipsis">\u2026</string>
-  <string name="emergency_call_dialog_call">Notruf</string>
-  <string name="emergency_call_dialog_cancel">Abbrechen</string>
-  <string name="emergency_call_dialog_number_for_display">Notrufnummer</string>
-  <string name="emergency_call_dialog_text">Notruf absetzen?</string>
-  <string name="emergency_call_number_uri">Tel:112</string>
-  <string name="emptyPhoneNumber">(Keine Telefonnummer)</string>
-  <string name="every_weekday">"Jeden Wochentag (Mon\u2013Fre)"</string>
-  <string name="factorytest_failed">Werkstest fehlgeschlagen</string>
-  <string name="factorytest_no_action">Es wurde kein Paket gefunden, dass die 
-        FACTORY_TEST-Aktion bereitstellt.</string>
-  <string name="factorytest_not_system">Die FACTORY_TEST-Aktion 
-        wird nur für Pakete unterstützt, die unter /system/app installiert sind.</string>
-  <string name="factorytest_reboot">Neustart</string>
-  <string name="force_close">Erzwungene Beendigung</string>
-  <string name="friday">Freitag</string>
-  <string name="gigabyteShort">GB</string>
-  <string name="global_action_lock">Displaysperre</string>
-  <string name="global_action_power_off">Ausschalten</string>
-  <string name="global_action_silent_mode_off_status">Sound ist EIN</string>
-  <string name="global_action_silent_mode_on_status">Sound ist AUS</string>
-  <string name="global_action_toggle_silent_mode">Lautlosmodus</string>
-  <string name="global_actions">Telefonoptionen</string>
-  <string name="hour">Stunde</string>
-  <string name="hours">Stunden</string>
-  <string name="httpError">Die Webseite enthält einen Fehler.</string>
-  <string name="httpErrorAuth">Die Authentifizierung war nicht erfolgreich.</string>
-  <string name="httpErrorBadUrl">Die Seite konnte nicht geöffnet werden, da die URL nicht gültig ist.</string>
-  <string name="httpErrorConnect">Die Verbindung zum Server war nicht erfolgreich.</string>
-  <string name="httpErrorFailedSslHandshake">Eine sichere Verbindung konnte nicht hergestellt werden.</string>
-  <string name="httpErrorFile">Zugriff auf die Datei war nicht möglich.</string>
-  <string name="httpErrorFileNotFound">Die angeforderte Datei wurde nicht gefunden.</string>
-  <string name="httpErrorIO">Kommunikation mit dem Server nicht möglich. Versuchen Sie es später noch einmal.</string>
-  <string name="httpErrorLookup">Die URL konnte nicht gefunden werden.</string>
-  <string name="httpErrorOk">OK</string>
-  <string name="httpErrorProxyAuth">Die Authentifizierung über den Proxy-Server war nicht erfolgreich.</string>
-  <string name="httpErrorRedirectLoop">Die Seite enthält zu viele Server-Umleitungen.</string>
-  <string name="httpErrorTimeout">Die Zeit für die Verbindung zum Server ist abgelaufen.</string>
-  <string name="httpErrorTooManyRequests">Es werden zu viele Aufgaben verabeitet. Versuchen Sie es später noch einmal.</string>
-  <string name="httpErrorUnsupportedAuthScheme">Das Schema für die Seitenauthentifizierung wird nicht unterstützt.</string>
-  <string name="httpErrorUnsupportedScheme">Das Protokoll wird nicht unterstützt.</string>
-  <string name="in">in</string>
-  <string name="invalidPin">Geben Sie eine PIN mit 4 bis 8 Stellen ein.</string>
-  <string name="keyguard_label_text">Drücken Sie zum Entsperren erst Menü und dann 0.</string>
-  <string name="keyguard_password_emergency_instructions">Anrufen-Taste drücken, um Notruf abzusetzen.</string>
-  <string name="keyguard_password_enter_pin_code">PIN-Code eingeben:</string>
-  <string name="keyguard_password_instructions">Passwort eingeben oder Notrufnummer wählen.</string>
-  <string name="keyguard_password_wrong_pin_code">Falscher PIN-Code!</string>
-  <string name="kilobyteShort">KB</string>
-  <string name="lockscreen_carrier_default">(Kein Dienst)</string>
-  <string name="lockscreen_carrier_key">gsm.operator.alpha</string>
-  <string name="lockscreen_emergency_call">Notruf</string>
-  <string name="lockscreen_failed_attempts_almost_glogin">
-        Sie haben das Entsperrmuster <xliff:g id="number">%d</xliff:g> Mal falsch gezeichnet.
-       Nach <xliff:g id="number">%d</xliff:g> weiteren nicht erfolgreichen Versuchen,
-       werden Sie aufgefordert das Gerät mit der Google-Anmeldung zu entsperren.\n\n
-      Versuchen Sie es bitte in <xliff:g id="number">%d</xliff:g> Sekunden noch einmal.
-    </string>
-  <string name="lockscreen_forgot_pattern_button_text">Muster vergessen?</string>
-  <string name="lockscreen_glogin_instructions">Um das Gerät zu entsperren,\nmelden Sie sich mit Ihrem Google-Konto an:</string>
-  <string name="lockscreen_glogin_invalid_input">Ungültiger Benutzername oder ungültiges Kennwort.</string>
-  <string name="lockscreen_glogin_password_hint">Kennwort</string>
-  <string name="lockscreen_glogin_submit_button">Anmelden</string>
-  <string name="lockscreen_glogin_too_many_attempts">Zu viele Musterversuche!</string>
-  <string name="lockscreen_glogin_username_hint">Benutzername (E-Mail)</string>
-  <string name="lockscreen_instructions_when_pattern_disabled">Zum Entsperren Menü drücken.</string>
-  <string name="lockscreen_instructions_when_pattern_enabled">Zum Entsperren oder Absetzen von Notruf Menü drücken.</string>
-  <string name="lockscreen_low_battery">Schließen Sie Ladegerät an.</string>
-  <string name="lockscreen_missing_sim_instructions">Bitte SIM-Karte einsetzen.</string>
-  <string name="lockscreen_missing_sim_message">Keine SIM-Karte im Telefon.</string>
-  <string name="lockscreen_missing_sim_message_short">Keine SIM-Karte.</string>
-  <string name="lockscreen_pattern_correct">Korrekt!</string>
-  <string name="lockscreen_pattern_instructions">Zum Entsperren Muster zeichnen:</string>
-  <string name="lockscreen_pattern_wrong">Versuchen Sie es erneut:</string>
-  <string name="lockscreen_plugged_in">Laden… (<xliff:g id="number">%d%%</xliff:g>)</string>
-  <string name="lockscreen_screen_locked">Display gesperrt</string>
-  <string name="lockscreen_sim_locked_message">SIM-Karte gesperrt.</string>
-  <string name="lockscreen_sim_puk_locked_instructions">Wenden Sie sich an den Kundendienst.</string>
-  <string name="lockscreen_sim_puk_locked_message">SIM-Karte ist mit PUK gesperrt.</string>
-  <string name="lockscreen_sim_unlock_progress_dialog_message">Entsperrung von SIM-Karte\u2026</string>
-  <string name="lockscreen_too_many_failed_attempts_countdown">In <xliff:g id="number">%d</xliff:g> Sekunden erneut versuchen</string>
-  <string name="lockscreen_too_many_failed_attempts_dialog_message">
-        Sie haben das Entsperrmuster <xliff:g id="number">%d</xliff:g> Mal falsch gezeichnet.
-        \n\nIn <xliff:g id="number">%d</xliff:g> Sekunden erneut versuchen.
-    </string>
-  <string name="lockscreen_too_many_failed_attempts_dialog_title">Warnhinweis zum Sperrmuster</string>
-  <string name="low_internal_storage_text">Interner Speicherplatz gering.</string>
-  <string name="low_internal_storage_view_text">Der interne Speicherplatz im Telefon ist gering.</string>
-  <string name="low_internal_storage_view_title">Speicherplatz gering</string>
-  <string name="low_memory">Telefonspeicher voll! Löschen Sie einige Dateien um Speicherplatz bereitzustellen.</string>
-  <string name="me">Mich</string>
-  <string name="megabyteShort">MB</string>
-  <string name="midnight">"Mitternacht"</string>
-  <string name="minute">Min</string>
-  <string name="minutes">Min</string>
-  <string name="mismatchPin">Die eingegebenen PINs stimmen nicht überein.</string>
-  <string name="mmiComplete">MMI komplett.</string>
-  <string name="mmiError">Fehler bei Verbindung oder ungültiger MMI-Code.</string>
-  <string name="monday">Montag</string>
-  <string name="month">"<xliff:g id="format">%B</xliff:g>"</string>
-  <string name="month_day">"<xliff:g id="format">%B %-d</xliff:g>"</string>
-  <string name="month_day_year">"<xliff:g id="format">%B %-d, %Y</xliff:g>"</string>
-  <string name="month_long_april">April</string>
-  <string name="month_long_august">August</string>
-  <string name="month_long_december">Dezember</string>
-  <string name="month_long_february">Februar</string>
-  <string name="month_long_january">Januar</string>
-  <string name="month_long_july">Juli</string>
-  <string name="month_long_june">Juni</string>
-  <string name="month_long_march">März</string>
-  <string name="month_long_may">Mai</string>
-  <string name="month_long_november">November</string>
-  <string name="month_long_october">Oktober</string>
-  <string name="month_long_september">September</string>
-  <string name="month_medium_april">Apr</string>
-  <string name="month_medium_august">Aug</string>
-  <string name="month_medium_december">Dez</string>
-  <string name="month_medium_february">Feb</string>
-  <string name="month_medium_january">Jan</string>
-  <string name="month_medium_july">Jul</string>
-  <string name="month_medium_june">Jun</string>
-  <string name="month_medium_march">Mär</string>
-  <string name="month_medium_may">Mai</string>
-  <string name="month_medium_november">Nov</string>
-  <string name="month_medium_october">Okt</string>
-  <string name="month_medium_september">Sep</string>
-  <string name="month_shortest_april">A</string>
-  <string name="month_shortest_august">A</string>
-  <string name="month_shortest_december">D</string>
-  <string name="month_shortest_february">F</string>
-  <string name="month_shortest_january">J</string>
-  <string name="month_shortest_july">J</string>
-  <string name="month_shortest_june">J</string>
-  <string name="month_shortest_march">M</string>
-  <string name="month_shortest_may">M</string>
-  <string name="month_shortest_november">N</string>
-  <string name="month_shortest_october">O</string>
-  <string name="month_shortest_september">S</string>
-  <string name="month_year">"<xliff:g id="format">%B %Y</xliff:g>"</string>
-  <string name="monthly">Monatlich</string>
-  <string name="monthly_format">MMM d</string>
-  <string name="more_item_label">Weitere</string>
-  <string name="needPuk2">Geben Sie die PUK2 ein, um die SIM-Karte zu entsperren.</string>
-  <string name="no">Abbrechen</string>
-  <string name="noApplications">Keine Anwendungen können diese Aktion durchführen.</string>
-  <string name="no_permissions">Keine Genehmigungen erforderlich</string>
-  <string name="no_recent_tasks">Keine letzten Anwendungen.</string>
-  <string name="noon">"Mittag"</string>
-  <string name="numeric_date">"<xliff:g id="format">%m/%d/%Y</xliff:g>"</string>
-  <string name="numeric_date_notation">"<xliff:g id="format">%m/%d/%y</xliff:g>"</string>
-  <string name="numeric_md1_md2">"<xliff:g id="format">%2$s/%3$s \u2013 %7$s/%8$s</xliff:g>"</string>
-  <string name="numeric_md1_time1_md2_time2">"<xliff:g id="format">%2$s/%3$s, %5$s \u2013 %7$s/%8$s, %10$s</xliff:g>"</string>
-  <string name="numeric_mdy1_mdy2">"<xliff:g id="format">%2$s/%3$s/%4$s \u2013 %7$s/%8$s/%9$s</xliff:g>"</string>
-  <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="format">%2$s/%3$s/%4$s, %5$s \u2013 %7$s/%8$s/%9$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %2$s/%3$s, %5$s \u2013 %6$s, %7$s/%8$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %2$s/%3$s \u2013 %6$s, %7$s/%8$s</xliff:g>"</string>
-  <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %2$s/%3$s/%4$s, %5$s \u2013 %6$s, %7$s/%8$s/%9$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %2$s/%3$s/%4$s \u2013 %6$s, %7$s/%8$s/%9$s</xliff:g>"</string>
-  <string name="ok">OK</string>
-  <string name="oneMonthDurationPast">Vor 1 Monat</string>
-  <string name="open_permission_deny">Sie haben keine Genehmigung zum Öffnen dieser Seite.</string>
-  <string name="passwordIncorrect">Falsches Kennwort.</string>
-  <string name="paste">Einfügen</string>
-  <string name="permdesc_accessCoarseLocation">Greifen Sie auf ungefähre Ortsquellen wie z. B. die
-        Funknetzdatenbank zu, um den ungefähren Ort des Telefons zu ermitteln, sofern dies möglich ist. Schädliche Anwendungen
-        können dies nutzen, um zu ermitteln, wo Sie sich ungefähr befinden.</string>
-  <string name="permdesc_accessFineLocation">Greifen Sie auf genaue Ortsquellen wie z. B. das
-        GPS auf dem Telefon zu, sofern dies möglich ist.
-        Schädliche Anwendungen können dies nutzen, um zu ermitteln, wo Sie sich befinden, und dabei
-        zusätzlichen Akkustrom verbrauchen.</string>
-  <string name="permdesc_accessMockLocation">Erstellen Sie einen Scheinort zum Testen.
-        Schädliche Anwendungen können dies nutzen, um den Ort und/oder Status zu überschreiben, der von echten
-        Ortsquellen, z. B.  GPS- oder Netzbetreibern angegeben wird.</string>
-  <string name="permdesc_accessNetworkState">Ermöglicht einer Anwendung,
-      den Zustand aller Netze zu erkennen.</string>
-  <string name="permdesc_accessSurfaceFlinger">Ermöglicht einer Anwendung
-        SurfaceFlinger-Low-Level-Funktionen zu nutzen.</string>
-  <string name="permdesc_accessWifiState">Ermöglicht einer Anwendung,
-      Informationen über den Zustand von Wi-Fi zu erkennen.</string>
-  <string name="permdesc_addSystemService">Ermöglicht einer Anwendung
-        eigene Low-Level-Systemdienste zu veröffentlichen. Schädliche Anwendungen können dies nutzen, um auf das
-        System zuzugreifen und Daten darauf zu entwenden oder zu ändern.</string>
-  <string name="permdesc_batteryStats">Ermöglicht die Änderung
-        gesammelter Akkudaten. Nicht für die Verwendung durch gewöhnliche Anwendungen bestimmt.</string>
-  <string name="permdesc_bluetooth">Ermöglicht einer Anwendung die
-      Konfiguration des lokalen Bluetooth-Telefons anzuzeigen und Verbindungen
-      mit gekoppelten Geräten anzunehmen.</string>
-  <string name="permdesc_bluetoothAdmin">Ermöglicht einer Anwendung das
-      lokale Bluetooth-Telefon zu konfigurieren und entfernte Geräte zu erkennen und zu
-      koppeln.</string>
-  <string name="permdesc_brick">Ermöglicht einer Anwendung das
-        gesamte Telefon bleibend zu aktivieren. Dies ist sehr riskant.</string>
-  <string name="permdesc_broadcastPackageRemoved">Ermöglicht einer Anwendung
-        eine Benachrichtigung zu senden, dass ein Anwendungspaket entfernt wurde.
-        Schädliche Anwendungen können dies nutzen, um alle anderen ausgeführten
-        Anwendungen zu zerstören.</string>
-  <string name="permdesc_broadcastSticky">Ermöglicht einer Anwendung
-        Übertragungen zu senden, die nach Beendigung der Sendung erhalten bleiben.
-        Schädliche Anwendungen können das Telefon langsamer oder unzuverlässiger machen, indem sie es veranlassen zu
-        viel Speicher zu nutzen.</string>
-  <string name="permdesc_callPhone">Ermöglicht einer Anwendung
-        Telefonnummern ohne Ihr Eingreifen zu wählen. Schädliche Anwendungen können dies nutzen, um
-        unerwartete Anrufe auf Ihrer Rechnung erscheinen zu lassen. Der Anwendung wird hierbei nicht
-        ermöglicht Notrufe abzusetzen.</string>
-  <string name="permdesc_camera">Ermöglicht einer Anwendung Bilder mit der
-        Kamera aufzunehmen. Die Anwendung kann jederzeit Bilder
-        aufnehmen, die von der Kamera erfasst werden.</string>
-  <string name="permdesc_changeComponentState">Ermöglicht einer Anwendung zu ändern, ob eine
-        Komponente einer anderen Anwendung aktiviert ist oder nicht. Schädliche Anwendungen können dies nutzen,
-        um wichtige Telefonfunktionen zu deaktivieren. Seien Sie mit dieser Genehmigung vorsichtig, da es möglich ist
-        Anwendungskomponenten unbrauchbar, unzuverlässig oder instabil zu machen.
-    </string>
-  <string name="permdesc_changeConfiguration">Ermöglicht einer Anwendung
-        die aktuelle Konfiguration wie z. B. die lokale oder allgemeine Schriftgröße zu
-        ändern.</string>
-  <string name="permdesc_changeNetworkState">Ermöglicht einer Anwendung,
-      den Zustand der Netzkonnektivität zu ändern.</string>
-  <string name="permdesc_changeWifiState">Ermöglicht einer Anwendung, eine Verbindung
-      mit Wi-Fi-Zugangspunkten herzustellen bzw. die Verbindung zu trennen, und Änderungen an
-      konfigurierten Wi-Fi-Netzen vorzunehmen.</string>
-  <string name="permdesc_clearAppCache">Ermöglicht einer Anwendung zusätzlichen Telefonspeicher bereitzustellen,
-        in dem sie Dateien im Cache-Verzeichnis löscht. Der Zugriff ist in der
-        Regel stark auf Systemvorgänge beschränkt.</string>
-  <string name="permdesc_clearAppUserData">Ermöglicht einer Anwendung, Benutzerdaten zu löschen.</string>
-  <string name="permdesc_createNetworkSockets">Ermöglicht einer Anwendung,
-      Netz-Sockets zu erstellen.</string>
-  <string name="permdesc_deleteCacheFiles">Ermöglicht einer Anwendung
-        Cache-Dateien zu löschen.</string>
-  <string name="permdesc_deletePackages">Ermöglicht einer Anwendung
-        Android-Pakete zu löschen. Schädliche Anwendungen können dies nutzen, um wichtige Anwendungen zu löschen.</string>
-  <string name="permdesc_devicePower">Ermöglicht einer Anwendung das
-        Telefon ein- oder auszuschalten.</string>
-  <string name="permdesc_disableKeyguard">Ermöglicht einer Anwendung,
-      die Tastensperre und einen entsprechenden Kennwortschutz zu deaktivieren. Ein typisches Beispiel hierfür ist,
-      wenn das Telefon die Tastensperre bei einem eingehenden Anruf deaktiviert
-      und nach Beendigung des Gesprächs wieder aktiviert.</string>
-  <string name="permdesc_dump">Ermöglicht einer Anwendung den
-        internen Zustand des Systems abzurufen. Schädliche Anwendungen können dies nutzen, um eine Vielzahl
-        von privaten und sicheren Daten abzurufen, die Sie normalerweise
-        niemals benötigen.</string>
-  <string name="permdesc_expandStatusBar">Ermöglicht einer Anwendung,
-        die Statusleiste zu erweitern oder zu verkleinern.</string>
-  <string name="permdesc_factoryTest">Dies wird als ein Low-Level-Herstellertest durchgeführt,
-        bei dem Sie kompletten Zugriff auf die Telefonhardware erhalten. Steht nur zur Verfügung,
-        wenn ein Telefon im Herstellertestmodus verwendet wird.</string>
-  <string name="permdesc_flashlight">Ermöglicht einer Anwendung das
-        Blitzlicht zu steuern.</string>
-  <string name="permdesc_forceBack">Ermöglicht einer Anwendung eine
-        Aktivität im Vordergrund zu beenden und in den Hintergrund treten zu lassen.
-        Für normale Anwendungen sollte dies niemals nötig sein.</string>
-  <string name="permdesc_fotaUpdate">Ermöglicht einer Anwendung
-        Benachrichtigungen über bereitstehende Systemupdates zu empfangen und deren
-        Installation auszulösen. Schädliche Anwendungen können dies nutzen, um das System mit
-        nicht autorisierten Updates zu beschädigen oder den Aktualisierungsvorgang
-        zu stören.</string>
-  <string name="permdesc_getAccounts">Ermöglicht einer Anwendung
-      die Liste mit Konten abzurufen, die dem Telefon bekannt sind.</string>
-  <string name="permdesc_getPackageSize">Ermöglicht einer Anwendung,
-        Code, Daten und Cache-Größen abzurufen.</string>
-  <string name="permdesc_getTasks">Ermöglicht einer Anwendung Daten
-        über aktuelle und ausgeführte Aufgaben abzurufen. Schädliche Anwendungen
-        können dies nutzen, um private Daten anderer Anwendungen aufzufinden.</string>
-  <string name="permdesc_hardware_test">Ermöglicht einer Anwendung verschiedene
-        Peripheriegeräte zum Testen der Hardware zu steuern.</string>
-  <string name="permdesc_injectEvents">Ermöglicht einer Anwendung 
-        eigene Eingaben (z. B. Tastendruck) auf andere Anwendungen zu übertragen. Schädliche Anwendungen 
-        können dies nutzen, um die Kontrolle über das Telefon zu erhalten.</string>
-  <string name="permdesc_installPackages">Ermöglicht einer Anwendung neue oder aktualisierte
-        Android-Pakete zu installieren. Schädliche Anwendungen können dies nutzen, um neue Anwendungen mit willkürlichen 
-        umfangreichen Genehmigungen hinzuzufügen.</string>
-  <string name="permdesc_internalSystemWindow">Ermöglicht die Erstellung von
-        Fenstern, die für die Verwendung durch die interne Systemanwenderoberfläche bestimmt sind.
-        Dies wird für normale Anwendungen nicht benötigt.</string>
-  <string name="permdesc_manageAppTokens">Ermöglicht einer Anwendung
-        eigene Tokens zu erstellen und verwalten, wobei die normale
-        Z-Reihenfolge umgangen wird. Dies sollte für normale Anwendungen nicht erforderlich sein.</string>
-  <string name="permdesc_masterClear">Ermöglicht einer Anwendung das System komplett
-        auf seine Standardwerte zurückzusetzen. Dabei werden alle Daten,
-        Konfigurationen und installierten Anwendungen gelöscht.</string>
-  <string name="permdesc_modifyAudioSettings">Ermöglicht einer Anwendung
-        globale Audioeinstellungen wie z. B. Lautstärke und Routing zu ändern.</string>
-  <string name="permdesc_modifyPhoneState">Ermöglicht einer Anwendung die
-        Telefonfunktionen des Gerätes zu steuern. Eine Anwendung mit dieser Genehmigung kann zwischen
-        Netzen wechseln, den Telefonfunk ein- und ausschalten und andere Schritte durchführen, ohne dass Sie darüber
-        unterrichtet werden.</string>
-  <string name="permdesc_mount_unmount_filesystems">Ermöglicht einer Anwendung Dateisysteme für
-         Wechselspeicher zu installieren und deinstallieren.</string>
-  <string name="permdesc_persistentActivity">Ermöglicht einer Anwendung
-        eigene Teile zu blockieren, so dass das System sie nicht für andere
-        Anwendungen nutzen kann.</string>
-  <string name="permdesc_processOutgoingCalls">Ermöglicht einer Anwendung
-        ausgehende Anrufe zu verarbeiten und die gewählte Nummer zu ändern.
-        Schädliche Anwendungen können dies nutzen, um ausgehende Anrufe zu überwachen, umzuleiten oder zu unterbinden.</string>
-  <string name="permdesc_readCalendar">Ermöglicht einer Anwendung alle
-        auf dem Telefon gespeicherten Kalenderereignisse zu lesen.
-        Schädliche Anwendungen können dies nutzen, um Kalenderereignisse anderen Personen zuzusenden.</string>
-  <string name="permdesc_readContacts">Ermöglicht einer Anwendung alle
-        auf dem Telefon gespeicherten Kontakte (Adressen) zu lesen.
-        Schädliche Anwendungen können dies nutzen, um Ihre Daten anderen Personen zuzusenden.</string>
-  <string name="permdesc_readFrameBuffer">Ermöglicht einer Anwendung den Inhalt
-        des Frame-Puffers zu lesen.</string>
-  <string name="permdesc_readInputState">Ermöglicht einer Anwendung die
-        Tasten zu erkennen, die Sie drücken, wenn Sie eine andere Anwendung nutzen
-        (z. B. wenn Sie ein Kennwort eingeben). Für normale Anwendungen sollte dies niemals erforderlich sein.</string>
-  <string name="permdesc_readLogs">Ermöglicht einer Anwendung
-        verschiedene Log-Dateien des Systems zu lesen.  Sie können so allgemeine
-        Informationen über die Aktionen auf dem Telefon erhalten. Diese Informationen sollten aber keine
-        persönlichen oder privaten Daten enthalten.</string>
-  <string name="permdesc_readOwnerData">Ermöglicht einer Anwendung
-        auf dem Telefon gespeicherte Daten des Besitzers zu lesen. Schädliche
-        Anwendungen können dies nutzen, um die Daten des Telefonbesitzers zu lesen.</string>
-  <string name="permdesc_readPhoneState">Ermöglicht der Anwendung auf  Telefonfunktionen
-        des Gerätes zuzugreifen.  Eine Anwendung mit dieser Genehmigung kann die Nummer dieses
-        Telefons ermitteln, erkennen, ob ein Gespräch geführt wird, die Nummer des Gesprächspartners erkennen 
- usw.</string>
-  <string name="permdesc_readSms">Ermöglicht einer Anwendung
-      SMS-Nachrichten zu lesen, die auf dem Telefon oder der SIM-Karte gespeichert sind. Schädliche Anwendungen
-      können dies nutzen, um vertrauliche Nachrichten zu lesen.</string>
-  <string name="permdesc_readSyncSettings">Ermöglicht einer Anwendung Synchronisierungseinstellungen zu lesen,
-        z. B. ob die Synchronisierung für Kontakte aktiviert ist.</string>
-  <string name="permdesc_readSyncStats">Ermöglicht einer Anwendung Synchronisierungs-Statistiken,
-        z. B. den Verlauf durchgeführter Synchronisierungen, neu zu fokussieren.</string>
-  <string name="permdesc_receiveBootCompleted">Ermöglicht einer Anwendung
-        sich selbst zu starten, nachdem das System hochgefahren wurde.
-        Dies kann dazu führen, dass das Telefon langsamer gestartet wird, und die Anwendung
-        kann das Telefon allgemein verlangsamen, wenn sie jederzeit ausgeführt wird.</string>
-  <string name="permdesc_receiveMms">Ermöglicht einer Anwendung
-      MMS-Nachrichten zu empfangen und zu verarbeiten.
-      Schädliche Anwendungen können Ihre Nachrichten verfolgen oder löschen, ohne dass sie Ihnen gezeigt werden.</string>
-  <string name="permdesc_receiveSms">Ermöglicht einer Anwendung
-      SMS-Nachrichten zu empfangen und zu verarbeiten.
-      Schädliche Anwendungen können Ihre Nachrichten verfolgen oder löschen, ohne dass sie Ihnen gezeigt werden.</string>
-  <string name="permdesc_receiveWapPush">Ermöglicht einer Anwendung
-      WAP-Nachrichten zu empfangen und zu verarbeiten.
-      Schädliche Anwendungen könnenIhre Nachrichten verfolgen oder löschen, ohne dass sie Ihnen gezeigt werden.</string>
-  <string name="permdesc_recordAudio">Ermöglicht einer Anwendung 
-        auf den Audioaufnahmepfad zuzugreifen.</string>
-  <string name="permdesc_reorderTasks">Ermöglicht einer Anwendung
-        Aufgaben in den Vordergrund oder den Hintergrund zu verschieben.
-        Schädliche Anwendungen können dies nutzen, um sichin den Vordergrund zu schieben, ohne dass Sie dies verhindern können.</string>
-  <string name="permdesc_restartPackages">Ermöglicht einer Anwendung
-        den Neustart anderer Anwendungen zu erzwingen.</string>
-  <string name="permdesc_runSetActivityWatcher">Ermöglicht einer Anwendung
-        zu überwachen und zu steuern, wie das System Aktivitäten startet.
-        Schädliche Anwendungen können dies nutzen, um das komplette System zu gefährden.
-        Diese Genehmigung wird nur für die Entwicklung und niemals für die normale
-        Verwendung des Telefons benötigt.</string>
-  <string name="permdesc_sendSms">Ermöglicht Anwendungen
-      SMS-Nachrichten zu senden. Schädliche Anwendungen können dies nutzen, um zusätzliche Kosten zu verursachen,
-      wenn Nachrichten ohne Ihre Zustimmung gesendet werden.</string>
-  <string name="permdesc_setAlwaysFinish">Ermöglicht einer Anwendung zu steuern,
-        ob Aktivitäten sofort beendet werden,sobald sie in den Hintergrund treten.
-        Dies wird für normale Anwendungen niemals benötigt.</string>
-  <string name="permdesc_setAnimationScale">Ermöglicht einer Anwendung
-        die allgemeine Animationsgeschwindigkeit (schnellere oder langsamera Animationen) jederzeit zu ändern.</string>
-  <string name="permdesc_setDebugApp">Ermöglicht einer Anwendung
-        Debugging für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können dies nutzen,
-        um andere Anwendungen zu zerstören.</string>
-  <string name="permdesc_setOrientation">Ermöglicht einer Anwendung die
-        Ausrichtung des Displays jederzeit zu ändern. Dies sollte für
-        normale Anwendungen niemals benötigt werden.</string>
-  <string name="permdesc_setPreferredApplications">Ermöglicht einer Anwendung
-        bevorzugte Anwendungen zu ändern. Schädliche Anwendungen können dies nutzen,
-        um die Anwendungen, die Sie verwenden, unbemerkt zu ändern und bestehende
-        Anwendungen zum Sammeln Ihrer privaten Daten zu veranlassen.</string>
-  <string name="permdesc_setProcessForeground">Ermöglicht einer Anwendung, jeden
-        Vorgang im Vordergrund ablaufen zu lassen, so dass er nicht unterbunden werden kann.
-        Für normale Anwendungen sollte dies nicht erforderlich sein.</string>
-  <string name="permdesc_setProcessLimit">Ermöglicht einer Anwendung 
-        die maximale Anzahl von Vorgängen zu steuern, die durchgeführt werden.Dies wird für
-        normale Anwendungen niemals benötigt.</string>
-  <string name="permdesc_setTimeZone">Ermöglicht einer Anwendung
-        die Zeitzone des Telefons zu ändern.</string>
-  <string name="permdesc_setWallpaper">Ermöglicht einer Anwendung
-        den Systembildschirmhintergrund einzustellen.</string>
-  <string name="permdesc_setWallpaperHints">Ermöglicht einer Anwendung
-        Hinweise für die Größe des Systembildschirmhintergrunds zu setzen.</string>
-  <string name="permdesc_signalPersistentProcesses">Ermöglicht einer Anwendung anzufordern, dass das ausgegebene
-        Signal allen anhaltenden Vorgängen zugesandt wird.</string>
-  <string name="permdesc_statusBar">Ermöglicht einer Anwendung die
-        Statusleiste zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen.</string>
-  <string name="permdesc_systemAlertWindow">Ermöglicht einer Anwendung
-        Systemwarnfenster anzuzeigen. Schädliche Anwendungen können dies nutzen,
-        um das gesamte Display des Telefons auszufüllen.</string>
-  <string name="permdesc_vibrate">Ermöglicht einer Anwendung die
-        Vibration zu steuern.</string>
-  <string name="permdesc_wakeLock">Ermöglicht einer Anwendung
-        zu verhindern, dass das Telefon den Schlafmodus aktiviert.</string>
-  <string name="permdesc_writeCalendar">Ermöglicht einer Anwendung
-        die auf dem Telefon gespeicherten Kalenderereignisse zu ändern.
-        Schädliche Anwendungen können dies nutzen, um die Kalenderdaten zu löschen oder modifizieren.</string>
-  <string name="permdesc_writeContacts">Ermöglicht einer Anwendung
-        die auf dem Telefon gespeicherten Kontaktdaten (Adressen) zu ändern.
-        Schädliche Anwendungen können dies nutzen, um die Kontaktdaten zu löschen oder modifizieren.</string>
-  <string name="permdesc_writeOwnerData">Ermöglicht einer Anwendung
-        die auf dem Telefon gespeicherten Besitzerdaten zu ändern.
-        Schädliche Anwendungen können dies nutzen, um die Benutzerdaten zu löschen oder modifizieren.</string>
-  <string name="permdesc_writeSettings">Ermöglicht einer Anwendung
-        die Einstellungen des Systems zu ändern. Schädliche Anwendungen können dies nutzen, um die Konfiguration des Systems
-        zu manipulieren.</string>
-  <string name="permdesc_writeSms">Ermöglicht einer Anwendung
-      SMS-Nachrichten zu schreiben, die auf dem Telefon oder der SIM-Karte gespeichert sind. Schädliche Anwendungen
-      können dies nutzen, um Ihre Nachrichten zu löschen.</string>
-  <string name="permdesc_writeSyncSettings">Ermöglicht einer Anwendung Synchronisierungseinstellungen zu ändern,
-        z. B. ob die Synchronisierung für Kontakte aktiviert ist.</string>
-  <string name="permgroupdesc_accounts">Greifen Sie auf verfügbare Google-Konten zu.</string>
-  <string name="permgroupdesc_costMoney">Ermöglicht einer Anwendung Vorgänge
-        durchzuführen, für die Kosten anfallen können.</string>
-  <string name="permgroupdesc_developmentTools">Funktionen werden nur von
-        Anwendungsentwicklern benötigt.</string>
-  <string name="permgroupdesc_hardwareControls">Direkter Zugriff auf Hardware
-        des Gerätes.</string>
-  <string name="permgroupdesc_location">Verfolgung des physischen Ortes</string>
-  <string name="permgroupdesc_messages">Lesen und schreiben Sie SMS,
-        E-Mails und andere Nachrichten.</string>
-  <string name="permgroupdesc_network">Ermöglicht Anwendungen auf
-        unterschiedliche Netzeigenschaften zuzugreifen.</string>
-  <string name="permgroupdesc_personalInfo">Direkter Zugriff auf Kontakte
-        und Kalenderdaten, die auf dem Gerät gespeichert sind.</string>
-  <string name="permgroupdesc_phoneCalls">Verfolgung, Aufnahme und Verarbeitung
-        von Anrufen.</string>
-  <string name="permgroupdesc_systemTools">Low-Level-Zugriff und Steuerung des
-        Systems.</string>
-  <string name="permgrouplab_accounts">Ihre Google-Konten</string>
-  <string name="permgrouplab_costMoney">Kosten Geld</string>
-  <string name="permgrouplab_developmentTools">Entwicklungstools</string>
-  <string name="permgrouplab_hardwareControls">Hardwaresteuerung</string>
-  <string name="permgrouplab_location">Eigener Ort</string>
-  <string name="permgrouplab_messages">Eigene Nachrichten</string>
-  <string name="permgrouplab_network">Netzkommunikation</string>
-  <string name="permgrouplab_personalInfo">Eigene persönliche Daten</string>
-  <string name="permgrouplab_phoneCalls">Anrufe</string>
-  <string name="permgrouplab_systemTools">Systemtools</string>
-  <string name="permissions_format"><xliff:g id="perm_line1">%1$s</xliff:g>, <xliff:g id="perm_line2">%2$s</xliff:g></string>
-  <string name="permlab_accessCoarseLocation">Ungefährer (netzbasierter) Ort</string>
-  <string name="permlab_accessFineLocation">Genauer (GPS) Ort</string>
-  <string name="permlab_accessMockLocation">Scheinortquellen für Tests</string>
-  <string name="permlab_accessNetworkState">Netzstatus anzeigen</string>
-  <string name="permlab_accessSurfaceFlinger">Auf SurfaceFlinger zugreifen</string>
-  <string name="permlab_accessWifiState">Wi-Fi-Status anzeigen</string>
-  <string name="permlab_addSystemService">Low-Level-Dienste veröffentlichen</string>
-  <string name="permlab_batteryStats">Akkustatistiken ändern</string>
-  <string name="permlab_bluetooth">Bluetooth-Verbindungen erstellen</string>
-  <string name="permlab_bluetoothAdmin">Bluetooth-Verwaltung</string>
-  <string name="permlab_brick">Telefon bleibend deaktivieren</string>
-  <string name="permlab_broadcastPackageRemoved">Als Paket entfernte Übertragung senden</string>
-  <string name="permlab_broadcastSticky">Als bleibende Übertragung senden</string>
-  <string name="permlab_callPhone">Telefonnummern direkt wählen</string>
-  <string name="permlab_camera">Bilder aufnehmen</string>
-  <string name="permlab_changeComponentState">Anwendungskomponenten aktivieren oder deaktivieren</string>
-  <string name="permlab_changeConfiguration">UI-Einstellungen ändern</string>
-  <string name="permlab_changeNetworkState">Netzkonnektivität ändern</string>
-  <string name="permlab_changeWifiState">Wi-Fi-Status ändern</string>
-  <string name="permlab_clearAppCache">Alle Cache-Daten der Anwendung löschen</string>
-  <string name="permlab_clearAppUserData">Andere Anwendungsdaten löschen</string>
-  <string name="permlab_createNetworkSockets">Kompletter Internetzugriff</string>
-  <string name="permlab_deleteCacheFiles">Cache anderer Anwendung löschen</string>
-  <string name="permlab_deletePackages">Anwendungen löschen</string>
-  <string name="permlab_devicePower">Telefon ein- oder ausschalten</string>
-  <string name="permlab_disableKeyguard">Tastensperre deaktivieren</string>
-  <string name="permlab_dump">Internen Systemstatus abrufen</string>
-  <string name="permlab_expandStatusBar">Statusleiste erweitern/verkleinern</string>
-  <string name="permlab_factoryTest">Werkstestmodus ausführen</string>
-  <string name="permlab_flashlight">Blitzlicht steuern</string>
-  <string name="permlab_forceBack">Beendigung von Anwendung erzwingen</string>
-  <string name="permlab_fotaUpdate">Systemupdates automatisch installieren</string>
-  <string name="permlab_getAccounts">Bekannte Konten auffinden</string>
-  <string name="permlab_getPackageSize">Speicherplatz für Anwendung messen</string>
-  <string name="permlab_getTasks">Ausgeführte Anwendungen abrufen</string>
-  <string name="permlab_hardware_test">Test-Hardware</string>
-  <string name="permlab_injectEvents">Tasten und Kontrollschaltflächen drücken</string>
-  <string name="permlab_installPackages">Anwendungen direkt installieren</string>
-  <string name="permlab_internalSystemWindow">Nicht autorisierte Fenster anzeigen</string>
-  <string name="permlab_manageAppTokens">Anwendungs-Token verwalten</string>
-  <string name="permlab_masterClear">System auf Standardeinstellungen zurücksetzen</string>
-  <string name="permlab_modifyAudioSettings">Audioeinstellungen ändern</string>
-  <string name="permlab_modifyPhoneState">Telefonzustand ändern</string>
-  <string name="permlab_mount_unmount_filesystems">Dateisysteme installieren und deinstallieren</string>
-  <string name="permlab_persistentActivity">Anwendung jederzeit ausführen</string>
-  <string name="permlab_processOutgoingCalls">Ausgehende Anrufe abfangen</string>
-  <string name="permlab_readCalendar">Kalenderdaten lesen</string>
-  <string name="permlab_readContacts">Kontaktdaten lesen</string>
-  <string name="permlab_readFrameBuffer">Frame-Buffer lesen</string>
-  <string name="permlab_readInputState">Aufzeichnen, was Sie eingeben und welche Aktionen Sie durchführen</string>
-  <string name="permlab_readLogs">System-Log-Dateien lesen</string>
-  <string name="permlab_readOwnerData">Besitzerdaten lesen</string>
-  <string name="permlab_readPhoneState">Telefonzustand lesen</string>
-  <string name="permlab_readSms">SMS oder MMS lesen</string>
-  <string name="permlab_readSyncSettings">Synchr.-Einstellungen lesen</string>
-  <string name="permlab_readSyncStats">Synchr.-Statistiken lesen</string>
-  <string name="permlab_receiveBootCompleted">Beim Hochfahren automatisch starten</string>
-  <string name="permlab_receiveMms">MMS empfangen</string>
-  <string name="permlab_receiveSms">SMS empfangen</string>
-  <string name="permlab_receiveWapPush">WAP empfangen</string>
-  <string name="permlab_recordAudio">Audio aufnehmen</string>
-  <string name="permlab_reorderTasks">Reihenfolge ausgeführter Anwendungen ändern</string>
-  <string name="permlab_restartPackages">Andere Anwendungen neu starten</string>
-  <string name="permlab_runSetActivityWatcher">Start aller Anwendungen überwachen und steuern</string>
-  <string name="permlab_sendSms">SMS-Nachrichten senden</string>
-  <string name="permlab_setAlwaysFinish">Alle Anwendungen im Hintergrund beenden</string>
-  <string name="permlab_setAnimationScale">Allgemeine Animationsgeschwindigkeit ändern</string>
-  <string name="permlab_setDebugApp">Anwendungs-Debugging aktivieren</string>
-  <string name="permlab_setOrientation">Displayausrichtung ändern</string>
-  <string name="permlab_setPreferredApplications">Bevorzugte Anwendungen einstellen</string>
-  <string name="permlab_setProcessForeground">Beendigung unterbinden</string>
-  <string name="permlab_setProcessLimit">Anzahl von ausgeführten Vorgängen beschränken</string>
-  <string name="permlab_setTimeZone">Zeitzone einstellen</string>
-  <string name="permlab_setWallpaper">Bildschirmhintergrund einstellen</string>
-  <string name="permlab_setWallpaperHints">Hinweise für Bildschirmhintergrundgröße einstellen</string>
-  <string name="permlab_signalPersistentProcesses">Linux-Signale zu Anwendungen senden</string>
-  <string name="permlab_statusBar">Statusleiste deaktivieren oder ändern</string>
-  <string name="permlab_systemAlertWindow">Systemstufen-Warnhinweise anzeigen</string>
-  <string name="permlab_vibrate">Vibration steuern</string>
-  <string name="permlab_wakeLock">Aktivierung des Schlafmodus auf Telefon unterbinden</string>
-  <string name="permlab_writeCalendar">Kalenderdaten schreiben</string>
-  <string name="permlab_writeContacts">Kontaktdaten schreiben</string>
-  <string name="permlab_writeOwnerData">Besitzerdaten schreiben</string>
-  <string name="permlab_writeSettings">Allgemeine Systemeinstellungen ändern</string>
-  <string name="permlab_writeSms">SMS oder MMS bearbeiten</string>
-  <string name="permlab_writeSyncSettings">Synchr.-Einstellungen schreiben</string>
-  <string name="petabyteShort">PB</string>
-  <string name="pm">"PM"</string>
-  <string name="power_dialog">Telefonoptionen</string>
-  <string name="power_off">Ausschalten</string>
-  <string name="prepend_shortcut_label">Menü+</string>
-  <string name="preposition_for_date">auf %s</string>
-  <string name="preposition_for_time">am %s</string>
-  <string name="preposition_for_year">in %s</string>
-  <string name="ringtone_default">Standard-Klingelton</string>
-  <string name="ringtone_default_with_actual">Standard-Klingelton (<xliff:g id="actual_ringtone">%1$s</xliff:g>)</string>
-  <string name="ringtone_picker_title">Klingelton auswählen</string>
-  <string name="ringtone_silent">Lautlos</string>
-  <string name="ringtone_unknown">Unbekannter Klingelton</string>
-  <string name="safeMode">Sicherer Modus</string>
-  <string name="same_month_md1_md2">"<xliff:g id="format">%2$s %3$s \u2013 %8$s</xliff:g>"</string>
-  <string name="same_month_md1_time1_md2_time2">"<xliff:g id="format">%2$s %3$s, %5$s \u2013 %7$s %8$s, %10$s</xliff:g>"</string>
-  <string name="same_month_mdy1_mdy2">"<xliff:g id="format">%2$s %3$s \u2013 %8$s, %9$s</xliff:g>"</string>
-  <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="format">%2$s %3$s, %4$s, %5$s \u2013 %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %5$s \u2013 %6$s, %7$s %8$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %2$s %3$s \u2013 %6$s, %7$s %8$s</xliff:g>"</string>
-  <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %4$s, %5$s \u2013 %6$s, %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %2$s %3$s, %4$s \u2013 %6$s, %7$s %8$s, %9$s</xliff:g>"</string>
-  <string name="same_year_md1_md2">"<xliff:g id="format">%2$s %3$s \u2013 %7$s %8$s</xliff:g>"</string>
-  <string name="same_year_md1_time1_md2_time2">"<xliff:g id="format">%2$s %3$s, %5$s \u2013 %7$s %8$s, %10$s</xliff:g>"</string>
-  <string name="same_year_mdy1_mdy2">"<xliff:g id="format">%2$s %3$s \u2013 %7$s %8$s, %9$s</xliff:g>"</string>
-  <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="format">%2$s %3$s, %4$s, %5$s \u2013 %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %5$s \u2013 %6$s, %7$s %8$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %2$s %3$s \u2013 %6$s, %7$s %8$s</xliff:g>"</string>
-  <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %4$s, %5$s \u2013 %6$s, %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %2$s %3$s \u2013 %6$s, %7$s %8$s, %9$s</xliff:g>"</string>
-  <string name="saturday">Samstag</string>
-  <string name="save_password_label">Bestätigen</string>
-  <string name="save_password_message">Möchten Sie, dass der Browser dieses Kennwort speichert?</string>
-  <string name="save_password_never">Niemals</string>
-  <string name="save_password_notnow">Jetzt nicht</string>
-  <string name="save_password_remember">Erinnern</string>
-  <string name="screen_lock">Displaysperre</string>
-  <string name="screen_progress">Verarbeitung\u2026</string>
-  <string name="search_go">Suchen</string>
-  <string name="second">Sek.</string>
-  <string name="seconds">Sek.</string>
-  <string name="selectAll">Alles auswählen</string>
-  <string name="selectMenuLabel">Auswählen</string>
-  <string name="select_character">Zeichen zum Einfügen auswählen</string>
-  <string name="sendText">Aktion für Text auswählen</string>
-  <string name="serviceClassData">Daten</string>
-  <string name="serviceClassDataAsync">Async</string>
-  <string name="serviceClassDataSync">Synchr.</string>
-  <string name="serviceClassFAX">FAX</string>
-  <string name="serviceClassPAD">PAD</string>
-  <string name="serviceClassPacket">Paket</string>
-  <string name="serviceClassSMS">SMS</string>
-  <string name="serviceClassVoice">Sprachnotiz</string>
-  <string name="serviceDisabled">Dienst wurde deaktiviert.</string>
-  <string name="serviceEnabled">Dienst wurde aktiviert.</string>
-  <string name="serviceEnabledFor">Dienst wurde aktiviert für:</string>
-  <string name="serviceErased">Löschen war erfolgreich.</string>
-  <string name="serviceNotProvisioned">Dienst nicht verfügbar.</string>
-  <string name="serviceRegistered">Registrierung war erfolgreich.</string>
-  <string name="shutdown_confirm">Das Telefon wird ausgeschaltet.</string>
-  <string name="shutdown_progress">Beendigung\u2026</string>
-  <string name="silent_mode">Lautlosmodus</string>
-  <string name="simAbsentLabel">SIM-Karte nicht vorhanden oder falsch eingesetzt.</string>
-  <string name="simNetworkPersonalizationLabel">SIM-Karte kann auf diesem Telefon nicht verwendet werden.</string>
-  <string name="simPINLabel">SIM PIN erforderlich (und wird derzeit nicht unterstützt).</string>
-  <string name="simPUKLabel">SIM PUK erforderlich (und wird derzeit nicht unterstützt).</string>
-  <string name="sms_control_message">Es werden eine große Anzahl von SMS-Nachrichten gesendet. Wählen Sie \"OK\", um fortzufahren, oder \"Abbrechen\", um das Senden zu beenden.</string>
-  <string name="sms_control_no">Abbrechen</string>
-  <string name="sms_control_title">Sendung von SMS-Nachrichten</string>
-  <string name="sms_control_yes">OK</string>
-  <string name="status_bar_applications_title">Anwendung</string>
-  <string name="status_bar_clear_all_button">Benachrichtigungen löschen</string>
-  <string name="status_bar_date_format">"<xliff:g id="format">MMMM T, JJJJ</xliff:g>"</string>
-  <string name="status_bar_latest_events_title">Benachrichtigungen</string>
-  <string name="status_bar_no_notifications_title">Keine Benachrichtigungen</string>
-  <string name="status_bar_ongoing_events_title">Laufend</string>
-  <string name="status_bar_time_format">"<xliff:g id="format">h:mm AA</xliff:g>"</string>
-  <string name="sunday">Sonntag</string>
-  <string name="terabyteShort">TB</string>
-  <string name="text_copied">In Zwischenablage kopierter Text.</string>
-  <string name="thursday">Donnerstag</string>
-  <string name="time1_time2">"<xliff:g id="format">%1$s \u2013 %2$s</xliff:g>"</string>
-  <string name="time_date">"<xliff:g id="format">%1$s, %3$s</xliff:g>"</string>
-  <string name="time_picker_set">Einstellen</string>
-  <string name="time_wday">"<xliff:g id="format">%1$s, %2$s</xliff:g>"</string>
-  <string name="time_wday_date">"<xliff:g id="format">%1$s, %2$s, %3$s</xliff:g>"</string>
-  <string name="today">Heute</string>
-  <string name="tomorrow">Morgen</string>
-  <string name="tuesday">Dienstag</string>
-  <string name="turn_off_radio">Wireless ausschalten</string>
-  <string name="turn_on_radio">Wireless einschalten</string>
-  <string name="unknownName">(Unbekannt)</string>
-  <string name="untitled">&lt;ohne Titel&gt;</string>
-  <string name="volume_alarm">Weckerlautstärke</string>
-  <string name="volume_call">Lautstärke während Anruf</string>
-  <string name="volume_music">Musik-/Videolautstärke</string>
-  <string name="volume_ringtone">Klingellautstärke</string>
-  <string name="volume_unknown">Lautstärke</string>
-  <string name="wait">Warten</string>
-  <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="format">%1$s, %2$s, %3$s \u2013 %4$s, %5$s, %6$s</xliff:g>"</string>
-  <string name="wday1_date1_wday2_date2">"<xliff:g id="format">%1$s, %2$s \u2013 %4$s, %5$s</xliff:g>"</string>
-  <string name="wday_date">"<xliff:g id="format">%2$s, %3$s</xliff:g>"</string>
-  <string name="web_user_agent"><xliff:g id="x">Mozilla/5.0 (Linux; U; Android 0,6; %s)
-        AppleWebKit/525.10+ (KHTML, z. B. Gecko) Version/3.0,4 Mobile Safari/523.12,2</xliff:g></string>
-  <string name="wednesday">Mittwoch</string>
-  <string name="week">Woche</string>
-  <string name="weekly">"Wöchentlich am <xliff:g id="day">%s</xliff:g>"</string>
-  <string name="weekly_format">MMM T</string>
-  <string name="weeks">Wochen</string>
-  <string name="whichApplication">Aktion durchführen mit</string>
-  <string name="year">Jahr</string>
-  <string name="yearly">Jährlich</string>
-  <string name="yearly_format">JJJJ</string>
-  <string name="years">Jahre</string>
-  <string name="yes">OK</string>
-  <string name="yesterday">Gestern</string>
-</resources>
diff --git a/core/res/res/values-de/arrays.xml b/core/res/res/values-de/arrays.xml
new file mode 100644
index 0000000..f9c904b
--- /dev/null
+++ b/core/res/res/values-de/arrays.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
new file mode 100644
index 0000000..4b0419c
--- /dev/null
+++ b/core/res/res/values-de/strings.xml
@@ -0,0 +1,698 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="byteShort">"B"</string>
+    <string name="kilobyteShort">"KB"</string>
+    <string name="megabyteShort">"MB"</string>
+    <string name="gigabyteShort">"GB"</string>
+    <string name="terabyteShort">"TB"</string>
+    <string name="petabyteShort">"PB"</string>
+    <string name="untitled">"&lt;Unbenannt&gt;"</string>
+    <string name="ellipsis">"…"</string>
+    <string name="emptyPhoneNumber">"(Keine Telefonnummer)"</string>
+    <string name="unknownName">"(Unbekannt)"</string>
+    <string name="defaultVoiceMailAlphaTag">"Mailbox"</string>
+    <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+    <string name="mmiError">"Verbindungsproblem oder ungültiger MMI-Code."</string>
+    <string name="serviceEnabled">"Dienst wurde aktiviert."</string>
+    <string name="serviceEnabledFor">"Dienst wurde aktiviert für:"</string>
+    <string name="serviceDisabled">"Dienst wurde deaktiviert."</string>
+    <string name="serviceRegistered">"Registrierung war erfolgreich."</string>
+    <string name="serviceErased">"Löschvorgang erfolgreich."</string>
+    <string name="passwordIncorrect">"Falsches Passwort."</string>
+    <string name="mmiComplete">"MMI abgeschlossen."</string>
+    <string name="badPin">"Die von Ihnen eingegebene alte PIN ist nicht korrekt."</string>
+    <string name="badPuk">"Der von Ihnen eingegebene PUK ist nicht korrekt."</string>
+    <string name="mismatchPin">"Die von Ihnen eingegebenen PIN-Nummern stimmen nicht überein."</string>
+    <string name="invalidPin">"Geben Sie eine PIN ein, die 4 bis 8 Zahlen enthält."</string>
+    <!-- no translation found for needPuk (919668385956251611) -->
+    <skip />
+    <string name="needPuk2">"Geben Sie zum Entsperren der SIM-Karte den PUK2 ein."</string>
+    <string name="ClipMmi">"Anrufer-ID für eingehenden Anruf"</string>
+    <string name="ClirMmi">"Anrufer-ID für abgehenden Anruf"</string>
+    <string name="CfMmi">"Anrufweiterleitung"</string>
+    <string name="CwMmi">"Anklopfen"</string>
+    <string name="BaMmi">"Anrufsperre"</string>
+    <string name="PwdMmi">"Passwort-Änderung"</string>
+    <string name="PinMmi">"PIN-Änderung"</string>
+    <string name="CLIRDefaultOnNextCallOn">"Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Beschränkt"</string>
+    <string name="CLIRDefaultOnNextCallOff">"Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Nicht beschränkt"</string>
+    <string name="CLIRDefaultOffNextCallOn">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Beschränkt"</string>
+    <string name="CLIRDefaultOffNextCallOff">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt"</string>
+    <string name="serviceNotProvisioned">"Dienst nicht eingerichtet."</string>
+    <string name="CLIRPermanent">"Die Einstellung für die Anrufer-ID kann nicht geändert werden."</string>
+    <string name="serviceClassVoice">"Sprachnotiz"</string>
+    <string name="serviceClassData">"Daten"</string>
+    <string name="serviceClassFAX">"FAX"</string>
+    <string name="serviceClassSMS">"SMS"</string>
+    <string name="serviceClassDataAsync">"Asynchron"</string>
+    <string name="serviceClassDataSync">"Synchron"</string>
+    <string name="serviceClassPacket">"Paket"</string>
+    <string name="serviceClassPAD">"PAD"</string>
+    <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
+    <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+    <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> nach <xliff:g id="TIME_DELAY">{2}</xliff:g> Sekunden."</string>
+    <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
+    <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
+    <string name="httpErrorOk">"OK"</string>
+    <string name="httpError">"Auf der Webseite ist ein Fehler aufgetreten."</string>
+    <string name="httpErrorLookup">"Die URL konnte nicht gefunden werden."</string>
+    <string name="httpErrorUnsupportedAuthScheme">"Das Authentifizierungsschema für die Site wird nicht unterstützt."</string>
+    <string name="httpErrorAuth">"Authentifizierung ist fehlgeschlagen."</string>
+    <string name="httpErrorProxyAuth">"Authentifizierung via Proxy-Server ist fehlgeschlagen."</string>
+    <string name="httpErrorConnect">"Es konnte keine Verbindung zum Server hergestellt werden."</string>
+    <string name="httpErrorIO">"Die Server-Kommunikation ist fehlgeschlagen. Versuchen Sie es später erneut."</string>
+    <string name="httpErrorTimeout">"Zeitüberschreitung bei Serververbindung."</string>
+    <string name="httpErrorRedirectLoop">"Die Seite enthält zu viele Server-Redirects."</string>
+    <string name="httpErrorUnsupportedScheme">"Das Protokoll wird nicht unterstützt."</string>
+    <string name="httpErrorFailedSslHandshake">"Es konnte keine sichere Verbindung aufgebaut werden."</string>
+    <string name="httpErrorBadUrl">"Die Seite konnte nicht geöffnet werden, weil die URL ungültig ist."</string>
+    <string name="httpErrorFile">"Auf die Datei konnte nicht zugegriffen werden."</string>
+    <string name="httpErrorFileNotFound">"Die angeforderte Datei wurde nicht gefunden."</string>
+    <string name="httpErrorTooManyRequests">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuchen Sie es später erneut."</string>
+    <string name="contentServiceSync">"Synchronisieren"</string>
+    <string name="contentServiceSyncNotificationTitle">"Synchronisieren"</string>
+    <string name="contentServiceTooManyDeletesNotificationDesc">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
+    <string name="low_memory">"Telefonspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
+    <string name="me">"Eigene"</string>
+    <string name="power_dialog">"Telefonoptionen"</string>
+    <string name="silent_mode">"Lautlos"</string>
+    <string name="turn_on_radio">"Funk einschalten"</string>
+    <string name="turn_off_radio">"Funk ausschalten"</string>
+    <string name="screen_lock">"Bildschirmsperre"</string>
+    <string name="power_off">"Ausschalten"</string>
+    <string name="shutdown_progress">"Herunterfahren..."</string>
+    <string name="shutdown_confirm">"Ihr Telefon wird heruntergefahren."</string>
+    <string name="no_recent_tasks">"Keine neuen Anwendungen."</string>
+    <string name="global_actions">"Telefonoptionen"</string>
+    <string name="global_action_lock">"Bildschirmsperre"</string>
+    <string name="global_action_power_off">"Ausschalten"</string>
+    <string name="global_action_toggle_silent_mode">"Lautlos"</string>
+    <string name="global_action_silent_mode_on_status">"Ton ist ausgeschaltet."</string>
+    <string name="global_action_silent_mode_off_status">"Ton ist EINGESCHALTET"</string>
+    <string name="safeMode">"Abgesicherter Modus"</string>
+    <string name="permgrouplab_costMoney">"Kostenpflichtige Dienste"</string>
+    <string name="permgroupdesc_costMoney">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen."</string>
+    <string name="permgrouplab_messages">"Ihre Nachrichten"</string>
+    <string name="permgroupdesc_messages">"Lesen und schreiben Sie Ihre SMS, E-Mails und anderen Nachrichten."</string>
+    <string name="permgrouplab_personalInfo">"Ihre persönlichen Informationen"</string>
+    <string name="permgroupdesc_personalInfo">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons."</string>
+    <string name="permgrouplab_location">"Ihr Standort"</string>
+    <string name="permgroupdesc_location">"Ihren physischen Standort überwachen"</string>
+    <string name="permgrouplab_network">"Netzwerkkommunikation"</string>
+    <string name="permgroupdesc_network">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen."</string>
+    <string name="permgrouplab_accounts">"Ihre Google-Konten"</string>
+    <string name="permgroupdesc_accounts">"Greift auf verfügbare Google-Konten zu."</string>
+    <string name="permgrouplab_hardwareControls">"Hardware-Steuerelemente"</string>
+    <string name="permgroupdesc_hardwareControls">"Direkter Zugriff auf Hardware über Headset"</string>
+    <string name="permgrouplab_phoneCalls">"Anrufe"</string>
+    <string name="permgroupdesc_phoneCalls">"Überwachen, Aufzeichnen und Verarbeiten von Telefonanrufen"</string>
+    <string name="permgrouplab_systemTools">"System-Tools"</string>
+    <string name="permgroupdesc_systemTools">"Zugriff und Steuerung des Systems auf niedrigerer Ebene."</string>
+    <string name="permgrouplab_developmentTools">"Entwickler-Tools"</string>
+    <string name="permgroupdesc_developmentTools">"Funktionen nur für Anwendungsentwickler vorgesehen."</string>
+    <string name="permlab_statusBar">"Statusleiste deaktivieren oder ändern"</string>
+    <string name="permdesc_statusBar">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen."</string>
+    <string name="permlab_expandStatusBar">"Statusleiste ein-/ausblenden"</string>
+    <string name="permdesc_expandStatusBar">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden."</string>
+    <string name="permlab_processOutgoingCalls">"Abgehende Anrufe abfangen"</string>
+    <string name="permdesc_processOutgoingCalls">"Ermöglicht einer Anwendung, abgehende Anrufe zu verarbeiten und die zu wählende Nummer zu ändern. Schädliche Anwendungen können so abgehende Anrufe eventuell überwachen, umleiten oder verhindern."</string>
+    <string name="permlab_receiveSms">"SMS empfangen"</string>
+    <string name="permdesc_receiveSms">"Ermöglicht der Anwendung, Kurzmitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
+    <string name="permlab_receiveMms">"MMS empfangen"</string>
+    <string name="permdesc_receiveMms">"Ermöglicht der Anwendung, MMS-Mitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
+    <string name="permlab_sendSms">"Kurznachrichten senden"</string>
+    <string name="permdesc_sendSms">"Ermöglicht Anwendungen das Senden von SMS-Nachrichten. Bei schädlichen Anwendungen können Kosten entstehen, wenn diese Nachrichten ohne Ihre Zustimmung versenden."</string>
+    <string name="permlab_readSms">"SMS oder MMS lesen"</string>
+    <string name="permdesc_readSms">"Ermöglicht einer Anwendung, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte Kurznachrichten zu lesen. Schädliche Anwendungen lesen so möglicherweise Ihre  vertraulichen Nachrichten."</string>
+    <string name="permlab_writeSms">"SMS oder MMS bearbeiten"</string>
+    <string name="permdesc_writeSms">"Ermöglicht einer Anwendung, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte Kurznachrichten zu bearbeiten. Schädliche Anwendungen löschen möglicherweise Ihre Nachrichten."</string>
+    <string name="permlab_receiveWapPush">"WAP-Nachrichten empfangen"</string>
+    <string name="permdesc_receiveWapPush">"Ermöglicht der Anwendung, WAP-Mitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
+    <string name="permlab_getTasks">"Laufende Anwendungen abrufen"</string>
+    <string name="permdesc_getTasks">"Ermöglicht der Anwendung, Informationen zu aktuellen und kürzlich ausführten Aufgaben abzurufen. Schädliche Anwendungen können so eventuell geheime Informationen zu anderen Anwendungen entdecken."</string>
+    <string name="permlab_reorderTasks">"Laufende Anwendungen neu ordnen"</string>
+    <string name="permdesc_reorderTasks">"Ermöglicht einer Anwendung, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Anwendungen können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
+    <string name="permlab_setDebugApp">"Fehlerbeseitigung für Anwendung aktivieren"</string>
+    <string name="permdesc_setDebugApp">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
+    <string name="permlab_changeConfiguration">"UI-Einstellungen ändern"</string>
+    <string name="permdesc_changeConfiguration">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße."</string>
+    <string name="permlab_restartPackages">"Andere Anwendungen neu starten"</string>
+    <string name="permdesc_restartPackages">"Ermöglicht einer Anwendung, den Neustart anderer Anwendungen zu erzwingen."</string>
+    <string name="permlab_setProcessForeground">"Beenden nicht zulassen"</string>
+    <string name="permdesc_setProcessForeground">"Ermöglicht einer Anwendung, beliebige Prozesse im Vordergrund auszuführen, damit diese nicht beendet werden können. Sollte nicht für normale Anwendungen benötigt werden."</string>
+    <string name="permlab_forceBack">"Schließen von Anwendung erzwingen"</string>
+    <string name="permdesc_forceBack">"Ermöglicht einer Anwendung, alle Aktivitäten, die im Vordergrund ablaufen, zu beenden und in den Hintergrund zu schieben. Sollte nicht für normale Anwendungen benötigt werden."</string>
+    <string name="permlab_dump">"Systeminternen Status abrufen"</string>
+    <string name="permdesc_dump">"Ermöglicht einer Anwendung, den internen Status des Systems abzurufen. Schädliche Anwendungen rufen hierbei möglicherweise eine Vielzahl an privaten und geschützten Daten ab, die Sie in der Regel nicht benötigen würden."</string>
+    <string name="permlab_addSystemService">"systemnahe Dienste veröffentlichen"</string>
+    <string name="permdesc_addSystemService">"Ermöglicht der Anwendung, ihre eigenen systemnahen Dienste anzubieten. Schädliche Anwendungen könnten in das System eindringen und darin befindliche Daten stehlen oder manipulieren."</string>
+    <string name="permlab_runSetActivityWatcher">"Start von Anwendungen überwachen und steuern"</string>
+    <string name="permdesc_runSetActivityWatcher">"Ermöglicht der Anwendung, den Start von Systemaktivitäten zu überwachen und zu steuern. Schädliche Anwendungen können so das gesamte System beeinträchtigen. Diese Berechtigung wird nur zu Entwicklungszwecken und nie für die normale Telefonnutzung benötigt."</string>
+    <string name="permlab_broadcastPackageRemoved">"Broadcast ohne Paket senden"</string>
+    <string name="permdesc_broadcastPackageRemoved">"Ermöglicht einer Anwendung, eine Benachrichtigung zur Entfernung eines Anwendungspakets zu senden. Schädliche Anwendungen können so laufende Anwendungen beenden."</string>
+    <!-- no translation found for permlab_broadcastSmsReceived (5689095009030336593) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSmsReceived (9122419277306740155) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastWapPush (3145347413028582371) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastWapPush (3955303669461378091) -->
+    <skip />
+    <string name="permlab_setProcessLimit">"Anzahl der laufenden Prozesse beschränken"</string>
+    <string name="permdesc_setProcessLimit">"Ermöglicht einer Anwendung, die maximale Anzahl an laufenden Prozessen zu steuern. Wird nicht für normale Anwendungen benötigt."</string>
+    <string name="permlab_setAlwaysFinish">"alle Anwendungen im Hintergrund schließen"</string>
+    <string name="permdesc_setAlwaysFinish">"Überlässt einer Anwendung die Entscheidung, ob Aktivitäten beendet werden, sobald Sie in den Hintergrund rücken. Wird nicht für normale Anwendungen benötigt."</string>
+    <string name="permlab_fotaUpdate">"System-Updates automatisch installieren"</string>
+    <string name="permdesc_fotaUpdate">"Ermöglicht einer Anwendung, Benachrichtigungen zu ausstehenden System-Updates zu erhalten und deren Installation einzuleiten. Schädliche Anwendungen können so das System durch nicht autorisierte Updates beschädigen oder in den Update-Prozess eingreifen."</string>
+    <string name="permlab_batteryStats">"Akku-Daten ändern"</string>
+    <string name="permdesc_batteryStats">"Ermöglicht die Änderung von gesammelten Akku-Daten. Nicht für normale Anwendungen vorgesehen."</string>
+    <string name="permlab_internalSystemWindow">"nicht autorisierte Fenster anzeigen"</string>
+    <string name="permdesc_internalSystemWindow">"Ermöglicht die Erstellung von Fenstern, die von der Benutzeroberfläche des internen Systems verwendet werden. Nicht für normale Anwendungen geeignet."</string>
+    <string name="permlab_systemAlertWindow">"Warnungen auf Systemebene anzeigen"</string>
+    <string name="permdesc_systemAlertWindow">"Ermöglicht einer Anwendung, Fenster mit Systemwarnungen anzuzeigen. Schädliche Anwendungen können so das gesamte Display des Telefons einnehmen."</string>
+    <string name="permlab_setAnimationScale">"Allgemeine Animationsgeschwindigkeit einstellen"</string>
+    <string name="permdesc_setAnimationScale">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen."</string>
+    <string name="permlab_manageAppTokens">"Anwendungs-Tokens verwalten"</string>
+    <string name="permdesc_manageAppTokens">"Ermöglicht Anwendungen, Ihre eigenen Tokens zu erstellen und zu verwalten. Hierbei wird die normale Z-Reihenfolge umgangen. Dies sollte nicht für normale Anwendungen benötigt werden."</string>
+    <string name="permlab_injectEvents">"Tasten und Steuerungstasten drücken"</string>
+    <string name="permdesc_injectEvents">"Ermöglicht einer Anwendung, ihre eigenen Eingabeaktionen (Drücken von Tasten etc.) an andere Anwendungen zu liefern.  Schädliche Anwendungen können so die Kontrolle über Ihr Telefon übernehmen."</string>
+    <string name="permlab_readInputState">"Tastatureingaben und Aktionen aufzeichnen"</string>
+    <string name="permdesc_readInputState">"Ermöglicht Anwendungen, die von Ihnen gedrückten Tasten zu überwachen (etwa die Eingabe eines Passworts). Dies gilt auch für die Interaktion mit anderen Anwendungen. Sollte für normale Anwendungen nicht benötigt werden."</string>
+    <string name="permlab_setOrientation">"Bildschirmausrichtung ändern"</string>
+    <string name="permdesc_setOrientation">"Ermöglicht der Anwendung, die Bildschirmdrehung jederzeit zu ändern. Sollte nicht für normale Anwendungen benötigt werden."</string>
+    <string name="permlab_signalPersistentProcesses">"Linux-Signale an Anwendungen senden"</string>
+    <string name="permdesc_signalPersistentProcesses">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern."</string>
+    <string name="permlab_persistentActivity">"Anwendungen permanent ausführen"</string>
+    <string name="permdesc_persistentActivity">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann."</string>
+    <string name="permlab_deletePackages">"Anwendungen löschen"</string>
+    <string name="permdesc_deletePackages">"Ermöglicht einer Anwendung, Android-Pakete zu löschen. Schädliche Anwendungen können so wichtige Anwendungen löschen."</string>
+    <string name="permlab_clearAppUserData">"Daten anderer Anwendungen löschen"</string>
+    <string name="permdesc_clearAppUserData">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten."</string>
+    <string name="permlab_deleteCacheFiles">"Caches anderer Anwendungen löschen"</string>
+    <string name="permdesc_deleteCacheFiles">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen."</string>
+    <string name="permlab_getPackageSize">"Speicherplatz der Anwendung abrufen"</string>
+    <string name="permdesc_getPackageSize">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen."</string>
+    <string name="permlab_installPackages">"Anwendungen direkt installieren"</string>
+    <string name="permdesc_installPackages">"Ermöglicht einer Anwendung, neue oder aktualisierte Android-Pakete zu installieren. Schädliche Anwendungen können so neue Anwendungen mit beliebig umfangreichen Berechtigungen hinzufügen."</string>
+    <string name="permlab_clearAppCache">"Alle Cache-Daten der Anwendung löschen"</string>
+    <string name="permdesc_clearAppCache">"Ermöglicht einer Anwendung, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
+    <string name="permlab_readLogs">"System-Protokolldateien lesen"</string>
+    <string name="permdesc_readLogs">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden, diese sollten jedoch keine persönlichen oder geheimen Daten enthalten."</string>
+    <string name="permlab_diagnostic">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
+    <string name="permdesc_diagnostic">"Ermöglicht einer Anwendung, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für Hardware-spezifische Diagnosen des Herstellers oder Netzbetreibers verwendet werden."</string>
+    <string name="permlab_changeComponentState">"Anwendungskomponenten aktivieren oder deaktivieren"</string>
+    <!-- no translation found for permdesc_changeComponentState (4569107043246700630) -->
+    <skip />
+    <string name="permlab_setPreferredApplications">"Bevorzugte Einstellungen festlegen"</string>
+    <string name="permdesc_setPreferredApplications">"Ermöglicht einer Anwendung, Ihre bevorzugten Einstellungen zu ändern. Schädliche Anwendungen können so laufende Anwendungen ohne Ihr Wissen ändern, damit die vorhandenen Anwendungen private Daten von Ihnen sammeln."</string>
+    <string name="permlab_writeSettings">"Allgemeine Systemeinstellungen ändern"</string>
+    <string name="permdesc_writeSettings">"Ermöglicht einer Anwendung, die Einstellungsdaten des Systems zu ändern. Schädliche Anwendungen können so die Systemkonfiguration beschädigen."</string>
+    <!-- no translation found for permlab_writeSecureSettings (204676251876718288) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSecureSettings (4116616249170428132) -->
+    <skip />
+    <string name="permlab_writeGservices">"Google Services Map ändern"</string>
+    <string name="permdesc_writeGservices">"Ermöglicht einer Anwendung, Änderungen an der Google Services Map vorzunehmen. Nicht für normale Anwendungen vorgesehen."</string>
+    <string name="permlab_receiveBootCompleted">"Automatisch nach dem Booten starten"</string>
+    <string name="permdesc_receiveBootCompleted">"Ermöglicht einer Anwendung, sich selbst zu starten, sobald das System gebootet wurde. Dadurch kann es länger dauern, bis das Telefon gestartet wird, und durch die ständige Aktivität der Anwendung wird die gesamte Leistung des Telefons beeinträchtigt."</string>
+    <string name="permlab_broadcastSticky">"dauerhaften Broadcast senden"</string>
+    <string name="permdesc_broadcastSticky">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Telefon langsam oder unstabil machen, da zuviel Speicherplatz belegt ist."</string>
+    <string name="permlab_readContacts">"Kontaktdaten lesen"</string>
+    <string name="permdesc_readContacts">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu lesen. Schädliche Anwendungen können so Ihre Daten an andere Personen senden."</string>
+    <string name="permlab_writeContacts">"Kontaktdaten schreiben"</string>
+    <string name="permdesc_writeContacts">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu ändern. Schädliche Anwendungen können so Ihre Kontaktdaten löschen oder verändern."</string>
+    <string name="permlab_writeOwnerData">"Eigentümerdaten schreiben"</string>
+    <string name="permdesc_writeOwnerData">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Eigentümerdaten zu ändern. Schädliche Anwendungen können so Eigentümerdaten löschen oder verändern."</string>
+    <string name="permlab_readOwnerData">"Eigentümerdaten lesen"</string>
+    <string name="permdesc_readOwnerData">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Eigentümerdaten zu lesen. Schädliche Anwendungen können so Eigentümerdaten lesen."</string>
+    <string name="permlab_readCalendar">"Kalenderdaten lesen"</string>
+    <string name="permdesc_readCalendar">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kalenderereignisse zu lesen. Schädliche Anwendungen können so Ihre Kalenderereignisse an andere Personen senden."</string>
+    <string name="permlab_writeCalendar">"Kalenderdaten schreiben"</string>
+    <string name="permdesc_writeCalendar">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Kalenderereignisse zu ändern. Schädliche Anwendungen können so Ihre Kalenderdaten löschen oder verändern."</string>
+    <string name="permlab_accessMockLocation">"Falsche Standortquellen für Testzwecke"</string>
+    <string name="permdesc_accessMockLocation">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben."</string>
+    <string name="permlab_accessLocationExtraCommands">"Auf zusätzliche Dienstanbieterbefehle für Standort zugreifen"</string>
+    <string name="permdesc_accessLocationExtraCommands">"Zugriff auf zusätzliche Dienstanbieterbefehle für Standort. Schädliche Anwendungen könnten so die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
+    <string name="permlab_accessFineLocation">"genauer (GPS-) Standort"</string>
+    <string name="permdesc_accessFineLocation">"Zugriff auf genaue Standortquellen wie GPS auf dem Telefon (falls verfügbar). Schädliche Anwendungen können damit bestimmen, so Sie sich befinden und so Ihren Akku zusätzlich belasten."</string>
+    <string name="permlab_accessCoarseLocation">"Ungefährer (netzwerkbasierter) Standort"</string>
+    <string name="permdesc_accessCoarseLocation">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzwerks zu, um falls möglich den ungefähren Standort des Telefons zu bestimmen. Schädliche Anwendungen können damit herauszufinden, wo Sie sich ungefähr befinden."</string>
+    <string name="permlab_accessSurfaceFlinger">"Auf SurfaceFlinger zugreifen"</string>
+    <string name="permdesc_accessSurfaceFlinger">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden."</string>
+    <string name="permlab_readFrameBuffer">"Frame-Puffer lesen"</string>
+    <string name="permdesc_readFrameBuffer">"Ermöglicht einer Anwendung, den Inhalt des Frame-Puffers zu lesen."</string>
+    <string name="permlab_modifyAudioSettings">"Audio-Einstellungen ändern"</string>
+    <string name="permdesc_modifyAudioSettings">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen."</string>
+    <string name="permlab_recordAudio">"Audio aufnehmen"</string>
+    <string name="permdesc_recordAudio">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen."</string>
+    <string name="permlab_camera">"Fotos aufnehmen"</string>
+    <string name="permdesc_camera">"Ermöglicht der Anwendung, Fotos mit der Kamera aufzunehmen. So kann die Anwendung jederzeit Bilder zusammentragen, die von der Kamera erfasst werden."</string>
+    <string name="permlab_brick">"Telefon dauerhaft deaktivieren."</string>
+    <string name="permdesc_brick">"Ermöglicht der Anwendung, das gesamte Telefon dauerhaft zu deaktivieren. Dies birgt hohe Risiken."</string>
+    <string name="permlab_reboot">"Neustart des Telefons erzwingen"</string>
+    <string name="permdesc_reboot">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen."</string>
+    <string name="permlab_mount_unmount_filesystems">"Dateisysteme bereitstellen oder Bereitstellung aufheben"</string>
+    <string name="permdesc_mount_unmount_filesystems">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Speicherplätze bereitzustellen oder die Bereitstellung aufzuheben."</string>
+    <string name="permlab_vibrate">"Vibrationsalarm steuern"</string>
+    <string name="permdesc_vibrate">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern."</string>
+    <string name="permlab_flashlight">"Lichtanzeige steuern"</string>
+    <string name="permdesc_flashlight">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern."</string>
+    <string name="permlab_hardware_test">"Hardware testen"</string>
+    <string name="permdesc_hardware_test">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern."</string>
+    <string name="permlab_callPhone">"Telefonnummern direkt anrufen"</string>
+    <string name="permdesc_callPhone">"Ermöglicht dem Anwendungen, Rufnummern ohne Ihr Eingreifen zu wählen. Schädliche Anwendungen können für unerwartete Anrufe auf Ihrer Telefonrechnung verantwortlich sein. Das Wählen von Notrufnummern ist allerdings nicht möglich."</string>
+    <string name="permlab_callPrivileged">"Alle Telefonnummern direkt anrufen"</string>
+    <string name="permdesc_callPrivileged">"Ermöglicht der Anwendung, ohne Ihr Eingreifen eine beliebige Telefonnummer zu wählen, einschließlich Notfallnummern. Schädliche Anwendungen können so unnötige und illegale Anrufe an Notdienste tätigen."</string>
+    <string name="permlab_locationUpdates">"Benachrichtigungen für Standortaktualisierung steuern"</string>
+    <string name="permdesc_locationUpdates">"Ermöglicht die Aktivierung/Deaktivierung der Radio-Benachrichtigungen über Standort-Updates. Nicht für normale Anwendungen vorgesehen."</string>
+    <string name="permlab_checkinProperties">"Auf Check-In-Eigenschaften zugreifen"</string>
+    <string name="permdesc_checkinProperties">"Ermöglicht den Schreib-/Lesezugriff auf vom Check-In-Service hochgeladene Elemente. Nicht für normale Anwendungen vorgesehen."</string>
+    <string name="permlab_modifyPhoneState">"Telefonstatus ändern"</string>
+    <string name="permdesc_modifyPhoneState">"Ermöglicht einer Anwendung, die Telefonfunktionen des Gerätes zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder das Radio des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
+    <string name="permlab_readPhoneState">"Telefonstatus lesen"</string>
+    <string name="permdesc_readPhoneState">"Ermöglicht der Anwendung, auf die Telefonfunktionen des Gerätes zuzugreifen. Eine Anwendung mit dieser Berechtigung kann unter anderem bestimmen, welche Telefonnummer dieses Telefon verwendet, ob ein Anruf aktiv ist oder mit welcher Nummer der Anrufer verbunden ist."</string>
+    <string name="permlab_wakeLock">"Standby-Modus deaktivieren"</string>
+    <string name="permdesc_wakeLock">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren."</string>
+    <string name="permlab_devicePower">"Gerät ein- oder ausschalten"</string>
+    <string name="permdesc_devicePower">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten."</string>
+    <string name="permlab_factoryTest">"In Werkstestmodus ausführen"</string>
+    <string name="permdesc_factoryTest">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Telefonhardware zugegriffen werden kann. Nur verfügbar, wenn ein Telefon im Werkstestmodus ausgeführt wird."</string>
+    <string name="permlab_setWallpaper">"Hintergrundbild festlegen"</string>
+    <string name="permdesc_setWallpaper">"Ermöglicht der Anwendung, das System-Hintergrundbild festzulegen."</string>
+    <string name="permlab_setWallpaperHints">"Größenhinweise für Hintergrundbild festlegen"</string>
+    <string name="permdesc_setWallpaperHints">"Ermöglicht der Anwendung, die Größenhinweise für das Hintergrundbild festzulegen."</string>
+    <string name="permlab_masterClear">"System auf Werkseinstellung zurücksetzen"</string>
+    <string name="permdesc_masterClear">"Ermöglicht einer Anwendung, das System komplett auf Werkseinstellung zurückzusetzen. Hierbei werden alle Daten, Konfigurationen und installierten Anwendungen gelöscht."</string>
+    <string name="permlab_setTimeZone">"Zeitzone festlegen"</string>
+    <string name="permdesc_setTimeZone">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern."</string>
+    <string name="permlab_getAccounts">"bekannte Konten suchen"</string>
+    <string name="permdesc_getAccounts">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen."</string>
+    <string name="permlab_accessNetworkState">"Netzwerkstatus anzeigen"</string>
+    <string name="permdesc_accessNetworkState">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen."</string>
+    <string name="permlab_createNetworkSockets">"Uneingeschränkter Internetzugriff"</string>
+    <string name="permdesc_createNetworkSockets">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten."</string>
+    <string name="permlab_writeApnSettings">"Einstellungen für Zugriffspunktname schreiben"</string>
+    <string name="permdesc_writeApnSettings">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern."</string>
+    <string name="permlab_changeNetworkState">"Netzwerkkonnektivität ändern"</string>
+    <string name="permdesc_changeNetworkState">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern."</string>
+    <string name="permlab_accessWifiState">"WLAN-Status anzeigen"</string>
+    <string name="permdesc_accessWifiState">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen."</string>
+    <string name="permlab_changeWifiState">"WLAN-Status ändern"</string>
+    <string name="permdesc_changeWifiState">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen."</string>
+    <string name="permlab_bluetoothAdmin">"Bluetooth-Verwaltung"</string>
+    <string name="permdesc_bluetoothAdmin">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen."</string>
+    <string name="permlab_bluetooth">"Bluetooth-Verbindungen herstellen"</string>
+    <string name="permdesc_bluetooth">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren."</string>
+    <string name="permlab_disableKeyguard">"Tastensperre deaktivieren"</string>
+    <string name="permdesc_disableKeyguard">"Ermöglicht einer Anwendung, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. So wird die Tastensperre vom Telefon deaktiviert, wenn ein Anruf eingeht, und nach Beendigung des Anrufs wieder aktiviert."</string>
+    <string name="permlab_readSyncSettings">"Synchronisierungseinstellungen lesen"</string>
+    <string name="permdesc_readSyncSettings">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+    <string name="permlab_writeSyncSettings">"Synchronisierungseinstellungen schreiben"</string>
+    <string name="permdesc_writeSyncSettings">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+    <string name="permlab_readSyncStats">"Synchronisierungsstatistiken lesen"</string>
+    <string name="permdesc_readSyncStats">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen."</string>
+    <string name="permlab_subscribedFeedsRead">"Abonnierte Feeds lesen"</string>
+    <string name="permdesc_subscribedFeedsRead">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen."</string>
+    <string name="permlab_subscribedFeedsWrite">"Abonnierte Feeds schreiben"</string>
+    <string name="permdesc_subscribedFeedsWrite">"Ermöglicht einer Anwendung, Änderungen an den kürzlich synchronisierten Feeds vorzunehmen. Schädliche Anwendungen könnten so Ihre synchronisierten Feeds ändern."</string>
+    <!-- no translation found for phoneTypes:7 (9192514806975898961) -->
+    <!-- no translation found for emailAddressTypes:3 (2374913952870110618) -->
+    <!-- no translation found for postalAddressTypes:3 (4932682847595299369) -->
+    <!-- no translation found for imAddressTypes:3 (3145118944639869809) -->
+    <!-- no translation found for organizationTypes:2 (3455047468583965104) -->
+  <string-array name="imProtocols">
+    <item>"AIM"</item>
+    <item>"Windows Live"</item>
+    <item>"Yahoo"</item>
+    <item>"Skype"</item>
+    <item>"QQ"</item>
+    <item>"Google Talk"</item>
+    <item>"ICQ"</item>
+    <item>"Jabber"</item>
+  </string-array>
+    <!-- no translation found for keyguard_password_enter_pin_code (3731488827218876115) -->
+    <skip />
+    <string name="keyguard_password_wrong_pin_code">"Falscher PIN-Code!"</string>
+    <string name="keyguard_label_text">"Drücken Sie zum Entsperren auf \"Menü\" und dann auf \"0\"."</string>
+    <string name="emergency_call_dialog_number_for_display">"Notrufnummer"</string>
+    <string name="lockscreen_carrier_default">"(kein Dienst)"</string>
+    <!-- no translation found for lockscreen_screen_locked (7288443074806832904) -->
+    <skip />
+    <string name="lockscreen_instructions_when_pattern_enabled">"Drücken Sie auf die \"Menü\", um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
+    <string name="lockscreen_instructions_when_pattern_disabled">"Drücken Sie zum Entsperren auf \"Menü\"."</string>
+    <!-- no translation found for lockscreen_pattern_instructions (7478703254964810302) -->
+    <skip />
+    <string name="lockscreen_emergency_call">"Notruf"</string>
+    <string name="lockscreen_pattern_correct">"Korrekt!"</string>
+    <!-- no translation found for lockscreen_pattern_wrong (4817583279053112312) -->
+    <skip />
+    <string name="lockscreen_plugged_in">"Wird aufgeladen (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+    <string name="lockscreen_low_battery">"Stecken Sie Ihr Ladegerät ein."</string>
+    <string name="lockscreen_missing_sim_message_short">"Keine SIM-Karte."</string>
+    <string name="lockscreen_missing_sim_message">"Keine SIM-Karte im Telefon."</string>
+    <string name="lockscreen_missing_sim_instructions">"Bitte legen Sie eine SIM-Karte ein."</string>
+    <string name="lockscreen_network_locked_message">"Netzwerk gesperrt"</string>
+    <string name="lockscreen_sim_puk_locked_message">"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."</string>
+    <string name="lockscreen_sim_puk_locked_instructions">"Wenden Sie sich an den Kunden-Support."</string>
+    <string name="lockscreen_sim_locked_message">"SIM-Karte ist gesperrt."</string>
+    <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM-Karte wird entsperrt..."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+    <string name="lockscreen_too_many_failed_attempts_countdown">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
+    <string name="lockscreen_forgot_pattern_button_text">"Muster vergessen?"</string>
+    <string name="lockscreen_glogin_too_many_attempts">"Zu viele Versuche!"</string>
+    <!-- no translation found for lockscreen_glogin_instructions (7400120254204758548) -->
+    <skip />
+    <string name="lockscreen_glogin_username_hint">"Nutzername (E-Mail)"</string>
+    <string name="lockscreen_glogin_password_hint">"Passwort"</string>
+    <string name="lockscreen_glogin_submit_button">"Anmelden"</string>
+    <string name="lockscreen_glogin_invalid_input">"Ungültiger  Nutzername oder ungültiges Passwort."</string>
+    <string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
+    <!-- no translation found for hour_minute_ampm (7044207493989843593) -->
+    <skip />
+    <!-- no translation found for hour_minute_cap_ampm (5778825208801303756) -->
+    <skip />
+    <!-- no translation found for hour_ampm (7618670480400517084) -->
+    <skip />
+    <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+    <skip />
+    <string name="status_bar_clear_all_button">"Benachrichtigungen löschen"</string>
+    <string name="status_bar_no_notifications_title">"Keine Benachrichtigungen"</string>
+    <string name="status_bar_ongoing_events_title">"Aktuell"</string>
+    <string name="status_bar_latest_events_title">"Benachrichtigungen"</string>
+    <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+    <skip />
+    <string name="battery_status_charging">"Wird aufgeladen..."</string>
+    <string name="battery_low_title">"Ladegerät anschließen"</string>
+    <string name="battery_low_subtitle">"Akku ist fast leer."</string>
+    <string name="battery_low_percent_format">"Nur noch weniger als <xliff:g id="NUMBER">%d%%</xliff:g> vorhanden."</string>
+    <string name="factorytest_failed">"Werkstest fehlgeschlagen"</string>
+    <string name="factorytest_not_system">"Die Aktion FACTORY_TEST wird nur für unter \"/system/app\" gespeicherte Pakete unterstützt."</string>
+    <string name="factorytest_no_action">"Es wurden kein Paket mit der Aktion FACTORY_TEST gefunden."</string>
+    <string name="factorytest_reboot">"Neu booten"</string>
+    <string name="save_password_label">"Bestätigen"</string>
+    <string name="save_password_message">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
+    <string name="save_password_notnow">"Nicht jetzt"</string>
+    <string name="save_password_remember">"Speichern"</string>
+    <string name="save_password_never">"Niemals"</string>
+    <string name="open_permission_deny">"Sie sind zum Öffnen dieser Seite nicht berechtigt."</string>
+    <string name="text_copied">"Text in Zwischenablage kopiert."</string>
+    <string name="more_item_label">"Mehr"</string>
+    <string name="prepend_shortcut_label">"Menü+"</string>
+    <string name="menu_space_shortcut_label">"Leerzeichen"</string>
+    <string name="menu_enter_shortcut_label">"Enter"</string>
+    <string name="menu_delete_shortcut_label">"löschen"</string>
+    <string name="search_go">"Suche"</string>
+    <string name="today">"Heute"</string>
+    <string name="yesterday">"Gestern"</string>
+    <string name="tomorrow">"Morgen"</string>
+    <string name="oneMonthDurationPast">"Vor 1 Monat"</string>
+    <!-- no translation found for beforeOneMonthDurationPast (909134546836499826) -->
+    <skip />
+  <plurals name="num_seconds_ago">
+    <item quantity="one">"Vor 1 Sekunde"</item>
+    <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+  </plurals>
+  <plurals name="num_minutes_ago">
+    <item quantity="one">"Vor 1 Minute"</item>
+    <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+  </plurals>
+  <plurals name="num_hours_ago">
+    <item quantity="one">"Vor 1 Stunde"</item>
+    <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+  </plurals>
+  <plurals name="num_days_ago">
+    <item quantity="one">"Gestern"</item>
+    <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+  </plurals>
+  <plurals name="in_num_seconds">
+    <item quantity="one">"in 1 Sekunde"</item>
+    <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+  </plurals>
+  <plurals name="in_num_minutes">
+    <item quantity="one">"in 1 Minute"</item>
+    <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+  </plurals>
+  <plurals name="in_num_hours">
+    <item quantity="one">"in 1 Stunde"</item>
+    <item quantity="other">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+  </plurals>
+  <plurals name="in_num_days">
+    <item quantity="one">"morgen"</item>
+    <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+  </plurals>
+    <string name="preposition_for_date">"am %s"</string>
+    <string name="preposition_for_time">"am %s"</string>
+    <string name="preposition_for_year">"in %s"</string>
+    <string name="day">"Tag"</string>
+    <string name="days">"Tage"</string>
+    <string name="hour">"Stunde"</string>
+    <string name="hours">"Stunden"</string>
+    <string name="minute">"Min"</string>
+    <string name="minutes">"Minuten"</string>
+    <string name="second">"Sek"</string>
+    <string name="seconds">"s"</string>
+    <string name="week">"Woche"</string>
+    <string name="weeks">"Wochen"</string>
+    <string name="year">"Jahr"</string>
+    <string name="years">"Jahre"</string>
+    <string name="sunday">"Sonntag"</string>
+    <string name="monday">"Montag"</string>
+    <string name="tuesday">"Dienstag"</string>
+    <string name="wednesday">"Mittwoch"</string>
+    <string name="thursday">"Donnerstag"</string>
+    <string name="friday">"Freitag"</string>
+    <string name="saturday">"Samstag"</string>
+    <string name="every_weekday">"Jeden Wochentag (Mo-Fr)"</string>
+    <string name="daily">"Täglich"</string>
+    <string name="weekly">"Jede Woche am <xliff:g id="DAY">%s</xliff:g>"</string>
+    <string name="monthly">"Monatlich"</string>
+    <string name="yearly">"Jährlich"</string>
+    <string name="VideoView_error_title">"Video kann nicht wiedergegeben werden."</string>
+    <string name="VideoView_error_text_unknown">"Dieses Video kann leider nicht abgespielt werden."</string>
+    <string name="VideoView_error_button">"OK"</string>
+    <!-- no translation found for am (4885350190794996052) -->
+    <skip />
+    <string name="pm">".."</string>
+    <string name="numeric_date">"<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="YEAR">%Y</xliff:g>"</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
+    <string name="wday1_date1_wday2_date2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>"</string>
+    <string name="date1_time1_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
+    <string name="date1_date2">"<xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>"</string>
+    <string name="time1_time2">"<xliff:g id="TIME1">%1$s</xliff:g> – <xliff:g id="TIME2">%2$s</xliff:g>"</string>
+    <string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
+    <string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
+    <string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
+    <string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
+    <!-- no translation found for full_date_month_first (4336173217988750514) -->
+    <skip />
+    <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g>. <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
+    <!-- no translation found for medium_date_month_first (4631100332959851900) -->
+    <skip />
+    <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g>. <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
+    <!-- no translation found for twelve_hour_time_format (8739508068310928118) -->
+    <skip />
+    <!-- no translation found for twenty_four_hour_time_format (2267729602804604858) -->
+    <skip />
+    <string name="noon">"Mittag"</string>
+    <string name="Noon">"Mittag"</string>
+    <string name="midnight">"Mitternacht"</string>
+    <string name="Midnight">"Mitternacht"</string>
+    <!-- no translation found for month_day (5565829181417740906) -->
+    <skip />
+    <!-- no translation found for month (7026169712234774086) -->
+    <skip />
+    <string name="month_day_year">"<xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
+    <!-- no translation found for month_year (9219019380312413367) -->
+    <skip />
+    <string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
+    <string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
+    <string name="same_year_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>"</string>
+    <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>"</string>
+    <string name="same_year_mdy1_mdy2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR">%9$s</xliff:g>"</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR">%9$s</xliff:g>"</string>
+    <string name="same_year_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>"</string>
+    <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>"</string>
+    <string name="numeric_mdy1_mdy2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+    <string name="numeric_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>"</string>
+    <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>"</string>
+    <string name="same_month_mdy1_mdy2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+    <string name="same_month_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="abbrev_month_day_year">"<xliff:g id="MONTH">%b</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
+    <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+    <skip />
+    <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+    <skip />
+    <!-- no translation found for abbrev_month (3131032032850777433) -->
+    <skip />
+    <string name="day_of_week_long_sunday">"Sonntag"</string>
+    <string name="day_of_week_long_monday">"Montag"</string>
+    <string name="day_of_week_long_tuesday">"Dienstag"</string>
+    <string name="day_of_week_long_wednesday">"Mittwoch"</string>
+    <string name="day_of_week_long_thursday">"Donnerstag"</string>
+    <string name="day_of_week_long_friday">"Freitag"</string>
+    <string name="day_of_week_long_saturday">"Samstag"</string>
+    <string name="day_of_week_medium_sunday">"So"</string>
+    <string name="day_of_week_medium_monday">"Mo"</string>
+    <string name="day_of_week_medium_tuesday">"Di"</string>
+    <string name="day_of_week_medium_wednesday">"Mi"</string>
+    <string name="day_of_week_medium_thursday">"Do"</string>
+    <string name="day_of_week_medium_friday">"Fr"</string>
+    <string name="day_of_week_medium_saturday">"Sa"</string>
+    <string name="day_of_week_short_sunday">"So"</string>
+    <string name="day_of_week_short_monday">"Mo"</string>
+    <string name="day_of_week_short_tuesday">"Di"</string>
+    <string name="day_of_week_short_wednesday">"Mi"</string>
+    <string name="day_of_week_short_thursday">"Do"</string>
+    <string name="day_of_week_short_friday">"Fr"</string>
+    <string name="day_of_week_short_saturday">"Sa"</string>
+    <string name="day_of_week_shorter_sunday">"So"</string>
+    <string name="day_of_week_shorter_monday">"März"</string>
+    <string name="day_of_week_shorter_tuesday">"Di"</string>
+    <string name="day_of_week_shorter_wednesday">"Mi"</string>
+    <string name="day_of_week_shorter_thursday">"Do"</string>
+    <string name="day_of_week_shorter_friday">"Fr"</string>
+    <string name="day_of_week_shorter_saturday">"Sa"</string>
+    <string name="day_of_week_shortest_sunday">"Sep"</string>
+    <string name="day_of_week_shortest_monday">"Mo"</string>
+    <string name="day_of_week_shortest_tuesday">"Do"</string>
+    <string name="day_of_week_shortest_wednesday">"Mi"</string>
+    <string name="day_of_week_shortest_thursday">"Do"</string>
+    <string name="day_of_week_shortest_friday">"Fr"</string>
+    <string name="day_of_week_shortest_saturday">"Sa"</string>
+    <string name="month_long_january">"Januar"</string>
+    <string name="month_long_february">"Februar"</string>
+    <string name="month_long_march">"März"</string>
+    <string name="month_long_april">"April"</string>
+    <string name="month_long_may">"Mai"</string>
+    <string name="month_long_june">"Juni"</string>
+    <string name="month_long_july">"Juli"</string>
+    <string name="month_long_august">"August"</string>
+    <string name="month_long_september">"September"</string>
+    <string name="month_long_october">"Oktober"</string>
+    <string name="month_long_november">"November"</string>
+    <string name="month_long_december">"Dezember"</string>
+    <string name="month_medium_january">"Jan."</string>
+    <string name="month_medium_february">"Feb."</string>
+    <string name="month_medium_march">"März"</string>
+    <string name="month_medium_april">"Apr."</string>
+    <string name="month_medium_may">"Mai"</string>
+    <string name="month_medium_june">"Juni"</string>
+    <string name="month_medium_july">"Juli"</string>
+    <string name="month_medium_august">"Aug"</string>
+    <string name="month_medium_september">"Sep."</string>
+    <string name="month_medium_october">"Okt."</string>
+    <string name="month_medium_november">"Nov."</string>
+    <string name="month_medium_december">"Dez."</string>
+    <string name="month_shortest_january">"Juli"</string>
+    <string name="month_shortest_february">"Fr"</string>
+    <string name="month_shortest_march">"März"</string>
+    <string name="month_shortest_april">"Apr"</string>
+    <string name="month_shortest_may">"Mo"</string>
+    <string name="month_shortest_june">"Juni"</string>
+    <string name="month_shortest_july">"Juli"</string>
+    <string name="month_shortest_august">"Aug."</string>
+    <string name="month_shortest_september">"Sep"</string>
+    <string name="month_shortest_october">"Okt."</string>
+    <string name="month_shortest_november">"No"</string>
+    <string name="month_shortest_december">"Dez."</string>
+    <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+    <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+    <string name="selectAll">"Alles auswählen"</string>
+    <string name="cut">"Ausschneiden"</string>
+    <string name="cutAll">"Alles ausschneiden"</string>
+    <string name="copy">"Kopieren"</string>
+    <string name="copyAll">"Alles kopieren"</string>
+    <string name="paste">"Einfügen"</string>
+    <string name="copyUrl">"URL kopieren"</string>
+    <!-- no translation found for inputMethod (7673923508389094672) -->
+    <skip />
+    <!-- no translation found for editTextMenuTitle (1672989176958581452) -->
+    <skip />
+    <string name="low_internal_storage_view_title">"Geringer Speicher"</string>
+    <string name="low_internal_storage_view_text">"Kaum noch freier Telefonspeicher verfügbar."</string>
+    <string name="ok">"OK"</string>
+    <string name="cancel">"Abbrechen"</string>
+    <string name="yes">"OK"</string>
+    <string name="no">"Abbrechen"</string>
+    <string name="capital_on">"EIN"</string>
+    <string name="capital_off">"AUS"</string>
+    <string name="whichApplication">"Aktion beenden mit"</string>
+    <string name="alwaysUse">"Standardmäßig für diese Aktion verwenden."</string>
+    <string name="clearDefaultHintMsg">"Löschen Sie die Standardeinstellungen unter \"Starteinstellungen &gt; Anwendungen &gt; Anwendungen verwalten\"."</string>
+    <string name="chooseActivity">"Aktion auswählen"</string>
+    <string name="noApplications">"Diese Aktion kann von keiner Anwendung ausgeführt werden."</string>
+    <string name="aerr_title">"Tut uns leid!"</string>
+    <string name="aerr_application">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) wurde unerwartet beendet. Versuchen Sie es erneut."</string>
+    <string name="aerr_process">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> wurde unerwartet beendet. Versuchen Sie es erneut."</string>
+    <string name="anr_title">"Tut uns leid!"</string>
+    <string name="anr_activity_application">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> (in Anwendung <xliff:g id="APPLICATION">%2$s</xliff:g>) reagiert nicht."</string>
+    <string name="anr_activity_process">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> (in Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) reagiert nicht."</string>
+    <string name="anr_application_process">"Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (in Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) reagiert nicht."</string>
+    <string name="anr_process">"Prozess <xliff:g id="PROCESS">%1$s</xliff:g> reagiert nicht."</string>
+    <string name="force_close">"Schließen erzwingen"</string>
+    <string name="wait">"Warten"</string>
+    <string name="debug">"Fehler suchen"</string>
+    <string name="sendText">"Aktion für Text auswählen"</string>
+    <string name="volume_ringtone">"Klingeltonlautstärke"</string>
+    <string name="volume_music">"Lautstärke"</string>
+    <string name="volume_call">"Lautstärke bei eingehendem Anruf"</string>
+    <string name="volume_alarm">"Lautstärke für Alarm"</string>
+    <string name="volume_unknown">"Lautstärke"</string>
+    <string name="ringtone_default">"Standard-Klingelton"</string>
+    <string name="ringtone_default_with_actual">"Standard-Klingelton (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+    <string name="ringtone_silent">"Lautlos"</string>
+    <!-- no translation found for ringtone_picker_title (3515143939175119094) -->
+    <skip />
+    <string name="ringtone_unknown">"Unbekannter Klingelton"</string>
+  <plurals name="wifi_available">
+    <item quantity="one">"WLAN-Netzwerk verfügbar"</item>
+    <item quantity="other">"WLAN-Netzwerke verfügbar"</item>
+  </plurals>
+  <plurals name="wifi_available_detailed">
+    <item quantity="one">"Verfügbares WLAN-Netzwerk öffnen"</item>
+    <item quantity="other">"Verfügbare WLAN-Netzwerke öffnen"</item>
+  </plurals>
+    <!-- no translation found for select_character (3365550120617701745) -->
+    <skip />
+    <string name="sms_control_default_app_name">"Unbekannte Anwendung"</string>
+    <string name="sms_control_title">"Kurznachrichten werden gesendet"</string>
+    <string name="sms_control_message">"Es werden eine große Anzahl an Kurznachrichten versendet. Wählen Sie \"OK\", um fortzufahren, oder drücken Sie auf \"Abbrechen\", um den Sendevorgang zu beenden."</string>
+    <string name="sms_control_yes">"OK"</string>
+    <string name="sms_control_no">"Abbrechen"</string>
+    <string name="date_time_set">"Einstellen"</string>
+    <string name="default_permission_group">"Standard"</string>
+    <string name="no_permissions">"Keine Berechtigungen erforderlich"</string>
+    <string name="perms_hide"><b>"Ausblenden"</b></string>
+    <string name="perms_show_all"><b>"Alle anzeigen"</b></string>
+    <string name="googlewebcontenthelper_loading">"Ladevorgang läuft..."</string>
+    <string name="usb_storage_title">"USB-Verbindung"</string>
+    <string name="usb_storage_message">"Sie haben Ihr Telefon über einen USB-Anschluss mit Ihrem Computer verbunden. Wählen Sie \"Bereitstellen\", wenn Sie Dateien auf Ihren Computer oder die SD-Karte Ihres Telefons kopieren möchten."</string>
+    <string name="usb_storage_button_mount">"Bereitstellen"</string>
+    <string name="usb_storage_button_unmount">"Nicht bereitstellen"</string>
+    <string name="usb_storage_error_message">"Bei der Verwendung Ihrer SD-Karte als USB-Speicher ist ein Problem aufgetreten."</string>
+    <string name="usb_storage_notification_title">"USB-Verbindung"</string>
+    <string name="usb_storage_notification_message">"Wählen Sie die Dateien aus, die von Ihrem oder auf Ihren Computer kopiert werden sollen."</string>
+    <!-- no translation found for select_input_method (2086499663193509436) -->
+    <skip />
+    <!-- no translation found for fast_scroll_alphabet (5433275485499039199) -->
+    <skip />
+    <!-- no translation found for fast_scroll_numeric_alphabet (4030170524595123610) -->
+    <skip />
+    <!-- no translation found for candidates_style (5248064431114273041) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-en-rAU/arrays.xml b/core/res/res/values-en-rAU/arrays.xml
new file mode 100644
index 0000000..46351e6
--- /dev/null
+++ b/core/res/res/values-en-rAU/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<resources>
+
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_lat_lng">
+        <item>-26037042</item>
+        <item>137197266</item>
+    </integer-array>
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_zoom">
+        <item>3</item>
+    </integer-array>
+
+</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..b9df983
--- /dev/null
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -0,0 +1,1256 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="byteShort">"B"</string>
+    <!-- no translation found for kilobyteShort (5865542430193761682) -->
+    <skip />
+    <!-- no translation found for megabyteShort (112984851085937882) -->
+    <skip />
+    <!-- no translation found for gigabyteShort (8586075069559273847) -->
+    <skip />
+    <!-- no translation found for terabyteShort (5828502357595687794) -->
+    <skip />
+    <!-- no translation found for petabyteShort (7523248732657962413) -->
+    <skip />
+    <!-- no translation found for untitled (284687023829080340) -->
+    <skip />
+    <!-- no translation found for ellipsis (8538883953764277342) -->
+    <skip />
+    <!-- no translation found for emptyPhoneNumber (6416283285732095329) -->
+    <skip />
+    <!-- no translation found for unknownName (3974255879290140525) -->
+    <skip />
+    <!-- no translation found for defaultVoiceMailAlphaTag (6484324201071049939) -->
+    <skip />
+    <!-- no translation found for defaultMsisdnAlphaTag (4953008223227371928) -->
+    <skip />
+    <!-- no translation found for mmiError (7480678835624852655) -->
+    <skip />
+    <!-- no translation found for serviceEnabled (4042194305396115167) -->
+    <skip />
+    <!-- no translation found for serviceEnabledFor (638808419103886277) -->
+    <skip />
+    <!-- no translation found for serviceDisabled (1059935666763511541) -->
+    <skip />
+    <!-- no translation found for serviceRegistered (7639869107156932038) -->
+    <skip />
+    <!-- no translation found for serviceErased (4602215208593071820) -->
+    <skip />
+    <!-- no translation found for passwordIncorrect (5142040651297346232) -->
+    <skip />
+    <!-- no translation found for mmiComplete (3178168770150013486) -->
+    <skip />
+    <!-- no translation found for badPin (5103184589972647739) -->
+    <skip />
+    <!-- no translation found for badPuk (2200634943393540609) -->
+    <skip />
+    <!-- no translation found for mismatchPin (5055729703806180857) -->
+    <skip />
+    <!-- no translation found for invalidPin (6201854814319326475) -->
+    <skip />
+    <!-- no translation found for needPuk (4788728144863892764) -->
+    <skip />
+    <!-- no translation found for needPuk2 (7056908944942451033) -->
+    <skip />
+    <!-- no translation found for ClipMmi (5649729434121615509) -->
+    <skip />
+    <!-- no translation found for ClirMmi (5220979296096544477) -->
+    <skip />
+    <!-- no translation found for CfMmi (4998483717856803914) -->
+    <skip />
+    <!-- no translation found for CwMmi (5678103638951836350) -->
+    <skip />
+    <!-- no translation found for BaMmi (6030555200442855833) -->
+    <skip />
+    <!-- no translation found for PwdMmi (2549941247959366670) -->
+    <skip />
+    <!-- no translation found for PinMmi (2463353963837922189) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOnNextCallOn (4005921990799469144) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOnNextCallOff (1497360760012205230) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOffNextCallOn (604591440398078227) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOffNextCallOff (5114039908683246336) -->
+    <skip />
+    <!-- no translation found for serviceNotProvisioned (3754416031529306610) -->
+    <skip />
+    <!-- no translation found for CLIRPermanent (3819908477891272611) -->
+    <skip />
+    <!-- no translation found for serviceClassVoice (3059107563169935913) -->
+    <skip />
+    <!-- no translation found for serviceClassData (2669025626575716504) -->
+    <skip />
+    <!-- no translation found for serviceClassFAX (973109472405729679) -->
+    <skip />
+    <!-- no translation found for serviceClassSMS (3857383928743625711) -->
+    <skip />
+    <!-- no translation found for serviceClassDataAsync (8526461993032174729) -->
+    <skip />
+    <!-- no translation found for serviceClassDataSync (2461138395498381801) -->
+    <skip />
+    <!-- no translation found for serviceClassPacket (8119604233041078065) -->
+    <skip />
+    <!-- no translation found for serviceClassPAD (202892636830042266) -->
+    <skip />
+    <!-- no translation found for cfTemplateNotForwarded (3171755805856206604) -->
+    <skip />
+    <!-- no translation found for cfTemplateForwarded (2468661573318024785) -->
+    <skip />
+    <!-- no translation found for cfTemplateForwardedTime (5151810870794744740) -->
+    <skip />
+    <!-- no translation found for cfTemplateRegistered (5685211900474527085) -->
+    <skip />
+    <!-- no translation found for cfTemplateRegisteredTime (2978918277762252776) -->
+    <skip />
+    <!-- no translation found for httpErrorOk (984913805621139001) -->
+    <skip />
+    <!-- no translation found for httpError (9177990053748151835) -->
+    <skip />
+    <!-- no translation found for httpErrorLookup (5251341716070330936) -->
+    <skip />
+    <!-- no translation found for httpErrorUnsupportedAuthScheme (2865679883634239474) -->
+    <skip />
+    <!-- no translation found for httpErrorAuth (1637382600929594620) -->
+    <skip />
+    <!-- no translation found for httpErrorProxyAuth (5947648983995807455) -->
+    <skip />
+    <!-- no translation found for httpErrorConnect (129984292497034683) -->
+    <skip />
+    <!-- no translation found for httpErrorIO (8128922048686581131) -->
+    <skip />
+    <!-- no translation found for httpErrorTimeout (8357966263983739012) -->
+    <skip />
+    <!-- no translation found for httpErrorRedirectLoop (4122379005100433886) -->
+    <skip />
+    <!-- no translation found for httpErrorUnsupportedScheme (4072339858288462569) -->
+    <skip />
+    <!-- no translation found for httpErrorFailedSslHandshake (2316625025255452595) -->
+    <skip />
+    <!-- no translation found for httpErrorBadUrl (8885244563103716039) -->
+    <skip />
+    <!-- no translation found for httpErrorFile (1408273621719669493) -->
+    <skip />
+    <!-- no translation found for httpErrorFileNotFound (2309088465300506314) -->
+    <skip />
+    <!-- no translation found for httpErrorTooManyRequests (3764334538393544875) -->
+    <skip />
+    <!-- no translation found for contentServiceSync (4863236165350475642) -->
+    <skip />
+    <!-- no translation found for contentServiceSyncNotificationTitle (6855304679069026824) -->
+    <skip />
+    <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8477597194404210723) -->
+    <skip />
+    <!-- no translation found for low_memory (4191592786596642367) -->
+    <skip />
+    <!-- no translation found for me (4616693653158602117) -->
+    <skip />
+    <!-- no translation found for power_dialog (8210256011408959109) -->
+    <skip />
+    <!-- no translation found for silent_mode (5218239246946854300) -->
+    <skip />
+    <!-- no translation found for turn_on_radio (1901054698789840131) -->
+    <skip />
+    <!-- no translation found for turn_off_radio (2870296409392615956) -->
+    <skip />
+    <!-- no translation found for screen_lock (1560333453597081877) -->
+    <skip />
+    <!-- no translation found for power_off (2412024417733516836) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (3735034517335251808) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm (699224922526414097) -->
+    <skip />
+    <!-- no translation found for no_recent_tasks (1367712919998349373) -->
+    <skip />
+    <!-- no translation found for global_actions (8299888906525675157) -->
+    <skip />
+    <!-- no translation found for global_action_lock (5943677976245541105) -->
+    <skip />
+    <!-- no translation found for global_action_power_off (3143027278596694254) -->
+    <skip />
+    <!-- no translation found for global_action_toggle_silent_mode (5849335789367070450) -->
+    <skip />
+    <!-- no translation found for global_action_silent_mode_on_status (6053429980569202260) -->
+    <skip />
+    <!-- no translation found for global_action_silent_mode_off_status (1994514127029249081) -->
+    <skip />
+    <!-- no translation found for safeMode (3375134507868534320) -->
+    <skip />
+    <!-- no translation found for permgrouplab_costMoney (904087853776533085) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_costMoney (4662370555643969515) -->
+    <skip />
+    <!-- no translation found for permgrouplab_messages (2984053976424233925) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_messages (2129093134354989379) -->
+    <skip />
+    <!-- no translation found for permgrouplab_personalInfo (4548406335021507392) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_personalInfo (8499310823817958034) -->
+    <skip />
+    <!-- no translation found for permgrouplab_location (8535677827151907069) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_location (2341662219604651887) -->
+    <skip />
+    <!-- no translation found for permgrouplab_network (3597781730625751831) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_network (8332572695347918340) -->
+    <skip />
+    <!-- no translation found for permgrouplab_accounts (8631201594657951893) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_accounts (443982868906396781) -->
+    <skip />
+    <!-- no translation found for permgrouplab_hardwareControls (5074512938567152139) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_hardwareControls (8772503144945278440) -->
+    <skip />
+    <!-- no translation found for permgrouplab_phoneCalls (7096448531266882376) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_phoneCalls (6703873478653366233) -->
+    <skip />
+    <!-- no translation found for permgrouplab_systemTools (1840847965111633430) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_systemTools (2810337951496685271) -->
+    <skip />
+    <!-- no translation found for permgrouplab_developmentTools (692844635256963358) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_developmentTools (5253915519857796400) -->
+    <skip />
+    <!-- no translation found for permlab_statusBar (8789506912215455922) -->
+    <skip />
+    <!-- no translation found for permdesc_statusBar (5034247171231682403) -->
+    <skip />
+    <!-- no translation found for permlab_expandStatusBar (6382500803293284173) -->
+    <skip />
+    <!-- no translation found for permdesc_expandStatusBar (90953162060681436) -->
+    <skip />
+    <!-- no translation found for permlab_processOutgoingCalls (786316295241100144) -->
+    <skip />
+    <!-- no translation found for permdesc_processOutgoingCalls (1655242138991854396) -->
+    <skip />
+    <!-- no translation found for permlab_receiveSms (5820796051959871222) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveSms (2265740044646990161) -->
+    <skip />
+    <!-- no translation found for permlab_receiveMms (7983091218880782611) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveMms (3641275586518289960) -->
+    <skip />
+    <!-- no translation found for permlab_sendSms (4713837923748234081) -->
+    <skip />
+    <!-- no translation found for permdesc_sendSms (7126594387176704010) -->
+    <skip />
+    <!-- no translation found for permlab_readSms (4256004535185449429) -->
+    <skip />
+    <!-- no translation found for permdesc_readSms (4586480500886941902) -->
+    <skip />
+    <!-- no translation found for permlab_writeSms (8453452414726246828) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSms (1036408118901361812) -->
+    <skip />
+    <!-- no translation found for permlab_receiveWapPush (5726837205927152203) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveWapPush (4779188629794134886) -->
+    <skip />
+    <!-- no translation found for permlab_getTasks (357640569227780364) -->
+    <skip />
+    <!-- no translation found for permdesc_getTasks (2916615403728003200) -->
+    <skip />
+    <!-- no translation found for permlab_reorderTasks (4758862288285224517) -->
+    <skip />
+    <!-- no translation found for permdesc_reorderTasks (7507060843941912021) -->
+    <skip />
+    <!-- no translation found for permlab_setDebugApp (2973363275929449444) -->
+    <skip />
+    <!-- no translation found for permdesc_setDebugApp (5720449860498265972) -->
+    <skip />
+    <!-- no translation found for permlab_changeConfiguration (8581093564179818627) -->
+    <skip />
+    <!-- no translation found for permdesc_changeConfiguration (4055366453803187171) -->
+    <skip />
+    <!-- no translation found for permlab_restartPackages (5836367540766044606) -->
+    <skip />
+    <!-- no translation found for permdesc_restartPackages (1764965996765573321) -->
+    <skip />
+    <!-- no translation found for permlab_setProcessForeground (4860990420780868638) -->
+    <skip />
+    <!-- no translation found for permdesc_setProcessForeground (3795477299954784360) -->
+    <skip />
+    <!-- no translation found for permlab_forceBack (4737517869935566733) -->
+    <skip />
+    <!-- no translation found for permdesc_forceBack (5579316297001154697) -->
+    <skip />
+    <!-- no translation found for permlab_dump (3177569414212943167) -->
+    <skip />
+    <!-- no translation found for permdesc_dump (1815913623373011608) -->
+    <skip />
+    <!-- no translation found for permlab_addSystemService (9166015020584794942) -->
+    <skip />
+    <!-- no translation found for permdesc_addSystemService (2310425587289835743) -->
+    <skip />
+    <!-- no translation found for permlab_runSetActivityWatcher (2615943932761994905) -->
+    <skip />
+    <!-- no translation found for permdesc_runSetActivityWatcher (2488524206195482220) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastPackageRemoved (355775368495637820) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastPackageRemoved (6486181398191058385) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
+    <skip />
+    <!-- no translation found for permlab_setProcessLimit (5190694306017260601) -->
+    <skip />
+    <!-- no translation found for permdesc_setProcessLimit (593938303319848578) -->
+    <skip />
+    <!-- no translation found for permlab_setAlwaysFinish (8745533365504920540) -->
+    <skip />
+    <!-- no translation found for permdesc_setAlwaysFinish (2437195869854312148) -->
+    <skip />
+    <!-- no translation found for permlab_fotaUpdate (1813039882829307079) -->
+    <skip />
+    <!-- no translation found for permdesc_fotaUpdate (2544137712607584763) -->
+    <skip />
+    <!-- no translation found for permlab_batteryStats (1598947993704535568) -->
+    <skip />
+    <!-- no translation found for permdesc_batteryStats (6247598531831307989) -->
+    <skip />
+    <!-- no translation found for permlab_internalSystemWindow (5780262737320556654) -->
+    <skip />
+    <!-- no translation found for permdesc_internalSystemWindow (6495031598062517795) -->
+    <skip />
+    <!-- no translation found for permlab_systemAlertWindow (843729657746130626) -->
+    <skip />
+    <!-- no translation found for permdesc_systemAlertWindow (2731854380682210852) -->
+    <skip />
+    <!-- no translation found for permlab_setAnimationScale (2419250686027992384) -->
+    <skip />
+    <!-- no translation found for permdesc_setAnimationScale (8518027785481727264) -->
+    <skip />
+    <!-- no translation found for permlab_manageAppTokens (1033424552444304594) -->
+    <skip />
+    <!-- no translation found for permdesc_manageAppTokens (7285840918912623550) -->
+    <skip />
+    <!-- no translation found for permlab_injectEvents (1383601196263145482) -->
+    <skip />
+    <!-- no translation found for permdesc_injectEvents (840097509341464737) -->
+    <skip />
+    <!-- no translation found for permlab_readInputState (2723668746963882102) -->
+    <skip />
+    <!-- no translation found for permdesc_readInputState (4651137638757852001) -->
+    <skip />
+    <!-- no translation found for permlab_setOrientation (1112555600323148680) -->
+    <skip />
+    <!-- no translation found for permdesc_setOrientation (1960269530378827858) -->
+    <skip />
+    <!-- no translation found for permlab_signalPersistentProcesses (8511163028160623175) -->
+    <skip />
+    <!-- no translation found for permdesc_signalPersistentProcesses (1099349638354917733) -->
+    <skip />
+    <!-- no translation found for permlab_persistentActivity (8163108526929094627) -->
+    <skip />
+    <!-- no translation found for permdesc_persistentActivity (5258975883823299624) -->
+    <skip />
+    <!-- no translation found for permlab_deletePackages (5005536434839333208) -->
+    <skip />
+    <!-- no translation found for permdesc_deletePackages (2687196995215591923) -->
+    <skip />
+    <!-- no translation found for permlab_clearAppUserData (3858185484601410171) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppUserData (7233537744753081136) -->
+    <skip />
+    <!-- no translation found for permlab_deleteCacheFiles (7362746182961997888) -->
+    <skip />
+    <!-- no translation found for permdesc_deleteCacheFiles (8293849509208181266) -->
+    <skip />
+    <!-- no translation found for permlab_getPackageSize (6743556676630447973) -->
+    <skip />
+    <!-- no translation found for permdesc_getPackageSize (2893996655828539776) -->
+    <skip />
+    <!-- no translation found for permlab_installPackages (1637554234554641998) -->
+    <skip />
+    <!-- no translation found for permdesc_installPackages (4747794850590875195) -->
+    <skip />
+    <!-- no translation found for permlab_clearAppCache (7860214328511700776) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppCache (5203820862573167878) -->
+    <skip />
+    <!-- no translation found for permlab_readLogs (6653488552442991707) -->
+    <skip />
+    <!-- no translation found for permdesc_readLogs (356352685800884319) -->
+    <skip />
+    <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
+    <skip />
+    <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
+    <skip />
+    <!-- no translation found for permlab_changeComponentState (8107835954049971459) -->
+    <skip />
+    <!-- no translation found for permdesc_changeComponentState (1791096057705836844) -->
+    <skip />
+    <!-- no translation found for permlab_setPreferredApplications (4355701371185331520) -->
+    <skip />
+    <!-- no translation found for permdesc_setPreferredApplications (9029326613767614711) -->
+    <skip />
+    <!-- no translation found for permlab_writeSettings (2915467191611898256) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSettings (8492982548350342641) -->
+    <skip />
+    <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
+    <skip />
+    <!-- no translation found for permlab_writeGservices (296370685945777755) -->
+    <skip />
+    <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
+    <skip />
+    <!-- no translation found for permlab_receiveBootCompleted (5598819384278633845) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveBootCompleted (3197439472472771192) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastSticky (8142357333543531543) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSticky (8488762822718743531) -->
+    <skip />
+    <!-- no translation found for permlab_readContacts (5116003370450871686) -->
+    <skip />
+    <!-- no translation found for permdesc_readContacts (3499378044902258770) -->
+    <skip />
+    <!-- no translation found for permlab_writeContacts (1555136823460617179) -->
+    <skip />
+    <!-- no translation found for permdesc_writeContacts (4787318403287293114) -->
+    <skip />
+    <!-- no translation found for permlab_writeOwnerData (8036840529708535113) -->
+    <skip />
+    <!-- no translation found for permdesc_writeOwnerData (5873447528845878348) -->
+    <skip />
+    <!-- no translation found for permlab_readOwnerData (1847040178513733757) -->
+    <skip />
+    <!-- no translation found for permdesc_readOwnerData (7563299529149214764) -->
+    <skip />
+    <!-- no translation found for permlab_readCalendar (2111238731453410895) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (4408253940601239114) -->
+    <skip />
+    <!-- no translation found for permlab_writeCalendar (7518052789370653396) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCalendar (8057304232140147596) -->
+    <skip />
+    <!-- no translation found for permlab_accessMockLocation (321094551062270213) -->
+    <skip />
+    <!-- no translation found for permdesc_accessMockLocation (3651565866471419739) -->
+    <skip />
+    <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
+    <skip />
+    <!-- no translation found for permlab_accessFineLocation (4846261651944924865) -->
+    <skip />
+    <!-- no translation found for permdesc_accessFineLocation (3572307331039348419) -->
+    <skip />
+    <!-- no translation found for permlab_accessCoarseLocation (1760779730797169189) -->
+    <skip />
+    <!-- no translation found for permdesc_accessCoarseLocation (8878785899768310712) -->
+    <skip />
+    <!-- no translation found for permlab_accessSurfaceFlinger (6405475452322847618) -->
+    <skip />
+    <!-- no translation found for permdesc_accessSurfaceFlinger (5348283543622360967) -->
+    <skip />
+    <!-- no translation found for permlab_readFrameBuffer (4655248388550039199) -->
+    <skip />
+    <!-- no translation found for permdesc_readFrameBuffer (794888199105081402) -->
+    <skip />
+    <!-- no translation found for permlab_modifyAudioSettings (1587341813207960943) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyAudioSettings (1447143004892708149) -->
+    <skip />
+    <!-- no translation found for permlab_recordAudio (4447848534036991667) -->
+    <skip />
+    <!-- no translation found for permdesc_recordAudio (6936874682400894820) -->
+    <skip />
+    <!-- no translation found for permlab_camera (1944473855727060380) -->
+    <skip />
+    <!-- no translation found for permdesc_camera (5978058582323766022) -->
+    <skip />
+    <!-- no translation found for permlab_brick (4749832243303289777) -->
+    <skip />
+    <!-- no translation found for permdesc_brick (7428524578693695766) -->
+    <skip />
+    <!-- no translation found for permlab_reboot (8844650672567077423) -->
+    <skip />
+    <!-- no translation found for permdesc_reboot (4704919552870918328) -->
+    <skip />
+    <!-- no translation found for permlab_mount_unmount_filesystems (1009574821038043781) -->
+    <skip />
+    <!-- no translation found for permdesc_mount_unmount_filesystems (100792065894811109) -->
+    <skip />
+    <!-- no translation found for permlab_vibrate (61984555644467146) -->
+    <skip />
+    <!-- no translation found for permdesc_vibrate (7831723100758509238) -->
+    <skip />
+    <!-- no translation found for permlab_flashlight (9097145977808182652) -->
+    <skip />
+    <!-- no translation found for permdesc_flashlight (7851502731988978358) -->
+    <skip />
+    <!-- no translation found for permlab_hardware_test (4103324677866524254) -->
+    <skip />
+    <!-- no translation found for permdesc_hardware_test (7315242723603994769) -->
+    <skip />
+    <!-- no translation found for permlab_callPhone (168275616535116686) -->
+    <skip />
+    <!-- no translation found for permdesc_callPhone (1852033967965785973) -->
+    <skip />
+    <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
+    <skip />
+    <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
+    <skip />
+    <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
+    <skip />
+    <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
+    <skip />
+    <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
+    <skip />
+    <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
+    <skip />
+    <!-- no translation found for permlab_modifyPhoneState (7791696535097912313) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyPhoneState (6352405226410454770) -->
+    <skip />
+    <!-- no translation found for permlab_readPhoneState (7320082586621086653) -->
+    <skip />
+    <!-- no translation found for permdesc_readPhoneState (8004450067066407969) -->
+    <skip />
+    <!-- no translation found for permlab_wakeLock (1591164750935072136) -->
+    <skip />
+    <!-- no translation found for permdesc_wakeLock (160471538196734936) -->
+    <skip />
+    <!-- no translation found for permlab_devicePower (9214865067086065548) -->
+    <skip />
+    <!-- no translation found for permdesc_devicePower (5608364066480036402) -->
+    <skip />
+    <!-- no translation found for permlab_factoryTest (7786199300637896247) -->
+    <skip />
+    <!-- no translation found for permdesc_factoryTest (3466066005210542042) -->
+    <skip />
+    <!-- no translation found for permlab_setWallpaper (2256730637138641725) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaper (3034653140208685093) -->
+    <skip />
+    <!-- no translation found for permlab_setWallpaperHints (4192438316932517807) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaperHints (738757439960921674) -->
+    <skip />
+    <!-- no translation found for permlab_masterClear (6155403967270586906) -->
+    <skip />
+    <!-- no translation found for permdesc_masterClear (4213553172342689754) -->
+    <skip />
+    <!-- no translation found for permlab_setTimeZone (477196167239548690) -->
+    <skip />
+    <!-- no translation found for permdesc_setTimeZone (8564892020460841198) -->
+    <skip />
+    <!-- no translation found for permlab_getAccounts (2764070033402295170) -->
+    <skip />
+    <!-- no translation found for permdesc_getAccounts (1203491378748649898) -->
+    <skip />
+    <!-- no translation found for permlab_accessNetworkState (2032916924886010827) -->
+    <skip />
+    <!-- no translation found for permdesc_accessNetworkState (7081329402551195933) -->
+    <skip />
+    <!-- no translation found for permlab_createNetworkSockets (4706698319966917864) -->
+    <skip />
+    <!-- no translation found for permdesc_createNetworkSockets (2580337178778551792) -->
+    <skip />
+    <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
+    <skip />
+    <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
+    <skip />
+    <!-- no translation found for permlab_changeNetworkState (2710779001260856872) -->
+    <skip />
+    <!-- no translation found for permdesc_changeNetworkState (8076109230787022270) -->
+    <skip />
+    <!-- no translation found for permlab_accessWifiState (3613679494230374297) -->
+    <skip />
+    <!-- no translation found for permdesc_accessWifiState (8226508433563326925) -->
+    <skip />
+    <!-- no translation found for permlab_changeWifiState (6043889338995432957) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWifiState (7829372845909567994) -->
+    <skip />
+    <!-- no translation found for permlab_bluetoothAdmin (5513286736585647334) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (1838208497914347365) -->
+    <skip />
+    <!-- no translation found for permlab_bluetooth (6378797624765639115) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetooth (8592386018922265273) -->
+    <skip />
+    <!-- no translation found for permlab_disableKeyguard (4574886811903233903) -->
+    <skip />
+    <!-- no translation found for permdesc_disableKeyguard (815972646344251271) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncSettings (8818819977141505127) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncSettings (8454705401908767847) -->
+    <skip />
+    <!-- no translation found for permlab_writeSyncSettings (4514911143753152941) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSyncSettings (7630627689635091836) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncStats (5748337739678952863) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncStats (582551457321957183) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
+    <skip />
+    <!-- no translation found for phoneTypes:0 (6070018634209800981) -->
+    <!-- no translation found for phoneTypes:1 (1514509689885965711) -->
+    <!-- no translation found for phoneTypes:2 (497473201754095234) -->
+    <!-- no translation found for phoneTypes:3 (5554432614281047787) -->
+    <!-- no translation found for phoneTypes:4 (2222084401110150993) -->
+    <!-- no translation found for phoneTypes:5 (2290007103906353121) -->
+    <!-- no translation found for phoneTypes:6 (6930783706213719251) -->
+    <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
+    <!-- no translation found for emailAddressTypes:0 (1540640638077615417) -->
+    <!-- no translation found for emailAddressTypes:1 (4252853367575831977) -->
+    <!-- no translation found for emailAddressTypes:2 (7158046581744435718) -->
+    <!-- no translation found for emailAddressTypes:3 (3625034471181268169) -->
+    <!-- no translation found for postalAddressTypes:0 (5732960259696659380) -->
+    <!-- no translation found for postalAddressTypes:1 (7132240704786130285) -->
+    <!-- no translation found for postalAddressTypes:2 (1317604357745852817) -->
+    <!-- no translation found for postalAddressTypes:3 (1582953598462826702) -->
+    <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
+    <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
+    <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
+    <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
+    <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
+    <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
+    <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
+    <!-- no translation found for imProtocols:0 (3318725788774688043) -->
+    <!-- no translation found for imProtocols:1 (1787713387022932886) -->
+    <!-- no translation found for imProtocols:2 (6751174158442316516) -->
+    <!-- no translation found for imProtocols:3 (1151283347465052653) -->
+    <!-- no translation found for imProtocols:4 (2157980008878817934) -->
+    <!-- no translation found for imProtocols:5 (7836237460308230767) -->
+    <!-- no translation found for imProtocols:6 (1180789904462172516) -->
+    <!-- no translation found for imProtocols:7 (21955111672779862) -->
+    <!-- no translation found for keyguard_password_enter_pin_code (6779835451906812518) -->
+    <skip />
+    <!-- no translation found for keyguard_password_wrong_pin_code (230312338493035499) -->
+    <skip />
+    <!-- no translation found for keyguard_label_text (3902954467573892533) -->
+    <skip />
+    <!-- no translation found for emergency_call_dialog_number_for_display (6256361184251050511) -->
+    <skip />
+    <!-- no translation found for lockscreen_carrier_default (5222269885486229730) -->
+    <skip />
+    <!-- no translation found for lockscreen_screen_locked (1922273663462058967) -->
+    <skip />
+    <!-- no translation found for lockscreen_instructions_when_pattern_enabled (7535864145009679967) -->
+    <skip />
+    <!-- no translation found for lockscreen_instructions_when_pattern_disabled (6526504555912746785) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_instructions (8984964506352089877) -->
+    <skip />
+    <!-- no translation found for lockscreen_emergency_call (422835617844547383) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_correct (7104753084746383672) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_wrong (7517004470797680361) -->
+    <skip />
+    <!-- no translation found for lockscreen_plugged_in (8806977650003537118) -->
+    <skip />
+    <!-- no translation found for lockscreen_low_battery (9002637795199621345) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message_short (5051192587315492957) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message (8912914495901434841) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_instructions (8125847194365725429) -->
+    <skip />
+    <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_message (1005803622871256359) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_instructions (5033160098036646955) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_locked_message (7398401200962556379) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (5939537246164692076) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6709066241494622136) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (1569017295989454551) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_attempts_countdown (8823588000022797566) -->
+    <skip />
+    <!-- no translation found for lockscreen_forgot_pattern_button_text (4219994639843985488) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_too_many_attempts (7504679498838839295) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_instructions (6542400673357252011) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_username_hint (6378418320242015111) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_password_hint (3224230234042131153) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_submit_button (5562051040043760034) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
+    <skip />
+    <!-- no translation found for status_bar_time_format (2168573805413119180) -->
+    <skip />
+    <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
+    <skip />
+    <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
+    <skip />
+    <!-- no translation found for hour_ampm (7665432130905376251) -->
+    <skip />
+    <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
+    <skip />
+    <!-- no translation found for status_bar_clear_all_button (2202004591253243750) -->
+    <skip />
+    <!-- no translation found for status_bar_no_notifications_title (5123133188102094464) -->
+    <skip />
+    <!-- no translation found for status_bar_ongoing_events_title (799961521630569167) -->
+    <skip />
+    <!-- no translation found for status_bar_latest_events_title (5414094466807164279) -->
+    <skip />
+    <!-- no translation found for battery_status_text_percent_format (7391464609447031944) -->
+    <skip />
+    <!-- no translation found for battery_status_charging (5078780715755132756) -->
+    <skip />
+    <!-- no translation found for battery_low_title (3665400828395001695) -->
+    <skip />
+    <!-- no translation found for battery_low_subtitle (7537149915372180016) -->
+    <skip />
+    <!-- no translation found for battery_low_percent_format (8635359708781261154) -->
+    <skip />
+    <!-- no translation found for factorytest_failed (5784901108608196679) -->
+    <skip />
+    <!-- no translation found for factorytest_not_system (6330339565054095688) -->
+    <skip />
+    <!-- no translation found for factorytest_no_action (1662569013408679347) -->
+    <skip />
+    <!-- no translation found for factorytest_reboot (6080912029718954885) -->
+    <skip />
+    <!-- no translation found for save_password_label (4129493019621348626) -->
+    <skip />
+    <!-- no translation found for save_password_message (7412617920202682045) -->
+    <skip />
+    <!-- no translation found for save_password_notnow (3887362423496820832) -->
+    <skip />
+    <!-- no translation found for save_password_remember (4319688896716308569) -->
+    <skip />
+    <!-- no translation found for save_password_never (1836981952883642377) -->
+    <skip />
+    <!-- no translation found for open_permission_deny (6408502671105717111) -->
+    <skip />
+    <!-- no translation found for text_copied (6106873823411904723) -->
+    <skip />
+    <!-- no translation found for more_item_label (5204075544750360778) -->
+    <skip />
+    <!-- no translation found for prepend_shortcut_label (6091430648975237047) -->
+    <skip />
+    <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
+    <skip />
+    <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
+    <skip />
+    <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
+    <skip />
+    <!-- no translation found for search_go (4823831235057123206) -->
+    <skip />
+    <!-- no translation found for today (6914914811057683636) -->
+    <skip />
+    <!-- no translation found for yesterday (5280495043584636271) -->
+    <skip />
+    <!-- no translation found for tomorrow (561215115479060939) -->
+    <skip />
+    <!-- no translation found for oneMonthDurationPast (3402179395240209557) -->
+    <skip />
+    <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
+    <skip />
+    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
+    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
+    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
+    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
+    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
+    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
+    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
+    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
+    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
+    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
+    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
+    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
+    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
+    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
+    <!-- no translation found for in_num_days:one (5608475533104443893) -->
+    <!-- no translation found for in_num_days:other (3827193006163842267) -->
+    <!-- no translation found for preposition_for_date (2689847983632851560) -->
+    <skip />
+    <!-- no translation found for preposition_for_time (2613388053493148013) -->
+    <skip />
+    <!-- no translation found for preposition_for_year (6968468294728152393) -->
+    <skip />
+    <!-- no translation found for day (7849249054576985912) -->
+    <skip />
+    <!-- no translation found for days (8381828105391141169) -->
+    <skip />
+    <!-- no translation found for hour (1044439788994278057) -->
+    <skip />
+    <!-- no translation found for hours (9008157371441255845) -->
+    <skip />
+    <!-- no translation found for minute (2434431396283136076) -->
+    <skip />
+    <!-- no translation found for minutes (8176836254200264856) -->
+    <skip />
+    <!-- no translation found for second (6620645953323664299) -->
+    <skip />
+    <!-- no translation found for seconds (6416703426008384360) -->
+    <skip />
+    <!-- no translation found for week (7738046527402739781) -->
+    <skip />
+    <!-- no translation found for weeks (3178327674459887377) -->
+    <skip />
+    <!-- no translation found for year (8024790425994085153) -->
+    <skip />
+    <!-- no translation found for years (8592090054773244417) -->
+    <skip />
+    <!-- no translation found for sunday (4811082193700148223) -->
+    <skip />
+    <!-- no translation found for monday (7543713499896911033) -->
+    <skip />
+    <!-- no translation found for tuesday (7962192298359117585) -->
+    <skip />
+    <!-- no translation found for wednesday (5768878309383390437) -->
+    <skip />
+    <!-- no translation found for thursday (5690060634904123607) -->
+    <skip />
+    <!-- no translation found for friday (2718325370375116889) -->
+    <skip />
+    <!-- no translation found for saturday (222899317300942333) -->
+    <skip />
+    <!-- no translation found for every_weekday (8466333034903391066) -->
+    <skip />
+    <!-- no translation found for daily (1661712840773846970) -->
+    <skip />
+    <!-- no translation found for weekly (578642117234613009) -->
+    <skip />
+    <!-- no translation found for monthly (8526124657540210537) -->
+    <skip />
+    <!-- no translation found for yearly (8083067713764127070) -->
+    <skip />
+    <!-- no translation found for VideoView_error_title (1024334251681931859) -->
+    <skip />
+    <!-- no translation found for VideoView_error_text_unknown (3398417247398476771) -->
+    <skip />
+    <!-- no translation found for VideoView_error_button (3144127115413163445) -->
+    <skip />
+    <!-- no translation found for am (5354895493921411502) -->
+    <skip />
+    <!-- no translation found for pm (7206933220587555766) -->
+    <skip />
+    <!-- no translation found for numeric_date (5120078478872821100) -->
+    <skip />
+    <!-- no translation found for wday1_date1_time1_wday2_date2_time2 (7066878981949584861) -->
+    <skip />
+    <!-- no translation found for wday1_date1_wday2_date2 (8671068747172261907) -->
+    <skip />
+    <!-- no translation found for date1_time1_date2_time2 (3645498975775629615) -->
+    <skip />
+    <!-- no translation found for date1_date2 (377057563556488062) -->
+    <skip />
+    <!-- no translation found for time1_time2 (3173474242109288305) -->
+    <skip />
+    <!-- no translation found for time_wday_date (8928955562064570313) -->
+    <skip />
+    <!-- no translation found for wday_date (8794741400546136975) -->
+    <skip />
+    <!-- no translation found for time_date (1922644512833014496) -->
+    <skip />
+    <!-- no translation found for time_wday (1422050241301754712) -->
+    <skip />
+    <!-- no translation found for full_date_month_first (6011143962222283357) -->
+    <skip />
+    <!-- no translation found for full_date_day_first (8621594762705478189) -->
+    <skip />
+    <!-- no translation found for medium_date_month_first (48990963718825728) -->
+    <skip />
+    <!-- no translation found for medium_date_day_first (2898992016440387123) -->
+    <skip />
+    <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
+    <skip />
+    <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
+    <skip />
+    <!-- no translation found for noon (8390796001560682897) -->
+    <skip />
+    <!-- no translation found for Noon (7698941576181064429) -->
+    <skip />
+    <!-- no translation found for midnight (7773339795626486146) -->
+    <skip />
+    <!-- no translation found for Midnight (1260172107848123187) -->
+    <skip />
+    <!-- no translation found for month_day (3356633704511426364) -->
+    <skip />
+    <!-- no translation found for month (3017405760734206414) -->
+    <skip />
+    <!-- no translation found for month_day_year (2435948225709176752) -->
+    <skip />
+    <!-- no translation found for month_year (6228414124777343135) -->
+    <skip />
+    <!-- no translation found for time_of_day (8375993139317154157) -->
+    <skip />
+    <!-- no translation found for date_and_time (9197690194373107109) -->
+    <skip />
+    <!-- no translation found for same_year_md1_md2 (9199324363135981317) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_md1_wday2_md2 (6006392413355305178) -->
+    <skip />
+    <!-- no translation found for same_year_mdy1_mdy2 (1576657593937827090) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_mdy1_wday2_mdy2 (9135935796468891580) -->
+    <skip />
+    <!-- no translation found for same_year_md1_time1_md2_time2 (2172964106375558081) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_md1_time1_wday2_md2_time2 (1702879534101786310) -->
+    <skip />
+    <!-- no translation found for same_year_mdy1_time1_mdy2_time2 (2476443311723358767) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_mdy1_time1_wday2_mdy2_time2 (1564837340334069879) -->
+    <skip />
+    <!-- no translation found for numeric_md1_md2 (8908376522875100300) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_md1_wday2_md2 (3239690882018292077) -->
+    <skip />
+    <!-- no translation found for numeric_mdy1_mdy2 (8883797176939233525) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_mdy1_wday2_mdy2 (4150475769255828954) -->
+    <skip />
+    <!-- no translation found for numeric_md1_time1_md2_time2 (3624746590607741419) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_md1_time1_wday2_md2_time2 (4258040955467298134) -->
+    <skip />
+    <!-- no translation found for numeric_mdy1_time1_mdy2_time2 (3598215409314517987) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_mdy1_time1_wday2_mdy2_time2 (264076937155877259) -->
+    <skip />
+    <!-- no translation found for same_month_md1_md2 (2393563617438036111) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_md1_wday2_md2 (1208946773794057819) -->
+    <skip />
+    <!-- no translation found for same_month_mdy1_mdy2 (3713236637869030492) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_mdy1_wday2_mdy2 (389638922479870472) -->
+    <skip />
+    <!-- no translation found for same_month_md1_time1_md2_time2 (7477075526337542685) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_md1_time1_wday2_md2_time2 (3516978303779391173) -->
+    <skip />
+    <!-- no translation found for same_month_mdy1_time1_mdy2_time2 (7320410992514057310) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_mdy1_time1_wday2_mdy2_time2 (1332950588774239228) -->
+    <skip />
+    <!-- no translation found for abbrev_month_day_year (5767271534015320250) -->
+    <skip />
+    <!-- no translation found for abbrev_month_year (8058929633673942490) -->
+    <skip />
+    <!-- no translation found for abbrev_month_day (458867920693482757) -->
+    <skip />
+    <!-- no translation found for abbrev_month (1674509986330181349) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_sunday (9057662850446501884) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_monday (7358451993082888343) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_tuesday (2282901451170509613) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_wednesday (2100217950343286482) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_thursday (5475158963242863176) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_friday (4081018004819837155) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_saturday (1929694088305891795) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_sunday (6462580883948669820) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_monday (6960587654241349502) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_tuesday (7004462235990108936) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_wednesday (5688564741951314696) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_thursday (1784339868453982400) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_friday (4314577583604069357) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_saturday (70321191398427845) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_sunday (7403409454572591357) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_monday (5278358100012478239) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_tuesday (5121116040712487059) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_wednesday (1601079579293330319) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_thursday (5863422096017401812) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_friday (2916686031099723960) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_saturday (8521564973195542073) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_sunday (1650484495176707638) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_monday (9133193697786876074) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_tuesday (4012095408481489663) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_wednesday (6279056612496078470) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_thursday (2748599403545071011) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_friday (5037282109124849673) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_saturday (3208167155877833783) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_sunday (4683862964821549758) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_monday (6701142261471667000) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_tuesday (9098171980161292477) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_wednesday (655049238289460956) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_thursday (7816913627500884083) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_friday (903301878650619398) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_saturday (5359692489649817988) -->
+    <skip />
+    <!-- no translation found for month_long_january (7128497801440564337) -->
+    <skip />
+    <!-- no translation found for month_long_february (7808570514581190617) -->
+    <skip />
+    <!-- no translation found for month_long_march (2061328556983796034) -->
+    <skip />
+    <!-- no translation found for month_long_april (6575007959043269919) -->
+    <skip />
+    <!-- no translation found for month_long_may (8404051103463071121) -->
+    <skip />
+    <!-- no translation found for month_long_june (6255771619238859451) -->
+    <skip />
+    <!-- no translation found for month_long_july (4129177743136800884) -->
+    <skip />
+    <!-- no translation found for month_long_august (5494331003296804494) -->
+    <skip />
+    <!-- no translation found for month_long_september (2691137479752033087) -->
+    <skip />
+    <!-- no translation found for month_long_october (7501261567327243313) -->
+    <skip />
+    <!-- no translation found for month_long_november (8759690753068763664) -->
+    <skip />
+    <!-- no translation found for month_long_december (4505008719696569497) -->
+    <skip />
+    <!-- no translation found for month_medium_january (2315492772833932512) -->
+    <skip />
+    <!-- no translation found for month_medium_february (118412521324313430) -->
+    <skip />
+    <!-- no translation found for month_medium_march (5546835583839352358) -->
+    <skip />
+    <!-- no translation found for month_medium_april (7052559668687733702) -->
+    <skip />
+    <!-- no translation found for month_medium_may (2825303871720116018) -->
+    <skip />
+    <!-- no translation found for month_medium_june (829843667101495271) -->
+    <skip />
+    <!-- no translation found for month_medium_july (5029778226925324789) -->
+    <skip />
+    <!-- no translation found for month_medium_august (8851230594641162805) -->
+    <skip />
+    <!-- no translation found for month_medium_september (8420590486625304647) -->
+    <skip />
+    <!-- no translation found for month_medium_october (1787382806172930239) -->
+    <skip />
+    <!-- no translation found for month_medium_november (675513809622370603) -->
+    <skip />
+    <!-- no translation found for month_medium_december (2934948295928978783) -->
+    <skip />
+    <!-- no translation found for month_shortest_january (6070060405144675883) -->
+    <skip />
+    <!-- no translation found for month_shortest_february (5632605004902176653) -->
+    <skip />
+    <!-- no translation found for month_shortest_march (4304231552356086624) -->
+    <skip />
+    <!-- no translation found for month_shortest_april (1166434066469385532) -->
+    <skip />
+    <!-- no translation found for month_shortest_may (9131326028845529001) -->
+    <skip />
+    <!-- no translation found for month_shortest_june (1875723154506665289) -->
+    <skip />
+    <!-- no translation found for month_shortest_july (2003596275389810773) -->
+    <skip />
+    <!-- no translation found for month_shortest_august (9120245162625763214) -->
+    <skip />
+    <!-- no translation found for month_shortest_september (7980651111022693669) -->
+    <skip />
+    <!-- no translation found for month_shortest_october (3640405450427788312) -->
+    <skip />
+    <!-- no translation found for month_shortest_november (4002935318566146993) -->
+    <skip />
+    <!-- no translation found for month_shortest_december (6213739417171334040) -->
+    <skip />
+    <!-- no translation found for elapsed_time_short_format_mm_ss (1294409362352514646) -->
+    <skip />
+    <!-- no translation found for elapsed_time_short_format_h_mm_ss (2997059666628785039) -->
+    <skip />
+    <!-- no translation found for selectAll (691691810023908884) -->
+    <skip />
+    <!-- no translation found for cut (5845613239192595662) -->
+    <skip />
+    <!-- no translation found for cutAll (4474519683293791451) -->
+    <skip />
+    <!-- no translation found for copy (8603721575469529820) -->
+    <skip />
+    <!-- no translation found for copyAll (4777548804630476932) -->
+    <skip />
+    <!-- no translation found for paste (6458036735811828538) -->
+    <skip />
+    <!-- no translation found for copyUrl (5785708478767435812) -->
+    <skip />
+    <!-- no translation found for inputMethod (7911866729148111492) -->
+    <skip />
+    <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_title (5997772070488639934) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_text (2230118755295375293) -->
+    <skip />
+    <!-- no translation found for ok (4003878536083514869) -->
+    <skip />
+    <!-- no translation found for cancel (1527674037280267012) -->
+    <skip />
+    <!-- no translation found for yes (8185296114406773873) -->
+    <skip />
+    <!-- no translation found for no (2300685350903156262) -->
+    <skip />
+    <!-- no translation found for capital_on (8418242581217554942) -->
+    <skip />
+    <!-- no translation found for capital_off (8870368560477693851) -->
+    <skip />
+    <!-- no translation found for whichApplication (2828159696176255212) -->
+    <skip />
+    <!-- no translation found for alwaysUse (6433627451071144629) -->
+    <skip />
+    <!-- no translation found for clearDefaultHintMsg (5742432113023174321) -->
+    <skip />
+    <!-- no translation found for chooseActivity (7588691622928031978) -->
+    <skip />
+    <!-- no translation found for noApplications (4068560364116066745) -->
+    <skip />
+    <!-- no translation found for aerr_title (2654390351574026098) -->
+    <skip />
+    <!-- no translation found for aerr_application (4917288809565116720) -->
+    <skip />
+    <!-- no translation found for aerr_process (1273819861108073461) -->
+    <skip />
+    <!-- no translation found for anr_title (3305935690891435915) -->
+    <skip />
+    <!-- no translation found for anr_activity_application (1653036325679156678) -->
+    <skip />
+    <!-- no translation found for anr_activity_process (2674027618362070465) -->
+    <skip />
+    <!-- no translation found for anr_application_process (2163656674970221928) -->
+    <skip />
+    <!-- no translation found for anr_process (7747550780123472160) -->
+    <skip />
+    <!-- no translation found for force_close (9020954128872810669) -->
+    <skip />
+    <!-- no translation found for wait (7973775702304037058) -->
+    <skip />
+    <!-- no translation found for debug (857932504764728770) -->
+    <skip />
+    <!-- no translation found for sendText (6158329286172492543) -->
+    <skip />
+    <!-- no translation found for volume_ringtone (4121694816346562058) -->
+    <skip />
+    <!-- no translation found for volume_music (4869950240104717493) -->
+    <skip />
+    <!-- no translation found for volume_call (5723421277753250395) -->
+    <skip />
+    <!-- no translation found for volume_alarm (2752102730973081294) -->
+    <skip />
+    <!-- no translation found for volume_unknown (6908187627672375742) -->
+    <skip />
+    <!-- no translation found for ringtone_default (2873893375149093475) -->
+    <skip />
+    <!-- no translation found for ringtone_default_with_actual (5474076151665761913) -->
+    <skip />
+    <!-- no translation found for ringtone_silent (7477159279081654685) -->
+    <skip />
+    <!-- no translation found for ringtone_picker_title (7055241890764367884) -->
+    <skip />
+    <!-- no translation found for ringtone_unknown (6888219771401173795) -->
+    <skip />
+    <!-- no translation found for wifi_available:one (8168012881468888470) -->
+    <!-- no translation found for wifi_available:other (4666122955807117718) -->
+    <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
+    <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
+    <!-- no translation found for select_character (3735110139249491726) -->
+    <skip />
+    <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
+    <skip />
+    <!-- no translation found for sms_control_title (2742400596989418394) -->
+    <skip />
+    <!-- no translation found for sms_control_message (3447126217666595989) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (8839660939359273650) -->
+    <skip />
+    <!-- no translation found for sms_control_no (909756849988183801) -->
+    <skip />
+    <!-- no translation found for date_time_set (2495199891239480952) -->
+    <skip />
+    <!-- no translation found for default_permission_group (7742780381379652409) -->
+    <skip />
+    <!-- no translation found for no_permissions (85461124044682315) -->
+    <skip />
+    <!-- no translation found for perms_hide (4145325555929151849) -->
+    <skip />
+    <!-- no translation found for perms_show_all (6040194843455403173) -->
+    <skip />
+    <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
+    <skip />
+    <!-- no translation found for usb_storage_title (8699631567051394409) -->
+    <skip />
+    <!-- no translation found for usb_storage_message (5344039189213308733) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
+    <skip />
+    <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
+    <skip />
+    <!-- no translation found for select_input_method (2658280517827502015) -->
+    <skip />
+    <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
+    <skip />
+    <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
+    <skip />
+    <!-- no translation found for candidates_style (7738463880139922176) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-en-rGB/arrays.xml b/core/res/res/values-en-rGB/arrays.xml
new file mode 100644
index 0000000..02a0e0f
--- /dev/null
+++ b/core/res/res/values-en-rGB/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<resources>
+
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_lat_lng">
+        <item>51500208</item>
+        <item>-126729</item>
+    </integer-array>
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_zoom">
+        <item>5</item>
+    </integer-array>
+
+</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c8260b17..4cb3ee1 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1,767 +1,765 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="BaMmi">Call barring</string>
-  <string name="CLIRDefaultOffNextCallOff">Caller ID defaults to not restricted. Next call: Not restricted</string>
-  <string name="CLIRDefaultOffNextCallOn">Caller ID defaults to not restricted. Next call: Restricted</string>
-  <string name="CLIRDefaultOnNextCallOff">Caller ID defaults to restricted. Next call: Not restricted</string>
-  <string name="CLIRDefaultOnNextCallOn">Caller ID defaults to restricted. Next call: Restricted</string>
-  <string name="CLIRPermanent">The caller ID setting cannot be changed.</string>
-  <string name="CfMmi">Call forwarding</string>
-  <string name="ClipMmi">Incoming Caller ID</string>
-  <string name="ClirMmi">Outgoing Caller ID</string>
-  <string name="CwMmi">Call waiting</string>
-  <string name="Midnight">"Midnight"</string>
-  <string name="Noon">"Noon"</string>
-  <string name="PinMmi">PIN change</string>
-  <string name="PwdMmi">Password change</string>
-  <string name="VideoView_error_button">OK</string>
-  <string name="VideoView_error_text_unknown">Sorry, this video cannot be played.</string>
-  <string name="VideoView_error_title">Cannot play video</string>
-  <string name="abbrev_month">"<xliff:g id="format">%b</xliff:g>"</string>
-  <string name="abbrev_month_day">"<xliff:g id="format">%-d %b</xliff:g>"</string>
-  <string name="abbrev_month_day_year">"<xliff:g id="format">%-d %b, %Y</xliff:g>"</string>
-  <string name="abbrev_month_year">"<xliff:g id="format">%b %Y</xliff:g>"</string>
-  <string name="activate_keyguard">Screen lock</string>
-  <string name="aerr_application">The application <xliff:g id="application">%1$s</xliff:g>
-        (process <xliff:g id="process">%2$s</xliff:g>) has stopped unexpectedly. Please try again.</string>
-  <string name="aerr_process">The process <xliff:g id="process">%1$s</xliff:g> has
-        stopped unexpectedly. Please try again.</string>
-  <string name="aerr_title">Sorry!</string>
-  <string name="ago">ago</string>
-  <string name="alwaysUse">Use by default for this action.</string>
-  <string name="am">"AM"</string>
-  <string name="anr_activity_application">Activity <xliff:g id="activity">%1$s</xliff:g> (in application <xliff:g id="application">%2$s</xliff:g>) is not responding.</string>
-  <string name="anr_activity_process">Activity <xliff:g id="activity">%1$s</xliff:g> (in process <xliff:g id="process">%2$s</xliff:g>) is not responding.</string>
-  <string name="anr_application_process">Application <xliff:g id="application">%1$s</xliff:g> (in process <xliff:g id="process">%2$s</xliff:g>) is not responding.</string>
-  <string name="anr_process">Process <xliff:g id="process">%1$s</xliff:g> is not responding.</string>
-  <string name="anr_title">Application unresponsive</string>
-  <string name="badPin">The old PIN you typed is not correct.</string>
-  <string name="badPuk">The PUK you typed is not correct.</string>
-  <string name="battery_low_percent_format">less than <xliff:g id="number">%d%%</xliff:g>
-    remaining.</string>
-  <string name="battery_low_subtitle">The battery is getting low:</string>
-  <string name="battery_low_title">Please connect charger</string>
-  <string name="battery_status_charging">Charging\u2026</string>
-  <string name="battery_status_text_percent_format"><xliff:g id="number">%d%%</xliff:g></string>
-  <string name="before">Before</string>
-  <string name="browserSavedFormData">Saved form data.</string>
-  <string name="byteShort">B</string>
-  <string name="cancel">Cancel</string>
-  <string name="capital_off">OFF</string>
-  <string name="capital_on">ON</string>
-  <string name="cfReasonBusy">Call forwarding - Busy</string>
-  <string name="cfReasonNR">Call forwarding - Not reachable</string>
-  <string name="cfReasonNRy">Call forwarding - No reply</string>
-  <string name="cfReasonUnconditional">Call forwarding - Always</string>
-  <string name="cfTemplateForwarded">{0}: {1}</string>
-  <string name="cfTemplateForwardedTime">{0}: {1} after {2} seconds</string>
-  <string name="cfTemplateNotForwarded">{0}: Not forwarded</string>
-  <string name="cfTemplateRegistered">{0}: Not forwarded</string>
-  <string name="cfTemplateRegisteredTime">{0}: Not forwarded</string>
-  <string name="chooseActivity">Select an action</string>
-  <string name="clearDefaultHintMsg">Clear default in Home Settings &gt; Applications &gt; Manage applications.</string>
-  <string name="compass_accuracy_banner">Compass requires calibration</string>
-  <string name="compass_accuracy_notificaction_body">Rotate phone in figure 8 patterns to calibrate compass.</string>
-  <string name="compass_accuracy_notificaction_title">Calibrate compass</string>
-  <string name="contentServiceSync">Sync</string>
-  <string name="contentServiceSyncErrorNotificationDesc">Sync is experiencing problems.</string>
-  <string name="contentServiceSyncNotificationDesc">Syncing</string>
-  <string name="contentServiceSyncNotificationTitle">Sync</string>
-  <string name="contentServiceTooManyDeletesNotificationDesc">Too many %s deletes.</string>
-  <string name="contentServiceXmppAvailable">XMPP Active</string>
-  <string name="copy">Copy</string>
-  <string name="copyAll">Copy all</string>
-  <string name="copyUrl">Copy URL</string>
-  <string name="cut">Cut</string>
-  <string name="cutAll">Cut all</string>
-  <string name="daily">Daily</string>
-  <string name="daily_format">h:mm aa</string>
-  <string name="date1_date2">"<xliff:g id="format">%2$s \u2013 %5$s</xliff:g>"</string>
-  <string name="date1_time1_date2_time2">"<xliff:g id="format">%2$s, %3$s \u2013 %5$s, %6$s</xliff:g>"</string>
-  <string name="date_picker_month">month</string>
-  <string name="date_picker_set">Set</string>
-  <string name="date_range_separator">" \u2013 "</string>
-  <string name="date_time_set">Set</string>
-  <string name="day">day</string>
-  <string name="day_of_week_long_friday">Friday</string>
-  <string name="day_of_week_long_monday">Monday</string>
-  <string name="day_of_week_long_saturday">Saturday</string>
-  <string name="day_of_week_long_sunday">Sunday</string>
-  <string name="day_of_week_long_thursday">Thursday</string>
-  <string name="day_of_week_long_tuesday">Tuesday</string>
-  <string name="day_of_week_long_wednesday">Wednesday</string>
-  <string name="day_of_week_medium_friday">Fri</string>
-  <string name="day_of_week_medium_monday">Mon</string>
-  <string name="day_of_week_medium_saturday">Sat</string>
-  <string name="day_of_week_medium_sunday">Sun</string>
-  <string name="day_of_week_medium_thursday">Thu</string>
-  <string name="day_of_week_medium_tuesday">Tue</string>
-  <string name="day_of_week_medium_wednesday">Wed</string>
-  <string name="day_of_week_short_friday">Fr</string>
-  <string name="day_of_week_short_monday">Mo</string>
-  <string name="day_of_week_short_saturday">Sa</string>
-  <string name="day_of_week_short_sunday">Su</string>
-  <string name="day_of_week_short_thursday">Th</string>
-  <string name="day_of_week_short_tuesday">Tu</string>
-  <string name="day_of_week_short_wednesday">We</string>
-  <string name="day_of_week_shorter_friday">F</string>
-  <string name="day_of_week_shorter_monday">M</string>
-  <string name="day_of_week_shorter_saturday">Sa</string>
-  <string name="day_of_week_shorter_sunday">Su</string>
-  <string name="day_of_week_shorter_thursday">Th</string>
-  <string name="day_of_week_shorter_tuesday">Tu</string>
-  <string name="day_of_week_shorter_wednesday">W</string>
-  <string name="day_of_week_shortest_friday">F</string>
-  <string name="day_of_week_shortest_monday">M</string>
-  <string name="day_of_week_shortest_saturday">S</string>
-  <string name="day_of_week_shortest_sunday">S</string>
-  <string name="day_of_week_shortest_thursday">T</string>
-  <string name="day_of_week_shortest_tuesday">T</string>
-  <string name="day_of_week_shortest_wednesday">W</string>
-  <string name="days">days</string>
-  <string name="daysDurationFuturePlural">in <xliff:g id="days">%d</xliff:g> days</string>
-  <string name="daysDurationPastPlural"><xliff:g id="days">%d</xliff:g> days ago</string>
-  <string name="debug">Debug</string>
-  <string name="defaultMsisdnAlphaTag">MSISDN1</string>
-  <string name="defaultVoiceMailAlphaTag">Voicemail</string>
-  <string name="default_permission_group">Default</string>
-  <string name="elapsed_time_short_format_h_mm_ss"><xliff:g id="format">%1$d:%2$02d:%3$02d</xliff:g></string>
-  <string name="elapsed_time_short_format_mm_ss"><xliff:g id="format">%1$02d:%2$02d</xliff:g></string>
-  <string name="ellipsis">\u2026</string>
-  <string name="emergency_call_dialog_call">Emergency call</string>
-  <string name="emergency_call_dialog_cancel">Cancel</string>
-  <string name="emergency_call_dialog_number_for_display">Emergency number</string>
-  <string name="emergency_call_dialog_text">Make an emergency call?</string>
-  <string name="emergency_call_number_uri">tel:112</string>
-  <string name="emptyPhoneNumber">(No phone number)</string>
-  <string name="every_weekday">"Every weekday (Mon\u2013Fri)"</string>
-  <string name="factorytest_failed">Factory test failed</string>
-  <string name="factorytest_no_action">No package was found that provides the
-        FACTORY_TEST action.</string>
-  <string name="factorytest_not_system">The FACTORY_TEST action
-        is only supported for packages installed in /system/app.</string>
-  <string name="factorytest_reboot">Reboot</string>
-  <string name="force_close">Force close</string>
-  <string name="friday">Friday</string>
-  <string name="gigabyteShort">GB</string>
-  <string name="global_action_lock">Screen lock</string>
-  <string name="global_action_power_off">Power off</string>
-  <string name="global_action_silent_mode_off_status">Sound is ON</string>
-  <string name="global_action_silent_mode_on_status">Sound is OFF</string>
-  <string name="global_action_toggle_silent_mode">Silent mode</string>
-  <string name="global_actions">Phone options</string>
-  <string name="hour">hour</string>
-  <string name="hours">hours</string>
-  <string name="httpError">The Web page contains an error.</string>
-  <string name="httpErrorAuth">Authentication was unsuccessful.</string>
-  <string name="httpErrorBadUrl">The page could not be opened because the URL is invalid.</string>
-  <string name="httpErrorConnect">The connection to the server was unsuccessful.</string>
-  <string name="httpErrorFailedSslHandshake">A secure connection could not be established.</string>
-  <string name="httpErrorFile">The file could not be accessed.</string>
-  <string name="httpErrorFileNotFound">The requested file was not found.</string>
-  <string name="httpErrorIO">The server failed to communicate. Try again later.</string>
-  <string name="httpErrorLookup">The URL could not be found.</string>
-  <string name="httpErrorOk">OK</string>
-  <string name="httpErrorProxyAuth">Authentication via the proxy server was unsuccessful.</string>
-  <string name="httpErrorRedirectLoop">The page contains too many server redirects.</string>
-  <string name="httpErrorTimeout">The connection to the server timed out.</string>
-  <string name="httpErrorTooManyRequests">Too many requests are being processed. Try again later.</string>
-  <string name="httpErrorUnsupportedAuthScheme">The site authentication scheme is not supported.</string>
-  <string name="httpErrorUnsupportedScheme">The protocol is not supported.</string>
-  <string name="in">in</string>
-  <string name="invalidPin">Type a PIN that is 4 to 8 numbers.</string>
-  <string name="keyguard_label_text">To unlock, press Menu then 0.</string>
-  <string name="keyguard_password_emergency_instructions">Press the Call button to make an emergency call.</string>
-  <string name="keyguard_password_enter_pin_code">Enter PIN code:</string>
-  <string name="keyguard_password_instructions">Enter passcode or dial emergency number.</string>
-  <string name="keyguard_password_wrong_pin_code">Incorrect PIN code!</string>
-  <string name="kilobyteShort">KB</string>
-  <string name="lockscreen_carrier_default">(No service)</string>
-  <string name="lockscreen_carrier_key">gsm.operator.alpha</string>
-  <string name="lockscreen_emergency_call">Emergency call</string>
-  <string name="lockscreen_failed_attempts_almost_glogin">
-        You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
-       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
-       you will be asked to unlock your phone using your Google sign-in.\n\n
-       Please try again in <xliff:g id="number">%d</xliff:g> seconds.
-    </string>
-  <string name="lockscreen_forgot_pattern_button_text">Forgot pattern?</string>
-  <string name="lockscreen_glogin_instructions">To unlock,\nsign in with your Google account:</string>
-  <string name="lockscreen_glogin_invalid_input">Invalid username or password.</string>
-  <string name="lockscreen_glogin_password_hint">Password</string>
-  <string name="lockscreen_glogin_submit_button">Sign in</string>
-  <string name="lockscreen_glogin_too_many_attempts">Too many pattern attempts!</string>
-  <string name="lockscreen_glogin_username_hint">Username (email)</string>
-  <string name="lockscreen_instructions_when_pattern_disabled">Press Menu to unlock.</string>
-  <string name="lockscreen_instructions_when_pattern_enabled">Press Menu to unlock or place emergency call.</string>
-  <string name="lockscreen_low_battery">Connect your charger.</string>
-  <string name="lockscreen_missing_sim_instructions">Please insert a SIM card.</string>
-  <string name="lockscreen_missing_sim_message">No SIM card in phone.</string>
-  <string name="lockscreen_missing_sim_message_short">No SIM card.</string>
-  <string name="lockscreen_pattern_correct">Correct!</string>
-  <string name="lockscreen_pattern_instructions">Draw pattern to unlock:</string>
-  <string name="lockscreen_pattern_wrong">Sorry, try again:</string>
-  <string name="lockscreen_plugged_in">Charging (<xliff:g id="number">%d%%</xliff:g>)</string>
-  <string name="lockscreen_screen_locked">Screen locked</string>
-  <string name="lockscreen_sim_locked_message">SIM card is locked.</string>
-  <string name="lockscreen_sim_puk_locked_instructions">Please contact Customer Care.</string>
-  <string name="lockscreen_sim_puk_locked_message">SIM card is PUK-locked.</string>
-  <string name="lockscreen_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
-  <string name="lockscreen_too_many_failed_attempts_countdown">Try again in <xliff:g id="number">%d</xliff:g> seconds.</string>
-  <string name="lockscreen_too_many_failed_attempts_dialog_message">
-        You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
-        \n\nPlease try again in <xliff:g id="number">%d</xliff:g> seconds.
-    </string>
-  <string name="lockscreen_too_many_failed_attempts_dialog_title">Lock pattern warning</string>
-  <string name="low_internal_storage_text">Low on internal storage space.</string>
-  <string name="low_internal_storage_view_text">Your phone is running low on internal storage space.</string>
-  <string name="low_internal_storage_view_title">Low on space</string>
-  <string name="low_memory">Phone storage is full! Delete some files to free space.</string>
-  <string name="me">Me</string>
-  <string name="megabyteShort">MB</string>
-  <string name="midnight">"midnight"</string>
-  <string name="minute">min</string>
-  <string name="minutes">mins</string>
-  <string name="mismatchPin">The PINs you entered do not match.</string>
-  <string name="mmiComplete">MMI complete.</string>
-  <string name="mmiError">Connection problem or invalid MMI code.</string>
-  <string name="monday">Monday</string>
-  <string name="month">"<xliff:g id="format">%B</xliff:g>"</string>
-  <string name="month_day">"<xliff:g id="format">%-d %B</xliff:g>"</string>
-  <string name="month_day_year">"<xliff:g id="format">%-d %B, %Y</xliff:g>"</string>
-  <string name="month_long_april">April</string>
-  <string name="month_long_august">August</string>
-  <string name="month_long_december">December</string>
-  <string name="month_long_february">February</string>
-  <string name="month_long_january">January</string>
-  <string name="month_long_july">July</string>
-  <string name="month_long_june">June</string>
-  <string name="month_long_march">March</string>
-  <string name="month_long_may">May</string>
-  <string name="month_long_november">November</string>
-  <string name="month_long_october">October</string>
-  <string name="month_long_september">September</string>
-  <string name="month_medium_april">Apr</string>
-  <string name="month_medium_august">Aug</string>
-  <string name="month_medium_december">Dec</string>
-  <string name="month_medium_february">Feb</string>
-  <string name="month_medium_january">Jan</string>
-  <string name="month_medium_july">Jul</string>
-  <string name="month_medium_june">Jun</string>
-  <string name="month_medium_march">Mar</string>
-  <string name="month_medium_may">May</string>
-  <string name="month_medium_november">Nov</string>
-  <string name="month_medium_october">Oct</string>
-  <string name="month_medium_september">Sep</string>
-  <string name="month_shortest_april">A</string>
-  <string name="month_shortest_august">A</string>
-  <string name="month_shortest_december">D</string>
-  <string name="month_shortest_february">F</string>
-  <string name="month_shortest_january">J</string>
-  <string name="month_shortest_july">J</string>
-  <string name="month_shortest_june">J</string>
-  <string name="month_shortest_march">M</string>
-  <string name="month_shortest_may">M</string>
-  <string name="month_shortest_november">N</string>
-  <string name="month_shortest_october">O</string>
-  <string name="month_shortest_september">S</string>
-  <string name="month_year">"<xliff:g id="format">%B %Y</xliff:g>"</string>
-  <string name="monthly">Monthly</string>
-  <string name="monthly_format">d MMM</string>
-  <string name="more_item_label">More</string>
-  <string name="needPuk2">Type PUK2 to unblock SIM card.</string>
-  <string name="no">Cancel</string>
-  <string name="noApplications">No applications can perform this action.</string>
-  <string name="no_permissions">No permissions required</string>
-  <string name="no_recent_tasks">No recent applications.</string>
-  <string name="noon">"noon"</string>
-  <string name="numeric_date">"<xliff:g id="format">%d/%m/%Y</xliff:g>"</string>
-  <string name="numeric_date_notation">"<xliff:g id="format">%d/%m/%y</xliff:g>"</string>
-  <string name="numeric_md1_md2">"<xliff:g id="format">%2$s/%3$s \u2013 %7$s/%8$s</xliff:g>"</string>
-  <string name="numeric_md1_time1_md2_time2">"<xliff:g id="format">%2$s/%3$s, %5$s \u2013 %7$s/%8$s, %10$s</xliff:g>"</string>
-  <string name="numeric_mdy1_mdy2">"<xliff:g id="format">%2$s/%3$s/%4$s \u2013 %7$s/%8$s/%9$s</xliff:g>"</string>
-  <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="format">%2$s/%3$s/%4$s, %5$s \u2013 %7$s/%8$s/%9$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %2$s/%3$s, %5$s \u2013 %6$s, %7$s/%8$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %2$s/%3$s \u2013 %6$s, %7$s/%8$s</xliff:g>"</string>
-  <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %2$s/%3$s/%4$s, %5$s \u2013 %6$s, %7$s/%8$s/%9$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %2$s/%3$s/%4$s \u2013 %6$s, %7$s/%8$s/%9$s</xliff:g>"</string>
-  <string name="ok">OK</string>
-  <string name="oneMonthDurationPast">1 month ago</string>
-  <string name="open_permission_deny">You do not have permission to open this page.</string>
-  <string name="passwordIncorrect">Incorrect password.</string>
-  <string name="paste">Paste</string>
-  <string name="permdesc_accessCoarseLocation">Access coarse location sources such as the cellular
-        network database to determine an approximate phone location, where available. Malicious
-        applications can use this to determine approximately where you are.</string>
-  <string name="permdesc_accessFineLocation">Access fine location sources such as the
-        Global Positioning System on the phone, where available.
-        Malicious applications can use this to determine where you are, and may
-        consume additional battery power.</string>
-  <string name="permdesc_accessMockLocation">Create mock location sources for testing.
-        Malicious applications can use this to override the location and/or status returned by real
-        location sources such as GPS or Network providers.</string>
-  <string name="permdesc_accessNetworkState">Allows an application to view
-      the state of all networks.</string>
-  <string name="permdesc_accessSurfaceFlinger">Allows application to use
-        SurfaceFlinger low-level features.</string>
-  <string name="permdesc_accessWifiState">Allows an application to view
-      the information about the state of Wi-Fi.</string>
-  <string name="permdesc_addSystemService">Allows application to publish
-        its own low-level system services. Malicious applications may hijack
-        the system, and steal or corrupt any data on it.</string>
-  <string name="permdesc_batteryStats">Allows the modification of
-        collected battery statistics. Not for use by normal applications.</string>
-  <string name="permdesc_bluetooth">Allows an application to view
-      configuration of the local Bluetooth phone, and to make and accept
-      connections with paired devices.</string>
-  <string name="permdesc_bluetoothAdmin">Allows an application to configure
-      the local Bluetooth phone, and to discover and pair with remote
-      devices.</string>
-  <string name="permdesc_brick">Allows the application to
-        disable the entire phone permanently. This is very dangerous.</string>
-  <string name="permdesc_broadcastPackageRemoved">Allows an application to
-        broadcast a notification that an application package has been removed.
-        Malicious applications may use this to kill any other running
-        application.</string>
-  <string name="permdesc_broadcastSticky">Allows an application to send
-        sticky broadcasts, which remain after the broadcast ends.
-        Malicious applications can make the phone slow or unstable by causing it
-        to use too much memory.</string>
-  <string name="permdesc_callPhone">Allows the application to call
-        phone numbers without your intervention. Malicious applications may
-        cause unexpected calls on your phone bill. Note that this does not
-        allow the application to call emergency numbers.</string>
-  <string name="permdesc_camera">Allows application to take pictures
-        with the camera. This allows the application at any time to collect
-        images the camera is seeing.</string>
-  <string name="permdesc_changeComponentState">Allows an application to change whether a
-        component of another application is enabled or not. Malicious applications can use this
-        to disable important phone capabilities. Care must be used with permission, as it is
-        possible to get application components into an unusable, inconsistant, or unstable state.
-    </string>
-  <string name="permdesc_changeConfiguration">Allows an application to
-        change the current configuration, such as the locale or overall font
-        size.</string>
-  <string name="permdesc_changeNetworkState">Allows an application to change
-      the state network connectivity.</string>
-  <string name="permdesc_changeWifiState">Allows an application to connect
-      to and disconnect from Wi-Fi access points, and to make changes to
-      configured Wi-Fi networks.</string>
-  <string name="permdesc_clearAppCache">Allows an application to free phone storage
-        by deleting files in application cache directory. Access is very
-        restricted usually to system process.</string>
-  <string name="permdesc_clearAppUserData">Allows an application to clear user data.</string>
-  <string name="permdesc_createNetworkSockets">Allows an application to
-      create network sockets.</string>
-  <string name="permdesc_deleteCacheFiles">Allows an application to delete
-        cache files.</string>
-  <string name="permdesc_deletePackages">Allows an application to delete
-        Android packages. Malicious applications can use this to delete important applications.</string>
-  <string name="permdesc_devicePower">Allows the application to turn the
-        phone on or off.</string>
-  <string name="permdesc_disableKeyguard">Allows an application to disable
-      the keylock and any associated password security. A legitimate example of
-      this is the phone disabling the keylock when receiving an incoming phone call,
-      then re-enabling the keylock when the call is finished.</string>
-  <string name="permdesc_dump">Allows application to retrieve
-        internal state of the system. Malicious applications may retrieve
-        a wide variety of private and secure information that they should
-        never normally need.</string>
-  <string name="permdesc_expandStatusBar">Allows application to
-        expand or collapse the status bar.</string>
-  <string name="permdesc_factoryTest">Run as a low-level manufacturer test,
-        allowing complete access to the phone hardware. Only available
-        when a phone is running in manufacturer test mode.</string>
-  <string name="permdesc_flashlight">Allows the application to control
-        the flashlight.</string>
-  <string name="permdesc_forceBack">Allows an application to force any
-        activity that is in the foreground to close and go back.
-        Should never be needed for normal applications.</string>
-  <string name="permdesc_fotaUpdate">Allows an application to receive
-        notifications about pending system updates and trigger their
-        installation. Malicious applications may use this to corrupt the system
-        with unauthorized updates, or generally interfere with the update
-        process.</string>
-  <string name="permdesc_getAccounts">Allows an application to get
-      the list of accounts known by the phone.</string>
-  <string name="permdesc_getPackageSize">Allows an application to retrieve
-        its code, data, and cache sizes</string>
-  <string name="permdesc_getTasks">Allows application to retrieve
-        information about currently and recently running tasks. May allow
-        malicious applications to discover private information about other applications.</string>
-  <string name="permdesc_hardware_test">Allows the application to control
-        various peripherals for the purpose of hardware testing.</string>
-  <string name="permdesc_injectEvents">Allows an application to deliver
-        its own input events (key presses, etc.) to other applications. Malicious
-        applications can use this to take over the phone.</string>
-  <string name="permdesc_installPackages">Allows an application to install new or updated
-        Android packages. Malicious applications can use this to add new applications with arbitrarily
-        powerful permissions.</string>
-  <string name="permdesc_internalSystemWindow">Allows the creation of
-        windows that are intended to be used by the internal system
-        user interface. Not for use by normal applications.</string>
-  <string name="permdesc_manageAppTokens">Allows applications to
-        create and manage their own tokens, bypassing their normal
-        Z-ordering. Should never be needed for normal applications.</string>
-  <string name="permdesc_masterClear">Allows an application to completely
-        reset the system to its factory settings, erasing all data,
-        configuration, and installed applications.</string>
-  <string name="permdesc_modifyAudioSettings">Allows application to modify
-        global audio settings such as volume and routing.</string>
-  <string name="permdesc_modifyPhoneState">Allows the application to control the
-        phone features of the device. An application with this permission can switch
-        networks, turn the phone radio on and off and the like without ever notifying
-        you.</string>
-  <string name="permdesc_mount_unmount_filesystems">Allows the application to mount and
-        unmount filesystems for removable storage.</string>
-  <string name="permdesc_persistentActivity">Allows an application to make
-        parts of itself persistent, so the system can't use it for other
-        applications.</string>
-  <string name="permdesc_processOutgoingCalls">Allows application to
-        process outgoing calls and change the number to be dialed.  Malicious
-        applications may monitor, redirect, or prevent outgoing calls.</string>
-  <string name="permdesc_readCalendar">Allows an application to read all
-        of the calendar events stored on your phone. Malicious applications
-        can use this to send your calendar events to other people.</string>
-  <string name="permdesc_readContacts">Allows an application to read all
-        of the contact (address) data stored on your phone. Malicious applications
-        can use this to send your data to other people.</string>
-  <string name="permdesc_readFrameBuffer">Allows application to use
-        read the content of the frame buffer.</string>
-  <string name="permdesc_readInputState">Allows applications to watch the
-        keys you press even when interacting with another application (such
-        as entering a password). Should never be needed for normal applications.</string>
-  <string name="permdesc_readLogs">Allows an application to read from the
-        system's various log files.  This allows it to discover general
-        information about what you are doing with the phone, but they should
-        not contain any personal or private information.</string>
-  <string name="permdesc_readOwnerData">Allows an application read the
-        phone owner data stored on your phone. Malicious
-        applications can use this to read phone owner data.</string>
-  <string name="permdesc_readPhoneState">Allows the application to access the phone
-        features of the device.  An application with this permission can determine the phone
-        number of this phone, whether a call is active, the number that call is connected to
-        and the like.</string>
-  <string name="permdesc_readSms">Allows application to read
-      SMS messages stored on your phone or SIM card. Malicious applications
-      may read your confidential messages.</string>
-  <string name="permdesc_readSyncSettings">Allows an application to read the sync settings,
-        such as whether sync is enabled for Contacts.</string>
-  <string name="permdesc_readSyncStats">Allows an application to reafocusd the sync stats; e.g., the
-        history of syncs that have occurred.</string>
-  <string name="permdesc_receiveBootCompleted">Allows an application to
-        have itself started as soon as the system has finished booting.
-        This can make it take longer to start the phone and allow the
-        application to slow down the overall phone by always running.</string>
-  <string name="permdesc_receiveMms">Allows application to receive
-      and process MMS messages. Malicious applications may monitor
-      your messages or delete them without showing them to you.</string>
-  <string name="permdesc_receiveSms">Allows application to receive
-      and process SMS messages. Malicious applications may monitor
-      your messages or delete them without showing them to you.</string>
-  <string name="permdesc_receiveWapPush">Allows application to receive
-      and process WAP messages. Malicious applications may monitor
-      your messages or delete them without showing them to you.</string>
-  <string name="permdesc_recordAudio">Allows application to access
-        the audio record path.</string>
-  <string name="permdesc_reorderTasks">Allows an application to move
-        tasks to the foreground and background. Malicious applications can force
-        themselves to the front without your control.</string>
-  <string name="permdesc_restartPackages">Allows an application to
-        forcibly restart other applications.</string>
-  <string name="permdesc_runSetActivityWatcher">Allows an application to
-        monitor and control how the system launches activities.
-        Malicious applications may completely compromise the system. This
-        permission is only needed for development, never for normal
-        phone usage.</string>
-  <string name="permdesc_sendSms">Allows application to send SMS
-      messages. Malicious applications may cost you money by sending
-      messages without your confirmation.</string>
-  <string name="permdesc_setAlwaysFinish">Allows an application
-        to control whether activities are always finished as soon as they
-        go to the background. Never needed for normal applications.</string>
-  <string name="permdesc_setAnimationScale">Allows an application to change
-        the global animation speed (faster or slower animations) at any time.</string>
-  <string name="permdesc_setDebugApp">Allows an application to turn
-        on debugging for another application. Malicious applications can use this
-        to kill other applications.</string>
-  <string name="permdesc_setOrientation">Allows an application to change
-        the rotation of the screen at any time. Should never be needed for
-        normal applications.</string>
-  <string name="permdesc_setPreferredApplications">Allows an application to
-        modify your preferred applications. This can allow malicious applications
-        to silently change the applications that are run, spoofing your
-        existing applications to collect private data from you.</string>
-  <string name="permdesc_setProcessForeground">Allows an application to make
-        any process run in the foreground, so it can't be killed.
-        Should never be needed for normal applications.</string>
-  <string name="permdesc_setProcessLimit">Allows an application
-        to control the maximum number of processes that will run. Never
-        needed for normal applications.</string>
-  <string name="permdesc_setTimeZone">Allows an application to change
-        the phone's time zone.</string>
-  <string name="permdesc_setWallpaper">Allows the application
-        to set the system wallpaper.</string>
-  <string name="permdesc_setWallpaperHints">Allows the application
-        to set the system wallpaper size hints.</string>
-  <string name="permdesc_signalPersistentProcesses">Allows application to request that the
-        supplied signal be sent to all persistent processes.</string>
-  <string name="permdesc_statusBar">Allows application to disable
-        the status bar or add and remove system icons.</string>
-  <string name="permdesc_systemAlertWindow">Allows an application to
-        show system alert windows. Malicious applications can take over the
-        entire screen of the phone.</string>
-  <string name="permdesc_vibrate">Allows the application to control
-        the vibrator.</string>
-  <string name="permdesc_wakeLock">Allows an application to prevent
-        the phone from going to sleep.</string>
-  <string name="permdesc_writeCalendar">Allows an application to modify the
-        calendar events stored on your phone. Malicious
-        applications can use this to erase or modify your calendar data.</string>
-  <string name="permdesc_writeContacts">Allows an application to modify the
-        contact (address) data stored on your phone. Malicious
-        applications can use this to erase or modify your contact data.</string>
-  <string name="permdesc_writeOwnerData">Allows an application to modify the
-        phone owner data stored on your phone. Malicious
-        applications can use this to erase or modify owner data.</string>
-  <string name="permdesc_writeSettings">Allows an application to modify the
-        system's settings data. Malicious applications can corrupt your system's
-        configuration.</string>
-  <string name="permdesc_writeSms">Allows application to write
-      to SMS messages stored on your phone or SIM card. Malicious applications
-      may delete your messages.</string>
-  <string name="permdesc_writeSyncSettings">Allows an application to modify the sync
-        settings, such as whether sync is enabled for Contacts.</string>
-  <string name="permgroupdesc_accounts">Access the available Google accounts.</string>
-  <string name="permgroupdesc_costMoney">Allow applications to do things
-        that can cost you money.</string>
-  <string name="permgroupdesc_developmentTools">Features only needed for
-        application developers.</string>
-  <string name="permgroupdesc_hardwareControls">Direct access to hardware on
-        the handset.</string>
-  <string name="permgroupdesc_location">Monitor your physical location</string>
-  <string name="permgroupdesc_messages">Read and write your SMS,
-        e-mail, and other messages.</string>
-  <string name="permgroupdesc_network">Allow applications to access
-        various network features.</string>
-  <string name="permgroupdesc_personalInfo">Direct access to your contacts
-        and calendar stored on the phone.</string>
-  <string name="permgroupdesc_phoneCalls">Monitor, record, and process
-        phone calls.</string>
-  <string name="permgroupdesc_systemTools">Lower-level access and control
-        of the system.</string>
-  <string name="permgrouplab_accounts">Your Google accounts</string>
-  <string name="permgrouplab_costMoney">Cost you money</string>
-  <string name="permgrouplab_developmentTools">Development tools</string>
-  <string name="permgrouplab_hardwareControls">Hardware controls</string>
-  <string name="permgrouplab_location">Your location</string>
-  <string name="permgrouplab_messages">Your messages</string>
-  <string name="permgrouplab_network">Network communication</string>
-  <string name="permgrouplab_personalInfo">Your personal information</string>
-  <string name="permgrouplab_phoneCalls">Phone calls</string>
-  <string name="permgrouplab_systemTools">System tools</string>
-  <string name="permissions_format"><xliff:g id="perm_line1">%1$s</xliff:g>, <xliff:g id="perm_line2">%2$s</xliff:g></string>
-  <string name="permlab_accessCoarseLocation">coarse (network-based) location</string>
-  <string name="permlab_accessFineLocation">fine (GPS) location</string>
-  <string name="permlab_accessMockLocation">mock location sources for testing</string>
-  <string name="permlab_accessNetworkState">view network state</string>
-  <string name="permlab_accessSurfaceFlinger">access SurfaceFlinger</string>
-  <string name="permlab_accessWifiState">view Wi-Fi state</string>
-  <string name="permlab_addSystemService">publish low-level services</string>
-  <string name="permlab_batteryStats">modify battery statistics</string>
-  <string name="permlab_bluetooth">create Bluetooth connections</string>
-  <string name="permlab_bluetoothAdmin">bluetooth administration</string>
-  <string name="permlab_brick">permanently disable phone</string>
-  <string name="permlab_broadcastPackageRemoved">send package removed broadcast</string>
-  <string name="permlab_broadcastSticky">send sticky broadcast</string>
-  <string name="permlab_callPhone">directly call phone numbers</string>
-  <string name="permlab_camera">take pictures</string>
-  <string name="permlab_changeComponentState">enable or disable application components</string>
-  <string name="permlab_changeConfiguration">change your UI settings</string>
-  <string name="permlab_changeNetworkState">change network connectivity</string>
-  <string name="permlab_changeWifiState">change Wi-Fi state</string>
-  <string name="permlab_clearAppCache">delete all application cache data</string>
-  <string name="permlab_clearAppUserData">delete other application's data</string>
-  <string name="permlab_createNetworkSockets">full Internet access</string>
-  <string name="permlab_deleteCacheFiles">delete other application's cache</string>
-  <string name="permlab_deletePackages">delete applications</string>
-  <string name="permlab_devicePower">power phone on or off</string>
-  <string name="permlab_disableKeyguard">disable keylock</string>
-  <string name="permlab_dump">retrieve system internal state</string>
-  <string name="permlab_expandStatusBar">expand/collapse status bar</string>
-  <string name="permlab_factoryTest">run in factory test mode</string>
-  <string name="permlab_flashlight">control flashlight</string>
-  <string name="permlab_forceBack">force application to close</string>
-  <string name="permlab_fotaUpdate">automatically install system updates</string>
-  <string name="permlab_getAccounts">discover known accounts</string>
-  <string name="permlab_getPackageSize">measure application storage space</string>
-  <string name="permlab_getTasks">retrieve running applications</string>
-  <string name="permlab_hardware_test">test hardware</string>
-  <string name="permlab_injectEvents">press keys and control buttons</string>
-  <string name="permlab_installPackages">directly install applications</string>
-  <string name="permlab_internalSystemWindow">display unauthorized windows</string>
-  <string name="permlab_manageAppTokens">manage application tokens</string>
-  <string name="permlab_masterClear">reset system to factory defaults</string>
-  <string name="permlab_modifyAudioSettings">change your audio settings</string>
-  <string name="permlab_modifyPhoneState">modify phone state</string>
-  <string name="permlab_mount_unmount_filesystems">mount and unmount filesystems</string>
-  <string name="permlab_persistentActivity">make application always run</string>
-  <string name="permlab_processOutgoingCalls">intercept outgoing calls</string>
-  <string name="permlab_readCalendar">read calendar data</string>
-  <string name="permlab_readContacts">read contact data</string>
-  <string name="permlab_readFrameBuffer">read frame buffer</string>
-  <string name="permlab_readInputState">record what you type and actions you take</string>
-  <string name="permlab_readLogs">read system log files</string>
-  <string name="permlab_readOwnerData">read owner data</string>
-  <string name="permlab_readPhoneState">read phone state</string>
-  <string name="permlab_readSms">read SMS or MMS</string>
-  <string name="permlab_readSyncSettings">read sync settings</string>
-  <string name="permlab_readSyncStats">read sync statistics</string>
-  <string name="permlab_receiveBootCompleted">automatically start at boot</string>
-  <string name="permlab_receiveMms">receive MMS</string>
-  <string name="permlab_receiveSms">receive SMS</string>
-  <string name="permlab_receiveWapPush">receive WAP</string>
-  <string name="permlab_recordAudio">record audio</string>
-  <string name="permlab_reorderTasks">reorder running applications</string>
-  <string name="permlab_restartPackages">restart other applications</string>
-  <string name="permlab_runSetActivityWatcher">monitor and control all application launching</string>
-  <string name="permlab_sendSms">send SMS messages</string>
-  <string name="permlab_setAlwaysFinish">make all background applications close</string>
-  <string name="permlab_setAnimationScale">modify global animation speed</string>
-  <string name="permlab_setDebugApp">enable application debugging</string>
-  <string name="permlab_setOrientation">change screen orientation</string>
-  <string name="permlab_setPreferredApplications">set preferred applications</string>
-  <string name="permlab_setProcessForeground">keep from being stopped</string>
-  <string name="permlab_setProcessLimit">limit number of running processes</string>
-  <string name="permlab_setTimeZone">set time zone</string>
-  <string name="permlab_setWallpaper">set wallpaper</string>
-  <string name="permlab_setWallpaperHints">set wallpaper size hints</string>
-  <string name="permlab_signalPersistentProcesses">send Linux signals to applications</string>
-  <string name="permlab_statusBar">disable or modify status bar</string>
-  <string name="permlab_systemAlertWindow">display system-level alerts</string>
-  <string name="permlab_vibrate">control vibrator</string>
-  <string name="permlab_wakeLock">prevent phone from sleeping</string>
-  <string name="permlab_writeCalendar">write calendar data</string>
-  <string name="permlab_writeContacts">write contact data</string>
-  <string name="permlab_writeOwnerData">write owner data</string>
-  <string name="permlab_writeSettings">modify global system settings</string>
-  <string name="permlab_writeSms">edit SMS or MMS</string>
-  <string name="permlab_writeSyncSettings">write sync settings</string>
-  <string name="petabyteShort">PB</string>
-  <string name="pm">"PM"</string>
-  <string name="power_dialog">Phone options</string>
-  <string name="power_off">Power off</string>
-  <string name="prepend_shortcut_label">Menu+</string>
-  <string name="preposition_for_date">on %s</string>
-  <string name="preposition_for_time">at %s</string>
-  <string name="preposition_for_year">in %s</string>
-  <string name="ringtone_default">Default ringtone</string>
-  <string name="ringtone_default_with_actual">Default ringtone (<xliff:g id="actual_ringtone">%1$s</xliff:g>)</string>
-  <string name="ringtone_picker_title">Select a ringtone</string>
-  <string name="ringtone_silent">Silent</string>
-  <string name="ringtone_unknown">Unknown ringtone</string>
-  <string name="safeMode">Safe mode</string>
-  <string name="same_month_md1_md2">"<xliff:g id="format">%2$s %3$s \u2013 %8$s</xliff:g>"</string>
-  <string name="same_month_md1_time1_md2_time2">"<xliff:g id="format">%2$s %3$s, %5$s \u2013 %7$s %8$s, %10$s</xliff:g>"</string>
-  <string name="same_month_mdy1_mdy2">"<xliff:g id="format">%2$s %3$s \u2013 %8$s, %9$s</xliff:g>"</string>
-  <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="format">%2$s %3$s, %4$s, %5$s \u2013 %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %5$s \u2013 %6$s, %7$s %8$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %2$s %3$s \u2013 %6$s, %7$s %8$s</xliff:g>"</string>
-  <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %4$s, %5$s \u2013 %6$s, %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %2$s %3$s, %4$s \u2013 %6$s, %7$s %8$s, %9$s</xliff:g>"</string>
-  <string name="same_year_md1_md2">"<xliff:g id="format">%2$s %3$s \u2013 %7$s %8$s</xliff:g>"</string>
-  <string name="same_year_md1_time1_md2_time2">"<xliff:g id="format">%2$s %3$s, %5$s \u2013 %7$s %8$s, %10$s</xliff:g>"</string>
-  <string name="same_year_mdy1_mdy2">"<xliff:g id="format">%2$s %3$s \u2013 %7$s %8$s, %9$s</xliff:g>"</string>
-  <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="format">%2$s %3$s, %4$s, %5$s \u2013 %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %5$s \u2013 %6$s, %7$s %8$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %2$s %3$s \u2013 %6$s, %7$s %8$s</xliff:g>"</string>
-  <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %4$s, %5$s \u2013 %6$s, %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %2$s %3$s \u2013 %6$s, %7$s %8$s, %9$s</xliff:g>"</string>
-  <string name="saturday">Saturday</string>
-  <string name="save_password_label">Confirm</string>
-  <string name="save_password_message">Do you want the browser to remember this password?</string>
-  <string name="save_password_never">Never</string>
-  <string name="save_password_notnow">Not now</string>
-  <string name="save_password_remember">Remember</string>
-  <string name="screen_lock">Screen lock</string>
-  <string name="screen_progress">Working\u2026</string>
-  <string name="search_go">Search</string>
-  <string name="second">sec</string>
-  <string name="seconds">secs</string>
-  <string name="selectAll">Select all</string>
-  <string name="selectMenuLabel">Select</string>
-  <string name="select_character">Select character to insert</string>
-  <string name="sendText">Select an action for text</string>
-  <string name="serviceClassData">Data</string>
-  <string name="serviceClassDataAsync">Async</string>
-  <string name="serviceClassDataSync">Sync</string>
-  <string name="serviceClassFAX">FAX</string>
-  <string name="serviceClassPAD">PAD</string>
-  <string name="serviceClassPacket">Packet</string>
-  <string name="serviceClassSMS">SMS</string>
-  <string name="serviceClassVoice">Voice</string>
-  <string name="serviceDisabled">Service has been disabled.</string>
-  <string name="serviceEnabled">Service was enabled.</string>
-  <string name="serviceEnabledFor">Service was enabled for:</string>
-  <string name="serviceErased">Erasure was successful.</string>
-  <string name="serviceNotProvisioned">Service not provisioned.</string>
-  <string name="serviceRegistered">Registration was successful.</string>
-  <string name="shutdown_confirm">Your phone will shut down.</string>
-  <string name="shutdown_progress">Shutting down\u2026</string>
-  <string name="silent_mode">Silent mode</string>
-  <string name="simAbsentLabel">SIM card absent or incorrectly inserted.</string>
-  <string name="simNetworkPersonalizationLabel">SIM card cannot be used on this phone.</string>
-  <string name="simPINLabel">SIM PIN required (and presently unsupported).</string>
-  <string name="simPUKLabel">SIM PUK required (and presently unsupported).</string>
-  <string name="sms_control_message">A large number of SMS messages are being sent. Select \"OK\" to continue, or \"Cancel\" to stop sending.</string>
-  <string name="sms_control_no">Cancel</string>
-  <string name="sms_control_title">Sending SMS messages</string>
-  <string name="sms_control_yes">OK</string>
-  <string name="status_bar_applications_title">Application</string>
-  <string name="status_bar_clear_all_button">Clear notifications</string>
-  <string name="status_bar_date_format">"<xliff:g id="format">d, MMMM, yyyy</xliff:g>"</string>
-  <string name="status_bar_latest_events_title">Notifications</string>
-  <string name="status_bar_no_notifications_title">No notifications</string>
-  <string name="status_bar_ongoing_events_title">Ongoing</string>
-  <string name="status_bar_time_format">"<xliff:g id="format">h:mm AA</xliff:g>"</string>
-  <string name="sunday">Sunday</string>
-  <string name="terabyteShort">TB</string>
-  <string name="text_copied">Text copied to clipboard.</string>
-  <string name="thursday">Thursday</string>
-  <string name="time1_time2">"<xliff:g id="format">%1$s \u2013 %2$s</xliff:g>"</string>
-  <string name="time_date">"<xliff:g id="format">%1$s, %3$s</xliff:g>"</string>
-  <string name="time_picker_set">Set</string>
-  <string name="time_wday">"<xliff:g id="format">%1$s, %2$s</xliff:g>"</string>
-  <string name="time_wday_date">"<xliff:g id="format">%1$s, %2$s, %3$s</xliff:g>"</string>
-  <string name="today">Today</string>
-  <string name="tomorrow">Tomorrow</string>
-  <string name="tuesday">Tuesday</string>
-  <string name="turn_off_radio">Turn off wireless</string>
-  <string name="turn_on_radio">Turn on wireless</string>
-  <string name="unknownName">(Unknown)</string>
-  <string name="untitled">&lt;untitled&gt;</string>
-  <string name="volume_alarm">Alarm volume</string>
-  <string name="volume_call">In-call volume</string>
-  <string name="volume_music">Music/video volume</string>
-  <string name="volume_ringtone">Ringer volume</string>
-  <string name="volume_unknown">Volume</string>
-  <string name="wait">Wait</string>
-  <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="format">%1$s, %2$s, %3$s \u2013 %4$s, %5$s, %6$s</xliff:g>"</string>
-  <string name="wday1_date1_wday2_date2">"<xliff:g id="format">%1$s, %2$s \u2013 %4$s, %5$s</xliff:g>"</string>
-  <string name="wday_date">"<xliff:g id="format">%2$s, %3$s</xliff:g>"</string>
-  <string name="web_user_agent"><xliff:g id="x">Mozilla/5.0 (Linux; U; Android 0.6; %s)
-        AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2</xliff:g></string>
-  <string name="wednesday">Wednesday</string>
-  <string name="week">week</string>
-  <string name="weekly">"Weekly on <xliff:g id="day">%s</xliff:g>"</string>
-  <string name="weekly_format">d MMM</string>
-  <string name="weeks">weeks</string>
-  <string name="whichApplication">Complete action using</string>
-  <string name="year">year</string>
-  <string name="yearly">Yearly</string>
-  <string name="yearly_format">yyyy</string>
-  <string name="years">years</string>
-  <string name="yes">OK</string>
-  <string name="yesterday">Yesterday</string>
+    <string name="byteShort">"B"</string>
+    <string name="kilobyteShort">"KB"</string>
+    <string name="megabyteShort">"MB"</string>
+    <string name="gigabyteShort">"GB"</string>
+    <string name="terabyteShort">"TB"</string>
+    <string name="petabyteShort">"PB"</string>
+    <string name="untitled">"&lt;untitled&gt;"</string>
+    <string name="ellipsis">"…"</string>
+    <string name="emptyPhoneNumber">"(No phone number)"</string>
+    <string name="unknownName">"(Unknown)"</string>
+    <string name="defaultVoiceMailAlphaTag">"Voicemail"</string>
+    <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+    <string name="mmiError">"Connection problem or invalid MMI code."</string>
+    <string name="serviceEnabled">"Service was enabled."</string>
+    <string name="serviceEnabledFor">"Service was enabled for:"</string>
+    <string name="serviceDisabled">"Service has been disabled."</string>
+    <string name="serviceRegistered">"Registration was successful."</string>
+    <string name="serviceErased">"Erasure was successful."</string>
+    <string name="passwordIncorrect">"Incorrect password."</string>
+    <string name="mmiComplete">"MMI complete."</string>
+    <string name="badPin">"The old PIN you typed is not correct."</string>
+    <string name="badPuk">"The PUK you typed is not correct."</string>
+    <string name="mismatchPin">"The PINs you entered do not match."</string>
+    <string name="invalidPin">"Type a PIN that is 4 to 8 numbers."</string>
+    <!-- no translation found for needPuk (4788728144863892764) -->
+    <skip />
+    <string name="needPuk2">"Type PUK2 to unblock SIM card."</string>
+    <string name="ClipMmi">"Incoming Caller ID"</string>
+    <string name="ClirMmi">"Outgoing Caller ID"</string>
+    <string name="CfMmi">"Call forwarding"</string>
+    <string name="CwMmi">"Call waiting"</string>
+    <string name="BaMmi">"Call barring"</string>
+    <string name="PwdMmi">"Password change"</string>
+    <string name="PinMmi">"PIN change"</string>
+    <string name="CLIRDefaultOnNextCallOn">"Caller ID defaults to restricted. Next call: Restricted"</string>
+    <string name="CLIRDefaultOnNextCallOff">"Caller ID defaults to restricted. Next call: Not restricted"</string>
+    <string name="CLIRDefaultOffNextCallOn">"Caller ID defaults to not restricted. Next call: Restricted"</string>
+    <string name="CLIRDefaultOffNextCallOff">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
+    <string name="serviceNotProvisioned">"Service not provisioned."</string>
+    <string name="CLIRPermanent">"The caller ID setting cannot be changed."</string>
+    <string name="serviceClassVoice">"Voice"</string>
+    <string name="serviceClassData">"Data"</string>
+    <string name="serviceClassFAX">"FAX"</string>
+    <string name="serviceClassSMS">"SMS"</string>
+    <string name="serviceClassDataAsync">"Async"</string>
+    <string name="serviceClassDataSync">"Sync"</string>
+    <string name="serviceClassPacket">"Packet"</string>
+    <string name="serviceClassPAD">"PAD"</string>
+    <string name="cfTemplateNotForwarded">"{0}: Not forwarded"</string>
+    <string name="cfTemplateForwarded">"{0}: {1}"</string>
+    <string name="cfTemplateForwardedTime">"{0}: {1} after {2} seconds"</string>
+    <string name="cfTemplateRegistered">"{0}: Not forwarded"</string>
+    <string name="cfTemplateRegisteredTime">"{0}: Not forwarded"</string>
+    <string name="httpErrorOk">"OK"</string>
+    <string name="httpError">"The Web page contains an error."</string>
+    <string name="httpErrorLookup">"The URL could not be found."</string>
+    <string name="httpErrorUnsupportedAuthScheme">"The site authentication scheme is not supported."</string>
+    <string name="httpErrorAuth">"Authentication was unsuccessful."</string>
+    <string name="httpErrorProxyAuth">"Authentication via the proxy server was unsuccessful."</string>
+    <string name="httpErrorConnect">"The connection to the server was unsuccessful."</string>
+    <string name="httpErrorIO">"The server failed to communicate. Try again later."</string>
+    <string name="httpErrorTimeout">"The connection to the server timed out."</string>
+    <string name="httpErrorRedirectLoop">"The page contains too many server redirects."</string>
+    <string name="httpErrorUnsupportedScheme">"The protocol is not supported."</string>
+    <string name="httpErrorFailedSslHandshake">"A secure connection could not be established."</string>
+    <string name="httpErrorBadUrl">"The page could not be opened because the URL is invalid."</string>
+    <string name="httpErrorFile">"The file could not be accessed."</string>
+    <string name="httpErrorFileNotFound">"The requested file was not found."</string>
+    <string name="httpErrorTooManyRequests">"Too many requests are being processed. Try again later."</string>
+    <string name="contentServiceSync">"Sync"</string>
+    <string name="contentServiceSyncNotificationTitle">"Sync"</string>
+    <string name="contentServiceTooManyDeletesNotificationDesc">"Too many %s deletes."</string>
+    <string name="low_memory">"Phone storage is full! Delete some files to free space."</string>
+    <string name="me">"Me"</string>
+    <string name="power_dialog">"Phone options"</string>
+    <string name="silent_mode">"Silent mode"</string>
+    <string name="turn_on_radio">"Turn on wireless"</string>
+    <string name="turn_off_radio">"Turn off wireless"</string>
+    <string name="screen_lock">"Screen lock"</string>
+    <string name="power_off">"Power off"</string>
+    <string name="shutdown_progress">"Shutting down…"</string>
+    <string name="shutdown_confirm">"Your phone will shut down."</string>
+    <string name="no_recent_tasks">"No recent applications."</string>
+    <string name="global_actions">"Phone options"</string>
+    <string name="global_action_lock">"Screen lock"</string>
+    <string name="global_action_power_off">"Power off"</string>
+    <string name="global_action_toggle_silent_mode">"Silent mode"</string>
+    <string name="global_action_silent_mode_on_status">"Sound is OFF"</string>
+    <string name="global_action_silent_mode_off_status">"Sound is ON"</string>
+    <string name="safeMode">"Safe mode"</string>
+    <string name="permgrouplab_costMoney">"Cost you money"</string>
+    <string name="permgroupdesc_costMoney">"Allow applications to do things that can cost you money."</string>
+    <string name="permgrouplab_messages">"Your messages"</string>
+    <string name="permgroupdesc_messages">"Read and write your SMS, e-mail, and other messages."</string>
+    <string name="permgrouplab_personalInfo">"Your personal information"</string>
+    <string name="permgroupdesc_personalInfo">"Direct access to your contacts and calendar stored on the phone."</string>
+    <string name="permgrouplab_location">"Your location"</string>
+    <string name="permgroupdesc_location">"Monitor your physical location"</string>
+    <string name="permgrouplab_network">"Network communication"</string>
+    <string name="permgroupdesc_network">"Allow applications to access various network features."</string>
+    <string name="permgrouplab_accounts">"Your Google accounts"</string>
+    <string name="permgroupdesc_accounts">"Access the available Google accounts."</string>
+    <string name="permgrouplab_hardwareControls">"Hardware controls"</string>
+    <string name="permgroupdesc_hardwareControls">"Direct access to hardware on the handset."</string>
+    <string name="permgrouplab_phoneCalls">"Phone calls"</string>
+    <string name="permgroupdesc_phoneCalls">"Monitor, record, and process phone calls."</string>
+    <string name="permgrouplab_systemTools">"System tools"</string>
+    <string name="permgroupdesc_systemTools">"Lower-level access and control of the system."</string>
+    <string name="permgrouplab_developmentTools">"Development tools"</string>
+    <string name="permgroupdesc_developmentTools">"Features only needed for application developers."</string>
+    <string name="permlab_statusBar">"disable or modify status bar"</string>
+    <string name="permdesc_statusBar">"Allows application to disable the status bar or add and remove system icons."</string>
+    <string name="permlab_expandStatusBar">"expand/collapse status bar"</string>
+    <string name="permdesc_expandStatusBar">"Allows application to expand or collapse the status bar."</string>
+    <string name="permlab_processOutgoingCalls">"intercept outgoing calls"</string>
+    <string name="permdesc_processOutgoingCalls">"Allows application to process outgoing calls and change the number to be dialed. Malicious applications may monitor, redirect, or prevent outgoing calls."</string>
+    <string name="permlab_receiveSms">"receive SMS"</string>
+    <string name="permdesc_receiveSms">"Allows application to receive and process SMS messages. Malicious applications may monitor your messages or delete them without showing them to you."</string>
+    <string name="permlab_receiveMms">"receive MMS"</string>
+    <string name="permdesc_receiveMms">"Allows application to receive and process MMS messages. Malicious applications may monitor your messages or delete them without showing them to you."</string>
+    <string name="permlab_sendSms">"send SMS messages"</string>
+    <string name="permdesc_sendSms">"Allows application to send SMS messages. Malicious applications may cost you money by sending messages without your confirmation."</string>
+    <string name="permlab_readSms">"read SMS or MMS"</string>
+    <string name="permdesc_readSms">"Allows application to read SMS messages stored on your phone or SIM card. Malicious applications may read your confidential messages."</string>
+    <string name="permlab_writeSms">"edit SMS or MMS"</string>
+    <string name="permdesc_writeSms">"Allows application to write to SMS messages stored on your phone or SIM card. Malicious applications may delete your messages."</string>
+    <string name="permlab_receiveWapPush">"receive WAP"</string>
+    <string name="permdesc_receiveWapPush">"Allows application to receive and process WAP messages. Malicious applications may monitor your messages or delete them without showing them to you."</string>
+    <string name="permlab_getTasks">"retrieve running applications"</string>
+    <string name="permdesc_getTasks">"Allows application to retrieve information about currently and recently running tasks. May allow malicious applications to discover private information about other applications."</string>
+    <string name="permlab_reorderTasks">"reorder running applications"</string>
+    <string name="permdesc_reorderTasks">"Allows an application to move tasks to the foreground and background. Malicious applications can force themselves to the front without your control."</string>
+    <string name="permlab_setDebugApp">"enable application debugging"</string>
+    <string name="permdesc_setDebugApp">"Allows an application to turn on debugging for another application. Malicious applications can use this to kill other applications."</string>
+    <string name="permlab_changeConfiguration">"change your UI settings"</string>
+    <string name="permdesc_changeConfiguration">"Allows an application to change the current configuration, such as the locale or overall font size."</string>
+    <string name="permlab_restartPackages">"restart other applications"</string>
+    <string name="permdesc_restartPackages">"Allows an application to forcibly restart other applications."</string>
+    <string name="permlab_setProcessForeground">"keep from being stopped"</string>
+    <!-- unknown placeholder BREAK in permdesc_setProcessForeground -->
+    <skip />
+    <string name="permlab_forceBack">"force application to close"</string>
+    <string name="permdesc_forceBack">"Allows an application to force any activity that is in the foreground to close and go back. Should never be needed for normal applications."</string>
+    <string name="permlab_dump">"retrieve system internal state"</string>
+    <string name="permdesc_dump">"Allows application to retrieve internal state of the system. Malicious applications may retrieve a wide variety of private and secure information that they should never normally need."</string>
+    <string name="permlab_addSystemService">"publish low-level services"</string>
+    <string name="permdesc_addSystemService">"Allows application to publish its own low-level system services. Malicious applications may hijack the system, and steal or corrupt any data on it."</string>
+    <string name="permlab_runSetActivityWatcher">"monitor and control all application launching"</string>
+    <string name="permdesc_runSetActivityWatcher">"Allows an application to monitor and control how the system launches activities. Malicious applications may completely compromise the system. This permission is only needed for development, never for normal phone usage."</string>
+    <string name="permlab_broadcastPackageRemoved">"send package removed broadcast"</string>
+    <string name="permdesc_broadcastPackageRemoved">"Allows an application to broadcast a notification that an application package has been removed. Malicious applications may use this to kill any other running application."</string>
+    <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
+    <skip />
+    <string name="permlab_setProcessLimit">"limit number of running processes"</string>
+    <string name="permdesc_setProcessLimit">"Allows an application to control the maximum number of processes that will run. Never needed for normal applications."</string>
+    <string name="permlab_setAlwaysFinish">"make all background applications close"</string>
+    <string name="permdesc_setAlwaysFinish">"Allows an application to control whether activities are always finished as soon as they go to the background. Never needed for normal applications."</string>
+    <string name="permlab_fotaUpdate">"automatically install system updates"</string>
+    <string name="permdesc_fotaUpdate">"Allows an application to receive notifications about pending system updates and trigger their installation. Malicious applications may use this to corrupt the system with unauthorized updates, or generally interfere with the update process."</string>
+    <string name="permlab_batteryStats">"modify battery statistics"</string>
+    <string name="permdesc_batteryStats">"Allows the modification of collected battery statistics. Not for use by normal applications."</string>
+    <string name="permlab_internalSystemWindow">"display unauthorized windows"</string>
+    <string name="permdesc_internalSystemWindow">"Allows the creation of windows that are intended to be used by the internal system user interface. Not for use by normal applications."</string>
+    <string name="permlab_systemAlertWindow">"display system-level alerts"</string>
+    <string name="permdesc_systemAlertWindow">"Allows an application to show system alert windows. Malicious applications can take over the entire screen of the phone."</string>
+    <string name="permlab_setAnimationScale">"modify global animation speed"</string>
+    <string name="permdesc_setAnimationScale">"Allows an application to change the global animation speed (faster or slower animations) at any time."</string>
+    <string name="permlab_manageAppTokens">"manage application tokens"</string>
+    <string name="permdesc_manageAppTokens">"Allows applications to create and manage their own tokens, bypassing their normal Z-ordering. Should never be needed for normal applications."</string>
+    <string name="permlab_injectEvents">"press keys and control buttons"</string>
+    <string name="permdesc_injectEvents">"Allows an application to deliver its own input events (key presses, etc.) to other applications. Malicious applications can use this to take over the phone."</string>
+    <string name="permlab_readInputState">"record what you type and actions you take"</string>
+    <string name="permdesc_readInputState">"Allows applications to watch the keys you press even when interacting with another application (such as entering a password). Should never be needed for normal applications."</string>
+    <string name="permlab_setOrientation">"change screen orientation"</string>
+    <string name="permdesc_setOrientation">"Allows an application to change the rotation of the screen at any time. Should never be needed for normal applications."</string>
+    <string name="permlab_signalPersistentProcesses">"send Linux signals to applications"</string>
+    <string name="permdesc_signalPersistentProcesses">"Allows application to request that the supplied signal be sent to all persistent processes."</string>
+    <string name="permlab_persistentActivity">"make application always run"</string>
+    <!-- unknown placeholder BREAK in permdesc_persistentActivity -->
+    <skip />
+    <string name="permlab_deletePackages">"delete applications"</string>
+    <string name="permdesc_deletePackages">"Allows an application to delete Android packages. Malicious applications can use this to delete important applications."</string>
+    <string name="permlab_clearAppUserData">"delete other applications data"</string>
+    <string name="permdesc_clearAppUserData">"Allows an application to clear user data."</string>
+    <string name="permlab_deleteCacheFiles">"delete other applications cache"</string>
+    <string name="permdesc_deleteCacheFiles">"Allows an application to delete cache files."</string>
+    <string name="permlab_getPackageSize">"measure application storage space"</string>
+    <string name="permdesc_getPackageSize">"Allows an application to retrieve its code, data, and cache sizes"</string>
+    <string name="permlab_installPackages">"directly install applications"</string>
+    <string name="permdesc_installPackages">"Allows an application to install new or updated Android packages. Malicious applications can use this to add new applications with arbitrarily powerful permissions."</string>
+    <string name="permlab_clearAppCache">"delete all application cache data"</string>
+    <string name="permdesc_clearAppCache">"Allows an application to free phone storage by deleting files in application cache directory. Access is very restricted usually to system process."</string>
+    <string name="permlab_readLogs">"read system log files"</string>
+    <!-- unknown placeholder BREAK_0 in permdesc_readLogs -->
+    <skip />
+    <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
+    <skip />
+    <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
+    <skip />
+    <string name="permlab_changeComponentState">"enable or disable application components"</string>
+    <string name="permdesc_changeComponentState">"Allows an application to change whether a component of another application is enabled or not. Malicious applications can use this to disable important phone capabilities. Care must be used with permission, as it is possible to get application components into an unusable, inconsistant, or unstable state."</string>
+    <string name="permlab_setPreferredApplications">"set preferred applications"</string>
+    <string name="permdesc_setPreferredApplications">"Allows an application to modify your preferred applications. This can allow malicious applications to silently change the applications that are run, spoofing your existing applications to collect private data from you."</string>
+    <string name="permlab_writeSettings">"modify global system settings"</string>
+    <string name="permdesc_writeSettings">"Allows an application to modify the systems settings data. Malicious applications can corrupt your systems configuration."</string>
+    <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
+    <skip />
+    <!-- no translation found for permlab_writeGservices (296370685945777755) -->
+    <skip />
+    <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
+    <skip />
+    <string name="permlab_receiveBootCompleted">"automatically start at boot"</string>
+    <string name="permdesc_receiveBootCompleted">"Allows an application to have itself started as soon as the system has finished booting. This can make it take longer to start the phone and allow the application to slow down the overall phone by always running."</string>
+    <string name="permlab_broadcastSticky">"send sticky broadcast"</string>
+    <string name="permdesc_broadcastSticky">"Allows an application to send sticky broadcasts, which remain after the broadcast ends. Malicious applications can make the phone slow or unstable by causing it to use too much memory."</string>
+    <string name="permlab_readContacts">"read contact data"</string>
+    <string name="permdesc_readContacts">"Allows an application to read all of the contact (address) data stored on your phone. Malicious applications can use this to send your data to other people."</string>
+    <string name="permlab_writeContacts">"write contact data"</string>
+    <string name="permdesc_writeContacts">"Allows an application to modify the contact (address) data stored on your phone. Malicious applications can use this to erase or modify your contact data."</string>
+    <string name="permlab_writeOwnerData">"write owner data"</string>
+    <string name="permdesc_writeOwnerData">"Allows an application to modify the phone owner data stored on your phone. Malicious applications can use this to erase or modify owner data."</string>
+    <string name="permlab_readOwnerData">"read owner data"</string>
+    <string name="permdesc_readOwnerData">"Allows an application read the phone owner data stored on your phone. Malicious applications can use this to read phone owner data."</string>
+    <string name="permlab_readCalendar">"read calendar data"</string>
+    <string name="permdesc_readCalendar">"Allows an application to read all of the calendar events stored on your phone. Malicious applications can use this to send your calendar events to other people."</string>
+    <string name="permlab_writeCalendar">"write calendar data"</string>
+    <string name="permdesc_writeCalendar">"Allows an application to modify the calendar events stored on your phone. Malicious applications can use this to erase or modify your calendar data."</string>
+    <string name="permlab_accessMockLocation">"mock location sources for testing"</string>
+    <string name="permdesc_accessMockLocation">"Create mock location sources for testing. Malicious applications can use this to override the location and/or status returned by real location sources such as GPS or Network providers."</string>
+    <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
+    <skip />
+    <string name="permlab_accessFineLocation">"fine (GPS) location"</string>
+    <string name="permdesc_accessFineLocation">"Access fine location sources such as the Global Positioning System on the phone, where available. Malicious applications can use this to determine where you are, and may consume additional battery power."</string>
+    <string name="permlab_accessCoarseLocation">"coarse (network-based) location"</string>
+    <string name="permdesc_accessCoarseLocation">"Access coarse location sources such as the cellular network database to determine an approximate phone location, where available. Malicious applications can use this to determine approximately where you are."</string>
+    <string name="permlab_accessSurfaceFlinger">"access SurfaceFlinger"</string>
+    <string name="permdesc_accessSurfaceFlinger">"Allows application to use SurfaceFlinger low-level features."</string>
+    <string name="permlab_readFrameBuffer">"read frame buffer"</string>
+    <string name="permdesc_readFrameBuffer">"Allows application to use read the content of the frame buffer."</string>
+    <string name="permlab_modifyAudioSettings">"change your audio settings"</string>
+    <string name="permdesc_modifyAudioSettings">"Allows application to modify global audio settings such as volume and routing."</string>
+    <string name="permlab_recordAudio">"record audio"</string>
+    <string name="permdesc_recordAudio">"Allows application to access the audio record path."</string>
+    <string name="permlab_camera">"take pictures"</string>
+    <string name="permdesc_camera">"Allows application to take pictures with the camera. This allows the application at any time to collect images the camera is seeing."</string>
+    <string name="permlab_brick">"permanently disable phone"</string>
+    <string name="permdesc_brick">"Allows the application to disable the entire phone permanently. This is very dangerous."</string>
+    <!-- no translation found for permlab_reboot (8844650672567077423) -->
+    <skip />
+    <!-- no translation found for permdesc_reboot (4704919552870918328) -->
+    <skip />
+    <string name="permlab_mount_unmount_filesystems">"mount and unmount filesystems"</string>
+    <string name="permdesc_mount_unmount_filesystems">"Allows the application to mount and unmount filesystems for removable storage."</string>
+    <string name="permlab_vibrate">"control vibrator"</string>
+    <string name="permdesc_vibrate">"Allows the application to control the vibrator."</string>
+    <string name="permlab_flashlight">"control flashlight"</string>
+    <string name="permdesc_flashlight">"Allows the application to control the flashlight."</string>
+    <string name="permlab_hardware_test">"test hardware"</string>
+    <string name="permdesc_hardware_test">"Allows the application to control various peripherals for the purpose of hardware testing."</string>
+    <string name="permlab_callPhone">"directly call phone numbers"</string>
+    <string name="permdesc_callPhone">"Allows the application to call phone numbers without your intervention. Malicious applications may cause unexpected calls on your phone bill. Note that this does not allow the application to call emergency numbers."</string>
+    <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
+    <skip />
+    <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
+    <skip />
+    <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
+    <skip />
+    <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
+    <skip />
+    <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
+    <skip />
+    <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
+    <skip />
+    <string name="permlab_modifyPhoneState">"modify phone state"</string>
+    <string name="permdesc_modifyPhoneState">"Allows the application to control the phone features of the device. An application with this permission can switch networks, turn the phone radio on and off and the like without ever notifying you."</string>
+    <string name="permlab_readPhoneState">"read phone state"</string>
+    <string name="permdesc_readPhoneState">"Allows the application to access the phone features of the device. An application with this permission can determine the phone number of this phone, whether a call is active, the number that call is connected to and the like."</string>
+    <string name="permlab_wakeLock">"prevent phone from sleeping"</string>
+    <string name="permdesc_wakeLock">"Allows an application to prevent the phone from going to sleep."</string>
+    <string name="permlab_devicePower">"power phone on or off"</string>
+    <string name="permdesc_devicePower">"Allows the application to turn the phone on or off."</string>
+    <string name="permlab_factoryTest">"run in factory test mode"</string>
+    <string name="permdesc_factoryTest">"Run as a low-level manufacturer test, allowing complete access to the phone hardware. Only available when a phone is running in manufacturer test mode."</string>
+    <string name="permlab_setWallpaper">"set wallpaper"</string>
+    <string name="permdesc_setWallpaper">"Allows the application to set the system wallpaper."</string>
+    <string name="permlab_setWallpaperHints">"set wallpaper size hints"</string>
+    <string name="permdesc_setWallpaperHints">"Allows the application to set the system wallpaper size hints."</string>
+    <string name="permlab_masterClear">"reset system to factory defaults"</string>
+    <string name="permdesc_masterClear">"Allows an application to completely reset the system to its factory settings, erasing all data, configuration, and installed applications."</string>
+    <string name="permlab_setTimeZone">"set time zone"</string>
+    <string name="permdesc_setTimeZone">"Allows an application to change the phones time zone."</string>
+    <string name="permlab_getAccounts">"discover known accounts"</string>
+    <string name="permdesc_getAccounts">"Allows an application to get the list of accounts known by the phone."</string>
+    <string name="permlab_accessNetworkState">"view network state"</string>
+    <string name="permdesc_accessNetworkState">"Allows an application to view the state of all networks."</string>
+    <string name="permlab_createNetworkSockets">"full Internet access"</string>
+    <string name="permdesc_createNetworkSockets">"Allows an application to create network sockets."</string>
+    <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
+    <skip />
+    <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
+    <skip />
+    <string name="permlab_changeNetworkState">"change network connectivity"</string>
+    <string name="permdesc_changeNetworkState">"Allows an application to change the state network connectivity."</string>
+    <string name="permlab_accessWifiState">"view Wi-Fi state"</string>
+    <string name="permdesc_accessWifiState">"Allows an application to view the information about the state of Wi-Fi."</string>
+    <string name="permlab_changeWifiState">"change Wi-Fi state"</string>
+    <string name="permdesc_changeWifiState">"Allows an application to connect to and disconnect from Wi-Fi access points, and to make changes to configured Wi-Fi networks."</string>
+    <string name="permlab_bluetoothAdmin">"bluetooth administration"</string>
+    <string name="permdesc_bluetoothAdmin">"Allows an application to configure the local Bluetooth phone, and to discover and pair with remote devices."</string>
+    <string name="permlab_bluetooth">"create Bluetooth connections"</string>
+    <string name="permdesc_bluetooth">"Allows an application to view configuration of the local Bluetooth phone, and to make and accept connections with paired devices."</string>
+    <string name="permlab_disableKeyguard">"disable keylock"</string>
+    <string name="permdesc_disableKeyguard">"Allows an application to disable the keylock and any associated password security. A legitimate example of this is the phone disabling the keylock when receiving an incoming phone call, then re-enabling the keylock when the call is finished."</string>
+    <string name="permlab_readSyncSettings">"read sync settings"</string>
+    <string name="permdesc_readSyncSettings">"Allows an application to read the sync settings, such as whether sync is enabled for Contacts."</string>
+    <string name="permlab_writeSyncSettings">"write sync settings"</string>
+    <string name="permdesc_writeSyncSettings">"Allows an application to modify the sync settings, such as whether sync is enabled for Contacts."</string>
+    <string name="permlab_readSyncStats">"read sync statistics"</string>
+    <string name="permdesc_readSyncStats">"Allows an application to reafocusd the sync stats; e.g., the history of syncs that have occurred."</string>
+    <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
+    <skip />
+    <!-- no translation found for phoneTypes:0 (6070018634209800981) -->
+    <!-- no translation found for phoneTypes:1 (1514509689885965711) -->
+    <!-- no translation found for phoneTypes:2 (497473201754095234) -->
+    <!-- no translation found for phoneTypes:3 (5554432614281047787) -->
+    <!-- no translation found for phoneTypes:4 (2222084401110150993) -->
+    <!-- no translation found for phoneTypes:5 (2290007103906353121) -->
+    <!-- no translation found for phoneTypes:6 (6930783706213719251) -->
+    <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
+    <!-- no translation found for emailAddressTypes:0 (1540640638077615417) -->
+    <!-- no translation found for emailAddressTypes:1 (4252853367575831977) -->
+    <!-- no translation found for emailAddressTypes:2 (7158046581744435718) -->
+    <!-- no translation found for emailAddressTypes:3 (3625034471181268169) -->
+    <!-- no translation found for postalAddressTypes:0 (5732960259696659380) -->
+    <!-- no translation found for postalAddressTypes:1 (7132240704786130285) -->
+    <!-- no translation found for postalAddressTypes:2 (1317604357745852817) -->
+    <!-- no translation found for postalAddressTypes:3 (1582953598462826702) -->
+    <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
+    <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
+    <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
+    <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
+    <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
+    <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
+    <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
+    <!-- no translation found for imProtocols:0 (3318725788774688043) -->
+    <!-- no translation found for imProtocols:1 (1787713387022932886) -->
+    <!-- no translation found for imProtocols:2 (6751174158442316516) -->
+    <!-- no translation found for imProtocols:3 (1151283347465052653) -->
+    <!-- no translation found for imProtocols:4 (2157980008878817934) -->
+    <!-- no translation found for imProtocols:5 (7836237460308230767) -->
+    <!-- no translation found for imProtocols:6 (1180789904462172516) -->
+    <!-- no translation found for imProtocols:7 (21955111672779862) -->
+    <string name="keyguard_password_enter_pin_code">"Enter PIN code:"</string>
+    <string name="keyguard_password_wrong_pin_code">"Incorrect PIN code!"</string>
+    <string name="keyguard_label_text">"To unlock, press Menu then 0."</string>
+    <string name="emergency_call_dialog_number_for_display">"Emergency number"</string>
+    <string name="lockscreen_carrier_default">"(No service)"</string>
+    <string name="lockscreen_screen_locked">"Screen locked"</string>
+    <string name="lockscreen_instructions_when_pattern_enabled">"Press Menu to unlock or place emergency call."</string>
+    <string name="lockscreen_instructions_when_pattern_disabled">"Press Menu to unlock."</string>
+    <string name="lockscreen_pattern_instructions">"Draw pattern to unlock:"</string>
+    <string name="lockscreen_emergency_call">"Emergency call"</string>
+    <string name="lockscreen_pattern_correct">"Correct!"</string>
+    <string name="lockscreen_pattern_wrong">"Sorry, try again:"</string>
+    <string name="lockscreen_plugged_in">"Charging (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+    <string name="lockscreen_low_battery">"Connect your charger."</string>
+    <string name="lockscreen_missing_sim_message_short">"No SIM card."</string>
+    <string name="lockscreen_missing_sim_message">"No SIM card in phone."</string>
+    <string name="lockscreen_missing_sim_instructions">"Please insert a SIM card."</string>
+    <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
+    <skip />
+    <string name="lockscreen_sim_puk_locked_message">"SIM card is PUK-locked."</string>
+    <string name="lockscreen_sim_puk_locked_instructions">"Please contact Customer Care."</string>
+    <string name="lockscreen_sim_locked_message">"SIM card is locked."</string>
+    <string name="lockscreen_sim_unlock_progress_dialog_message">"Unlocking SIM card…"</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="lockscreen_too_many_failed_attempts_countdown">"Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
+    <string name="lockscreen_forgot_pattern_button_text">"Forgot pattern?"</string>
+    <string name="lockscreen_glogin_too_many_attempts">"Too many pattern attempts!"</string>
+    <string name="lockscreen_glogin_instructions">"To unlock,"\n"sign in with your Google account:"</string>
+    <string name="lockscreen_glogin_username_hint">"Username (email)"</string>
+    <string name="lockscreen_glogin_password_hint">"Password"</string>
+    <string name="lockscreen_glogin_submit_button">"Sign in"</string>
+    <string name="lockscreen_glogin_invalid_input">"Invalid username or password."</string>
+    <!-- unknown placeholder FORMAT in status_bar_time_format -->
+    <skip />
+    <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
+    <skip />
+    <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
+    <skip />
+    <!-- no translation found for hour_ampm (7665432130905376251) -->
+    <skip />
+    <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
+    <skip />
+    <string name="status_bar_clear_all_button">"Clear notifications"</string>
+    <string name="status_bar_no_notifications_title">"No notifications"</string>
+    <string name="status_bar_ongoing_events_title">"Ongoing"</string>
+    <string name="status_bar_latest_events_title">"Notifications"</string>
+    <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g>"</string>
+    <string name="battery_status_charging">"Charging…"</string>
+    <string name="battery_low_title">"Please connect charger"</string>
+    <string name="battery_low_subtitle">"The battery is getting low:"</string>
+    <string name="battery_low_percent_format">"less than <xliff:g id="NUMBER">%d%%</xliff:g> remaining."</string>
+    <string name="factorytest_failed">"Factory test failed"</string>
+    <string name="factorytest_not_system">"The FACTORY_TEST action is only supported for packages installed in /system/app."</string>
+    <string name="factorytest_no_action">"No package was found that provides the FACTORY_TEST action."</string>
+    <string name="factorytest_reboot">"Reboot"</string>
+    <string name="save_password_label">"Confirm"</string>
+    <string name="save_password_message">"Do you want the browser to remember this password?"</string>
+    <string name="save_password_notnow">"Not now"</string>
+    <string name="save_password_remember">"Remember"</string>
+    <string name="save_password_never">"Never"</string>
+    <string name="open_permission_deny">"You do not have permission to open this page."</string>
+    <string name="text_copied">"Text copied to clipboard."</string>
+    <string name="more_item_label">"More"</string>
+    <string name="prepend_shortcut_label">"Menu+"</string>
+    <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
+    <skip />
+    <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
+    <skip />
+    <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
+    <skip />
+    <string name="search_go">"Search"</string>
+    <string name="today">"Today"</string>
+    <string name="yesterday">"Yesterday"</string>
+    <string name="tomorrow">"Tomorrow"</string>
+    <string name="oneMonthDurationPast">"1 month ago"</string>
+    <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
+    <skip />
+    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
+    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
+    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
+    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
+    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
+    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
+    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
+    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
+    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
+    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
+    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
+    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
+    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
+    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
+    <!-- no translation found for in_num_days:one (5608475533104443893) -->
+    <!-- no translation found for in_num_days:other (3827193006163842267) -->
+    <string name="preposition_for_date">"on %s"</string>
+    <string name="preposition_for_time">"at %s"</string>
+    <string name="preposition_for_year">"in %s"</string>
+    <string name="day">"day"</string>
+    <string name="days">"days"</string>
+    <string name="hour">"hour"</string>
+    <string name="hours">"hours"</string>
+    <string name="minute">"min"</string>
+    <string name="minutes">"mins"</string>
+    <string name="second">"sec"</string>
+    <string name="seconds">"secs"</string>
+    <string name="week">"week"</string>
+    <string name="weeks">"weeks"</string>
+    <string name="year">"year"</string>
+    <string name="years">"years"</string>
+    <string name="sunday">"Sunday"</string>
+    <string name="monday">"Monday"</string>
+    <string name="tuesday">"Tuesday"</string>
+    <string name="wednesday">"Wednesday"</string>
+    <string name="thursday">"Thursday"</string>
+    <string name="friday">"Friday"</string>
+    <string name="saturday">"Saturday"</string>
+    <string name="every_weekday">"Every weekday (Mon–Fri)"</string>
+    <string name="daily">"Daily"</string>
+    <string name="weekly">"Weekly on <xliff:g id="DAY">%s</xliff:g>"</string>
+    <string name="monthly">"Monthly"</string>
+    <string name="yearly">"Yearly"</string>
+    <string name="VideoView_error_title">"Cannot play video"</string>
+    <string name="VideoView_error_text_unknown">"Sorry, this video cannot be played."</string>
+    <string name="VideoView_error_button">"OK"</string>
+    <string name="am">"AM"</string>
+    <string name="pm">"PM"</string>
+    <!-- unknown placeholder FORMAT in numeric_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in wday1_date1_time1_wday2_date2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in wday1_date1_wday2_date2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in date1_time1_date2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in date1_date2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time1_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time_wday_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in wday_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time_wday -->
+    <skip />
+    <!-- no translation found for full_date_month_first (6011143962222283357) -->
+    <skip />
+    <!-- no translation found for full_date_day_first (8621594762705478189) -->
+    <skip />
+    <!-- no translation found for medium_date_month_first (48990963718825728) -->
+    <skip />
+    <!-- no translation found for medium_date_day_first (2898992016440387123) -->
+    <skip />
+    <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
+    <skip />
+    <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
+    <skip />
+    <string name="noon">"noon"</string>
+    <string name="Noon">"Noon"</string>
+    <string name="midnight">"midnight"</string>
+    <string name="Midnight">"Midnight"</string>
+    <!-- unknown placeholder FORMAT in month_day -->
+    <skip />
+    <!-- unknown placeholder FORMAT in month -->
+    <skip />
+    <!-- unknown placeholder FORMAT in month_day_year -->
+    <skip />
+    <!-- unknown placeholder FORMAT in month_year -->
+    <skip />
+    <!-- no translation found for time_of_day (8375993139317154157) -->
+    <skip />
+    <!-- no translation found for date_and_time (9197690194373107109) -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_md1_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_md1_wday2_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_mdy1_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_wday2_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_md1_time1_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_md1_time1_wday2_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_mdy1_time1_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_time1_wday2_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_md1_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_md1_wday2_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_mdy1_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_wday2_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_md1_time1_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_md1_time1_wday2_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_mdy1_time1_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_time1_wday2_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_md1_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_md1_wday2_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_mdy1_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_wday2_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_md1_time1_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_md1_time1_wday2_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_mdy1_time1_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_time1_wday2_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month_day_year -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month_year -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month_day -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month -->
+    <skip />
+    <string name="day_of_week_long_sunday">"Sunday"</string>
+    <string name="day_of_week_long_monday">"Monday"</string>
+    <string name="day_of_week_long_tuesday">"Tuesday"</string>
+    <string name="day_of_week_long_wednesday">"Wednesday"</string>
+    <string name="day_of_week_long_thursday">"Thursday"</string>
+    <string name="day_of_week_long_friday">"Friday"</string>
+    <string name="day_of_week_long_saturday">"Saturday"</string>
+    <string name="day_of_week_medium_sunday">"Sun"</string>
+    <string name="day_of_week_medium_monday">"Mon"</string>
+    <string name="day_of_week_medium_tuesday">"Tue"</string>
+    <string name="day_of_week_medium_wednesday">"Wed"</string>
+    <string name="day_of_week_medium_thursday">"Thu"</string>
+    <string name="day_of_week_medium_friday">"Fri"</string>
+    <string name="day_of_week_medium_saturday">"Sat"</string>
+    <string name="day_of_week_short_sunday">"Su"</string>
+    <string name="day_of_week_short_monday">"Mo"</string>
+    <string name="day_of_week_short_tuesday">"Tu"</string>
+    <string name="day_of_week_short_wednesday">"We"</string>
+    <string name="day_of_week_short_thursday">"Th"</string>
+    <string name="day_of_week_short_friday">"Fr"</string>
+    <string name="day_of_week_short_saturday">"Sa"</string>
+    <string name="day_of_week_shorter_sunday">"Su"</string>
+    <string name="day_of_week_shorter_monday">"M"</string>
+    <string name="day_of_week_shorter_tuesday">"Tu"</string>
+    <string name="day_of_week_shorter_wednesday">"W"</string>
+    <string name="day_of_week_shorter_thursday">"Th"</string>
+    <string name="day_of_week_shorter_friday">"F"</string>
+    <string name="day_of_week_shorter_saturday">"Sa"</string>
+    <string name="day_of_week_shortest_sunday">"S"</string>
+    <string name="day_of_week_shortest_monday">"M"</string>
+    <string name="day_of_week_shortest_tuesday">"T"</string>
+    <string name="day_of_week_shortest_wednesday">"W"</string>
+    <string name="day_of_week_shortest_thursday">"T"</string>
+    <string name="day_of_week_shortest_friday">"F"</string>
+    <string name="day_of_week_shortest_saturday">"S"</string>
+    <string name="month_long_january">"January"</string>
+    <string name="month_long_february">"February"</string>
+    <string name="month_long_march">"March"</string>
+    <string name="month_long_april">"April"</string>
+    <string name="month_long_may">"May"</string>
+    <string name="month_long_june">"June"</string>
+    <string name="month_long_july">"July"</string>
+    <string name="month_long_august">"August"</string>
+    <string name="month_long_september">"September"</string>
+    <string name="month_long_october">"October"</string>
+    <string name="month_long_november">"November"</string>
+    <string name="month_long_december">"December"</string>
+    <string name="month_medium_january">"Jan"</string>
+    <string name="month_medium_february">"Feb"</string>
+    <string name="month_medium_march">"Mar"</string>
+    <string name="month_medium_april">"Apr"</string>
+    <string name="month_medium_may">"May"</string>
+    <string name="month_medium_june">"Jun"</string>
+    <string name="month_medium_july">"Jul"</string>
+    <string name="month_medium_august">"Aug"</string>
+    <string name="month_medium_september">"Sep"</string>
+    <string name="month_medium_october">"Oct"</string>
+    <string name="month_medium_november">"Nov"</string>
+    <string name="month_medium_december">"Dec"</string>
+    <string name="month_shortest_january">"J"</string>
+    <string name="month_shortest_february">"F"</string>
+    <string name="month_shortest_march">"M"</string>
+    <string name="month_shortest_april">"A"</string>
+    <string name="month_shortest_may">"M"</string>
+    <string name="month_shortest_june">"J"</string>
+    <string name="month_shortest_july">"J"</string>
+    <string name="month_shortest_august">"A"</string>
+    <string name="month_shortest_september">"S"</string>
+    <string name="month_shortest_october">"O"</string>
+    <string name="month_shortest_november">"N"</string>
+    <string name="month_shortest_december">"D"</string>
+    <!-- unknown placeholder FORMAT in elapsed_time_short_format_mm_ss -->
+    <skip />
+    <!-- unknown placeholder FORMAT in elapsed_time_short_format_h_mm_ss -->
+    <skip />
+    <string name="selectAll">"Select all"</string>
+    <string name="cut">"Cut"</string>
+    <string name="cutAll">"Cut all"</string>
+    <string name="copy">"Copy"</string>
+    <string name="copyAll">"Copy all"</string>
+    <string name="paste">"Paste"</string>
+    <string name="copyUrl">"Copy URL"</string>
+    <!-- no translation found for inputMethod (7911866729148111492) -->
+    <skip />
+    <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
+    <skip />
+    <string name="low_internal_storage_view_title">"Low on space"</string>
+    <string name="low_internal_storage_view_text">"Your phone is running low on internal storage space."</string>
+    <string name="ok">"OK"</string>
+    <string name="cancel">"Cancel"</string>
+    <string name="yes">"OK"</string>
+    <string name="no">"Cancel"</string>
+    <string name="capital_on">"ON"</string>
+    <string name="capital_off">"OFF"</string>
+    <string name="whichApplication">"Complete action using"</string>
+    <string name="alwaysUse">"Use by default for this action."</string>
+    <string name="clearDefaultHintMsg">"Clear default in Home Settings &gt; Applications &gt; Manage applications."</string>
+    <string name="chooseActivity">"Select an action"</string>
+    <string name="noApplications">"No applications can perform this action."</string>
+    <string name="aerr_title">"Sorry!"</string>
+    <string name="aerr_application">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has stopped unexpectedly. Please try again."</string>
+    <string name="aerr_process">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has stopped unexpectedly. Please try again."</string>
+    <string name="anr_title">"Application unresponsive"</string>
+    <string name="anr_activity_application">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in application <xliff:g id="APPLICATION">%2$s</xliff:g>) is not responding."</string>
+    <string name="anr_activity_process">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
+    <string name="anr_application_process">"Application <xliff:g id="APPLICATION">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
+    <string name="anr_process">"Process <xliff:g id="PROCESS">%1$s</xliff:g> is not responding."</string>
+    <string name="force_close">"Force close"</string>
+    <string name="wait">"Wait"</string>
+    <string name="debug">"Debug"</string>
+    <string name="sendText">"Select an action for text"</string>
+    <string name="volume_ringtone">"Ringer volume"</string>
+    <string name="volume_music">"Music/video volume"</string>
+    <string name="volume_call">"In-call volume"</string>
+    <string name="volume_alarm">"Alarm volume"</string>
+    <string name="volume_unknown">"Volume"</string>
+    <string name="ringtone_default">"Default ringtone"</string>
+    <string name="ringtone_default_with_actual">"Default ringtone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+    <string name="ringtone_silent">"Silent"</string>
+    <string name="ringtone_picker_title">"Select a ringtone"</string>
+    <string name="ringtone_unknown">"Unknown ringtone"</string>
+    <!-- no translation found for wifi_available:one (8168012881468888470) -->
+    <!-- no translation found for wifi_available:other (4666122955807117718) -->
+    <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
+    <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
+    <string name="select_character">"Select character to insert"</string>
+    <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
+    <skip />
+    <string name="sms_control_title">"Sending SMS messages"</string>
+    <string name="sms_control_message">"A large number of SMS messages are being sent. Select \"OK\" to continue, or \"Cancel\" to stop sending."</string>
+    <string name="sms_control_yes">"OK"</string>
+    <string name="sms_control_no">"Cancel"</string>
+    <string name="date_time_set">"Set"</string>
+    <string name="default_permission_group">"Default"</string>
+    <string name="no_permissions">"No permissions required"</string>
+    <!-- no translation found for perms_hide (4145325555929151849) -->
+    <skip />
+    <!-- no translation found for perms_show_all (6040194843455403173) -->
+    <skip />
+    <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
+    <skip />
+    <!-- no translation found for usb_storage_title (8699631567051394409) -->
+    <skip />
+    <!-- no translation found for usb_storage_message (5344039189213308733) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
+    <skip />
+    <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
+    <skip />
+    <!-- no translation found for select_input_method (2658280517827502015) -->
+    <skip />
+    <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
+    <skip />
+    <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
+    <skip />
+    <!-- no translation found for candidates_style (7738463880139922176) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rSG/strings.xml b/core/res/res/values-en-rSG/strings.xml
new file mode 100644
index 0000000..b9df983
--- /dev/null
+++ b/core/res/res/values-en-rSG/strings.xml
@@ -0,0 +1,1256 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="byteShort">"B"</string>
+    <!-- no translation found for kilobyteShort (5865542430193761682) -->
+    <skip />
+    <!-- no translation found for megabyteShort (112984851085937882) -->
+    <skip />
+    <!-- no translation found for gigabyteShort (8586075069559273847) -->
+    <skip />
+    <!-- no translation found for terabyteShort (5828502357595687794) -->
+    <skip />
+    <!-- no translation found for petabyteShort (7523248732657962413) -->
+    <skip />
+    <!-- no translation found for untitled (284687023829080340) -->
+    <skip />
+    <!-- no translation found for ellipsis (8538883953764277342) -->
+    <skip />
+    <!-- no translation found for emptyPhoneNumber (6416283285732095329) -->
+    <skip />
+    <!-- no translation found for unknownName (3974255879290140525) -->
+    <skip />
+    <!-- no translation found for defaultVoiceMailAlphaTag (6484324201071049939) -->
+    <skip />
+    <!-- no translation found for defaultMsisdnAlphaTag (4953008223227371928) -->
+    <skip />
+    <!-- no translation found for mmiError (7480678835624852655) -->
+    <skip />
+    <!-- no translation found for serviceEnabled (4042194305396115167) -->
+    <skip />
+    <!-- no translation found for serviceEnabledFor (638808419103886277) -->
+    <skip />
+    <!-- no translation found for serviceDisabled (1059935666763511541) -->
+    <skip />
+    <!-- no translation found for serviceRegistered (7639869107156932038) -->
+    <skip />
+    <!-- no translation found for serviceErased (4602215208593071820) -->
+    <skip />
+    <!-- no translation found for passwordIncorrect (5142040651297346232) -->
+    <skip />
+    <!-- no translation found for mmiComplete (3178168770150013486) -->
+    <skip />
+    <!-- no translation found for badPin (5103184589972647739) -->
+    <skip />
+    <!-- no translation found for badPuk (2200634943393540609) -->
+    <skip />
+    <!-- no translation found for mismatchPin (5055729703806180857) -->
+    <skip />
+    <!-- no translation found for invalidPin (6201854814319326475) -->
+    <skip />
+    <!-- no translation found for needPuk (4788728144863892764) -->
+    <skip />
+    <!-- no translation found for needPuk2 (7056908944942451033) -->
+    <skip />
+    <!-- no translation found for ClipMmi (5649729434121615509) -->
+    <skip />
+    <!-- no translation found for ClirMmi (5220979296096544477) -->
+    <skip />
+    <!-- no translation found for CfMmi (4998483717856803914) -->
+    <skip />
+    <!-- no translation found for CwMmi (5678103638951836350) -->
+    <skip />
+    <!-- no translation found for BaMmi (6030555200442855833) -->
+    <skip />
+    <!-- no translation found for PwdMmi (2549941247959366670) -->
+    <skip />
+    <!-- no translation found for PinMmi (2463353963837922189) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOnNextCallOn (4005921990799469144) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOnNextCallOff (1497360760012205230) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOffNextCallOn (604591440398078227) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOffNextCallOff (5114039908683246336) -->
+    <skip />
+    <!-- no translation found for serviceNotProvisioned (3754416031529306610) -->
+    <skip />
+    <!-- no translation found for CLIRPermanent (3819908477891272611) -->
+    <skip />
+    <!-- no translation found for serviceClassVoice (3059107563169935913) -->
+    <skip />
+    <!-- no translation found for serviceClassData (2669025626575716504) -->
+    <skip />
+    <!-- no translation found for serviceClassFAX (973109472405729679) -->
+    <skip />
+    <!-- no translation found for serviceClassSMS (3857383928743625711) -->
+    <skip />
+    <!-- no translation found for serviceClassDataAsync (8526461993032174729) -->
+    <skip />
+    <!-- no translation found for serviceClassDataSync (2461138395498381801) -->
+    <skip />
+    <!-- no translation found for serviceClassPacket (8119604233041078065) -->
+    <skip />
+    <!-- no translation found for serviceClassPAD (202892636830042266) -->
+    <skip />
+    <!-- no translation found for cfTemplateNotForwarded (3171755805856206604) -->
+    <skip />
+    <!-- no translation found for cfTemplateForwarded (2468661573318024785) -->
+    <skip />
+    <!-- no translation found for cfTemplateForwardedTime (5151810870794744740) -->
+    <skip />
+    <!-- no translation found for cfTemplateRegistered (5685211900474527085) -->
+    <skip />
+    <!-- no translation found for cfTemplateRegisteredTime (2978918277762252776) -->
+    <skip />
+    <!-- no translation found for httpErrorOk (984913805621139001) -->
+    <skip />
+    <!-- no translation found for httpError (9177990053748151835) -->
+    <skip />
+    <!-- no translation found for httpErrorLookup (5251341716070330936) -->
+    <skip />
+    <!-- no translation found for httpErrorUnsupportedAuthScheme (2865679883634239474) -->
+    <skip />
+    <!-- no translation found for httpErrorAuth (1637382600929594620) -->
+    <skip />
+    <!-- no translation found for httpErrorProxyAuth (5947648983995807455) -->
+    <skip />
+    <!-- no translation found for httpErrorConnect (129984292497034683) -->
+    <skip />
+    <!-- no translation found for httpErrorIO (8128922048686581131) -->
+    <skip />
+    <!-- no translation found for httpErrorTimeout (8357966263983739012) -->
+    <skip />
+    <!-- no translation found for httpErrorRedirectLoop (4122379005100433886) -->
+    <skip />
+    <!-- no translation found for httpErrorUnsupportedScheme (4072339858288462569) -->
+    <skip />
+    <!-- no translation found for httpErrorFailedSslHandshake (2316625025255452595) -->
+    <skip />
+    <!-- no translation found for httpErrorBadUrl (8885244563103716039) -->
+    <skip />
+    <!-- no translation found for httpErrorFile (1408273621719669493) -->
+    <skip />
+    <!-- no translation found for httpErrorFileNotFound (2309088465300506314) -->
+    <skip />
+    <!-- no translation found for httpErrorTooManyRequests (3764334538393544875) -->
+    <skip />
+    <!-- no translation found for contentServiceSync (4863236165350475642) -->
+    <skip />
+    <!-- no translation found for contentServiceSyncNotificationTitle (6855304679069026824) -->
+    <skip />
+    <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8477597194404210723) -->
+    <skip />
+    <!-- no translation found for low_memory (4191592786596642367) -->
+    <skip />
+    <!-- no translation found for me (4616693653158602117) -->
+    <skip />
+    <!-- no translation found for power_dialog (8210256011408959109) -->
+    <skip />
+    <!-- no translation found for silent_mode (5218239246946854300) -->
+    <skip />
+    <!-- no translation found for turn_on_radio (1901054698789840131) -->
+    <skip />
+    <!-- no translation found for turn_off_radio (2870296409392615956) -->
+    <skip />
+    <!-- no translation found for screen_lock (1560333453597081877) -->
+    <skip />
+    <!-- no translation found for power_off (2412024417733516836) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (3735034517335251808) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm (699224922526414097) -->
+    <skip />
+    <!-- no translation found for no_recent_tasks (1367712919998349373) -->
+    <skip />
+    <!-- no translation found for global_actions (8299888906525675157) -->
+    <skip />
+    <!-- no translation found for global_action_lock (5943677976245541105) -->
+    <skip />
+    <!-- no translation found for global_action_power_off (3143027278596694254) -->
+    <skip />
+    <!-- no translation found for global_action_toggle_silent_mode (5849335789367070450) -->
+    <skip />
+    <!-- no translation found for global_action_silent_mode_on_status (6053429980569202260) -->
+    <skip />
+    <!-- no translation found for global_action_silent_mode_off_status (1994514127029249081) -->
+    <skip />
+    <!-- no translation found for safeMode (3375134507868534320) -->
+    <skip />
+    <!-- no translation found for permgrouplab_costMoney (904087853776533085) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_costMoney (4662370555643969515) -->
+    <skip />
+    <!-- no translation found for permgrouplab_messages (2984053976424233925) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_messages (2129093134354989379) -->
+    <skip />
+    <!-- no translation found for permgrouplab_personalInfo (4548406335021507392) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_personalInfo (8499310823817958034) -->
+    <skip />
+    <!-- no translation found for permgrouplab_location (8535677827151907069) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_location (2341662219604651887) -->
+    <skip />
+    <!-- no translation found for permgrouplab_network (3597781730625751831) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_network (8332572695347918340) -->
+    <skip />
+    <!-- no translation found for permgrouplab_accounts (8631201594657951893) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_accounts (443982868906396781) -->
+    <skip />
+    <!-- no translation found for permgrouplab_hardwareControls (5074512938567152139) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_hardwareControls (8772503144945278440) -->
+    <skip />
+    <!-- no translation found for permgrouplab_phoneCalls (7096448531266882376) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_phoneCalls (6703873478653366233) -->
+    <skip />
+    <!-- no translation found for permgrouplab_systemTools (1840847965111633430) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_systemTools (2810337951496685271) -->
+    <skip />
+    <!-- no translation found for permgrouplab_developmentTools (692844635256963358) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_developmentTools (5253915519857796400) -->
+    <skip />
+    <!-- no translation found for permlab_statusBar (8789506912215455922) -->
+    <skip />
+    <!-- no translation found for permdesc_statusBar (5034247171231682403) -->
+    <skip />
+    <!-- no translation found for permlab_expandStatusBar (6382500803293284173) -->
+    <skip />
+    <!-- no translation found for permdesc_expandStatusBar (90953162060681436) -->
+    <skip />
+    <!-- no translation found for permlab_processOutgoingCalls (786316295241100144) -->
+    <skip />
+    <!-- no translation found for permdesc_processOutgoingCalls (1655242138991854396) -->
+    <skip />
+    <!-- no translation found for permlab_receiveSms (5820796051959871222) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveSms (2265740044646990161) -->
+    <skip />
+    <!-- no translation found for permlab_receiveMms (7983091218880782611) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveMms (3641275586518289960) -->
+    <skip />
+    <!-- no translation found for permlab_sendSms (4713837923748234081) -->
+    <skip />
+    <!-- no translation found for permdesc_sendSms (7126594387176704010) -->
+    <skip />
+    <!-- no translation found for permlab_readSms (4256004535185449429) -->
+    <skip />
+    <!-- no translation found for permdesc_readSms (4586480500886941902) -->
+    <skip />
+    <!-- no translation found for permlab_writeSms (8453452414726246828) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSms (1036408118901361812) -->
+    <skip />
+    <!-- no translation found for permlab_receiveWapPush (5726837205927152203) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveWapPush (4779188629794134886) -->
+    <skip />
+    <!-- no translation found for permlab_getTasks (357640569227780364) -->
+    <skip />
+    <!-- no translation found for permdesc_getTasks (2916615403728003200) -->
+    <skip />
+    <!-- no translation found for permlab_reorderTasks (4758862288285224517) -->
+    <skip />
+    <!-- no translation found for permdesc_reorderTasks (7507060843941912021) -->
+    <skip />
+    <!-- no translation found for permlab_setDebugApp (2973363275929449444) -->
+    <skip />
+    <!-- no translation found for permdesc_setDebugApp (5720449860498265972) -->
+    <skip />
+    <!-- no translation found for permlab_changeConfiguration (8581093564179818627) -->
+    <skip />
+    <!-- no translation found for permdesc_changeConfiguration (4055366453803187171) -->
+    <skip />
+    <!-- no translation found for permlab_restartPackages (5836367540766044606) -->
+    <skip />
+    <!-- no translation found for permdesc_restartPackages (1764965996765573321) -->
+    <skip />
+    <!-- no translation found for permlab_setProcessForeground (4860990420780868638) -->
+    <skip />
+    <!-- no translation found for permdesc_setProcessForeground (3795477299954784360) -->
+    <skip />
+    <!-- no translation found for permlab_forceBack (4737517869935566733) -->
+    <skip />
+    <!-- no translation found for permdesc_forceBack (5579316297001154697) -->
+    <skip />
+    <!-- no translation found for permlab_dump (3177569414212943167) -->
+    <skip />
+    <!-- no translation found for permdesc_dump (1815913623373011608) -->
+    <skip />
+    <!-- no translation found for permlab_addSystemService (9166015020584794942) -->
+    <skip />
+    <!-- no translation found for permdesc_addSystemService (2310425587289835743) -->
+    <skip />
+    <!-- no translation found for permlab_runSetActivityWatcher (2615943932761994905) -->
+    <skip />
+    <!-- no translation found for permdesc_runSetActivityWatcher (2488524206195482220) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastPackageRemoved (355775368495637820) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastPackageRemoved (6486181398191058385) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
+    <skip />
+    <!-- no translation found for permlab_setProcessLimit (5190694306017260601) -->
+    <skip />
+    <!-- no translation found for permdesc_setProcessLimit (593938303319848578) -->
+    <skip />
+    <!-- no translation found for permlab_setAlwaysFinish (8745533365504920540) -->
+    <skip />
+    <!-- no translation found for permdesc_setAlwaysFinish (2437195869854312148) -->
+    <skip />
+    <!-- no translation found for permlab_fotaUpdate (1813039882829307079) -->
+    <skip />
+    <!-- no translation found for permdesc_fotaUpdate (2544137712607584763) -->
+    <skip />
+    <!-- no translation found for permlab_batteryStats (1598947993704535568) -->
+    <skip />
+    <!-- no translation found for permdesc_batteryStats (6247598531831307989) -->
+    <skip />
+    <!-- no translation found for permlab_internalSystemWindow (5780262737320556654) -->
+    <skip />
+    <!-- no translation found for permdesc_internalSystemWindow (6495031598062517795) -->
+    <skip />
+    <!-- no translation found for permlab_systemAlertWindow (843729657746130626) -->
+    <skip />
+    <!-- no translation found for permdesc_systemAlertWindow (2731854380682210852) -->
+    <skip />
+    <!-- no translation found for permlab_setAnimationScale (2419250686027992384) -->
+    <skip />
+    <!-- no translation found for permdesc_setAnimationScale (8518027785481727264) -->
+    <skip />
+    <!-- no translation found for permlab_manageAppTokens (1033424552444304594) -->
+    <skip />
+    <!-- no translation found for permdesc_manageAppTokens (7285840918912623550) -->
+    <skip />
+    <!-- no translation found for permlab_injectEvents (1383601196263145482) -->
+    <skip />
+    <!-- no translation found for permdesc_injectEvents (840097509341464737) -->
+    <skip />
+    <!-- no translation found for permlab_readInputState (2723668746963882102) -->
+    <skip />
+    <!-- no translation found for permdesc_readInputState (4651137638757852001) -->
+    <skip />
+    <!-- no translation found for permlab_setOrientation (1112555600323148680) -->
+    <skip />
+    <!-- no translation found for permdesc_setOrientation (1960269530378827858) -->
+    <skip />
+    <!-- no translation found for permlab_signalPersistentProcesses (8511163028160623175) -->
+    <skip />
+    <!-- no translation found for permdesc_signalPersistentProcesses (1099349638354917733) -->
+    <skip />
+    <!-- no translation found for permlab_persistentActivity (8163108526929094627) -->
+    <skip />
+    <!-- no translation found for permdesc_persistentActivity (5258975883823299624) -->
+    <skip />
+    <!-- no translation found for permlab_deletePackages (5005536434839333208) -->
+    <skip />
+    <!-- no translation found for permdesc_deletePackages (2687196995215591923) -->
+    <skip />
+    <!-- no translation found for permlab_clearAppUserData (3858185484601410171) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppUserData (7233537744753081136) -->
+    <skip />
+    <!-- no translation found for permlab_deleteCacheFiles (7362746182961997888) -->
+    <skip />
+    <!-- no translation found for permdesc_deleteCacheFiles (8293849509208181266) -->
+    <skip />
+    <!-- no translation found for permlab_getPackageSize (6743556676630447973) -->
+    <skip />
+    <!-- no translation found for permdesc_getPackageSize (2893996655828539776) -->
+    <skip />
+    <!-- no translation found for permlab_installPackages (1637554234554641998) -->
+    <skip />
+    <!-- no translation found for permdesc_installPackages (4747794850590875195) -->
+    <skip />
+    <!-- no translation found for permlab_clearAppCache (7860214328511700776) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppCache (5203820862573167878) -->
+    <skip />
+    <!-- no translation found for permlab_readLogs (6653488552442991707) -->
+    <skip />
+    <!-- no translation found for permdesc_readLogs (356352685800884319) -->
+    <skip />
+    <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
+    <skip />
+    <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
+    <skip />
+    <!-- no translation found for permlab_changeComponentState (8107835954049971459) -->
+    <skip />
+    <!-- no translation found for permdesc_changeComponentState (1791096057705836844) -->
+    <skip />
+    <!-- no translation found for permlab_setPreferredApplications (4355701371185331520) -->
+    <skip />
+    <!-- no translation found for permdesc_setPreferredApplications (9029326613767614711) -->
+    <skip />
+    <!-- no translation found for permlab_writeSettings (2915467191611898256) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSettings (8492982548350342641) -->
+    <skip />
+    <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
+    <skip />
+    <!-- no translation found for permlab_writeGservices (296370685945777755) -->
+    <skip />
+    <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
+    <skip />
+    <!-- no translation found for permlab_receiveBootCompleted (5598819384278633845) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveBootCompleted (3197439472472771192) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastSticky (8142357333543531543) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSticky (8488762822718743531) -->
+    <skip />
+    <!-- no translation found for permlab_readContacts (5116003370450871686) -->
+    <skip />
+    <!-- no translation found for permdesc_readContacts (3499378044902258770) -->
+    <skip />
+    <!-- no translation found for permlab_writeContacts (1555136823460617179) -->
+    <skip />
+    <!-- no translation found for permdesc_writeContacts (4787318403287293114) -->
+    <skip />
+    <!-- no translation found for permlab_writeOwnerData (8036840529708535113) -->
+    <skip />
+    <!-- no translation found for permdesc_writeOwnerData (5873447528845878348) -->
+    <skip />
+    <!-- no translation found for permlab_readOwnerData (1847040178513733757) -->
+    <skip />
+    <!-- no translation found for permdesc_readOwnerData (7563299529149214764) -->
+    <skip />
+    <!-- no translation found for permlab_readCalendar (2111238731453410895) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (4408253940601239114) -->
+    <skip />
+    <!-- no translation found for permlab_writeCalendar (7518052789370653396) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCalendar (8057304232140147596) -->
+    <skip />
+    <!-- no translation found for permlab_accessMockLocation (321094551062270213) -->
+    <skip />
+    <!-- no translation found for permdesc_accessMockLocation (3651565866471419739) -->
+    <skip />
+    <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
+    <skip />
+    <!-- no translation found for permlab_accessFineLocation (4846261651944924865) -->
+    <skip />
+    <!-- no translation found for permdesc_accessFineLocation (3572307331039348419) -->
+    <skip />
+    <!-- no translation found for permlab_accessCoarseLocation (1760779730797169189) -->
+    <skip />
+    <!-- no translation found for permdesc_accessCoarseLocation (8878785899768310712) -->
+    <skip />
+    <!-- no translation found for permlab_accessSurfaceFlinger (6405475452322847618) -->
+    <skip />
+    <!-- no translation found for permdesc_accessSurfaceFlinger (5348283543622360967) -->
+    <skip />
+    <!-- no translation found for permlab_readFrameBuffer (4655248388550039199) -->
+    <skip />
+    <!-- no translation found for permdesc_readFrameBuffer (794888199105081402) -->
+    <skip />
+    <!-- no translation found for permlab_modifyAudioSettings (1587341813207960943) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyAudioSettings (1447143004892708149) -->
+    <skip />
+    <!-- no translation found for permlab_recordAudio (4447848534036991667) -->
+    <skip />
+    <!-- no translation found for permdesc_recordAudio (6936874682400894820) -->
+    <skip />
+    <!-- no translation found for permlab_camera (1944473855727060380) -->
+    <skip />
+    <!-- no translation found for permdesc_camera (5978058582323766022) -->
+    <skip />
+    <!-- no translation found for permlab_brick (4749832243303289777) -->
+    <skip />
+    <!-- no translation found for permdesc_brick (7428524578693695766) -->
+    <skip />
+    <!-- no translation found for permlab_reboot (8844650672567077423) -->
+    <skip />
+    <!-- no translation found for permdesc_reboot (4704919552870918328) -->
+    <skip />
+    <!-- no translation found for permlab_mount_unmount_filesystems (1009574821038043781) -->
+    <skip />
+    <!-- no translation found for permdesc_mount_unmount_filesystems (100792065894811109) -->
+    <skip />
+    <!-- no translation found for permlab_vibrate (61984555644467146) -->
+    <skip />
+    <!-- no translation found for permdesc_vibrate (7831723100758509238) -->
+    <skip />
+    <!-- no translation found for permlab_flashlight (9097145977808182652) -->
+    <skip />
+    <!-- no translation found for permdesc_flashlight (7851502731988978358) -->
+    <skip />
+    <!-- no translation found for permlab_hardware_test (4103324677866524254) -->
+    <skip />
+    <!-- no translation found for permdesc_hardware_test (7315242723603994769) -->
+    <skip />
+    <!-- no translation found for permlab_callPhone (168275616535116686) -->
+    <skip />
+    <!-- no translation found for permdesc_callPhone (1852033967965785973) -->
+    <skip />
+    <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
+    <skip />
+    <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
+    <skip />
+    <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
+    <skip />
+    <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
+    <skip />
+    <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
+    <skip />
+    <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
+    <skip />
+    <!-- no translation found for permlab_modifyPhoneState (7791696535097912313) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyPhoneState (6352405226410454770) -->
+    <skip />
+    <!-- no translation found for permlab_readPhoneState (7320082586621086653) -->
+    <skip />
+    <!-- no translation found for permdesc_readPhoneState (8004450067066407969) -->
+    <skip />
+    <!-- no translation found for permlab_wakeLock (1591164750935072136) -->
+    <skip />
+    <!-- no translation found for permdesc_wakeLock (160471538196734936) -->
+    <skip />
+    <!-- no translation found for permlab_devicePower (9214865067086065548) -->
+    <skip />
+    <!-- no translation found for permdesc_devicePower (5608364066480036402) -->
+    <skip />
+    <!-- no translation found for permlab_factoryTest (7786199300637896247) -->
+    <skip />
+    <!-- no translation found for permdesc_factoryTest (3466066005210542042) -->
+    <skip />
+    <!-- no translation found for permlab_setWallpaper (2256730637138641725) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaper (3034653140208685093) -->
+    <skip />
+    <!-- no translation found for permlab_setWallpaperHints (4192438316932517807) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaperHints (738757439960921674) -->
+    <skip />
+    <!-- no translation found for permlab_masterClear (6155403967270586906) -->
+    <skip />
+    <!-- no translation found for permdesc_masterClear (4213553172342689754) -->
+    <skip />
+    <!-- no translation found for permlab_setTimeZone (477196167239548690) -->
+    <skip />
+    <!-- no translation found for permdesc_setTimeZone (8564892020460841198) -->
+    <skip />
+    <!-- no translation found for permlab_getAccounts (2764070033402295170) -->
+    <skip />
+    <!-- no translation found for permdesc_getAccounts (1203491378748649898) -->
+    <skip />
+    <!-- no translation found for permlab_accessNetworkState (2032916924886010827) -->
+    <skip />
+    <!-- no translation found for permdesc_accessNetworkState (7081329402551195933) -->
+    <skip />
+    <!-- no translation found for permlab_createNetworkSockets (4706698319966917864) -->
+    <skip />
+    <!-- no translation found for permdesc_createNetworkSockets (2580337178778551792) -->
+    <skip />
+    <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
+    <skip />
+    <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
+    <skip />
+    <!-- no translation found for permlab_changeNetworkState (2710779001260856872) -->
+    <skip />
+    <!-- no translation found for permdesc_changeNetworkState (8076109230787022270) -->
+    <skip />
+    <!-- no translation found for permlab_accessWifiState (3613679494230374297) -->
+    <skip />
+    <!-- no translation found for permdesc_accessWifiState (8226508433563326925) -->
+    <skip />
+    <!-- no translation found for permlab_changeWifiState (6043889338995432957) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWifiState (7829372845909567994) -->
+    <skip />
+    <!-- no translation found for permlab_bluetoothAdmin (5513286736585647334) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (1838208497914347365) -->
+    <skip />
+    <!-- no translation found for permlab_bluetooth (6378797624765639115) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetooth (8592386018922265273) -->
+    <skip />
+    <!-- no translation found for permlab_disableKeyguard (4574886811903233903) -->
+    <skip />
+    <!-- no translation found for permdesc_disableKeyguard (815972646344251271) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncSettings (8818819977141505127) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncSettings (8454705401908767847) -->
+    <skip />
+    <!-- no translation found for permlab_writeSyncSettings (4514911143753152941) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSyncSettings (7630627689635091836) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncStats (5748337739678952863) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncStats (582551457321957183) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
+    <skip />
+    <!-- no translation found for phoneTypes:0 (6070018634209800981) -->
+    <!-- no translation found for phoneTypes:1 (1514509689885965711) -->
+    <!-- no translation found for phoneTypes:2 (497473201754095234) -->
+    <!-- no translation found for phoneTypes:3 (5554432614281047787) -->
+    <!-- no translation found for phoneTypes:4 (2222084401110150993) -->
+    <!-- no translation found for phoneTypes:5 (2290007103906353121) -->
+    <!-- no translation found for phoneTypes:6 (6930783706213719251) -->
+    <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
+    <!-- no translation found for emailAddressTypes:0 (1540640638077615417) -->
+    <!-- no translation found for emailAddressTypes:1 (4252853367575831977) -->
+    <!-- no translation found for emailAddressTypes:2 (7158046581744435718) -->
+    <!-- no translation found for emailAddressTypes:3 (3625034471181268169) -->
+    <!-- no translation found for postalAddressTypes:0 (5732960259696659380) -->
+    <!-- no translation found for postalAddressTypes:1 (7132240704786130285) -->
+    <!-- no translation found for postalAddressTypes:2 (1317604357745852817) -->
+    <!-- no translation found for postalAddressTypes:3 (1582953598462826702) -->
+    <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
+    <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
+    <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
+    <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
+    <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
+    <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
+    <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
+    <!-- no translation found for imProtocols:0 (3318725788774688043) -->
+    <!-- no translation found for imProtocols:1 (1787713387022932886) -->
+    <!-- no translation found for imProtocols:2 (6751174158442316516) -->
+    <!-- no translation found for imProtocols:3 (1151283347465052653) -->
+    <!-- no translation found for imProtocols:4 (2157980008878817934) -->
+    <!-- no translation found for imProtocols:5 (7836237460308230767) -->
+    <!-- no translation found for imProtocols:6 (1180789904462172516) -->
+    <!-- no translation found for imProtocols:7 (21955111672779862) -->
+    <!-- no translation found for keyguard_password_enter_pin_code (6779835451906812518) -->
+    <skip />
+    <!-- no translation found for keyguard_password_wrong_pin_code (230312338493035499) -->
+    <skip />
+    <!-- no translation found for keyguard_label_text (3902954467573892533) -->
+    <skip />
+    <!-- no translation found for emergency_call_dialog_number_for_display (6256361184251050511) -->
+    <skip />
+    <!-- no translation found for lockscreen_carrier_default (5222269885486229730) -->
+    <skip />
+    <!-- no translation found for lockscreen_screen_locked (1922273663462058967) -->
+    <skip />
+    <!-- no translation found for lockscreen_instructions_when_pattern_enabled (7535864145009679967) -->
+    <skip />
+    <!-- no translation found for lockscreen_instructions_when_pattern_disabled (6526504555912746785) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_instructions (8984964506352089877) -->
+    <skip />
+    <!-- no translation found for lockscreen_emergency_call (422835617844547383) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_correct (7104753084746383672) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_wrong (7517004470797680361) -->
+    <skip />
+    <!-- no translation found for lockscreen_plugged_in (8806977650003537118) -->
+    <skip />
+    <!-- no translation found for lockscreen_low_battery (9002637795199621345) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message_short (5051192587315492957) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message (8912914495901434841) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_instructions (8125847194365725429) -->
+    <skip />
+    <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_message (1005803622871256359) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_instructions (5033160098036646955) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_locked_message (7398401200962556379) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (5939537246164692076) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6709066241494622136) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (1569017295989454551) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_attempts_countdown (8823588000022797566) -->
+    <skip />
+    <!-- no translation found for lockscreen_forgot_pattern_button_text (4219994639843985488) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_too_many_attempts (7504679498838839295) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_instructions (6542400673357252011) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_username_hint (6378418320242015111) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_password_hint (3224230234042131153) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_submit_button (5562051040043760034) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
+    <skip />
+    <!-- no translation found for status_bar_time_format (2168573805413119180) -->
+    <skip />
+    <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
+    <skip />
+    <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
+    <skip />
+    <!-- no translation found for hour_ampm (7665432130905376251) -->
+    <skip />
+    <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
+    <skip />
+    <!-- no translation found for status_bar_clear_all_button (2202004591253243750) -->
+    <skip />
+    <!-- no translation found for status_bar_no_notifications_title (5123133188102094464) -->
+    <skip />
+    <!-- no translation found for status_bar_ongoing_events_title (799961521630569167) -->
+    <skip />
+    <!-- no translation found for status_bar_latest_events_title (5414094466807164279) -->
+    <skip />
+    <!-- no translation found for battery_status_text_percent_format (7391464609447031944) -->
+    <skip />
+    <!-- no translation found for battery_status_charging (5078780715755132756) -->
+    <skip />
+    <!-- no translation found for battery_low_title (3665400828395001695) -->
+    <skip />
+    <!-- no translation found for battery_low_subtitle (7537149915372180016) -->
+    <skip />
+    <!-- no translation found for battery_low_percent_format (8635359708781261154) -->
+    <skip />
+    <!-- no translation found for factorytest_failed (5784901108608196679) -->
+    <skip />
+    <!-- no translation found for factorytest_not_system (6330339565054095688) -->
+    <skip />
+    <!-- no translation found for factorytest_no_action (1662569013408679347) -->
+    <skip />
+    <!-- no translation found for factorytest_reboot (6080912029718954885) -->
+    <skip />
+    <!-- no translation found for save_password_label (4129493019621348626) -->
+    <skip />
+    <!-- no translation found for save_password_message (7412617920202682045) -->
+    <skip />
+    <!-- no translation found for save_password_notnow (3887362423496820832) -->
+    <skip />
+    <!-- no translation found for save_password_remember (4319688896716308569) -->
+    <skip />
+    <!-- no translation found for save_password_never (1836981952883642377) -->
+    <skip />
+    <!-- no translation found for open_permission_deny (6408502671105717111) -->
+    <skip />
+    <!-- no translation found for text_copied (6106873823411904723) -->
+    <skip />
+    <!-- no translation found for more_item_label (5204075544750360778) -->
+    <skip />
+    <!-- no translation found for prepend_shortcut_label (6091430648975237047) -->
+    <skip />
+    <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
+    <skip />
+    <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
+    <skip />
+    <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
+    <skip />
+    <!-- no translation found for search_go (4823831235057123206) -->
+    <skip />
+    <!-- no translation found for today (6914914811057683636) -->
+    <skip />
+    <!-- no translation found for yesterday (5280495043584636271) -->
+    <skip />
+    <!-- no translation found for tomorrow (561215115479060939) -->
+    <skip />
+    <!-- no translation found for oneMonthDurationPast (3402179395240209557) -->
+    <skip />
+    <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
+    <skip />
+    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
+    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
+    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
+    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
+    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
+    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
+    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
+    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
+    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
+    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
+    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
+    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
+    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
+    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
+    <!-- no translation found for in_num_days:one (5608475533104443893) -->
+    <!-- no translation found for in_num_days:other (3827193006163842267) -->
+    <!-- no translation found for preposition_for_date (2689847983632851560) -->
+    <skip />
+    <!-- no translation found for preposition_for_time (2613388053493148013) -->
+    <skip />
+    <!-- no translation found for preposition_for_year (6968468294728152393) -->
+    <skip />
+    <!-- no translation found for day (7849249054576985912) -->
+    <skip />
+    <!-- no translation found for days (8381828105391141169) -->
+    <skip />
+    <!-- no translation found for hour (1044439788994278057) -->
+    <skip />
+    <!-- no translation found for hours (9008157371441255845) -->
+    <skip />
+    <!-- no translation found for minute (2434431396283136076) -->
+    <skip />
+    <!-- no translation found for minutes (8176836254200264856) -->
+    <skip />
+    <!-- no translation found for second (6620645953323664299) -->
+    <skip />
+    <!-- no translation found for seconds (6416703426008384360) -->
+    <skip />
+    <!-- no translation found for week (7738046527402739781) -->
+    <skip />
+    <!-- no translation found for weeks (3178327674459887377) -->
+    <skip />
+    <!-- no translation found for year (8024790425994085153) -->
+    <skip />
+    <!-- no translation found for years (8592090054773244417) -->
+    <skip />
+    <!-- no translation found for sunday (4811082193700148223) -->
+    <skip />
+    <!-- no translation found for monday (7543713499896911033) -->
+    <skip />
+    <!-- no translation found for tuesday (7962192298359117585) -->
+    <skip />
+    <!-- no translation found for wednesday (5768878309383390437) -->
+    <skip />
+    <!-- no translation found for thursday (5690060634904123607) -->
+    <skip />
+    <!-- no translation found for friday (2718325370375116889) -->
+    <skip />
+    <!-- no translation found for saturday (222899317300942333) -->
+    <skip />
+    <!-- no translation found for every_weekday (8466333034903391066) -->
+    <skip />
+    <!-- no translation found for daily (1661712840773846970) -->
+    <skip />
+    <!-- no translation found for weekly (578642117234613009) -->
+    <skip />
+    <!-- no translation found for monthly (8526124657540210537) -->
+    <skip />
+    <!-- no translation found for yearly (8083067713764127070) -->
+    <skip />
+    <!-- no translation found for VideoView_error_title (1024334251681931859) -->
+    <skip />
+    <!-- no translation found for VideoView_error_text_unknown (3398417247398476771) -->
+    <skip />
+    <!-- no translation found for VideoView_error_button (3144127115413163445) -->
+    <skip />
+    <!-- no translation found for am (5354895493921411502) -->
+    <skip />
+    <!-- no translation found for pm (7206933220587555766) -->
+    <skip />
+    <!-- no translation found for numeric_date (5120078478872821100) -->
+    <skip />
+    <!-- no translation found for wday1_date1_time1_wday2_date2_time2 (7066878981949584861) -->
+    <skip />
+    <!-- no translation found for wday1_date1_wday2_date2 (8671068747172261907) -->
+    <skip />
+    <!-- no translation found for date1_time1_date2_time2 (3645498975775629615) -->
+    <skip />
+    <!-- no translation found for date1_date2 (377057563556488062) -->
+    <skip />
+    <!-- no translation found for time1_time2 (3173474242109288305) -->
+    <skip />
+    <!-- no translation found for time_wday_date (8928955562064570313) -->
+    <skip />
+    <!-- no translation found for wday_date (8794741400546136975) -->
+    <skip />
+    <!-- no translation found for time_date (1922644512833014496) -->
+    <skip />
+    <!-- no translation found for time_wday (1422050241301754712) -->
+    <skip />
+    <!-- no translation found for full_date_month_first (6011143962222283357) -->
+    <skip />
+    <!-- no translation found for full_date_day_first (8621594762705478189) -->
+    <skip />
+    <!-- no translation found for medium_date_month_first (48990963718825728) -->
+    <skip />
+    <!-- no translation found for medium_date_day_first (2898992016440387123) -->
+    <skip />
+    <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
+    <skip />
+    <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
+    <skip />
+    <!-- no translation found for noon (8390796001560682897) -->
+    <skip />
+    <!-- no translation found for Noon (7698941576181064429) -->
+    <skip />
+    <!-- no translation found for midnight (7773339795626486146) -->
+    <skip />
+    <!-- no translation found for Midnight (1260172107848123187) -->
+    <skip />
+    <!-- no translation found for month_day (3356633704511426364) -->
+    <skip />
+    <!-- no translation found for month (3017405760734206414) -->
+    <skip />
+    <!-- no translation found for month_day_year (2435948225709176752) -->
+    <skip />
+    <!-- no translation found for month_year (6228414124777343135) -->
+    <skip />
+    <!-- no translation found for time_of_day (8375993139317154157) -->
+    <skip />
+    <!-- no translation found for date_and_time (9197690194373107109) -->
+    <skip />
+    <!-- no translation found for same_year_md1_md2 (9199324363135981317) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_md1_wday2_md2 (6006392413355305178) -->
+    <skip />
+    <!-- no translation found for same_year_mdy1_mdy2 (1576657593937827090) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_mdy1_wday2_mdy2 (9135935796468891580) -->
+    <skip />
+    <!-- no translation found for same_year_md1_time1_md2_time2 (2172964106375558081) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_md1_time1_wday2_md2_time2 (1702879534101786310) -->
+    <skip />
+    <!-- no translation found for same_year_mdy1_time1_mdy2_time2 (2476443311723358767) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_mdy1_time1_wday2_mdy2_time2 (1564837340334069879) -->
+    <skip />
+    <!-- no translation found for numeric_md1_md2 (8908376522875100300) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_md1_wday2_md2 (3239690882018292077) -->
+    <skip />
+    <!-- no translation found for numeric_mdy1_mdy2 (8883797176939233525) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_mdy1_wday2_mdy2 (4150475769255828954) -->
+    <skip />
+    <!-- no translation found for numeric_md1_time1_md2_time2 (3624746590607741419) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_md1_time1_wday2_md2_time2 (4258040955467298134) -->
+    <skip />
+    <!-- no translation found for numeric_mdy1_time1_mdy2_time2 (3598215409314517987) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_mdy1_time1_wday2_mdy2_time2 (264076937155877259) -->
+    <skip />
+    <!-- no translation found for same_month_md1_md2 (2393563617438036111) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_md1_wday2_md2 (1208946773794057819) -->
+    <skip />
+    <!-- no translation found for same_month_mdy1_mdy2 (3713236637869030492) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_mdy1_wday2_mdy2 (389638922479870472) -->
+    <skip />
+    <!-- no translation found for same_month_md1_time1_md2_time2 (7477075526337542685) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_md1_time1_wday2_md2_time2 (3516978303779391173) -->
+    <skip />
+    <!-- no translation found for same_month_mdy1_time1_mdy2_time2 (7320410992514057310) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_mdy1_time1_wday2_mdy2_time2 (1332950588774239228) -->
+    <skip />
+    <!-- no translation found for abbrev_month_day_year (5767271534015320250) -->
+    <skip />
+    <!-- no translation found for abbrev_month_year (8058929633673942490) -->
+    <skip />
+    <!-- no translation found for abbrev_month_day (458867920693482757) -->
+    <skip />
+    <!-- no translation found for abbrev_month (1674509986330181349) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_sunday (9057662850446501884) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_monday (7358451993082888343) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_tuesday (2282901451170509613) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_wednesday (2100217950343286482) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_thursday (5475158963242863176) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_friday (4081018004819837155) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_saturday (1929694088305891795) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_sunday (6462580883948669820) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_monday (6960587654241349502) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_tuesday (7004462235990108936) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_wednesday (5688564741951314696) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_thursday (1784339868453982400) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_friday (4314577583604069357) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_saturday (70321191398427845) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_sunday (7403409454572591357) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_monday (5278358100012478239) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_tuesday (5121116040712487059) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_wednesday (1601079579293330319) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_thursday (5863422096017401812) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_friday (2916686031099723960) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_saturday (8521564973195542073) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_sunday (1650484495176707638) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_monday (9133193697786876074) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_tuesday (4012095408481489663) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_wednesday (6279056612496078470) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_thursday (2748599403545071011) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_friday (5037282109124849673) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_saturday (3208167155877833783) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_sunday (4683862964821549758) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_monday (6701142261471667000) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_tuesday (9098171980161292477) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_wednesday (655049238289460956) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_thursday (7816913627500884083) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_friday (903301878650619398) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_saturday (5359692489649817988) -->
+    <skip />
+    <!-- no translation found for month_long_january (7128497801440564337) -->
+    <skip />
+    <!-- no translation found for month_long_february (7808570514581190617) -->
+    <skip />
+    <!-- no translation found for month_long_march (2061328556983796034) -->
+    <skip />
+    <!-- no translation found for month_long_april (6575007959043269919) -->
+    <skip />
+    <!-- no translation found for month_long_may (8404051103463071121) -->
+    <skip />
+    <!-- no translation found for month_long_june (6255771619238859451) -->
+    <skip />
+    <!-- no translation found for month_long_july (4129177743136800884) -->
+    <skip />
+    <!-- no translation found for month_long_august (5494331003296804494) -->
+    <skip />
+    <!-- no translation found for month_long_september (2691137479752033087) -->
+    <skip />
+    <!-- no translation found for month_long_october (7501261567327243313) -->
+    <skip />
+    <!-- no translation found for month_long_november (8759690753068763664) -->
+    <skip />
+    <!-- no translation found for month_long_december (4505008719696569497) -->
+    <skip />
+    <!-- no translation found for month_medium_january (2315492772833932512) -->
+    <skip />
+    <!-- no translation found for month_medium_february (118412521324313430) -->
+    <skip />
+    <!-- no translation found for month_medium_march (5546835583839352358) -->
+    <skip />
+    <!-- no translation found for month_medium_april (7052559668687733702) -->
+    <skip />
+    <!-- no translation found for month_medium_may (2825303871720116018) -->
+    <skip />
+    <!-- no translation found for month_medium_june (829843667101495271) -->
+    <skip />
+    <!-- no translation found for month_medium_july (5029778226925324789) -->
+    <skip />
+    <!-- no translation found for month_medium_august (8851230594641162805) -->
+    <skip />
+    <!-- no translation found for month_medium_september (8420590486625304647) -->
+    <skip />
+    <!-- no translation found for month_medium_october (1787382806172930239) -->
+    <skip />
+    <!-- no translation found for month_medium_november (675513809622370603) -->
+    <skip />
+    <!-- no translation found for month_medium_december (2934948295928978783) -->
+    <skip />
+    <!-- no translation found for month_shortest_january (6070060405144675883) -->
+    <skip />
+    <!-- no translation found for month_shortest_february (5632605004902176653) -->
+    <skip />
+    <!-- no translation found for month_shortest_march (4304231552356086624) -->
+    <skip />
+    <!-- no translation found for month_shortest_april (1166434066469385532) -->
+    <skip />
+    <!-- no translation found for month_shortest_may (9131326028845529001) -->
+    <skip />
+    <!-- no translation found for month_shortest_june (1875723154506665289) -->
+    <skip />
+    <!-- no translation found for month_shortest_july (2003596275389810773) -->
+    <skip />
+    <!-- no translation found for month_shortest_august (9120245162625763214) -->
+    <skip />
+    <!-- no translation found for month_shortest_september (7980651111022693669) -->
+    <skip />
+    <!-- no translation found for month_shortest_october (3640405450427788312) -->
+    <skip />
+    <!-- no translation found for month_shortest_november (4002935318566146993) -->
+    <skip />
+    <!-- no translation found for month_shortest_december (6213739417171334040) -->
+    <skip />
+    <!-- no translation found for elapsed_time_short_format_mm_ss (1294409362352514646) -->
+    <skip />
+    <!-- no translation found for elapsed_time_short_format_h_mm_ss (2997059666628785039) -->
+    <skip />
+    <!-- no translation found for selectAll (691691810023908884) -->
+    <skip />
+    <!-- no translation found for cut (5845613239192595662) -->
+    <skip />
+    <!-- no translation found for cutAll (4474519683293791451) -->
+    <skip />
+    <!-- no translation found for copy (8603721575469529820) -->
+    <skip />
+    <!-- no translation found for copyAll (4777548804630476932) -->
+    <skip />
+    <!-- no translation found for paste (6458036735811828538) -->
+    <skip />
+    <!-- no translation found for copyUrl (5785708478767435812) -->
+    <skip />
+    <!-- no translation found for inputMethod (7911866729148111492) -->
+    <skip />
+    <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_title (5997772070488639934) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_text (2230118755295375293) -->
+    <skip />
+    <!-- no translation found for ok (4003878536083514869) -->
+    <skip />
+    <!-- no translation found for cancel (1527674037280267012) -->
+    <skip />
+    <!-- no translation found for yes (8185296114406773873) -->
+    <skip />
+    <!-- no translation found for no (2300685350903156262) -->
+    <skip />
+    <!-- no translation found for capital_on (8418242581217554942) -->
+    <skip />
+    <!-- no translation found for capital_off (8870368560477693851) -->
+    <skip />
+    <!-- no translation found for whichApplication (2828159696176255212) -->
+    <skip />
+    <!-- no translation found for alwaysUse (6433627451071144629) -->
+    <skip />
+    <!-- no translation found for clearDefaultHintMsg (5742432113023174321) -->
+    <skip />
+    <!-- no translation found for chooseActivity (7588691622928031978) -->
+    <skip />
+    <!-- no translation found for noApplications (4068560364116066745) -->
+    <skip />
+    <!-- no translation found for aerr_title (2654390351574026098) -->
+    <skip />
+    <!-- no translation found for aerr_application (4917288809565116720) -->
+    <skip />
+    <!-- no translation found for aerr_process (1273819861108073461) -->
+    <skip />
+    <!-- no translation found for anr_title (3305935690891435915) -->
+    <skip />
+    <!-- no translation found for anr_activity_application (1653036325679156678) -->
+    <skip />
+    <!-- no translation found for anr_activity_process (2674027618362070465) -->
+    <skip />
+    <!-- no translation found for anr_application_process (2163656674970221928) -->
+    <skip />
+    <!-- no translation found for anr_process (7747550780123472160) -->
+    <skip />
+    <!-- no translation found for force_close (9020954128872810669) -->
+    <skip />
+    <!-- no translation found for wait (7973775702304037058) -->
+    <skip />
+    <!-- no translation found for debug (857932504764728770) -->
+    <skip />
+    <!-- no translation found for sendText (6158329286172492543) -->
+    <skip />
+    <!-- no translation found for volume_ringtone (4121694816346562058) -->
+    <skip />
+    <!-- no translation found for volume_music (4869950240104717493) -->
+    <skip />
+    <!-- no translation found for volume_call (5723421277753250395) -->
+    <skip />
+    <!-- no translation found for volume_alarm (2752102730973081294) -->
+    <skip />
+    <!-- no translation found for volume_unknown (6908187627672375742) -->
+    <skip />
+    <!-- no translation found for ringtone_default (2873893375149093475) -->
+    <skip />
+    <!-- no translation found for ringtone_default_with_actual (5474076151665761913) -->
+    <skip />
+    <!-- no translation found for ringtone_silent (7477159279081654685) -->
+    <skip />
+    <!-- no translation found for ringtone_picker_title (7055241890764367884) -->
+    <skip />
+    <!-- no translation found for ringtone_unknown (6888219771401173795) -->
+    <skip />
+    <!-- no translation found for wifi_available:one (8168012881468888470) -->
+    <!-- no translation found for wifi_available:other (4666122955807117718) -->
+    <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
+    <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
+    <!-- no translation found for select_character (3735110139249491726) -->
+    <skip />
+    <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
+    <skip />
+    <!-- no translation found for sms_control_title (2742400596989418394) -->
+    <skip />
+    <!-- no translation found for sms_control_message (3447126217666595989) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (8839660939359273650) -->
+    <skip />
+    <!-- no translation found for sms_control_no (909756849988183801) -->
+    <skip />
+    <!-- no translation found for date_time_set (2495199891239480952) -->
+    <skip />
+    <!-- no translation found for default_permission_group (7742780381379652409) -->
+    <skip />
+    <!-- no translation found for no_permissions (85461124044682315) -->
+    <skip />
+    <!-- no translation found for perms_hide (4145325555929151849) -->
+    <skip />
+    <!-- no translation found for perms_show_all (6040194843455403173) -->
+    <skip />
+    <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
+    <skip />
+    <!-- no translation found for usb_storage_title (8699631567051394409) -->
+    <skip />
+    <!-- no translation found for usb_storage_message (5344039189213308733) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
+    <skip />
+    <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
+    <skip />
+    <!-- no translation found for select_input_method (2658280517827502015) -->
+    <skip />
+    <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
+    <skip />
+    <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
+    <skip />
+    <!-- no translation found for candidates_style (7738463880139922176) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-en-rUS/strings.xml b/core/res/res/values-en-rUS/strings.xml
new file mode 100644
index 0000000..b9df983
--- /dev/null
+++ b/core/res/res/values-en-rUS/strings.xml
@@ -0,0 +1,1256 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="byteShort">"B"</string>
+    <!-- no translation found for kilobyteShort (5865542430193761682) -->
+    <skip />
+    <!-- no translation found for megabyteShort (112984851085937882) -->
+    <skip />
+    <!-- no translation found for gigabyteShort (8586075069559273847) -->
+    <skip />
+    <!-- no translation found for terabyteShort (5828502357595687794) -->
+    <skip />
+    <!-- no translation found for petabyteShort (7523248732657962413) -->
+    <skip />
+    <!-- no translation found for untitled (284687023829080340) -->
+    <skip />
+    <!-- no translation found for ellipsis (8538883953764277342) -->
+    <skip />
+    <!-- no translation found for emptyPhoneNumber (6416283285732095329) -->
+    <skip />
+    <!-- no translation found for unknownName (3974255879290140525) -->
+    <skip />
+    <!-- no translation found for defaultVoiceMailAlphaTag (6484324201071049939) -->
+    <skip />
+    <!-- no translation found for defaultMsisdnAlphaTag (4953008223227371928) -->
+    <skip />
+    <!-- no translation found for mmiError (7480678835624852655) -->
+    <skip />
+    <!-- no translation found for serviceEnabled (4042194305396115167) -->
+    <skip />
+    <!-- no translation found for serviceEnabledFor (638808419103886277) -->
+    <skip />
+    <!-- no translation found for serviceDisabled (1059935666763511541) -->
+    <skip />
+    <!-- no translation found for serviceRegistered (7639869107156932038) -->
+    <skip />
+    <!-- no translation found for serviceErased (4602215208593071820) -->
+    <skip />
+    <!-- no translation found for passwordIncorrect (5142040651297346232) -->
+    <skip />
+    <!-- no translation found for mmiComplete (3178168770150013486) -->
+    <skip />
+    <!-- no translation found for badPin (5103184589972647739) -->
+    <skip />
+    <!-- no translation found for badPuk (2200634943393540609) -->
+    <skip />
+    <!-- no translation found for mismatchPin (5055729703806180857) -->
+    <skip />
+    <!-- no translation found for invalidPin (6201854814319326475) -->
+    <skip />
+    <!-- no translation found for needPuk (4788728144863892764) -->
+    <skip />
+    <!-- no translation found for needPuk2 (7056908944942451033) -->
+    <skip />
+    <!-- no translation found for ClipMmi (5649729434121615509) -->
+    <skip />
+    <!-- no translation found for ClirMmi (5220979296096544477) -->
+    <skip />
+    <!-- no translation found for CfMmi (4998483717856803914) -->
+    <skip />
+    <!-- no translation found for CwMmi (5678103638951836350) -->
+    <skip />
+    <!-- no translation found for BaMmi (6030555200442855833) -->
+    <skip />
+    <!-- no translation found for PwdMmi (2549941247959366670) -->
+    <skip />
+    <!-- no translation found for PinMmi (2463353963837922189) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOnNextCallOn (4005921990799469144) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOnNextCallOff (1497360760012205230) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOffNextCallOn (604591440398078227) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOffNextCallOff (5114039908683246336) -->
+    <skip />
+    <!-- no translation found for serviceNotProvisioned (3754416031529306610) -->
+    <skip />
+    <!-- no translation found for CLIRPermanent (3819908477891272611) -->
+    <skip />
+    <!-- no translation found for serviceClassVoice (3059107563169935913) -->
+    <skip />
+    <!-- no translation found for serviceClassData (2669025626575716504) -->
+    <skip />
+    <!-- no translation found for serviceClassFAX (973109472405729679) -->
+    <skip />
+    <!-- no translation found for serviceClassSMS (3857383928743625711) -->
+    <skip />
+    <!-- no translation found for serviceClassDataAsync (8526461993032174729) -->
+    <skip />
+    <!-- no translation found for serviceClassDataSync (2461138395498381801) -->
+    <skip />
+    <!-- no translation found for serviceClassPacket (8119604233041078065) -->
+    <skip />
+    <!-- no translation found for serviceClassPAD (202892636830042266) -->
+    <skip />
+    <!-- no translation found for cfTemplateNotForwarded (3171755805856206604) -->
+    <skip />
+    <!-- no translation found for cfTemplateForwarded (2468661573318024785) -->
+    <skip />
+    <!-- no translation found for cfTemplateForwardedTime (5151810870794744740) -->
+    <skip />
+    <!-- no translation found for cfTemplateRegistered (5685211900474527085) -->
+    <skip />
+    <!-- no translation found for cfTemplateRegisteredTime (2978918277762252776) -->
+    <skip />
+    <!-- no translation found for httpErrorOk (984913805621139001) -->
+    <skip />
+    <!-- no translation found for httpError (9177990053748151835) -->
+    <skip />
+    <!-- no translation found for httpErrorLookup (5251341716070330936) -->
+    <skip />
+    <!-- no translation found for httpErrorUnsupportedAuthScheme (2865679883634239474) -->
+    <skip />
+    <!-- no translation found for httpErrorAuth (1637382600929594620) -->
+    <skip />
+    <!-- no translation found for httpErrorProxyAuth (5947648983995807455) -->
+    <skip />
+    <!-- no translation found for httpErrorConnect (129984292497034683) -->
+    <skip />
+    <!-- no translation found for httpErrorIO (8128922048686581131) -->
+    <skip />
+    <!-- no translation found for httpErrorTimeout (8357966263983739012) -->
+    <skip />
+    <!-- no translation found for httpErrorRedirectLoop (4122379005100433886) -->
+    <skip />
+    <!-- no translation found for httpErrorUnsupportedScheme (4072339858288462569) -->
+    <skip />
+    <!-- no translation found for httpErrorFailedSslHandshake (2316625025255452595) -->
+    <skip />
+    <!-- no translation found for httpErrorBadUrl (8885244563103716039) -->
+    <skip />
+    <!-- no translation found for httpErrorFile (1408273621719669493) -->
+    <skip />
+    <!-- no translation found for httpErrorFileNotFound (2309088465300506314) -->
+    <skip />
+    <!-- no translation found for httpErrorTooManyRequests (3764334538393544875) -->
+    <skip />
+    <!-- no translation found for contentServiceSync (4863236165350475642) -->
+    <skip />
+    <!-- no translation found for contentServiceSyncNotificationTitle (6855304679069026824) -->
+    <skip />
+    <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8477597194404210723) -->
+    <skip />
+    <!-- no translation found for low_memory (4191592786596642367) -->
+    <skip />
+    <!-- no translation found for me (4616693653158602117) -->
+    <skip />
+    <!-- no translation found for power_dialog (8210256011408959109) -->
+    <skip />
+    <!-- no translation found for silent_mode (5218239246946854300) -->
+    <skip />
+    <!-- no translation found for turn_on_radio (1901054698789840131) -->
+    <skip />
+    <!-- no translation found for turn_off_radio (2870296409392615956) -->
+    <skip />
+    <!-- no translation found for screen_lock (1560333453597081877) -->
+    <skip />
+    <!-- no translation found for power_off (2412024417733516836) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (3735034517335251808) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm (699224922526414097) -->
+    <skip />
+    <!-- no translation found for no_recent_tasks (1367712919998349373) -->
+    <skip />
+    <!-- no translation found for global_actions (8299888906525675157) -->
+    <skip />
+    <!-- no translation found for global_action_lock (5943677976245541105) -->
+    <skip />
+    <!-- no translation found for global_action_power_off (3143027278596694254) -->
+    <skip />
+    <!-- no translation found for global_action_toggle_silent_mode (5849335789367070450) -->
+    <skip />
+    <!-- no translation found for global_action_silent_mode_on_status (6053429980569202260) -->
+    <skip />
+    <!-- no translation found for global_action_silent_mode_off_status (1994514127029249081) -->
+    <skip />
+    <!-- no translation found for safeMode (3375134507868534320) -->
+    <skip />
+    <!-- no translation found for permgrouplab_costMoney (904087853776533085) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_costMoney (4662370555643969515) -->
+    <skip />
+    <!-- no translation found for permgrouplab_messages (2984053976424233925) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_messages (2129093134354989379) -->
+    <skip />
+    <!-- no translation found for permgrouplab_personalInfo (4548406335021507392) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_personalInfo (8499310823817958034) -->
+    <skip />
+    <!-- no translation found for permgrouplab_location (8535677827151907069) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_location (2341662219604651887) -->
+    <skip />
+    <!-- no translation found for permgrouplab_network (3597781730625751831) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_network (8332572695347918340) -->
+    <skip />
+    <!-- no translation found for permgrouplab_accounts (8631201594657951893) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_accounts (443982868906396781) -->
+    <skip />
+    <!-- no translation found for permgrouplab_hardwareControls (5074512938567152139) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_hardwareControls (8772503144945278440) -->
+    <skip />
+    <!-- no translation found for permgrouplab_phoneCalls (7096448531266882376) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_phoneCalls (6703873478653366233) -->
+    <skip />
+    <!-- no translation found for permgrouplab_systemTools (1840847965111633430) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_systemTools (2810337951496685271) -->
+    <skip />
+    <!-- no translation found for permgrouplab_developmentTools (692844635256963358) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_developmentTools (5253915519857796400) -->
+    <skip />
+    <!-- no translation found for permlab_statusBar (8789506912215455922) -->
+    <skip />
+    <!-- no translation found for permdesc_statusBar (5034247171231682403) -->
+    <skip />
+    <!-- no translation found for permlab_expandStatusBar (6382500803293284173) -->
+    <skip />
+    <!-- no translation found for permdesc_expandStatusBar (90953162060681436) -->
+    <skip />
+    <!-- no translation found for permlab_processOutgoingCalls (786316295241100144) -->
+    <skip />
+    <!-- no translation found for permdesc_processOutgoingCalls (1655242138991854396) -->
+    <skip />
+    <!-- no translation found for permlab_receiveSms (5820796051959871222) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveSms (2265740044646990161) -->
+    <skip />
+    <!-- no translation found for permlab_receiveMms (7983091218880782611) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveMms (3641275586518289960) -->
+    <skip />
+    <!-- no translation found for permlab_sendSms (4713837923748234081) -->
+    <skip />
+    <!-- no translation found for permdesc_sendSms (7126594387176704010) -->
+    <skip />
+    <!-- no translation found for permlab_readSms (4256004535185449429) -->
+    <skip />
+    <!-- no translation found for permdesc_readSms (4586480500886941902) -->
+    <skip />
+    <!-- no translation found for permlab_writeSms (8453452414726246828) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSms (1036408118901361812) -->
+    <skip />
+    <!-- no translation found for permlab_receiveWapPush (5726837205927152203) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveWapPush (4779188629794134886) -->
+    <skip />
+    <!-- no translation found for permlab_getTasks (357640569227780364) -->
+    <skip />
+    <!-- no translation found for permdesc_getTasks (2916615403728003200) -->
+    <skip />
+    <!-- no translation found for permlab_reorderTasks (4758862288285224517) -->
+    <skip />
+    <!-- no translation found for permdesc_reorderTasks (7507060843941912021) -->
+    <skip />
+    <!-- no translation found for permlab_setDebugApp (2973363275929449444) -->
+    <skip />
+    <!-- no translation found for permdesc_setDebugApp (5720449860498265972) -->
+    <skip />
+    <!-- no translation found for permlab_changeConfiguration (8581093564179818627) -->
+    <skip />
+    <!-- no translation found for permdesc_changeConfiguration (4055366453803187171) -->
+    <skip />
+    <!-- no translation found for permlab_restartPackages (5836367540766044606) -->
+    <skip />
+    <!-- no translation found for permdesc_restartPackages (1764965996765573321) -->
+    <skip />
+    <!-- no translation found for permlab_setProcessForeground (4860990420780868638) -->
+    <skip />
+    <!-- no translation found for permdesc_setProcessForeground (3795477299954784360) -->
+    <skip />
+    <!-- no translation found for permlab_forceBack (4737517869935566733) -->
+    <skip />
+    <!-- no translation found for permdesc_forceBack (5579316297001154697) -->
+    <skip />
+    <!-- no translation found for permlab_dump (3177569414212943167) -->
+    <skip />
+    <!-- no translation found for permdesc_dump (1815913623373011608) -->
+    <skip />
+    <!-- no translation found for permlab_addSystemService (9166015020584794942) -->
+    <skip />
+    <!-- no translation found for permdesc_addSystemService (2310425587289835743) -->
+    <skip />
+    <!-- no translation found for permlab_runSetActivityWatcher (2615943932761994905) -->
+    <skip />
+    <!-- no translation found for permdesc_runSetActivityWatcher (2488524206195482220) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastPackageRemoved (355775368495637820) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastPackageRemoved (6486181398191058385) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
+    <skip />
+    <!-- no translation found for permlab_setProcessLimit (5190694306017260601) -->
+    <skip />
+    <!-- no translation found for permdesc_setProcessLimit (593938303319848578) -->
+    <skip />
+    <!-- no translation found for permlab_setAlwaysFinish (8745533365504920540) -->
+    <skip />
+    <!-- no translation found for permdesc_setAlwaysFinish (2437195869854312148) -->
+    <skip />
+    <!-- no translation found for permlab_fotaUpdate (1813039882829307079) -->
+    <skip />
+    <!-- no translation found for permdesc_fotaUpdate (2544137712607584763) -->
+    <skip />
+    <!-- no translation found for permlab_batteryStats (1598947993704535568) -->
+    <skip />
+    <!-- no translation found for permdesc_batteryStats (6247598531831307989) -->
+    <skip />
+    <!-- no translation found for permlab_internalSystemWindow (5780262737320556654) -->
+    <skip />
+    <!-- no translation found for permdesc_internalSystemWindow (6495031598062517795) -->
+    <skip />
+    <!-- no translation found for permlab_systemAlertWindow (843729657746130626) -->
+    <skip />
+    <!-- no translation found for permdesc_systemAlertWindow (2731854380682210852) -->
+    <skip />
+    <!-- no translation found for permlab_setAnimationScale (2419250686027992384) -->
+    <skip />
+    <!-- no translation found for permdesc_setAnimationScale (8518027785481727264) -->
+    <skip />
+    <!-- no translation found for permlab_manageAppTokens (1033424552444304594) -->
+    <skip />
+    <!-- no translation found for permdesc_manageAppTokens (7285840918912623550) -->
+    <skip />
+    <!-- no translation found for permlab_injectEvents (1383601196263145482) -->
+    <skip />
+    <!-- no translation found for permdesc_injectEvents (840097509341464737) -->
+    <skip />
+    <!-- no translation found for permlab_readInputState (2723668746963882102) -->
+    <skip />
+    <!-- no translation found for permdesc_readInputState (4651137638757852001) -->
+    <skip />
+    <!-- no translation found for permlab_setOrientation (1112555600323148680) -->
+    <skip />
+    <!-- no translation found for permdesc_setOrientation (1960269530378827858) -->
+    <skip />
+    <!-- no translation found for permlab_signalPersistentProcesses (8511163028160623175) -->
+    <skip />
+    <!-- no translation found for permdesc_signalPersistentProcesses (1099349638354917733) -->
+    <skip />
+    <!-- no translation found for permlab_persistentActivity (8163108526929094627) -->
+    <skip />
+    <!-- no translation found for permdesc_persistentActivity (5258975883823299624) -->
+    <skip />
+    <!-- no translation found for permlab_deletePackages (5005536434839333208) -->
+    <skip />
+    <!-- no translation found for permdesc_deletePackages (2687196995215591923) -->
+    <skip />
+    <!-- no translation found for permlab_clearAppUserData (3858185484601410171) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppUserData (7233537744753081136) -->
+    <skip />
+    <!-- no translation found for permlab_deleteCacheFiles (7362746182961997888) -->
+    <skip />
+    <!-- no translation found for permdesc_deleteCacheFiles (8293849509208181266) -->
+    <skip />
+    <!-- no translation found for permlab_getPackageSize (6743556676630447973) -->
+    <skip />
+    <!-- no translation found for permdesc_getPackageSize (2893996655828539776) -->
+    <skip />
+    <!-- no translation found for permlab_installPackages (1637554234554641998) -->
+    <skip />
+    <!-- no translation found for permdesc_installPackages (4747794850590875195) -->
+    <skip />
+    <!-- no translation found for permlab_clearAppCache (7860214328511700776) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppCache (5203820862573167878) -->
+    <skip />
+    <!-- no translation found for permlab_readLogs (6653488552442991707) -->
+    <skip />
+    <!-- no translation found for permdesc_readLogs (356352685800884319) -->
+    <skip />
+    <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
+    <skip />
+    <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
+    <skip />
+    <!-- no translation found for permlab_changeComponentState (8107835954049971459) -->
+    <skip />
+    <!-- no translation found for permdesc_changeComponentState (1791096057705836844) -->
+    <skip />
+    <!-- no translation found for permlab_setPreferredApplications (4355701371185331520) -->
+    <skip />
+    <!-- no translation found for permdesc_setPreferredApplications (9029326613767614711) -->
+    <skip />
+    <!-- no translation found for permlab_writeSettings (2915467191611898256) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSettings (8492982548350342641) -->
+    <skip />
+    <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
+    <skip />
+    <!-- no translation found for permlab_writeGservices (296370685945777755) -->
+    <skip />
+    <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
+    <skip />
+    <!-- no translation found for permlab_receiveBootCompleted (5598819384278633845) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveBootCompleted (3197439472472771192) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastSticky (8142357333543531543) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSticky (8488762822718743531) -->
+    <skip />
+    <!-- no translation found for permlab_readContacts (5116003370450871686) -->
+    <skip />
+    <!-- no translation found for permdesc_readContacts (3499378044902258770) -->
+    <skip />
+    <!-- no translation found for permlab_writeContacts (1555136823460617179) -->
+    <skip />
+    <!-- no translation found for permdesc_writeContacts (4787318403287293114) -->
+    <skip />
+    <!-- no translation found for permlab_writeOwnerData (8036840529708535113) -->
+    <skip />
+    <!-- no translation found for permdesc_writeOwnerData (5873447528845878348) -->
+    <skip />
+    <!-- no translation found for permlab_readOwnerData (1847040178513733757) -->
+    <skip />
+    <!-- no translation found for permdesc_readOwnerData (7563299529149214764) -->
+    <skip />
+    <!-- no translation found for permlab_readCalendar (2111238731453410895) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (4408253940601239114) -->
+    <skip />
+    <!-- no translation found for permlab_writeCalendar (7518052789370653396) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCalendar (8057304232140147596) -->
+    <skip />
+    <!-- no translation found for permlab_accessMockLocation (321094551062270213) -->
+    <skip />
+    <!-- no translation found for permdesc_accessMockLocation (3651565866471419739) -->
+    <skip />
+    <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
+    <skip />
+    <!-- no translation found for permlab_accessFineLocation (4846261651944924865) -->
+    <skip />
+    <!-- no translation found for permdesc_accessFineLocation (3572307331039348419) -->
+    <skip />
+    <!-- no translation found for permlab_accessCoarseLocation (1760779730797169189) -->
+    <skip />
+    <!-- no translation found for permdesc_accessCoarseLocation (8878785899768310712) -->
+    <skip />
+    <!-- no translation found for permlab_accessSurfaceFlinger (6405475452322847618) -->
+    <skip />
+    <!-- no translation found for permdesc_accessSurfaceFlinger (5348283543622360967) -->
+    <skip />
+    <!-- no translation found for permlab_readFrameBuffer (4655248388550039199) -->
+    <skip />
+    <!-- no translation found for permdesc_readFrameBuffer (794888199105081402) -->
+    <skip />
+    <!-- no translation found for permlab_modifyAudioSettings (1587341813207960943) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyAudioSettings (1447143004892708149) -->
+    <skip />
+    <!-- no translation found for permlab_recordAudio (4447848534036991667) -->
+    <skip />
+    <!-- no translation found for permdesc_recordAudio (6936874682400894820) -->
+    <skip />
+    <!-- no translation found for permlab_camera (1944473855727060380) -->
+    <skip />
+    <!-- no translation found for permdesc_camera (5978058582323766022) -->
+    <skip />
+    <!-- no translation found for permlab_brick (4749832243303289777) -->
+    <skip />
+    <!-- no translation found for permdesc_brick (7428524578693695766) -->
+    <skip />
+    <!-- no translation found for permlab_reboot (8844650672567077423) -->
+    <skip />
+    <!-- no translation found for permdesc_reboot (4704919552870918328) -->
+    <skip />
+    <!-- no translation found for permlab_mount_unmount_filesystems (1009574821038043781) -->
+    <skip />
+    <!-- no translation found for permdesc_mount_unmount_filesystems (100792065894811109) -->
+    <skip />
+    <!-- no translation found for permlab_vibrate (61984555644467146) -->
+    <skip />
+    <!-- no translation found for permdesc_vibrate (7831723100758509238) -->
+    <skip />
+    <!-- no translation found for permlab_flashlight (9097145977808182652) -->
+    <skip />
+    <!-- no translation found for permdesc_flashlight (7851502731988978358) -->
+    <skip />
+    <!-- no translation found for permlab_hardware_test (4103324677866524254) -->
+    <skip />
+    <!-- no translation found for permdesc_hardware_test (7315242723603994769) -->
+    <skip />
+    <!-- no translation found for permlab_callPhone (168275616535116686) -->
+    <skip />
+    <!-- no translation found for permdesc_callPhone (1852033967965785973) -->
+    <skip />
+    <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
+    <skip />
+    <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
+    <skip />
+    <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
+    <skip />
+    <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
+    <skip />
+    <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
+    <skip />
+    <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
+    <skip />
+    <!-- no translation found for permlab_modifyPhoneState (7791696535097912313) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyPhoneState (6352405226410454770) -->
+    <skip />
+    <!-- no translation found for permlab_readPhoneState (7320082586621086653) -->
+    <skip />
+    <!-- no translation found for permdesc_readPhoneState (8004450067066407969) -->
+    <skip />
+    <!-- no translation found for permlab_wakeLock (1591164750935072136) -->
+    <skip />
+    <!-- no translation found for permdesc_wakeLock (160471538196734936) -->
+    <skip />
+    <!-- no translation found for permlab_devicePower (9214865067086065548) -->
+    <skip />
+    <!-- no translation found for permdesc_devicePower (5608364066480036402) -->
+    <skip />
+    <!-- no translation found for permlab_factoryTest (7786199300637896247) -->
+    <skip />
+    <!-- no translation found for permdesc_factoryTest (3466066005210542042) -->
+    <skip />
+    <!-- no translation found for permlab_setWallpaper (2256730637138641725) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaper (3034653140208685093) -->
+    <skip />
+    <!-- no translation found for permlab_setWallpaperHints (4192438316932517807) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaperHints (738757439960921674) -->
+    <skip />
+    <!-- no translation found for permlab_masterClear (6155403967270586906) -->
+    <skip />
+    <!-- no translation found for permdesc_masterClear (4213553172342689754) -->
+    <skip />
+    <!-- no translation found for permlab_setTimeZone (477196167239548690) -->
+    <skip />
+    <!-- no translation found for permdesc_setTimeZone (8564892020460841198) -->
+    <skip />
+    <!-- no translation found for permlab_getAccounts (2764070033402295170) -->
+    <skip />
+    <!-- no translation found for permdesc_getAccounts (1203491378748649898) -->
+    <skip />
+    <!-- no translation found for permlab_accessNetworkState (2032916924886010827) -->
+    <skip />
+    <!-- no translation found for permdesc_accessNetworkState (7081329402551195933) -->
+    <skip />
+    <!-- no translation found for permlab_createNetworkSockets (4706698319966917864) -->
+    <skip />
+    <!-- no translation found for permdesc_createNetworkSockets (2580337178778551792) -->
+    <skip />
+    <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
+    <skip />
+    <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
+    <skip />
+    <!-- no translation found for permlab_changeNetworkState (2710779001260856872) -->
+    <skip />
+    <!-- no translation found for permdesc_changeNetworkState (8076109230787022270) -->
+    <skip />
+    <!-- no translation found for permlab_accessWifiState (3613679494230374297) -->
+    <skip />
+    <!-- no translation found for permdesc_accessWifiState (8226508433563326925) -->
+    <skip />
+    <!-- no translation found for permlab_changeWifiState (6043889338995432957) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWifiState (7829372845909567994) -->
+    <skip />
+    <!-- no translation found for permlab_bluetoothAdmin (5513286736585647334) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (1838208497914347365) -->
+    <skip />
+    <!-- no translation found for permlab_bluetooth (6378797624765639115) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetooth (8592386018922265273) -->
+    <skip />
+    <!-- no translation found for permlab_disableKeyguard (4574886811903233903) -->
+    <skip />
+    <!-- no translation found for permdesc_disableKeyguard (815972646344251271) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncSettings (8818819977141505127) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncSettings (8454705401908767847) -->
+    <skip />
+    <!-- no translation found for permlab_writeSyncSettings (4514911143753152941) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSyncSettings (7630627689635091836) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncStats (5748337739678952863) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncStats (582551457321957183) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
+    <skip />
+    <!-- no translation found for phoneTypes:0 (6070018634209800981) -->
+    <!-- no translation found for phoneTypes:1 (1514509689885965711) -->
+    <!-- no translation found for phoneTypes:2 (497473201754095234) -->
+    <!-- no translation found for phoneTypes:3 (5554432614281047787) -->
+    <!-- no translation found for phoneTypes:4 (2222084401110150993) -->
+    <!-- no translation found for phoneTypes:5 (2290007103906353121) -->
+    <!-- no translation found for phoneTypes:6 (6930783706213719251) -->
+    <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
+    <!-- no translation found for emailAddressTypes:0 (1540640638077615417) -->
+    <!-- no translation found for emailAddressTypes:1 (4252853367575831977) -->
+    <!-- no translation found for emailAddressTypes:2 (7158046581744435718) -->
+    <!-- no translation found for emailAddressTypes:3 (3625034471181268169) -->
+    <!-- no translation found for postalAddressTypes:0 (5732960259696659380) -->
+    <!-- no translation found for postalAddressTypes:1 (7132240704786130285) -->
+    <!-- no translation found for postalAddressTypes:2 (1317604357745852817) -->
+    <!-- no translation found for postalAddressTypes:3 (1582953598462826702) -->
+    <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
+    <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
+    <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
+    <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
+    <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
+    <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
+    <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
+    <!-- no translation found for imProtocols:0 (3318725788774688043) -->
+    <!-- no translation found for imProtocols:1 (1787713387022932886) -->
+    <!-- no translation found for imProtocols:2 (6751174158442316516) -->
+    <!-- no translation found for imProtocols:3 (1151283347465052653) -->
+    <!-- no translation found for imProtocols:4 (2157980008878817934) -->
+    <!-- no translation found for imProtocols:5 (7836237460308230767) -->
+    <!-- no translation found for imProtocols:6 (1180789904462172516) -->
+    <!-- no translation found for imProtocols:7 (21955111672779862) -->
+    <!-- no translation found for keyguard_password_enter_pin_code (6779835451906812518) -->
+    <skip />
+    <!-- no translation found for keyguard_password_wrong_pin_code (230312338493035499) -->
+    <skip />
+    <!-- no translation found for keyguard_label_text (3902954467573892533) -->
+    <skip />
+    <!-- no translation found for emergency_call_dialog_number_for_display (6256361184251050511) -->
+    <skip />
+    <!-- no translation found for lockscreen_carrier_default (5222269885486229730) -->
+    <skip />
+    <!-- no translation found for lockscreen_screen_locked (1922273663462058967) -->
+    <skip />
+    <!-- no translation found for lockscreen_instructions_when_pattern_enabled (7535864145009679967) -->
+    <skip />
+    <!-- no translation found for lockscreen_instructions_when_pattern_disabled (6526504555912746785) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_instructions (8984964506352089877) -->
+    <skip />
+    <!-- no translation found for lockscreen_emergency_call (422835617844547383) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_correct (7104753084746383672) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_wrong (7517004470797680361) -->
+    <skip />
+    <!-- no translation found for lockscreen_plugged_in (8806977650003537118) -->
+    <skip />
+    <!-- no translation found for lockscreen_low_battery (9002637795199621345) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message_short (5051192587315492957) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message (8912914495901434841) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_instructions (8125847194365725429) -->
+    <skip />
+    <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_message (1005803622871256359) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_instructions (5033160098036646955) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_locked_message (7398401200962556379) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (5939537246164692076) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6709066241494622136) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (1569017295989454551) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_attempts_countdown (8823588000022797566) -->
+    <skip />
+    <!-- no translation found for lockscreen_forgot_pattern_button_text (4219994639843985488) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_too_many_attempts (7504679498838839295) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_instructions (6542400673357252011) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_username_hint (6378418320242015111) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_password_hint (3224230234042131153) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_submit_button (5562051040043760034) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
+    <skip />
+    <!-- no translation found for status_bar_time_format (2168573805413119180) -->
+    <skip />
+    <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
+    <skip />
+    <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
+    <skip />
+    <!-- no translation found for hour_ampm (7665432130905376251) -->
+    <skip />
+    <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
+    <skip />
+    <!-- no translation found for status_bar_clear_all_button (2202004591253243750) -->
+    <skip />
+    <!-- no translation found for status_bar_no_notifications_title (5123133188102094464) -->
+    <skip />
+    <!-- no translation found for status_bar_ongoing_events_title (799961521630569167) -->
+    <skip />
+    <!-- no translation found for status_bar_latest_events_title (5414094466807164279) -->
+    <skip />
+    <!-- no translation found for battery_status_text_percent_format (7391464609447031944) -->
+    <skip />
+    <!-- no translation found for battery_status_charging (5078780715755132756) -->
+    <skip />
+    <!-- no translation found for battery_low_title (3665400828395001695) -->
+    <skip />
+    <!-- no translation found for battery_low_subtitle (7537149915372180016) -->
+    <skip />
+    <!-- no translation found for battery_low_percent_format (8635359708781261154) -->
+    <skip />
+    <!-- no translation found for factorytest_failed (5784901108608196679) -->
+    <skip />
+    <!-- no translation found for factorytest_not_system (6330339565054095688) -->
+    <skip />
+    <!-- no translation found for factorytest_no_action (1662569013408679347) -->
+    <skip />
+    <!-- no translation found for factorytest_reboot (6080912029718954885) -->
+    <skip />
+    <!-- no translation found for save_password_label (4129493019621348626) -->
+    <skip />
+    <!-- no translation found for save_password_message (7412617920202682045) -->
+    <skip />
+    <!-- no translation found for save_password_notnow (3887362423496820832) -->
+    <skip />
+    <!-- no translation found for save_password_remember (4319688896716308569) -->
+    <skip />
+    <!-- no translation found for save_password_never (1836981952883642377) -->
+    <skip />
+    <!-- no translation found for open_permission_deny (6408502671105717111) -->
+    <skip />
+    <!-- no translation found for text_copied (6106873823411904723) -->
+    <skip />
+    <!-- no translation found for more_item_label (5204075544750360778) -->
+    <skip />
+    <!-- no translation found for prepend_shortcut_label (6091430648975237047) -->
+    <skip />
+    <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
+    <skip />
+    <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
+    <skip />
+    <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
+    <skip />
+    <!-- no translation found for search_go (4823831235057123206) -->
+    <skip />
+    <!-- no translation found for today (6914914811057683636) -->
+    <skip />
+    <!-- no translation found for yesterday (5280495043584636271) -->
+    <skip />
+    <!-- no translation found for tomorrow (561215115479060939) -->
+    <skip />
+    <!-- no translation found for oneMonthDurationPast (3402179395240209557) -->
+    <skip />
+    <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
+    <skip />
+    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
+    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
+    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
+    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
+    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
+    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
+    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
+    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
+    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
+    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
+    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
+    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
+    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
+    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
+    <!-- no translation found for in_num_days:one (5608475533104443893) -->
+    <!-- no translation found for in_num_days:other (3827193006163842267) -->
+    <!-- no translation found for preposition_for_date (2689847983632851560) -->
+    <skip />
+    <!-- no translation found for preposition_for_time (2613388053493148013) -->
+    <skip />
+    <!-- no translation found for preposition_for_year (6968468294728152393) -->
+    <skip />
+    <!-- no translation found for day (7849249054576985912) -->
+    <skip />
+    <!-- no translation found for days (8381828105391141169) -->
+    <skip />
+    <!-- no translation found for hour (1044439788994278057) -->
+    <skip />
+    <!-- no translation found for hours (9008157371441255845) -->
+    <skip />
+    <!-- no translation found for minute (2434431396283136076) -->
+    <skip />
+    <!-- no translation found for minutes (8176836254200264856) -->
+    <skip />
+    <!-- no translation found for second (6620645953323664299) -->
+    <skip />
+    <!-- no translation found for seconds (6416703426008384360) -->
+    <skip />
+    <!-- no translation found for week (7738046527402739781) -->
+    <skip />
+    <!-- no translation found for weeks (3178327674459887377) -->
+    <skip />
+    <!-- no translation found for year (8024790425994085153) -->
+    <skip />
+    <!-- no translation found for years (8592090054773244417) -->
+    <skip />
+    <!-- no translation found for sunday (4811082193700148223) -->
+    <skip />
+    <!-- no translation found for monday (7543713499896911033) -->
+    <skip />
+    <!-- no translation found for tuesday (7962192298359117585) -->
+    <skip />
+    <!-- no translation found for wednesday (5768878309383390437) -->
+    <skip />
+    <!-- no translation found for thursday (5690060634904123607) -->
+    <skip />
+    <!-- no translation found for friday (2718325370375116889) -->
+    <skip />
+    <!-- no translation found for saturday (222899317300942333) -->
+    <skip />
+    <!-- no translation found for every_weekday (8466333034903391066) -->
+    <skip />
+    <!-- no translation found for daily (1661712840773846970) -->
+    <skip />
+    <!-- no translation found for weekly (578642117234613009) -->
+    <skip />
+    <!-- no translation found for monthly (8526124657540210537) -->
+    <skip />
+    <!-- no translation found for yearly (8083067713764127070) -->
+    <skip />
+    <!-- no translation found for VideoView_error_title (1024334251681931859) -->
+    <skip />
+    <!-- no translation found for VideoView_error_text_unknown (3398417247398476771) -->
+    <skip />
+    <!-- no translation found for VideoView_error_button (3144127115413163445) -->
+    <skip />
+    <!-- no translation found for am (5354895493921411502) -->
+    <skip />
+    <!-- no translation found for pm (7206933220587555766) -->
+    <skip />
+    <!-- no translation found for numeric_date (5120078478872821100) -->
+    <skip />
+    <!-- no translation found for wday1_date1_time1_wday2_date2_time2 (7066878981949584861) -->
+    <skip />
+    <!-- no translation found for wday1_date1_wday2_date2 (8671068747172261907) -->
+    <skip />
+    <!-- no translation found for date1_time1_date2_time2 (3645498975775629615) -->
+    <skip />
+    <!-- no translation found for date1_date2 (377057563556488062) -->
+    <skip />
+    <!-- no translation found for time1_time2 (3173474242109288305) -->
+    <skip />
+    <!-- no translation found for time_wday_date (8928955562064570313) -->
+    <skip />
+    <!-- no translation found for wday_date (8794741400546136975) -->
+    <skip />
+    <!-- no translation found for time_date (1922644512833014496) -->
+    <skip />
+    <!-- no translation found for time_wday (1422050241301754712) -->
+    <skip />
+    <!-- no translation found for full_date_month_first (6011143962222283357) -->
+    <skip />
+    <!-- no translation found for full_date_day_first (8621594762705478189) -->
+    <skip />
+    <!-- no translation found for medium_date_month_first (48990963718825728) -->
+    <skip />
+    <!-- no translation found for medium_date_day_first (2898992016440387123) -->
+    <skip />
+    <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
+    <skip />
+    <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
+    <skip />
+    <!-- no translation found for noon (8390796001560682897) -->
+    <skip />
+    <!-- no translation found for Noon (7698941576181064429) -->
+    <skip />
+    <!-- no translation found for midnight (7773339795626486146) -->
+    <skip />
+    <!-- no translation found for Midnight (1260172107848123187) -->
+    <skip />
+    <!-- no translation found for month_day (3356633704511426364) -->
+    <skip />
+    <!-- no translation found for month (3017405760734206414) -->
+    <skip />
+    <!-- no translation found for month_day_year (2435948225709176752) -->
+    <skip />
+    <!-- no translation found for month_year (6228414124777343135) -->
+    <skip />
+    <!-- no translation found for time_of_day (8375993139317154157) -->
+    <skip />
+    <!-- no translation found for date_and_time (9197690194373107109) -->
+    <skip />
+    <!-- no translation found for same_year_md1_md2 (9199324363135981317) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_md1_wday2_md2 (6006392413355305178) -->
+    <skip />
+    <!-- no translation found for same_year_mdy1_mdy2 (1576657593937827090) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_mdy1_wday2_mdy2 (9135935796468891580) -->
+    <skip />
+    <!-- no translation found for same_year_md1_time1_md2_time2 (2172964106375558081) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_md1_time1_wday2_md2_time2 (1702879534101786310) -->
+    <skip />
+    <!-- no translation found for same_year_mdy1_time1_mdy2_time2 (2476443311723358767) -->
+    <skip />
+    <!-- no translation found for same_year_wday1_mdy1_time1_wday2_mdy2_time2 (1564837340334069879) -->
+    <skip />
+    <!-- no translation found for numeric_md1_md2 (8908376522875100300) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_md1_wday2_md2 (3239690882018292077) -->
+    <skip />
+    <!-- no translation found for numeric_mdy1_mdy2 (8883797176939233525) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_mdy1_wday2_mdy2 (4150475769255828954) -->
+    <skip />
+    <!-- no translation found for numeric_md1_time1_md2_time2 (3624746590607741419) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_md1_time1_wday2_md2_time2 (4258040955467298134) -->
+    <skip />
+    <!-- no translation found for numeric_mdy1_time1_mdy2_time2 (3598215409314517987) -->
+    <skip />
+    <!-- no translation found for numeric_wday1_mdy1_time1_wday2_mdy2_time2 (264076937155877259) -->
+    <skip />
+    <!-- no translation found for same_month_md1_md2 (2393563617438036111) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_md1_wday2_md2 (1208946773794057819) -->
+    <skip />
+    <!-- no translation found for same_month_mdy1_mdy2 (3713236637869030492) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_mdy1_wday2_mdy2 (389638922479870472) -->
+    <skip />
+    <!-- no translation found for same_month_md1_time1_md2_time2 (7477075526337542685) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_md1_time1_wday2_md2_time2 (3516978303779391173) -->
+    <skip />
+    <!-- no translation found for same_month_mdy1_time1_mdy2_time2 (7320410992514057310) -->
+    <skip />
+    <!-- no translation found for same_month_wday1_mdy1_time1_wday2_mdy2_time2 (1332950588774239228) -->
+    <skip />
+    <!-- no translation found for abbrev_month_day_year (5767271534015320250) -->
+    <skip />
+    <!-- no translation found for abbrev_month_year (8058929633673942490) -->
+    <skip />
+    <!-- no translation found for abbrev_month_day (458867920693482757) -->
+    <skip />
+    <!-- no translation found for abbrev_month (1674509986330181349) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_sunday (9057662850446501884) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_monday (7358451993082888343) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_tuesday (2282901451170509613) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_wednesday (2100217950343286482) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_thursday (5475158963242863176) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_friday (4081018004819837155) -->
+    <skip />
+    <!-- no translation found for day_of_week_long_saturday (1929694088305891795) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_sunday (6462580883948669820) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_monday (6960587654241349502) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_tuesday (7004462235990108936) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_wednesday (5688564741951314696) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_thursday (1784339868453982400) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_friday (4314577583604069357) -->
+    <skip />
+    <!-- no translation found for day_of_week_medium_saturday (70321191398427845) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_sunday (7403409454572591357) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_monday (5278358100012478239) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_tuesday (5121116040712487059) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_wednesday (1601079579293330319) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_thursday (5863422096017401812) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_friday (2916686031099723960) -->
+    <skip />
+    <!-- no translation found for day_of_week_short_saturday (8521564973195542073) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_sunday (1650484495176707638) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_monday (9133193697786876074) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_tuesday (4012095408481489663) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_wednesday (6279056612496078470) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_thursday (2748599403545071011) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_friday (5037282109124849673) -->
+    <skip />
+    <!-- no translation found for day_of_week_shorter_saturday (3208167155877833783) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_sunday (4683862964821549758) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_monday (6701142261471667000) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_tuesday (9098171980161292477) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_wednesday (655049238289460956) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_thursday (7816913627500884083) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_friday (903301878650619398) -->
+    <skip />
+    <!-- no translation found for day_of_week_shortest_saturday (5359692489649817988) -->
+    <skip />
+    <!-- no translation found for month_long_january (7128497801440564337) -->
+    <skip />
+    <!-- no translation found for month_long_february (7808570514581190617) -->
+    <skip />
+    <!-- no translation found for month_long_march (2061328556983796034) -->
+    <skip />
+    <!-- no translation found for month_long_april (6575007959043269919) -->
+    <skip />
+    <!-- no translation found for month_long_may (8404051103463071121) -->
+    <skip />
+    <!-- no translation found for month_long_june (6255771619238859451) -->
+    <skip />
+    <!-- no translation found for month_long_july (4129177743136800884) -->
+    <skip />
+    <!-- no translation found for month_long_august (5494331003296804494) -->
+    <skip />
+    <!-- no translation found for month_long_september (2691137479752033087) -->
+    <skip />
+    <!-- no translation found for month_long_october (7501261567327243313) -->
+    <skip />
+    <!-- no translation found for month_long_november (8759690753068763664) -->
+    <skip />
+    <!-- no translation found for month_long_december (4505008719696569497) -->
+    <skip />
+    <!-- no translation found for month_medium_january (2315492772833932512) -->
+    <skip />
+    <!-- no translation found for month_medium_february (118412521324313430) -->
+    <skip />
+    <!-- no translation found for month_medium_march (5546835583839352358) -->
+    <skip />
+    <!-- no translation found for month_medium_april (7052559668687733702) -->
+    <skip />
+    <!-- no translation found for month_medium_may (2825303871720116018) -->
+    <skip />
+    <!-- no translation found for month_medium_june (829843667101495271) -->
+    <skip />
+    <!-- no translation found for month_medium_july (5029778226925324789) -->
+    <skip />
+    <!-- no translation found for month_medium_august (8851230594641162805) -->
+    <skip />
+    <!-- no translation found for month_medium_september (8420590486625304647) -->
+    <skip />
+    <!-- no translation found for month_medium_october (1787382806172930239) -->
+    <skip />
+    <!-- no translation found for month_medium_november (675513809622370603) -->
+    <skip />
+    <!-- no translation found for month_medium_december (2934948295928978783) -->
+    <skip />
+    <!-- no translation found for month_shortest_january (6070060405144675883) -->
+    <skip />
+    <!-- no translation found for month_shortest_february (5632605004902176653) -->
+    <skip />
+    <!-- no translation found for month_shortest_march (4304231552356086624) -->
+    <skip />
+    <!-- no translation found for month_shortest_april (1166434066469385532) -->
+    <skip />
+    <!-- no translation found for month_shortest_may (9131326028845529001) -->
+    <skip />
+    <!-- no translation found for month_shortest_june (1875723154506665289) -->
+    <skip />
+    <!-- no translation found for month_shortest_july (2003596275389810773) -->
+    <skip />
+    <!-- no translation found for month_shortest_august (9120245162625763214) -->
+    <skip />
+    <!-- no translation found for month_shortest_september (7980651111022693669) -->
+    <skip />
+    <!-- no translation found for month_shortest_october (3640405450427788312) -->
+    <skip />
+    <!-- no translation found for month_shortest_november (4002935318566146993) -->
+    <skip />
+    <!-- no translation found for month_shortest_december (6213739417171334040) -->
+    <skip />
+    <!-- no translation found for elapsed_time_short_format_mm_ss (1294409362352514646) -->
+    <skip />
+    <!-- no translation found for elapsed_time_short_format_h_mm_ss (2997059666628785039) -->
+    <skip />
+    <!-- no translation found for selectAll (691691810023908884) -->
+    <skip />
+    <!-- no translation found for cut (5845613239192595662) -->
+    <skip />
+    <!-- no translation found for cutAll (4474519683293791451) -->
+    <skip />
+    <!-- no translation found for copy (8603721575469529820) -->
+    <skip />
+    <!-- no translation found for copyAll (4777548804630476932) -->
+    <skip />
+    <!-- no translation found for paste (6458036735811828538) -->
+    <skip />
+    <!-- no translation found for copyUrl (5785708478767435812) -->
+    <skip />
+    <!-- no translation found for inputMethod (7911866729148111492) -->
+    <skip />
+    <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_title (5997772070488639934) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_text (2230118755295375293) -->
+    <skip />
+    <!-- no translation found for ok (4003878536083514869) -->
+    <skip />
+    <!-- no translation found for cancel (1527674037280267012) -->
+    <skip />
+    <!-- no translation found for yes (8185296114406773873) -->
+    <skip />
+    <!-- no translation found for no (2300685350903156262) -->
+    <skip />
+    <!-- no translation found for capital_on (8418242581217554942) -->
+    <skip />
+    <!-- no translation found for capital_off (8870368560477693851) -->
+    <skip />
+    <!-- no translation found for whichApplication (2828159696176255212) -->
+    <skip />
+    <!-- no translation found for alwaysUse (6433627451071144629) -->
+    <skip />
+    <!-- no translation found for clearDefaultHintMsg (5742432113023174321) -->
+    <skip />
+    <!-- no translation found for chooseActivity (7588691622928031978) -->
+    <skip />
+    <!-- no translation found for noApplications (4068560364116066745) -->
+    <skip />
+    <!-- no translation found for aerr_title (2654390351574026098) -->
+    <skip />
+    <!-- no translation found for aerr_application (4917288809565116720) -->
+    <skip />
+    <!-- no translation found for aerr_process (1273819861108073461) -->
+    <skip />
+    <!-- no translation found for anr_title (3305935690891435915) -->
+    <skip />
+    <!-- no translation found for anr_activity_application (1653036325679156678) -->
+    <skip />
+    <!-- no translation found for anr_activity_process (2674027618362070465) -->
+    <skip />
+    <!-- no translation found for anr_application_process (2163656674970221928) -->
+    <skip />
+    <!-- no translation found for anr_process (7747550780123472160) -->
+    <skip />
+    <!-- no translation found for force_close (9020954128872810669) -->
+    <skip />
+    <!-- no translation found for wait (7973775702304037058) -->
+    <skip />
+    <!-- no translation found for debug (857932504764728770) -->
+    <skip />
+    <!-- no translation found for sendText (6158329286172492543) -->
+    <skip />
+    <!-- no translation found for volume_ringtone (4121694816346562058) -->
+    <skip />
+    <!-- no translation found for volume_music (4869950240104717493) -->
+    <skip />
+    <!-- no translation found for volume_call (5723421277753250395) -->
+    <skip />
+    <!-- no translation found for volume_alarm (2752102730973081294) -->
+    <skip />
+    <!-- no translation found for volume_unknown (6908187627672375742) -->
+    <skip />
+    <!-- no translation found for ringtone_default (2873893375149093475) -->
+    <skip />
+    <!-- no translation found for ringtone_default_with_actual (5474076151665761913) -->
+    <skip />
+    <!-- no translation found for ringtone_silent (7477159279081654685) -->
+    <skip />
+    <!-- no translation found for ringtone_picker_title (7055241890764367884) -->
+    <skip />
+    <!-- no translation found for ringtone_unknown (6888219771401173795) -->
+    <skip />
+    <!-- no translation found for wifi_available:one (8168012881468888470) -->
+    <!-- no translation found for wifi_available:other (4666122955807117718) -->
+    <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
+    <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
+    <!-- no translation found for select_character (3735110139249491726) -->
+    <skip />
+    <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
+    <skip />
+    <!-- no translation found for sms_control_title (2742400596989418394) -->
+    <skip />
+    <!-- no translation found for sms_control_message (3447126217666595989) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (8839660939359273650) -->
+    <skip />
+    <!-- no translation found for sms_control_no (909756849988183801) -->
+    <skip />
+    <!-- no translation found for date_time_set (2495199891239480952) -->
+    <skip />
+    <!-- no translation found for default_permission_group (7742780381379652409) -->
+    <skip />
+    <!-- no translation found for no_permissions (85461124044682315) -->
+    <skip />
+    <!-- no translation found for perms_hide (4145325555929151849) -->
+    <skip />
+    <!-- no translation found for perms_show_all (6040194843455403173) -->
+    <skip />
+    <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
+    <skip />
+    <!-- no translation found for usb_storage_title (8699631567051394409) -->
+    <skip />
+    <!-- no translation found for usb_storage_message (5344039189213308733) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
+    <skip />
+    <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
+    <skip />
+    <!-- no translation found for select_input_method (2658280517827502015) -->
+    <skip />
+    <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
+    <skip />
+    <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
+    <skip />
+    <!-- no translation found for candidates_style (7738463880139922176) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 9e165d9..a2fd8d5 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1,574 +1,904 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="BaMmi">Bloqueo de llamadas</string>
-  <string name="CLIRDefaultOffNextCallOff">El valor predeterminado de la restricción de ID es no restringida. Próxima llamada: no restringida</string>
-  <string name="CLIRDefaultOffNextCallOn">El valor predeterminado de la restricción de ID es no restringida. Próxima llamada: restringida</string>
-  <string name="CLIRDefaultOnNextCallOff">El valor predeterminado de la restricción de ID es restringida. Próxima llamada: no restringida</string>
-  <string name="CLIRDefaultOnNextCallOn">El valor predeterminado de la restricción de ID es restringida. Próxima llamada: restringida</string>
-  <string name="CLIRPermanent">Restricción de ID prevista en el modo permanente.</string>
-  <string name="CfMmi">Desvío de llamadas</string>
-  <string name="ClipMmi">ID de llamada entrante</string>
-  <string name="ClirMmi">ID de llamada saliente</string>
-  <string name="CwMmi">Llamada en espera</string>
-  <string name="Midnight">"Media noche"</string>
-  <string name="Noon">"Mediodía"</string>
-  <string name="PinMmi">Cambio de PIN</string>
-  <string name="PwdMmi">Cambio de contraseña</string>
-  <string name="VideoView_error_button">Aceptar</string>
-  <string name="VideoView_error_text_unknown">Se ha producido un error al reproducir el vídeo seleccionado.</string>
-  <string name="VideoView_error_title">Error de reproducción del vídeo</string>
-  <string name="abbrev_month">"<xliff:g id="format">%b</xliff:g>"</string>
-  <string name="abbrev_month_day">"<xliff:g id="format">%-d %b</xliff:g>"</string>
-  <string name="abbrev_month_day_year">"<xliff:g id="format">%-d %b, %Y</xliff:g>"</string>
-  <string name="abbrev_month_year">"<xliff:g id="format">%b %Y</xliff:g>"</string>
-  <string name="activate_keyguard">Activar protección de clave</string>
-  <string name="ago">hace</string>
-  <string name="alwaysUse">Usar siempre esta aplicación para esta actividad</string>
-  <string name="am">"AM"</string>
-  <string name="battery_low_percent_format">Menos de <xliff:g id="number">%d%%</xliff:g>
-    restantes</string>
-  <string name="battery_low_subtitle">Batería baja</string>
-  <string name="battery_low_title">Conectar cargador</string>
-  <string name="battery_status_charging">Cargando\u2026</string>
-  <string name="battery_status_text_percent_format"><xliff:g id="number">%d%%</xliff:g></string>
-  <string name="before">Antes</string>
-  <string name="browserSavedFormData">Datos de formulario guardados</string>
-  <string name="byteShort">b</string>
-  <string name="cancel">Cancelar</string>
-  <string name="capital_off">Desactivar</string>
-  <string name="capital_on">Activar</string>
-  <string name="cfReasonBusy">Desvío de llamadas ocupado</string>
-  <string name="cfReasonNR">Desvío de llamadas no accesible</string>
-  <string name="cfReasonNRy">Desvío de llamadas sin respuesta</string>
-  <string name="cfReasonUnconditional">Desvío de llamadas incondicional</string>
-  <string name="cfTemplateForwarded">{0}: {1}</string>
-  <string name="cfTemplateForwardedTime">{0}: {1} después de {2} segundos</string>
-  <string name="cfTemplateNotForwarded">{0}: No desviada</string>
-  <string name="cfTemplateRegistered">{0}: No desviada ({1})</string>
-  <string name="cfTemplateRegisteredTime">{0}: No desviada ({1} después de {2} segundos)</string>
-  <string name="chooseActivity">Seleccionar una acción</string>
-  <string name="contentServiceSync">Sincronizar</string>
-  <string name="contentServiceSyncNotificationDesc">Sincronizando</string>
-  <string name="contentServiceSyncNotificationTitle">Sincronizar</string>
-  <string name="contentServiceXmppAvailable">XMPP activo</string>
-  <string name="copy">Copiar</string>
-  <string name="copyUrl">Copiar URL</string>
-  <string name="cut">Cortar</string>
-  <string name="daily">Diario</string>
-  <string name="daily_format">h:mm aa</string>
-  <string name="date1_date2">"<xliff:g id="format">%2$s \u2013 %5$s</xliff:g>"</string>
-  <string name="date1_time1_date2_time2">"<xliff:g id="format">%2$s, %3$s \u2013 %5$s, %6$s</xliff:g>"</string>
-  <string name="date_picker_set">Establecer</string>
-  <string name="date_range_separator">" \u2013 "</string>
-  <string name="day">día</string>
-  <string name="day_of_week_long_friday">Viernes</string>
-  <string name="day_of_week_long_monday">Lunes</string>
-  <string name="day_of_week_long_saturday">Sábado</string>
-  <string name="day_of_week_long_sunday">Domingo</string>
-  <string name="day_of_week_long_thursday">Jueves</string>
-  <string name="day_of_week_long_tuesday">Martes</string>
-  <string name="day_of_week_long_wednesday">Miércoles</string>
-  <string name="day_of_week_medium_friday">Vie</string>
-  <string name="day_of_week_medium_monday">Lun</string>
-  <string name="day_of_week_medium_saturday">Sáb</string>
-  <string name="day_of_week_medium_sunday">Dom</string>
-  <string name="day_of_week_medium_thursday">Jue</string>
-  <string name="day_of_week_medium_tuesday">Mar</string>
-  <string name="day_of_week_medium_wednesday">Mié</string>
-  <string name="day_of_week_short_friday">Vi</string>
-  <string name="day_of_week_short_monday">Lu</string>
-  <string name="day_of_week_short_saturday">Sá</string>
-  <string name="day_of_week_short_sunday">Do</string>
-  <string name="day_of_week_short_thursday">Ju</string>
-  <string name="day_of_week_short_tuesday">Ma</string>
-  <string name="day_of_week_short_wednesday">Mi</string>
-  <string name="day_of_week_shorter_friday">V</string>
-  <string name="day_of_week_shorter_monday">L</string>
-  <string name="day_of_week_shorter_saturday">S</string>
-  <string name="day_of_week_shorter_sunday">D</string>
-  <string name="day_of_week_shorter_thursday">J</string>
-  <string name="day_of_week_shorter_tuesday">M</string>
-  <string name="day_of_week_shorter_wednesday">X</string>
-  <string name="day_of_week_shortest_friday">V</string>
-  <string name="day_of_week_shortest_monday">L</string>
-  <string name="day_of_week_shortest_saturday">S</string>
-  <string name="day_of_week_shortest_sunday">D</string>
-  <string name="day_of_week_shortest_thursday">J</string>
-  <string name="day_of_week_shortest_tuesday">M</string>
-  <string name="day_of_week_shortest_wednesday">X</string>
-  <string name="days">días</string>
-  <string name="daysDurationFuturePlural">en <xliff:g id="days">%d</xliff:g> días</string>
-  <string name="daysDurationPastPlural">Hace <xliff:g id="days">%d</xliff:g> días</string>
-  <string name="defaultMsisdnAlphaTag">Msisdn1</string>
-  <string name="defaultVoiceMailAlphaTag">Correo de voz</string>
-  <string name="elapsed_time_short_format_h_mm_ss"><xliff:g id="format">%1$d:%2$02d:%3$02d</xliff:g></string>
-  <string name="elapsed_time_short_format_mm_ss"><xliff:g id="format">%1$02d:%2$02d</xliff:g></string>
-  <string name="ellipsis">\u2026</string>
-  <string name="emergency_call_dialog_call">Llamada de emergencia</string>
-  <string name="emergency_call_dialog_cancel">Cancelar</string>
-  <string name="emergency_call_dialog_number_for_display">Número de emergencia</string>
-  <string name="emergency_call_dialog_text">¿Realizar una llamada de emergencia?</string>
-  <string name="emergency_call_number_uri">tel:112</string>
-  <string name="emptyPhoneNumber">(ningún número de teléfono)</string>
-  <string name="every_weekday">"Todos los días laborables (Lun\u2013Vie)"</string>
-  <string name="factorytest_failed">Fallo al realizar la prueba de fábrica</string>
-  <string name="factorytest_no_action">No se ha encontrado ningún paquete que proporcione la
-        acción FACTORY_TEST.</string>
-  <string name="factorytest_not_system">La acción FACTORY_TEST
-        sólo es compatible con los paquetes instalados en /system/app.</string>
-  <string name="factorytest_reboot">Reiniciar</string>
-  <string name="friday">Viernes</string>
-  <string name="gigabyteShort">Gb</string>
-  <string name="global_action_lock">Bloquear</string>
-  <string name="global_action_power_off">Apagado</string>
-  <string name="global_action_silent_mode_off_status">El sonido está activado</string>
-  <string name="global_action_silent_mode_on_status">El sonido está desactivado</string>
-  <string name="global_action_toggle_silent_mode">Modo silencioso</string>
-  <string name="global_actions">Acciones globales</string>
-  <string name="hour">hora</string>
-  <string name="hours">horas</string>
-  <string name="httpError">Error desconocido</string>
-  <string name="httpErrorAuth">Error de autenticación</string>
-  <string name="httpErrorBadUrl">URL no válida</string>
-  <string name="httpErrorConnect">Fallo al conectar con el servidor</string>
-  <string name="httpErrorFailedSslHandshake">Fallo al realizar SSL mutuo</string>
-  <string name="httpErrorFile">Error en el archivo</string>
-  <string name="httpErrorFileNotFound">Archivo no encontrado</string>
-  <string name="httpErrorIO">Fallo al leer o escribir en el servidor</string>
-  <string name="httpErrorLookup">Host desconocido</string>
-  <string name="httpErrorOk">Aceptar</string>
-  <string name="httpErrorProxyAuth">Error de autenticación de servidor proxy</string>
-  <string name="httpErrorRedirectLoop">Demasiadas redirecciones de servidor</string>
-  <string name="httpErrorTimeout">Agotado el tiempo de espera de conexión con el servidor</string>
-  <string name="httpErrorUnsupportedAuthScheme">Esquema de autenticación no compatible. Fallo al autenticar.</string>
-  <string name="httpErrorUnsupportedScheme">Protocolo no compatible</string>
-  <string name="in">en</string>
-  <string name="keyguard_label_text">Para desbloquear, pulse Menú y luego 0.</string>
-  <string name="keyguard_password_emergency_instructions">Pulse la tecla Llamar para realizar la llamada de emergencia.</string>
-  <string name="keyguard_password_enter_pin_code">Introducir código PIN</string>
-  <string name="keyguard_password_instructions">Introduzca el código de acceso o marque un número de emergencia.</string>
-  <string name="keyguard_password_wrong_pin_code">¡Código PIN incorrecto!</string>
-  <string name="kilobyteShort">Kb</string>
-  <string name="lockscreen_carrier_default">(Fuera de servicio)</string>
-  <string name="lockscreen_carrier_key">gsm.operator.alpha</string>
-  <string name="lockscreen_emergency_call">Llamada de emergencia</string>
-  <string name="lockscreen_instructions_when_pattern_disabled">Pulse Menú para desbloquear</string>
-  <string name="lockscreen_instructions_when_pattern_enabled">Pulse Menú para desbloquear o realice una llamada de emergencia</string>
-  <string name="lockscreen_low_battery">Conectar cargador</string>
-  <string name="lockscreen_missing_sim_instructions">Inserte una tarjeta SIM</string>
-  <string name="lockscreen_missing_sim_message">No hay ninguna tarjeta SIM en el dispositivo</string>
-  <string name="lockscreen_pattern_correct">¡Correcto!</string>
-  <string name="lockscreen_pattern_instructions">Trazar patrón de desbloqueo</string>
-  <string name="lockscreen_pattern_wrong">¡Patrón incorrecto! Inténtelo de nuevo</string>
-  <string name="lockscreen_plugged_in">Cargando (<xliff:g id="number">%d%%</xliff:g>)</string>
-  <string name="lockscreen_screen_locked">Pantalla bloqueada</string>
-  <string name="lockscreen_too_many_failed_attempts_countdown">Inténtelo de nuevo en <xliff:g id="number">%d</xliff:g>  segundos</string>
-  <string name="lockscreen_too_many_failed_attempts_dialog_message">
-        Tiene <xliff:g id="number">%d</xliff:g> intentos fallidos para
-        trazar correctamente su patrón de desbloqueo.\n
-        Inténtelo de nuevo en <xliff:g id="number">%d</xliff:g> segundos.
-    </string>
-  <string name="lockscreen_too_many_failed_attempts_dialog_title">Advertencia de patrón de bloqueo</string>
-  <string name="low_internal_storage_text">Espacio de almacenamiento interno bajo</string>
-  <string name="low_internal_storage_view_text">El dispositivo se está quedando sin espacio de almacenamiento interno</string>
-  <string name="low_internal_storage_view_title">Espacio de almacenamiento interno bajo</string>
-  <string name="megabyteShort">Mb</string>
-  <string name="midnight">"media noche"</string>
-  <string name="minute">minuto</string>
-  <string name="minutes">minutos</string>
-  <string name="mmiComplete">MMI completo</string>
-  <string name="mmiError">Error de red o código MMI no válido.</string>
-  <string name="monday">Lunes</string>
-  <string name="month">"<xliff:g id="format">%B</xliff:g>"</string>
-  <string name="month_day">"<xliff:g id="format">%-d %B</xliff:g>"</string>
-  <string name="month_day_year">"<xliff:g id="format">%-d %B, %Y</xliff:g>"</string>
-  <string name="month_long_april">Abril</string>
-  <string name="month_long_august">Agosto</string>
-  <string name="month_long_december">Diciembre</string>
-  <string name="month_long_february">Febrero</string>
-  <string name="month_long_january">Enero</string>
-  <string name="month_long_july">Julio</string>
-  <string name="month_long_june">Junio</string>
-  <string name="month_long_march">Marzo</string>
-  <string name="month_long_may">Mayo</string>
-  <string name="month_long_november">Noviembre</string>
-  <string name="month_long_october">Octubre</string>
-  <string name="month_long_september">Septiembre</string>
-  <string name="month_medium_april">Abr</string>
-  <string name="month_medium_august">Ago</string>
-  <string name="month_medium_december">Dic</string>
-  <string name="month_medium_february">Feb</string>
-  <string name="month_medium_january">Ene</string>
-  <string name="month_medium_july">Jul</string>
-  <string name="month_medium_june">Jun</string>
-  <string name="month_medium_march">Mar</string>
-  <string name="month_medium_may">May</string>
-  <string name="month_medium_november">Nov</string>
-  <string name="month_medium_october">Oct</string>
-  <string name="month_medium_september">Sep</string>
-  <string name="month_shortest_april">A</string>
-  <string name="month_shortest_august">A</string>
-  <string name="month_shortest_december">D</string>
-  <string name="month_shortest_february">F</string>
-  <string name="month_shortest_january">E</string>
-  <string name="month_shortest_july">E</string>
-  <string name="month_shortest_june">E</string>
-  <string name="month_shortest_march">M</string>
-  <string name="month_shortest_may">M</string>
-  <string name="month_shortest_november">N</string>
-  <string name="month_shortest_october">O</string>
-  <string name="month_shortest_september">S</string>
-  <string name="month_year">"<xliff:g id="format">%B %Y</xliff:g>"</string>
-  <string name="monthly">Mensual</string>
-  <string name="monthly_format">d MMM</string>
-  <string name="more_item_label">Más</string>
-  <string name="no">Cancelar</string>
-  <string name="noApplications">No hay ninguna aplicación disponible para llevar a cabo
-        la acción</string>
-  <string name="no_recent_tasks">Ninguna aplicación reciente</string>
-  <string name="noon">"mediodía"</string>
-  <string name="numeric_date">"<xliff:g id="format">%d/%m/%Y</xliff:g>"</string>
-  <string name="numeric_date_notation">"<xliff:g id="format">%d/%m/%Y</xliff:g>"</string>
-  <string name="numeric_md1_md2">"<xliff:g id="format">%3$s/%2$s \u2013 %8$s/%7$s</xliff:g>"</string>
-  <string name="numeric_md1_time1_md2_time2">"<xliff:g id="format">%3$s/%2$s, %5$s \u2013 %8$s/%7$s, %10$s</xliff:g>"</string>
-  <string name="numeric_mdy1_mdy2">"<xliff:g id="format">%3$s/%2$s/%4$s \u2013 %8$s/%7$s/%9$s</xliff:g>"</string>
-  <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="format">%3$s/%2$s/%4$s, %5$s \u2013 %8$s/%7$s/%9$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %3$s/%2$s, %5$s \u2013 %6$s, %8$s/%7$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %3$s/%2$s \u2013 %6$s, %8$s/%7$s</xliff:g>"</string>
-  <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %3$s/%2$s/%4$s, %5$s \u2013 %6$s, %8$s/%7$s/%9$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %3$s/%2$s/%4$s \u2013 %6$s, %8$s/%7$s/%9$s</xliff:g>"</string>
-  <string name="ok">Aceptar</string>
-  <string name="open_permission_deny">No tiene permiso para abrir esta página.</string>
-  <string name="passwordIncorrect">Contraseña incorrecta</string>
-  <string name="paste">Pegar</string>
-  <string name="permdesc_accessFineLocation">Acceda al sistema de posicionamiento global (GPS) del
-        dispositivo, en caso de que esté disponible.
-        Una aplicación maliciosa puede usar esta función para determinar dónde está y puede
-        consumir batería adicional.</string>
-  <string name="permdesc_accessCoarseLocation">Utilice la base de datos de la red para determinar una
-        ubicación aproximada del dispositivo, en caso de que esté disponible. Una aplicación maliciosa puede usar
-        esta opción para determinar aproximadamente dónde está.</string>
-  <string name="permdesc_accessPhoneInterface">Permite que la aplicación acceda
-        a la interfaz interna del teléfono. Esta función no debería ser necesaria para las aplicaciones normales.</string>
-  <string name="permdesc_accessSurfaceFlinger">Permite que la aplicación use
-        las características de bajo nivel de SurfaceFlinger.</string>
-  <string name="permdesc_addSystemService">Permite que la aplicación publique
-        sus propios servicios de sistema de bajo nivel. Una aplicación maliciosa puede apropiarse del sistema y robar
-        o dañar cualquier dato.</string>
-  <string name="permdesc_brick">Permite que la aplicación deshabilite
-        de forma permanente todo el dispositivo. Esto es muy peligroso.</string>
-  <string name="permdesc_broadcastPackageRemoved">Permite que una aplicación
-        emita una notificación de que se ha eliminado un paquete de la aplicación.
-        Una aplicación maliciosa puede usar esta función para acabar con cualquier otra
-        aplicación que se esté ejecutando.</string>
-  <string name="permdesc_broadcastSticky">Permite que una aplicación envíe
-        emisiones continuas, que permanecen una vez que termina la emisión.
-        Una aplicación maliciosa puede hacer que el dispositivo sea lento o inestable y
-        use demasiada memoria.</string>
-  <string name="permdesc_callPhone">Permite que la aplicación llame
-        a los números de teléfono sin que usted intervenga. Una aplicación maliciosa puede
-        hacer que aparezcan llamadas inesperadas en su factura del teléfono.</string>
-  <string name="permdesc_camera">Permite que la aplicación saque fotos
-        con la cámara. Esto permite que la aplicación capture en cualquier momento
-        imágenes que la cámara esté viendo.</string>
-  <string name="permdesc_changeComponentState">Permite que una aplicación cambie si un
-        componente de otra aplicación está habilitado o no. Una aplicación maliciosa puede usar esta función
-        para deshabilitar importantes capacidades del dispositivo. Se debe tener cuidado con el permiso, ya que
-        los componentes de la aplicación se pueden volver inestables o inconsistentes.
-    </string>
-  <string name="permdesc_changeConfiguration">Permite que una aplicación
-        cambie la configuración actual, como la hora local o el tamaño general de la
-        fuente.</string>
-  <string name="permdesc_clearAppCache">Permite que una aplicación libere memoria de almacenamiento
-        del dispositivo eliminando archivos del directorio caché de la aplicación. El acceso suele estar 
-        muy restringido al proceso del sistema.</string>
-  <string name="permdesc_deleteCacheFiles">Permite que una aplicación elimine
-        archivos de la caché.</string>
-  <string name="permdesc_deletePackages">Permite que una aplicación elimine
-        paquetes Android. Una aplicación maliciosa puede usar esta función para eliminar importantes aplicaciones.</string>
-  <string name="permdesc_devicePower">Permite a la aplicación encender o
-        apagar el dispositivo o mantenerlo encendido.</string>
-  <string name="permdesc_dump">Permite a la aplicación recuperar
-        el estado interno del sistema. Una aplicación maliciosa puede recuperar
-        una gran variedad de información privada y segura que normalmente
-        no debería necesitar nunca.</string>
-  <string name="permdesc_factoryTest">Se ejecuta como una prueba de fabricante de bajo nivel,
-        permitiendo el acceso completo al hardware del dispositivo. Sólo disponible
-        cuando un dispositivo se ejecuta en el modo de prueba del fabricante.</string>
-  <string name="permdesc_flashlight">Permite a la aplicación controlar
-        la linterna.</string>
-  <string name="permdesc_forceBack">Permite a la aplicación hacer que cualquier
-        actividad que esté en primer plano se cierre y pase a segundo plano.
-        Esta función no debería ser necesaria para las aplicaciones normales.</string>
-  <string name="permdesc_fotaUpdate">Permite a una aplicación recibir
-        notifications about pending system updates and trigger their
-        su instalación. Una aplicación maliciosa puede usar esta función para corromper el sistema
-        con actualizaciones no autorizadas o interferir en el proceso
-        de actualización.</string>
-  <string name="permdesc_getTasks">Permite a la aplicación recuperar
-        información sobre tareas que se acaban de ejecutar y tareas que se están ejecutando actualmente. Puede permitir que
-        una aplicación maliciosa
-        descubra información privada sobre otras aplicaciones.</string>
-  <string name="permdesc_hardware_test">Permite a la aplicación controlar
-        distintos periféricos para realizar una prueba de hardware.</string>
-  <string name="permdesc_injectEvents">Permite a una aplicación ofrecer
-        sus propios eventos de entrada (pulsaciones de teclas, etc.) a otras aplicaciones. Una aplicación
-        maliciosa puede usar esta función para controlar el dispositivo.</string>
-  <string name="permdesc_installPackages">Permite a una aplicación instalar paquetes Android
-        nuevos o actualizados. Una aplicación maliciosa puede usar esta función para agregar nuevas aplicaciones con
-        permisos arbitrariamente poderosos.</string>
-  <string name="permdesc_internalSystemWindow">Permite la creación de
-        ventanas destinadas a ser usadas por la interfaz de usuario
-        del sistema interno. No está destinada al uso por aplicaciones normales.</string>
-  <string name="permdesc_manageAppTokens">Permite a las aplicaciones
-        crear y gestionar sus propios credenciales, saltándose su orden Z
-        normal. Esta función no debería ser necesaria para las aplicaciones normales.</string>
-  <string name="permdesc_masterClear">Permite que una aplicación restablezca
-        por completo los valores de fábrica del sistema, borrando todos los datos,
-        la configuración y las aplicaciones instaladas.</string>
-  <string name="permdesc_modifyAudioSettings">Permite que la aplicación modifique
-        la configuración de audio global, como el volumen y el enrutamiento.</string>
-  <string name="permdesc_mount_unmount_filesystems">Permite que la aplicación monte y
-        desmonte archivos del sistema para el almacenamiento extraíble.</string>
-  <string name="permdesc_persistentActivity">Permite que una aplicación convierta
-        partes de sí misma en persistentes, de forma que el sistema no pueda usarlas
-        para otras aplicaciones.</string>
-  <string name="permdesc_raisedThreadPriority">Permite que la aplicación use
-        prioridades de cadena elevadas, lo que puede afectar a la capacidad de respuesta
-        de la interfaz de usuario.</string>
-  <string name="permdesc_readContacts">Permite que una aplicación lea todos
-        los datos (de dirección) de contacto almacenados en su dispositivo. Una aplicación maliciosa
-        puede usar esta función para enviar sus datos a otras personas.</string>
-  <string name="permdesc_readFrameBuffer">Permite que la aplicación
-        lea el contenido del búfer de trama.</string>
-  <string name="permdesc_readInputState">Permite que las aplicaciones vigilen las
-        teclas que pulsa incluso cuando interactúe con otra aplicación (como
-        al introducir una contraseña). Esta función no debería ser necesaria para las aplicaciones normales.</string>
-  <string name="permdesc_readSms">Permite que la aplicación lea
-      los mensajes SMS almacenados en su teléfono o tarjeta SIM. Una aplicación maliciosa
-      puede leer sus mensajes confidenciales.</string>
-  <string name="permdesc_receiveBootCompleted">Permite que una aplicación
-        se inicie en cuanto el sistema haya terminado de arrancar.
-        Esto puede hacer que el dispositivo tarde más en iniciarse y que
-        la aplicación ralentice todo el dispositivo al ejecutarse siempre.</string>
-  <string name="permdesc_receiveMms">Permite que la aplicación reciba
-      y procese mensajes multimedia. Una aplicación maliciosa puede controlar
-      sus mensajes o eliminarlos sin que usted los vea.</string>
-  <string name="permdesc_receiveSms">Permite que la aplicación reciba
-      y procese mensajes de texto. Una aplicación maliciosa puede controlar
-      sus mensajes o eliminarlos sin que usted los vea.</string>
-  <string name="permdesc_receiveWapPush">Permite que la aplicación reciba
-      y procese mensajes WAP. Una aplicación maliciosa puede controlar
-      sus mensajes o eliminarlos sin que usted los vea.</string>
-  <string name="permdesc_recordAudio">Permite que la aplicación acceda
-        a la ruta de grabación de audio.</string>
-  <string name="permdesc_reorderTasks">Permite que una aplicación mueva
-        las tareas a primer plano y a segundo plano. Una aplicación maliciosa puede
-        aparecer en primer plano sin su control.</string>
-  <string name="permdesc_runInstrumentation">Permite que una aplicación
-        inserte su propio código de instrumentación en cualquier otra aplicación.
-        Una aplicación maliciosa puede comprometer todo el sistema. Este
-        permiso sólo es necesario para el desarrollo, nunca para el uso
-        normal del dispositivo.</string>
-  <string name="permdesc_runSetActivityWatcher">Permite que una aplicación
-        controle y supervise el modo en que el sistema inicia las actividades.
-        Una aplicación maliciosa puede comprometer todo el sistema. Este
-        permiso sólo es necesario para el desarrollo, nunca para el uso
-        normal del dispositivo.</string>
-  <string name="permdesc_sendSms">Permite a la aplicación enviar
-      mensajes de texto. Una aplicación maliciosa puede hacerle gastar dinero
-      enviando mensajes sin su confirmación.</string>
-  <string name="permdesc_setAlwaysFinish">Permite a una aplicación
-        controlar si las actividades han acabado en cuanto pasan
-        a segundo plano. Esta función
-        no es necesaria para las aplicaciones normales.</string>
-  <string name="permdesc_setAnimationScale">Permite que una aplicación cambie
-        la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento.</string>
-  <string name="permdesc_setDebugApp">Permite a una aplicación activar
-        la depuración para otra aplicación. Una aplicación maliciosa puede usar esta función
-        para acabar con otras aplicaciones.</string>
-  <string name="permdesc_setOrientation">Permite que una aplicación cambie
-        la rotación de la pantalla en cualquier momento. No debería ser necesaria en
-        aplicaciones normales.</string>
-  <string name="permdesc_setPreferredApplications">Permite que una aplicación
-        modifique sus aplicaciones preferidas. Esta función puede permitir que una aplicación maliciosa
-        cambie silenciosamente las aplicaciones que se están ejecutando y
-        haga que las aplicaciones existentes recopilen datos privados.</string>
-  <string name="permdesc_setProcessLimit">Permite a una aplicación
-        controle el número máximo de procesos que se ejecutarán. Esta función
-        no es necesaria para las aplicaciones normales.</string>
-  <string name="permdesc_setWallpaper">Permite a la aplicación
-        establecer el fondo de escritorio del sistema.</string>
-  <string name="permdesc_signalPersistentProcesses">Permite a la aplicación solicitar que la señal
-        suministrada se envíe a todos los procesos persistentes.</string>
-  <string name="permdesc_statusBar">Permite a las aplicaciones
-        abrir, cerrar o deshabilitar la barra de estado y sus iconos.</string>
-  <string name="permdesc_systemAlertWindow">Permite a una aplicación
-        mostrar ventanas de alerta del sistema. Una aplicación maliciosa puede controlar toda la
-        pantalla del dispositivo.</string>
-  <string name="permdesc_vibrate">Permite a la aplicación controlar
-        el vibrador.</string>
-  <string name="permdesc_writeContacts">Permite a una aplicación modificar los
-        datos (de dirección) de contacto almacenados en su dispositivo. Una aplicación
-        maliciosa puede usar esta función para borrar o modificar sus datos de contacto.</string>
-  <string name="permdesc_writeSettings">Permite a una aplicación modificar los
-        datos de configuración del sistema. Una aplicación maliciosa puede corromper la configuración
-        del sistema.</string>
-  <string name="permdesc_writeSms">Permite a la aplicación escribir
-      mensajes SMS almacenados en su teléfono o tarjeta SIM. Una aplicación maliciosa
-      puede eliminar sus mensajes.</string>
-  <string name="permlab_accessFineLocation">Acceder a ubicación de GPS</string>
-  <string name="permlab_accessCoarseLocation">Acceder a ubicación de red</string>
-  <string name="permlab_accessPhoneInterface">Acceder a la interfaz del teléfono</string>
-  <string name="permlab_accessSurfaceFlinger">Acceder a SurfaceFlinger</string>
-  <string name="permlab_addSystemService">Agregar servicio del sistema</string>
-  <string name="permlab_brick">Deshabilitar dispositivo</string>
-  <string name="permlab_broadcastPackageRemoved">Paquete de emisión eliminado</string>
-  <string name="permlab_broadcastSticky">Intento de emisión permanente</string>
-  <string name="permlab_callPhone">Llamar a números de teléfono</string>
-  <string name="permlab_camera">Cámara</string>
-  <string name="permlab_changeComponentState">Habilitar o deshabilitar componentes de la aplicación</string>
-  <string name="permlab_changeConfiguration">Cambiar configuración</string>
-  <string name="permlab_clearAppCache">Borrar datos de la caché de la aplicación</string>
-  <string name="permlab_deleteCacheFiles">Borrar archivos de caché</string>
-  <string name="permlab_deletePackages">Borrar paquetes</string>
-  <string name="permlab_devicePower">Alimentación del dispositivo</string>
-  <string name="permlab_dump">Volcar estado del sistema</string>
-  <string name="permlab_factoryTest">Prueba de fábrica</string>
-  <string name="permlab_flashlight">Linterna</string>
-  <string name="permlab_forceBack">Restablecer</string>
-  <string name="permlab_fotaUpdate">Instalación de actualización del sistema</string>
-  <string name="permlab_getTasks">Obtener información de tareas</string>
-  <string name="permlab_hardware_test">Prueba de hardware</string>
-  <string name="permlab_injectEvents">Introducir eventos de entrada</string>
-  <string name="permlab_installPackages">Instalar paquetes</string>
-  <string name="permlab_internalSystemWindow">Ventana de sistema interno</string>
-  <string name="permlab_manageAppTokens">Administrar credenciales de aplicación</string>
-  <string name="permlab_masterClear">Restablecimiento de todo el sistema</string>
-  <string name="permlab_modifyAudioSettings">Modificar configuración de audio</string>
-  <string name="permlab_mount_unmount_filesystems">Montar y desmontar archivos del sistema</string>
-  <string name="permlab_persistentActivity">Actividades persistentes</string>
-  <string name="permlab_raisedThreadPriority">Prioridades de cadena elevadas</string>
-  <string name="permlab_readContacts">Leer datos de contacto</string>
-  <string name="permlab_readFrameBuffer">Leer búfer de trama</string>
-  <string name="permlab_readInputState">Leer estado de entrada</string>
-  <string name="permlab_readSms">Leer mensajes SMS/MMS</string>
-  <string name="permlab_receiveBootCompleted">Ejecutar al arrancar</string>
-  <string name="permlab_receiveMms">Recibir mensajes MMS</string>
-  <string name="permlab_receiveSms">Recibir mensajes SMS</string>
-  <string name="permlab_receiveWapPush">Recibir mensajes WAP</string>
-  <string name="permlab_recordAudio">Grabar audio</string>
-  <string name="permlab_reorderTasks">Reordenar tareas</string>
-  <string name="permlab_runInstrumentation">Ejecutar instrumentación</string>
-  <string name="permlab_runSetActivityWatcher">Establecer vigilante de actividades</string>
-  <string name="permlab_sendSms">Enviar mensajes SMS</string>
-  <string name="permlab_setAlwaysFinish">Establecer finalizar siempre</string>
-  <string name="permlab_setAnimationScale">Establecer escala de animación</string>
-  <string name="permlab_setDebugApp">Establecer aplicación de depuración</string>
-  <string name="permlab_setOrientation">Establecer orientación</string>
-  <string name="permlab_setPreferredApplications">Establecer aplicaciones preferidas</string>
-  <string name="permlab_setProcessLimit">Establecer límite de procesos</string>
-  <string name="permlab_setWallpaper">Establecer fondo de escritorio</string>
-  <string name="permlab_signalPersistentProcesses">Señalar procesos persistentes</string>
-  <string name="permlab_statusBar">Controlar la barra de estado</string>
-  <string name="permlab_systemAlertWindow">Ventana de alerta del sistema</string>
-  <string name="permlab_vibrate">Vibrador</string>
-  <string name="permlab_writeContacts">Escribir datos de contactos</string>
-  <string name="permlab_writeSettings">Escribir configuración del sistema</string>
-  <string name="permlab_writeSms">Escribir mensajes SMS/MMS</string>
-  <string name="petabyteShort">Pb</string>
-  <string name="pm">"PM"</string>
-  <string name="power_dialog">Opciones de energía</string>
-  <string name="power_off">Apagado</string>
-  <string name="prepend_shortcut_label">Menú+</string>
-  <string name="preposition_for_date">en %s</string>
-  <string name="preposition_for_time">en %s</string>
-  <string name="preposition_for_year">en %s</string>
-  <string name="safeMode">Modo seguro</string>
-  <string name="same_month_md1_md2">"<xliff:g id="format">%3$s \u2013 %8$s %2$s</xliff:g>"</string>
-  <string name="same_month_md1_time1_md2_time2">"<xliff:g id="format">%3$s %2$s, %5$s \u2013 %8$s %7$s, %10$s</xliff:g>"</string>
-  <string name="same_month_mdy1_mdy2">"<xliff:g id="format">%3$s \u2013 %8$s %2$s, %9$s</xliff:g>"</string>
-  <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="format">%3$s %2$s, %4$s, %5$s \u2013 %8$s %7$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %3$s %2$s, %5$s \u2013 %6$s, %8$s %7$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %3$s %2$s \u2013 %6$s, %8$s %7$s</xliff:g>"</string>
-  <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %3$s %2$s, %4$s, %5$s \u2013 %6$s, %8$s %7$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %3$s %2$s, %4$s \u2013 %6$s, %8$s %7$s, %9$s</xliff:g>"</string>
-  <string name="same_year_md1_md2">"<xliff:g id="format">%3$s %2$s \u2013 %8$s %7$s</xliff:g>"</string>
-  <string name="same_year_md1_time1_md2_time2">"<xliff:g id="format">%3$s %2$s, %5$s \u2013 %8$s %7$s, %10$s</xliff:g>"</string>
-  <string name="same_year_mdy1_mdy2">"<xliff:g id="format">%3$s %2$s \u2013 %8$s %7$s, %9$s</xliff:g>"</string>
-  <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="format">%3$s %2$s, %4$s, %5$s \u2013 %8$s %7$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %3$s %2$s, %5$s \u2013 %6$s, %8$s %7$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %3$s %2$s \u2013 %6$s, %8$s %7$s</xliff:g>"</string>
-  <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %3$s %2$s, %4$s, %5$s \u2013 %6$s, %8$s %7$s, %9$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %3$s %2$s \u2013 %6$s, %8$s %7$s, %9$s</xliff:g>"</string>
-  <string name="saturday">Sábado</string>
-  <string name="save_password_label">Confirmar</string>
-  <string name="save_password_message">¿Quiere que el explorador recuerde esta contraseña?</string>
-  <string name="save_password_never">Nunca</string>
-  <string name="save_password_notnow">Ahora no</string>
-  <string name="save_password_remember">Recordar</string>
-  <string name="screen_lock">Bloquear</string>
-  <string name="screen_progress">Trabajando\u2026</string>
-  <string name="search_go">IR</string>
-  <string name="second">segundo</string>
-  <string name="seconds">segundos</string>
-  <string name="selectAll">Seleccionar todo</string>
-  <string name="selectMenuLabel">Seleccionar</string>
-  <string name="sendText">Seleccionar qué hacer con el texto</string>
-  <string name="serviceClassData">Datos</string>
-  <string name="serviceClassDataAsync">Asíncrono</string>
-  <string name="serviceClassDataSync">Sincronizar</string>
-  <string name="serviceClassFAX">FAX</string>
-  <string name="serviceClassPAD">PAD</string>
-  <string name="serviceClassPacket">Paquete</string>
-  <string name="serviceClassSMS">SMS</string>
-  <string name="serviceClassVoice">Voz</string>
-  <string name="serviceDisabled">Servicio deshabilitado</string>
-  <string name="serviceEnabled">Servicio habilitado</string>
-  <string name="serviceEnabledFor">Servicio habilitado para:</string>
-  <string name="serviceErased">Borrado completado</string>
-  <string name="serviceNotProvisioned">Servicio no previsto.</string>
-  <string name="serviceRegistered">Registro completado</string>
-  <string name="silent_mode">Modo silencioso</string>
-  <string name="simAbsentLabel">No hay SIM o está mal insertada</string>
-  <string name="simNetworkPersonalizationLabel">La SIM no se puede usar en este dispositivo</string>
-  <string name="simPINLabel">PIN de SIM necesario (y actualmente no compatible)</string>
-  <string name="simPUKLabel">PUK de SIM necesario (y actualmente no compatible)</string>
-  <string name="status_bar_applications_title">Aplicación</string>
-  <string name="status_bar_date_format">"<xliff:g id="format">d MMMM, yyyy</xliff:g>"</string>
-  <string name="status_bar_latest_events_title">Últimos eventos</string>
-  <string name="status_bar_no_notifications_title">Notificaciones</string>
-  <string name="status_bar_ongoing_events_title">En curso</string>
-  <string name="status_bar_time_format">"<xliff:g id="format">h:mm AA</xliff:g>"</string>
-  <string name="sunday">Domingo</string>
-  <string name="terabyteShort">Tb</string>
-  <string name="thursday">Jueves</string>
-  <string name="time1_time2">"<xliff:g id="format">%1$s \u2013 %2$s</xliff:g>"</string>
-  <string name="time_date">"<xliff:g id="format">%1$s, %3$s</xliff:g>"</string>
-  <string name="time_picker_set">Establecer</string>
-  <string name="time_wday">"<xliff:g id="format">%1$s, %2$s</xliff:g>"</string>
-  <string name="time_wday_date">"<xliff:g id="format">%1$s, %2$s, %3$s</xliff:g>"</string>
-  <string name="today">Hoy</string>
-  <string name="tomorrow">Mañana</string>
-  <string name="tuesday">Martes</string>
-  <string name="turn_off_radio">Apagar radio</string>
-  <string name="turn_on_radio">Encender radio</string>
-  <string name="unknownName">(desconocido)</string>
-  <string name="untitled">&lt;sin título&gt;</string>
-  <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="format">%1$s, %2$s, %3$s \u2013 %4$s, %5$s, %6$s</xliff:g>"</string>
-  <string name="wday1_date1_wday2_date2">"<xliff:g id="format">%1$s, %2$s \u2013 %4$s, %5$s</xliff:g>"</string>
-  <string name="wday_date">"<xliff:g id="format">%2$s, %3$s</xliff:g>"</string>
-  <string name="web_user_agent">Mozilla/5.0 (Linux; U; Android 0.6; en)
-        AppleWebKit/525.10+ (KHTML, como Gecko) Versión/3.0.4 Mobile Safari/523.12.2</string>
-  <string name="wednesday">Miércoles</string>
-  <string name="week">semana</string>
-  <string name="weekly">"Semanal en <xliff:g id="day">%s</xliff:g>"</string>
-  <string name="weekly_format">d MMM</string>
-  <string name="weeks">semanas</string>
-  <string name="whichApplication">¿Qué aplicación desea usar?</string>
-  <string name="yearly">Anual</string>
-  <string name="yearly_format">yyyy</string>
-  <string name="yes">Aceptar</string>
-  <string name="yesterday">Ayer</string>
+    <string name="byteShort">"b"</string>
+    <string name="kilobyteShort">"Kb"</string>
+    <string name="megabyteShort">"Mb"</string>
+    <string name="gigabyteShort">"Gb"</string>
+    <string name="terabyteShort">"Tb"</string>
+    <string name="petabyteShort">"Pb"</string>
+    <string name="untitled">"&lt;sin título&gt;"</string>
+    <string name="ellipsis">"…"</string>
+    <string name="emptyPhoneNumber">"(ningún número de teléfono)"</string>
+    <string name="unknownName">"(desconocido)"</string>
+    <string name="defaultVoiceMailAlphaTag">"Correo de voz"</string>
+    <string name="defaultMsisdnAlphaTag">"Msisdn1"</string>
+    <string name="mmiError">"Error de red o código MMI no válido."</string>
+    <string name="serviceEnabled">"Servicio habilitado"</string>
+    <string name="serviceEnabledFor">"Servicio habilitado para:"</string>
+    <string name="serviceDisabled">"Servicio deshabilitado"</string>
+    <string name="serviceRegistered">"Registro completado"</string>
+    <string name="serviceErased">"Borrado completado"</string>
+    <string name="passwordIncorrect">"Contraseña incorrecta"</string>
+    <string name="mmiComplete">"MMI completo"</string>
+    <!-- no translation found for badPin (5103184589972647739) -->
+    <skip />
+    <!-- no translation found for badPuk (2200634943393540609) -->
+    <skip />
+    <!-- no translation found for mismatchPin (5055729703806180857) -->
+    <skip />
+    <!-- no translation found for invalidPin (6201854814319326475) -->
+    <skip />
+    <!-- no translation found for needPuk (4788728144863892764) -->
+    <skip />
+    <!-- no translation found for needPuk2 (7056908944942451033) -->
+    <skip />
+    <string name="ClipMmi">"ID de llamada entrante"</string>
+    <string name="ClirMmi">"ID de llamada saliente"</string>
+    <string name="CfMmi">"Desvío de llamadas"</string>
+    <string name="CwMmi">"Llamada en espera"</string>
+    <string name="BaMmi">"Bloqueo de llamadas"</string>
+    <string name="PwdMmi">"Cambio de contraseña"</string>
+    <string name="PinMmi">"Cambio de PIN"</string>
+    <string name="CLIRDefaultOnNextCallOn">"El valor predeterminado de la restricción de ID es restringida. Próxima llamada: restringida"</string>
+    <string name="CLIRDefaultOnNextCallOff">"El valor predeterminado de la restricción de ID es restringida. Próxima llamada: no restringida"</string>
+    <string name="CLIRDefaultOffNextCallOn">"El valor predeterminado de la restricción de ID es no restringida. Próxima llamada: restringida"</string>
+    <string name="CLIRDefaultOffNextCallOff">"El valor predeterminado de la restricción de ID es no restringida. Próxima llamada: no restringida"</string>
+    <string name="serviceNotProvisioned">"Servicio no previsto."</string>
+    <string name="CLIRPermanent">"Restricción de ID prevista en el modo permanente."</string>
+    <string name="serviceClassVoice">"Voz"</string>
+    <string name="serviceClassData">"Datos"</string>
+    <string name="serviceClassFAX">"FAX"</string>
+    <string name="serviceClassSMS">"SMS"</string>
+    <string name="serviceClassDataAsync">"Asíncrono"</string>
+    <string name="serviceClassDataSync">"Sincronizar"</string>
+    <string name="serviceClassPacket">"Paquete"</string>
+    <string name="serviceClassPAD">"PAD"</string>
+    <string name="cfTemplateNotForwarded">"{0}: No desviada"</string>
+    <string name="cfTemplateForwarded">"{0}: {1}"</string>
+    <string name="cfTemplateForwardedTime">"{0}: {1} después de {2} segundos"</string>
+    <string name="cfTemplateRegistered">"{0}: No desviada ({1})"</string>
+    <string name="cfTemplateRegisteredTime">"{0}: No desviada ({1} después de {2} segundos)"</string>
+    <string name="httpErrorOk">"Aceptar"</string>
+    <string name="httpError">"Error desconocido"</string>
+    <string name="httpErrorLookup">"Host desconocido"</string>
+    <string name="httpErrorUnsupportedAuthScheme">"Esquema de autenticación no compatible. Fallo al autenticar."</string>
+    <string name="httpErrorAuth">"Error de autenticación"</string>
+    <string name="httpErrorProxyAuth">"Error de autenticación de servidor proxy"</string>
+    <string name="httpErrorConnect">"Fallo al conectar con el servidor"</string>
+    <string name="httpErrorIO">"Fallo al leer o escribir en el servidor"</string>
+    <string name="httpErrorTimeout">"Agotado el tiempo de espera de conexión con el servidor"</string>
+    <string name="httpErrorRedirectLoop">"Demasiadas redirecciones de servidor"</string>
+    <string name="httpErrorUnsupportedScheme">"Protocolo no compatible"</string>
+    <string name="httpErrorFailedSslHandshake">"Fallo al realizar SSL mutuo"</string>
+    <string name="httpErrorBadUrl">"URL no válida"</string>
+    <string name="httpErrorFile">"Error en el archivo"</string>
+    <string name="httpErrorFileNotFound">"Archivo no encontrado"</string>
+    <!-- no translation found for httpErrorTooManyRequests (3764334538393544875) -->
+    <skip />
+    <string name="contentServiceSync">"Sincronizar"</string>
+    <string name="contentServiceSyncNotificationTitle">"Sincronizar"</string>
+    <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8477597194404210723) -->
+    <skip />
+    <!-- no translation found for low_memory (4191592786596642367) -->
+    <skip />
+    <!-- no translation found for me (4616693653158602117) -->
+    <skip />
+    <string name="power_dialog">"Opciones de energía"</string>
+    <string name="silent_mode">"Modo silencioso"</string>
+    <string name="turn_on_radio">"Encender radio"</string>
+    <string name="turn_off_radio">"Apagar radio"</string>
+    <string name="screen_lock">"Bloquear"</string>
+    <string name="power_off">"Apagado"</string>
+    <!-- no translation found for shutdown_progress (3735034517335251808) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm (699224922526414097) -->
+    <skip />
+    <string name="no_recent_tasks">"Ninguna aplicación reciente"</string>
+    <string name="global_actions">"Acciones globales"</string>
+    <string name="global_action_lock">"Bloquear"</string>
+    <string name="global_action_power_off">"Apagado"</string>
+    <string name="global_action_toggle_silent_mode">"Modo silencioso"</string>
+    <string name="global_action_silent_mode_on_status">"El sonido está desactivado"</string>
+    <string name="global_action_silent_mode_off_status">"El sonido está activado"</string>
+    <string name="safeMode">"Modo seguro"</string>
+    <!-- no translation found for permgrouplab_costMoney (904087853776533085) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_costMoney (4662370555643969515) -->
+    <skip />
+    <!-- no translation found for permgrouplab_messages (2984053976424233925) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_messages (2129093134354989379) -->
+    <skip />
+    <!-- no translation found for permgrouplab_personalInfo (4548406335021507392) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_personalInfo (8499310823817958034) -->
+    <skip />
+    <!-- no translation found for permgrouplab_location (8535677827151907069) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_location (2341662219604651887) -->
+    <skip />
+    <!-- no translation found for permgrouplab_network (3597781730625751831) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_network (8332572695347918340) -->
+    <skip />
+    <!-- no translation found for permgrouplab_accounts (8631201594657951893) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_accounts (443982868906396781) -->
+    <skip />
+    <!-- no translation found for permgrouplab_hardwareControls (5074512938567152139) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_hardwareControls (8772503144945278440) -->
+    <skip />
+    <!-- no translation found for permgrouplab_phoneCalls (7096448531266882376) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_phoneCalls (6703873478653366233) -->
+    <skip />
+    <!-- no translation found for permgrouplab_systemTools (1840847965111633430) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_systemTools (2810337951496685271) -->
+    <skip />
+    <!-- no translation found for permgrouplab_developmentTools (692844635256963358) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_developmentTools (5253915519857796400) -->
+    <skip />
+    <string name="permlab_statusBar">"Controlar la barra de estado"</string>
+    <string name="permdesc_statusBar">"Permite a las aplicaciones abrir, cerrar o deshabilitar la barra de estado y sus iconos."</string>
+    <!-- no translation found for permlab_expandStatusBar (6382500803293284173) -->
+    <skip />
+    <!-- no translation found for permdesc_expandStatusBar (90953162060681436) -->
+    <skip />
+    <!-- no translation found for permlab_processOutgoingCalls (786316295241100144) -->
+    <skip />
+    <!-- no translation found for permdesc_processOutgoingCalls (1655242138991854396) -->
+    <skip />
+    <string name="permlab_receiveSms">"Recibir mensajes SMS"</string>
+    <string name="permdesc_receiveSms">"Permite que la aplicación reciba y procese mensajes de texto. Una aplicación maliciosa puede controlar sus mensajes o eliminarlos sin que usted los vea."</string>
+    <string name="permlab_receiveMms">"Recibir mensajes MMS"</string>
+    <string name="permdesc_receiveMms">"Permite que la aplicación reciba y procese mensajes multimedia. Una aplicación maliciosa puede controlar sus mensajes o eliminarlos sin que usted los vea."</string>
+    <string name="permlab_sendSms">"Enviar mensajes SMS"</string>
+    <string name="permdesc_sendSms">"Permite a la aplicación enviar mensajes de texto. Una aplicación maliciosa puede hacerle gastar dinero enviando mensajes sin su confirmación."</string>
+    <string name="permlab_readSms">"Leer mensajes SMS/MMS"</string>
+    <string name="permdesc_readSms">"Permite que la aplicación lea los mensajes SMS almacenados en su teléfono o tarjeta SIM. Una aplicación maliciosa puede leer sus mensajes confidenciales."</string>
+    <string name="permlab_writeSms">"Escribir mensajes SMS/MMS"</string>
+    <string name="permdesc_writeSms">"Permite a la aplicación escribir mensajes SMS almacenados en su teléfono o tarjeta SIM. Una aplicación maliciosa puede eliminar sus mensajes."</string>
+    <string name="permlab_receiveWapPush">"Recibir mensajes WAP"</string>
+    <string name="permdesc_receiveWapPush">"Permite que la aplicación reciba y procese mensajes WAP. Una aplicación maliciosa puede controlar sus mensajes o eliminarlos sin que usted los vea."</string>
+    <string name="permlab_getTasks">"Obtener información de tareas"</string>
+    <string name="permdesc_getTasks">"Permite a la aplicación recuperar información sobre tareas que se acaban de ejecutar y tareas que se están ejecutando actualmente. Puede permitir que una aplicación maliciosa descubra información privada sobre otras aplicaciones."</string>
+    <string name="permlab_reorderTasks">"Reordenar tareas"</string>
+    <string name="permdesc_reorderTasks">"Permite que una aplicación mueva las tareas a primer plano y a segundo plano. Una aplicación maliciosa puede aparecer en primer plano sin su control."</string>
+    <string name="permlab_setDebugApp">"Establecer aplicación de depuración"</string>
+    <string name="permdesc_setDebugApp">"Permite a una aplicación activar la depuración para otra aplicación. Una aplicación maliciosa puede usar esta función para acabar con otras aplicaciones."</string>
+    <string name="permlab_changeConfiguration">"Cambiar configuración"</string>
+    <string name="permdesc_changeConfiguration">"Permite que una aplicación cambie la configuración actual, como la hora local o el tamaño general de la fuente."</string>
+    <!-- no translation found for permlab_restartPackages (5836367540766044606) -->
+    <skip />
+    <!-- no translation found for permdesc_restartPackages (1764965996765573321) -->
+    <skip />
+    <!-- no translation found for permlab_setProcessForeground (4860990420780868638) -->
+    <skip />
+    <!-- no translation found for permdesc_setProcessForeground (3795477299954784360) -->
+    <skip />
+    <string name="permlab_forceBack">"Restablecer"</string>
+    <string name="permdesc_forceBack">"Permite a la aplicación hacer que cualquier actividad que esté en primer plano se cierre y pase a segundo plano. Esta función no debería ser necesaria para las aplicaciones normales."</string>
+    <string name="permlab_dump">"Volcar estado del sistema"</string>
+    <string name="permdesc_dump">"Permite a la aplicación recuperar el estado interno del sistema. Una aplicación maliciosa puede recuperar una gran variedad de información privada y segura que normalmente no debería necesitar nunca."</string>
+    <string name="permlab_addSystemService">"Agregar servicio del sistema"</string>
+    <string name="permdesc_addSystemService">"Permite que la aplicación publique sus propios servicios de sistema de bajo nivel. Una aplicación maliciosa puede apropiarse del sistema y robar o dañar cualquier dato."</string>
+    <string name="permlab_runSetActivityWatcher">"Establecer vigilante de actividades"</string>
+    <string name="permdesc_runSetActivityWatcher">"Permite que una aplicación controle y supervise el modo en que el sistema inicia las actividades. Una aplicación maliciosa puede comprometer todo el sistema. Este permiso sólo es necesario para el desarrollo, nunca para el uso normal del dispositivo."</string>
+    <string name="permlab_broadcastPackageRemoved">"Paquete de emisión eliminado"</string>
+    <string name="permdesc_broadcastPackageRemoved">"Permite que una aplicación emita una notificación de que se ha eliminado un paquete de la aplicación. Una aplicación maliciosa puede usar esta función para acabar con cualquier otra aplicación que se esté ejecutando."</string>
+    <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
+    <skip />
+    <string name="permlab_setProcessLimit">"Establecer límite de procesos"</string>
+    <string name="permdesc_setProcessLimit">"Permite a una aplicación controle el número máximo de procesos que se ejecutarán. Esta función no es necesaria para las aplicaciones normales."</string>
+    <string name="permlab_setAlwaysFinish">"Establecer finalizar siempre"</string>
+    <string name="permdesc_setAlwaysFinish">"Permite a una aplicación controlar si las actividades han acabado en cuanto pasan a segundo plano. Esta función no es necesaria para las aplicaciones normales."</string>
+    <string name="permlab_fotaUpdate">"Instalación de actualización del sistema"</string>
+    <string name="permdesc_fotaUpdate">"Permite a una aplicación recibir notifications about pending system updates and trigger their su instalación. Una aplicación maliciosa puede usar esta función para corromper el sistema con actualizaciones no autorizadas o interferir en el proceso de actualización."</string>
+    <!-- no translation found for permlab_batteryStats (1598947993704535568) -->
+    <skip />
+    <!-- no translation found for permdesc_batteryStats (6247598531831307989) -->
+    <skip />
+    <string name="permlab_internalSystemWindow">"Ventana de sistema interno"</string>
+    <string name="permdesc_internalSystemWindow">"Permite la creación de ventanas destinadas a ser usadas por la interfaz de usuario del sistema interno. No está destinada al uso por aplicaciones normales."</string>
+    <string name="permlab_systemAlertWindow">"Ventana de alerta del sistema"</string>
+    <string name="permdesc_systemAlertWindow">"Permite a una aplicación mostrar ventanas de alerta del sistema. Una aplicación maliciosa puede controlar toda la pantalla del dispositivo."</string>
+    <string name="permlab_setAnimationScale">"Establecer escala de animación"</string>
+    <string name="permdesc_setAnimationScale">"Permite que una aplicación cambie la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
+    <string name="permlab_manageAppTokens">"Administrar credenciales de aplicación"</string>
+    <string name="permdesc_manageAppTokens">"Permite a las aplicaciones crear y gestionar sus propios credenciales, saltándose su orden Z normal. Esta función no debería ser necesaria para las aplicaciones normales."</string>
+    <string name="permlab_injectEvents">"Introducir eventos de entrada"</string>
+    <string name="permdesc_injectEvents">"Permite a una aplicación ofrecer sus propios eventos de entrada (pulsaciones de teclas, etc.) a otras aplicaciones. Una aplicación maliciosa puede usar esta función para controlar el dispositivo."</string>
+    <string name="permlab_readInputState">"Leer estado de entrada"</string>
+    <string name="permdesc_readInputState">"Permite que las aplicaciones vigilen las teclas que pulsa incluso cuando interactúe con otra aplicación (como al introducir una contraseña). Esta función no debería ser necesaria para las aplicaciones normales."</string>
+    <string name="permlab_setOrientation">"Establecer orientación"</string>
+    <string name="permdesc_setOrientation">"Permite que una aplicación cambie la rotación de la pantalla en cualquier momento. No debería ser necesaria en aplicaciones normales."</string>
+    <string name="permlab_signalPersistentProcesses">"Señalar procesos persistentes"</string>
+    <string name="permdesc_signalPersistentProcesses">"Permite a la aplicación solicitar que la señal suministrada se envíe a todos los procesos persistentes."</string>
+    <string name="permlab_persistentActivity">"Actividades persistentes"</string>
+    <string name="permdesc_persistentActivity">"Permite que una aplicación convierta partes de sí misma en persistentes, de forma que el sistema no pueda usarlas para otras aplicaciones."</string>
+    <string name="permlab_deletePackages">"Borrar paquetes"</string>
+    <string name="permdesc_deletePackages">"Permite que una aplicación elimine paquetes Android. Una aplicación maliciosa puede usar esta función para eliminar importantes aplicaciones."</string>
+    <!-- no translation found for permlab_clearAppUserData (3858185484601410171) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppUserData (7233537744753081136) -->
+    <skip />
+    <string name="permlab_deleteCacheFiles">"Borrar archivos de caché"</string>
+    <string name="permdesc_deleteCacheFiles">"Permite que una aplicación elimine archivos de la caché."</string>
+    <!-- no translation found for permlab_getPackageSize (6743556676630447973) -->
+    <skip />
+    <!-- no translation found for permdesc_getPackageSize (2893996655828539776) -->
+    <skip />
+    <string name="permlab_installPackages">"Instalar paquetes"</string>
+    <string name="permdesc_installPackages">"Permite a una aplicación instalar paquetes Android nuevos o actualizados. Una aplicación maliciosa puede usar esta función para agregar nuevas aplicaciones con permisos arbitrariamente poderosos."</string>
+    <string name="permlab_clearAppCache">"Borrar datos de la caché de la aplicación"</string>
+    <string name="permdesc_clearAppCache">"Permite que una aplicación libere memoria de almacenamiento del dispositivo eliminando archivos del directorio caché de la aplicación. El acceso suele estar muy restringido al proceso del sistema."</string>
+    <!-- no translation found for permlab_readLogs (6653488552442991707) -->
+    <skip />
+    <!-- no translation found for permdesc_readLogs (356352685800884319) -->
+    <skip />
+    <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
+    <skip />
+    <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
+    <skip />
+    <string name="permlab_changeComponentState">"Habilitar o deshabilitar componentes de la aplicación"</string>
+    <string name="permdesc_changeComponentState">"Permite que una aplicación cambie si un componente de otra aplicación está habilitado o no. Una aplicación maliciosa puede usar esta función para deshabilitar importantes capacidades del dispositivo. Se debe tener cuidado con el permiso, ya que los componentes de la aplicación se pueden volver inestables o inconsistentes."</string>
+    <string name="permlab_setPreferredApplications">"Establecer aplicaciones preferidas"</string>
+    <string name="permdesc_setPreferredApplications">"Permite que una aplicación modifique sus aplicaciones preferidas. Esta función puede permitir que una aplicación maliciosa cambie silenciosamente las aplicaciones que se están ejecutando y haga que las aplicaciones existentes recopilen datos privados."</string>
+    <string name="permlab_writeSettings">"Escribir configuración del sistema"</string>
+    <string name="permdesc_writeSettings">"Permite a una aplicación modificar los datos de configuración del sistema. Una aplicación maliciosa puede corromper la configuración del sistema."</string>
+    <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
+    <skip />
+    <!-- no translation found for permlab_writeGservices (296370685945777755) -->
+    <skip />
+    <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
+    <skip />
+    <string name="permlab_receiveBootCompleted">"Ejecutar al arrancar"</string>
+    <string name="permdesc_receiveBootCompleted">"Permite que una aplicación se inicie en cuanto el sistema haya terminado de arrancar. Esto puede hacer que el dispositivo tarde más en iniciarse y que la aplicación ralentice todo el dispositivo al ejecutarse siempre."</string>
+    <string name="permlab_broadcastSticky">"Intento de emisión permanente"</string>
+    <string name="permdesc_broadcastSticky">"Permite que una aplicación envíe emisiones continuas, que permanecen una vez que termina la emisión. Una aplicación maliciosa puede hacer que el dispositivo sea lento o inestable y use demasiada memoria."</string>
+    <string name="permlab_readContacts">"Leer datos de contacto"</string>
+    <string name="permdesc_readContacts">"Permite que una aplicación lea todos los datos (de dirección) de contacto almacenados en su dispositivo. Una aplicación maliciosa puede usar esta función para enviar sus datos a otras personas."</string>
+    <string name="permlab_writeContacts">"Escribir datos de contactos"</string>
+    <string name="permdesc_writeContacts">"Permite a una aplicación modificar los datos (de dirección) de contacto almacenados en su dispositivo. Una aplicación maliciosa puede usar esta función para borrar o modificar sus datos de contacto."</string>
+    <!-- no translation found for permlab_writeOwnerData (8036840529708535113) -->
+    <skip />
+    <!-- no translation found for permdesc_writeOwnerData (5873447528845878348) -->
+    <skip />
+    <!-- no translation found for permlab_readOwnerData (1847040178513733757) -->
+    <skip />
+    <!-- no translation found for permdesc_readOwnerData (7563299529149214764) -->
+    <skip />
+    <!-- no translation found for permlab_readCalendar (2111238731453410895) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (4408253940601239114) -->
+    <skip />
+    <!-- no translation found for permlab_writeCalendar (7518052789370653396) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCalendar (8057304232140147596) -->
+    <skip />
+    <!-- no translation found for permlab_accessMockLocation (321094551062270213) -->
+    <skip />
+    <!-- no translation found for permdesc_accessMockLocation (3651565866471419739) -->
+    <skip />
+    <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
+    <skip />
+    <string name="permlab_accessFineLocation">"Acceder a ubicación de GPS"</string>
+    <string name="permdesc_accessFineLocation">"Acceda al sistema de posicionamiento global (GPS) del dispositivo, en caso de que esté disponible. Una aplicación maliciosa puede usar esta función para determinar dónde está y puede consumir batería adicional."</string>
+    <string name="permlab_accessCoarseLocation">"Acceder a ubicación de red"</string>
+    <string name="permdesc_accessCoarseLocation">"Utilice la base de datos de la red para determinar una ubicación aproximada del dispositivo, en caso de que esté disponible. Una aplicación maliciosa puede usar esta opción para determinar aproximadamente dónde está."</string>
+    <string name="permlab_accessSurfaceFlinger">"Acceder a SurfaceFlinger"</string>
+    <string name="permdesc_accessSurfaceFlinger">"Permite que la aplicación use las características de bajo nivel de SurfaceFlinger."</string>
+    <string name="permlab_readFrameBuffer">"Leer búfer de trama"</string>
+    <string name="permdesc_readFrameBuffer">"Permite que la aplicación lea el contenido del búfer de trama."</string>
+    <string name="permlab_modifyAudioSettings">"Modificar configuración de audio"</string>
+    <string name="permdesc_modifyAudioSettings">"Permite que la aplicación modifique la configuración de audio global, como el volumen y el enrutamiento."</string>
+    <string name="permlab_recordAudio">"Grabar audio"</string>
+    <string name="permdesc_recordAudio">"Permite que la aplicación acceda a la ruta de grabación de audio."</string>
+    <string name="permlab_camera">"Cámara"</string>
+    <string name="permdesc_camera">"Permite que la aplicación saque fotos con la cámara. Esto permite que la aplicación capture en cualquier momento imágenes que la cámara esté viendo."</string>
+    <string name="permlab_brick">"Deshabilitar dispositivo"</string>
+    <string name="permdesc_brick">"Permite que la aplicación deshabilite de forma permanente todo el dispositivo. Esto es muy peligroso."</string>
+    <!-- no translation found for permlab_reboot (8844650672567077423) -->
+    <skip />
+    <!-- no translation found for permdesc_reboot (4704919552870918328) -->
+    <skip />
+    <string name="permlab_mount_unmount_filesystems">"Montar y desmontar archivos del sistema"</string>
+    <string name="permdesc_mount_unmount_filesystems">"Permite que la aplicación monte y desmonte archivos del sistema para el almacenamiento extraíble."</string>
+    <string name="permlab_vibrate">"Vibrador"</string>
+    <string name="permdesc_vibrate">"Permite a la aplicación controlar el vibrador."</string>
+    <string name="permlab_flashlight">"Linterna"</string>
+    <string name="permdesc_flashlight">"Permite a la aplicación controlar la linterna."</string>
+    <string name="permlab_hardware_test">"Prueba de hardware"</string>
+    <string name="permdesc_hardware_test">"Permite a la aplicación controlar distintos periféricos para realizar una prueba de hardware."</string>
+    <string name="permlab_callPhone">"Llamar a números de teléfono"</string>
+    <string name="permdesc_callPhone">"Permite que la aplicación llame a los números de teléfono sin que usted intervenga. Una aplicación maliciosa puede hacer que aparezcan llamadas inesperadas en su factura del teléfono."</string>
+    <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
+    <skip />
+    <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
+    <skip />
+    <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
+    <skip />
+    <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
+    <skip />
+    <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
+    <skip />
+    <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
+    <skip />
+    <!-- no translation found for permlab_modifyPhoneState (7791696535097912313) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyPhoneState (6352405226410454770) -->
+    <skip />
+    <!-- no translation found for permlab_readPhoneState (7320082586621086653) -->
+    <skip />
+    <!-- no translation found for permdesc_readPhoneState (8004450067066407969) -->
+    <skip />
+    <!-- no translation found for permlab_wakeLock (1591164750935072136) -->
+    <skip />
+    <!-- no translation found for permdesc_wakeLock (160471538196734936) -->
+    <skip />
+    <string name="permlab_devicePower">"Alimentación del dispositivo"</string>
+    <string name="permdesc_devicePower">"Permite a la aplicación encender o apagar el dispositivo o mantenerlo encendido."</string>
+    <string name="permlab_factoryTest">"Prueba de fábrica"</string>
+    <string name="permdesc_factoryTest">"Se ejecuta como una prueba de fabricante de bajo nivel, permitiendo el acceso completo al hardware del dispositivo. Sólo disponible cuando un dispositivo se ejecuta en el modo de prueba del fabricante."</string>
+    <string name="permlab_setWallpaper">"Establecer fondo de escritorio"</string>
+    <string name="permdesc_setWallpaper">"Permite a la aplicación establecer el fondo de escritorio del sistema."</string>
+    <!-- no translation found for permlab_setWallpaperHints (4192438316932517807) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaperHints (738757439960921674) -->
+    <skip />
+    <string name="permlab_masterClear">"Restablecimiento de todo el sistema"</string>
+    <string name="permdesc_masterClear">"Permite que una aplicación restablezca por completo los valores de fábrica del sistema, borrando todos los datos, la configuración y las aplicaciones instaladas."</string>
+    <!-- no translation found for permlab_setTimeZone (477196167239548690) -->
+    <skip />
+    <!-- no translation found for permdesc_setTimeZone (8564892020460841198) -->
+    <skip />
+    <!-- no translation found for permlab_getAccounts (2764070033402295170) -->
+    <skip />
+    <!-- no translation found for permdesc_getAccounts (1203491378748649898) -->
+    <skip />
+    <!-- no translation found for permlab_accessNetworkState (2032916924886010827) -->
+    <skip />
+    <!-- no translation found for permdesc_accessNetworkState (7081329402551195933) -->
+    <skip />
+    <!-- no translation found for permlab_createNetworkSockets (4706698319966917864) -->
+    <skip />
+    <!-- no translation found for permdesc_createNetworkSockets (2580337178778551792) -->
+    <skip />
+    <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
+    <skip />
+    <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
+    <skip />
+    <!-- no translation found for permlab_changeNetworkState (2710779001260856872) -->
+    <skip />
+    <!-- no translation found for permdesc_changeNetworkState (8076109230787022270) -->
+    <skip />
+    <!-- no translation found for permlab_accessWifiState (3613679494230374297) -->
+    <skip />
+    <!-- no translation found for permdesc_accessWifiState (8226508433563326925) -->
+    <skip />
+    <!-- no translation found for permlab_changeWifiState (6043889338995432957) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWifiState (7829372845909567994) -->
+    <skip />
+    <!-- no translation found for permlab_bluetoothAdmin (5513286736585647334) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (1838208497914347365) -->
+    <skip />
+    <!-- no translation found for permlab_bluetooth (6378797624765639115) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetooth (8592386018922265273) -->
+    <skip />
+    <!-- no translation found for permlab_disableKeyguard (4574886811903233903) -->
+    <skip />
+    <!-- no translation found for permdesc_disableKeyguard (815972646344251271) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncSettings (8818819977141505127) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncSettings (8454705401908767847) -->
+    <skip />
+    <!-- no translation found for permlab_writeSyncSettings (4514911143753152941) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSyncSettings (7630627689635091836) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncStats (5748337739678952863) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncStats (582551457321957183) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
+    <skip />
+    <!-- no translation found for phoneTypes:0 (6070018634209800981) -->
+    <!-- no translation found for phoneTypes:1 (1514509689885965711) -->
+    <!-- no translation found for phoneTypes:2 (497473201754095234) -->
+    <!-- no translation found for phoneTypes:3 (5554432614281047787) -->
+    <!-- no translation found for phoneTypes:4 (2222084401110150993) -->
+    <!-- no translation found for phoneTypes:5 (2290007103906353121) -->
+    <!-- no translation found for phoneTypes:6 (6930783706213719251) -->
+    <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
+    <!-- no translation found for emailAddressTypes:0 (1540640638077615417) -->
+    <!-- no translation found for emailAddressTypes:1 (4252853367575831977) -->
+    <!-- no translation found for emailAddressTypes:2 (7158046581744435718) -->
+    <!-- no translation found for emailAddressTypes:3 (3625034471181268169) -->
+    <!-- no translation found for postalAddressTypes:0 (5732960259696659380) -->
+    <!-- no translation found for postalAddressTypes:1 (7132240704786130285) -->
+    <!-- no translation found for postalAddressTypes:2 (1317604357745852817) -->
+    <!-- no translation found for postalAddressTypes:3 (1582953598462826702) -->
+    <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
+    <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
+    <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
+    <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
+    <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
+    <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
+    <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
+    <!-- no translation found for imProtocols:0 (3318725788774688043) -->
+    <!-- no translation found for imProtocols:1 (1787713387022932886) -->
+    <!-- no translation found for imProtocols:2 (6751174158442316516) -->
+    <!-- no translation found for imProtocols:3 (1151283347465052653) -->
+    <!-- no translation found for imProtocols:4 (2157980008878817934) -->
+    <!-- no translation found for imProtocols:5 (7836237460308230767) -->
+    <!-- no translation found for imProtocols:6 (1180789904462172516) -->
+    <!-- no translation found for imProtocols:7 (21955111672779862) -->
+    <string name="keyguard_password_enter_pin_code">"Introducir código PIN"</string>
+    <string name="keyguard_password_wrong_pin_code">"¡Código PIN incorrecto!"</string>
+    <string name="keyguard_label_text">"Para desbloquear, pulse Menú y luego 0."</string>
+    <string name="emergency_call_dialog_number_for_display">"Número de emergencia"</string>
+    <string name="lockscreen_carrier_default">"(Fuera de servicio)"</string>
+    <string name="lockscreen_screen_locked">"Pantalla bloqueada"</string>
+    <string name="lockscreen_instructions_when_pattern_enabled">"Pulse Menú para desbloquear o realice una llamada de emergencia"</string>
+    <string name="lockscreen_instructions_when_pattern_disabled">"Pulse Menú para desbloquear"</string>
+    <string name="lockscreen_pattern_instructions">"Trazar patrón de desbloqueo"</string>
+    <string name="lockscreen_emergency_call">"Llamada de emergencia"</string>
+    <string name="lockscreen_pattern_correct">"¡Correcto!"</string>
+    <string name="lockscreen_pattern_wrong">"¡Patrón incorrecto! Inténtelo de nuevo"</string>
+    <string name="lockscreen_plugged_in">"Cargando (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+    <string name="lockscreen_low_battery">"Conectar cargador"</string>
+    <!-- no translation found for lockscreen_missing_sim_message_short (5051192587315492957) -->
+    <skip />
+    <string name="lockscreen_missing_sim_message">"No hay ninguna tarjeta SIM en el dispositivo"</string>
+    <string name="lockscreen_missing_sim_instructions">"Inserte una tarjeta SIM"</string>
+    <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_message (1005803622871256359) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_instructions (5033160098036646955) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_locked_message (7398401200962556379) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (5939537246164692076) -->
+    <skip />
+    <!-- unknown placeholder BREAK in lockscreen_too_many_failed_attempts_dialog_message -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (1569017295989454551) -->
+    <skip />
+    <string name="lockscreen_too_many_failed_attempts_countdown">"Inténtelo de nuevo en <xliff:g id="NUMBER">%d</xliff:g> segundos"</string>
+    <!-- no translation found for lockscreen_forgot_pattern_button_text (4219994639843985488) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_too_many_attempts (7504679498838839295) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_instructions (6542400673357252011) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_username_hint (6378418320242015111) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_password_hint (3224230234042131153) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_submit_button (5562051040043760034) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
+    <skip />
+    <!-- unknown placeholder FORMAT in status_bar_time_format -->
+    <skip />
+    <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
+    <skip />
+    <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
+    <skip />
+    <!-- no translation found for hour_ampm (7665432130905376251) -->
+    <skip />
+    <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
+    <skip />
+    <!-- no translation found for status_bar_clear_all_button (2202004591253243750) -->
+    <skip />
+    <string name="status_bar_no_notifications_title">"Notificaciones"</string>
+    <string name="status_bar_ongoing_events_title">"En curso"</string>
+    <string name="status_bar_latest_events_title">"Últimos eventos"</string>
+    <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g>"</string>
+    <string name="battery_status_charging">"Cargando…"</string>
+    <string name="battery_low_title">"Conectar cargador"</string>
+    <string name="battery_low_subtitle">"Batería baja"</string>
+    <string name="battery_low_percent_format">"Menos de <xliff:g id="NUMBER">%d%%</xliff:g> restantes"</string>
+    <string name="factorytest_failed">"Fallo al realizar la prueba de fábrica"</string>
+    <string name="factorytest_not_system">"La acción FACTORY_TEST sólo es compatible con los paquetes instalados en /system/app."</string>
+    <string name="factorytest_no_action">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST."</string>
+    <string name="factorytest_reboot">"Reiniciar"</string>
+    <string name="save_password_label">"Confirmar"</string>
+    <string name="save_password_message">"¿Quiere que el explorador recuerde esta contraseña?"</string>
+    <string name="save_password_notnow">"Ahora no"</string>
+    <string name="save_password_remember">"Recordar"</string>
+    <string name="save_password_never">"Nunca"</string>
+    <string name="open_permission_deny">"No tiene permiso para abrir esta página."</string>
+    <!-- no translation found for text_copied (6106873823411904723) -->
+    <skip />
+    <string name="more_item_label">"Más"</string>
+    <string name="prepend_shortcut_label">"Menú+"</string>
+    <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
+    <skip />
+    <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
+    <skip />
+    <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
+    <skip />
+    <string name="search_go">"IR"</string>
+    <string name="today">"Hoy"</string>
+    <string name="yesterday">"Ayer"</string>
+    <string name="tomorrow">"Mañana"</string>
+    <!-- no translation found for oneMonthDurationPast (3402179395240209557) -->
+    <skip />
+    <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
+    <skip />
+    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
+    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
+    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
+    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
+    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
+    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
+    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
+    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
+    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
+    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
+    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
+    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
+    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
+    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
+    <!-- no translation found for in_num_days:one (5608475533104443893) -->
+    <!-- no translation found for in_num_days:other (3827193006163842267) -->
+    <string name="preposition_for_date">"en %s"</string>
+    <string name="preposition_for_time">"en %s"</string>
+    <string name="preposition_for_year">"en %s"</string>
+    <string name="day">"día"</string>
+    <string name="days">"días"</string>
+    <string name="hour">"hora"</string>
+    <string name="hours">"horas"</string>
+    <string name="minute">"minuto"</string>
+    <string name="minutes">"minutos"</string>
+    <string name="second">"segundo"</string>
+    <string name="seconds">"segundos"</string>
+    <string name="week">"semana"</string>
+    <string name="weeks">"semanas"</string>
+    <!-- no translation found for year (8024790425994085153) -->
+    <skip />
+    <!-- no translation found for years (8592090054773244417) -->
+    <skip />
+    <string name="sunday">"Domingo"</string>
+    <string name="monday">"Lunes"</string>
+    <string name="tuesday">"Martes"</string>
+    <string name="wednesday">"Miércoles"</string>
+    <string name="thursday">"Jueves"</string>
+    <string name="friday">"Viernes"</string>
+    <string name="saturday">"Sábado"</string>
+    <string name="every_weekday">"Todos los días laborables (Lun–Vie)"</string>
+    <string name="daily">"Diario"</string>
+    <string name="weekly">"Semanal en <xliff:g id="DAY">%s</xliff:g>"</string>
+    <string name="monthly">"Mensual"</string>
+    <string name="yearly">"Anual"</string>
+    <string name="VideoView_error_title">"Error de reproducción del vídeo"</string>
+    <string name="VideoView_error_text_unknown">"Se ha producido un error al reproducir el vídeo seleccionado."</string>
+    <string name="VideoView_error_button">"Aceptar"</string>
+    <string name="am">"AM"</string>
+    <string name="pm">"PM"</string>
+    <!-- unknown placeholder FORMAT in numeric_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in wday1_date1_time1_wday2_date2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in wday1_date1_wday2_date2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in date1_time1_date2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in date1_date2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time1_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time_wday_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in wday_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time_wday -->
+    <skip />
+    <!-- no translation found for full_date_month_first (6011143962222283357) -->
+    <skip />
+    <!-- no translation found for full_date_day_first (8621594762705478189) -->
+    <skip />
+    <!-- no translation found for medium_date_month_first (48990963718825728) -->
+    <skip />
+    <!-- no translation found for medium_date_day_first (2898992016440387123) -->
+    <skip />
+    <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
+    <skip />
+    <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
+    <skip />
+    <string name="noon">"mediodía"</string>
+    <string name="Noon">"Mediodía"</string>
+    <string name="midnight">"media noche"</string>
+    <string name="Midnight">"Media noche"</string>
+    <!-- unknown placeholder FORMAT in month_day -->
+    <skip />
+    <!-- unknown placeholder FORMAT in month -->
+    <skip />
+    <!-- unknown placeholder FORMAT in month_day_year -->
+    <skip />
+    <!-- unknown placeholder FORMAT in month_year -->
+    <skip />
+    <!-- no translation found for time_of_day (8375993139317154157) -->
+    <skip />
+    <!-- no translation found for date_and_time (9197690194373107109) -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_md1_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_md1_wday2_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_mdy1_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_wday2_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_md1_time1_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_md1_time1_wday2_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_mdy1_time1_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_time1_wday2_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_md1_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_md1_wday2_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_mdy1_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_wday2_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_md1_time1_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_md1_time1_wday2_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_mdy1_time1_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_time1_wday2_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_md1_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_md1_wday2_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_mdy1_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_wday2_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_md1_time1_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_md1_time1_wday2_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_mdy1_time1_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_time1_wday2_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month_day_year -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month_year -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month_day -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month -->
+    <skip />
+    <string name="day_of_week_long_sunday">"Domingo"</string>
+    <string name="day_of_week_long_monday">"Lunes"</string>
+    <string name="day_of_week_long_tuesday">"Martes"</string>
+    <string name="day_of_week_long_wednesday">"Miércoles"</string>
+    <string name="day_of_week_long_thursday">"Jueves"</string>
+    <string name="day_of_week_long_friday">"Viernes"</string>
+    <string name="day_of_week_long_saturday">"Sábado"</string>
+    <string name="day_of_week_medium_sunday">"Dom"</string>
+    <string name="day_of_week_medium_monday">"Lun"</string>
+    <string name="day_of_week_medium_tuesday">"Mar"</string>
+    <string name="day_of_week_medium_wednesday">"Mié"</string>
+    <string name="day_of_week_medium_thursday">"Jue"</string>
+    <string name="day_of_week_medium_friday">"Vie"</string>
+    <string name="day_of_week_medium_saturday">"Sáb"</string>
+    <string name="day_of_week_short_sunday">"Do"</string>
+    <string name="day_of_week_short_monday">"Lu"</string>
+    <string name="day_of_week_short_tuesday">"Ma"</string>
+    <string name="day_of_week_short_wednesday">"Mi"</string>
+    <string name="day_of_week_short_thursday">"Ju"</string>
+    <string name="day_of_week_short_friday">"Vi"</string>
+    <string name="day_of_week_short_saturday">"Sá"</string>
+    <string name="day_of_week_shorter_sunday">"D"</string>
+    <string name="day_of_week_shorter_monday">"L"</string>
+    <string name="day_of_week_shorter_tuesday">"M"</string>
+    <string name="day_of_week_shorter_wednesday">"X"</string>
+    <string name="day_of_week_shorter_thursday">"J"</string>
+    <string name="day_of_week_shorter_friday">"V"</string>
+    <string name="day_of_week_shorter_saturday">"S"</string>
+    <string name="day_of_week_shortest_sunday">"D"</string>
+    <string name="day_of_week_shortest_monday">"L"</string>
+    <string name="day_of_week_shortest_tuesday">"M"</string>
+    <string name="day_of_week_shortest_wednesday">"X"</string>
+    <string name="day_of_week_shortest_thursday">"J"</string>
+    <string name="day_of_week_shortest_friday">"V"</string>
+    <string name="day_of_week_shortest_saturday">"S"</string>
+    <string name="month_long_january">"Enero"</string>
+    <string name="month_long_february">"Febrero"</string>
+    <string name="month_long_march">"Marzo"</string>
+    <string name="month_long_april">"Abril"</string>
+    <string name="month_long_may">"Mayo"</string>
+    <string name="month_long_june">"Junio"</string>
+    <string name="month_long_july">"Julio"</string>
+    <string name="month_long_august">"Agosto"</string>
+    <string name="month_long_september">"Septiembre"</string>
+    <string name="month_long_october">"Octubre"</string>
+    <string name="month_long_november">"Noviembre"</string>
+    <string name="month_long_december">"Diciembre"</string>
+    <string name="month_medium_january">"Ene"</string>
+    <string name="month_medium_february">"Feb"</string>
+    <string name="month_medium_march">"Mar"</string>
+    <string name="month_medium_april">"Abr"</string>
+    <string name="month_medium_may">"May"</string>
+    <string name="month_medium_june">"Jun"</string>
+    <string name="month_medium_july">"Jul"</string>
+    <string name="month_medium_august">"Ago"</string>
+    <string name="month_medium_september">"Sep"</string>
+    <string name="month_medium_october">"Oct"</string>
+    <string name="month_medium_november">"Nov"</string>
+    <string name="month_medium_december">"Dic"</string>
+    <string name="month_shortest_january">"E"</string>
+    <string name="month_shortest_february">"F"</string>
+    <string name="month_shortest_march">"M"</string>
+    <string name="month_shortest_april">"A"</string>
+    <string name="month_shortest_may">"M"</string>
+    <string name="month_shortest_june">"E"</string>
+    <string name="month_shortest_july">"E"</string>
+    <string name="month_shortest_august">"A"</string>
+    <string name="month_shortest_september">"S"</string>
+    <string name="month_shortest_october">"O"</string>
+    <string name="month_shortest_november">"N"</string>
+    <string name="month_shortest_december">"D"</string>
+    <!-- unknown placeholder FORMAT in elapsed_time_short_format_mm_ss -->
+    <skip />
+    <!-- unknown placeholder FORMAT in elapsed_time_short_format_h_mm_ss -->
+    <skip />
+    <string name="selectAll">"Seleccionar todo"</string>
+    <string name="cut">"Cortar"</string>
+    <!-- no translation found for cutAll (4474519683293791451) -->
+    <skip />
+    <string name="copy">"Copiar"</string>
+    <!-- no translation found for copyAll (4777548804630476932) -->
+    <skip />
+    <string name="paste">"Pegar"</string>
+    <string name="copyUrl">"Copiar URL"</string>
+    <!-- no translation found for inputMethod (7911866729148111492) -->
+    <skip />
+    <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
+    <skip />
+    <string name="low_internal_storage_view_title">"Espacio de almacenamiento interno bajo"</string>
+    <string name="low_internal_storage_view_text">"El dispositivo se está quedando sin espacio de almacenamiento interno"</string>
+    <string name="ok">"Aceptar"</string>
+    <string name="cancel">"Cancelar"</string>
+    <string name="yes">"Aceptar"</string>
+    <string name="no">"Cancelar"</string>
+    <string name="capital_on">"Activar"</string>
+    <string name="capital_off">"Desactivar"</string>
+    <string name="whichApplication">"¿Qué aplicación desea usar?"</string>
+    <string name="alwaysUse">"Usar siempre esta aplicación para esta actividad"</string>
+    <!-- no translation found for clearDefaultHintMsg (5742432113023174321) -->
+    <skip />
+    <string name="chooseActivity">"Seleccionar una acción"</string>
+    <string name="noApplications">"No hay ninguna aplicación disponible para llevar a cabo la acción"</string>
+    <!-- no translation found for aerr_title (2654390351574026098) -->
+    <skip />
+    <!-- no translation found for aerr_application (4917288809565116720) -->
+    <skip />
+    <!-- no translation found for aerr_process (1273819861108073461) -->
+    <skip />
+    <!-- no translation found for anr_title (3305935690891435915) -->
+    <skip />
+    <!-- no translation found for anr_activity_application (1653036325679156678) -->
+    <skip />
+    <!-- no translation found for anr_activity_process (2674027618362070465) -->
+    <skip />
+    <!-- no translation found for anr_application_process (2163656674970221928) -->
+    <skip />
+    <!-- no translation found for anr_process (7747550780123472160) -->
+    <skip />
+    <!-- no translation found for force_close (9020954128872810669) -->
+    <skip />
+    <!-- no translation found for wait (7973775702304037058) -->
+    <skip />
+    <!-- no translation found for debug (857932504764728770) -->
+    <skip />
+    <string name="sendText">"Seleccionar qué hacer con el texto"</string>
+    <!-- no translation found for volume_ringtone (4121694816346562058) -->
+    <skip />
+    <!-- no translation found for volume_music (4869950240104717493) -->
+    <skip />
+    <!-- no translation found for volume_call (5723421277753250395) -->
+    <skip />
+    <!-- no translation found for volume_alarm (2752102730973081294) -->
+    <skip />
+    <!-- no translation found for volume_unknown (6908187627672375742) -->
+    <skip />
+    <!-- no translation found for ringtone_default (2873893375149093475) -->
+    <skip />
+    <!-- no translation found for ringtone_default_with_actual (5474076151665761913) -->
+    <skip />
+    <!-- no translation found for ringtone_silent (7477159279081654685) -->
+    <skip />
+    <!-- no translation found for ringtone_picker_title (7055241890764367884) -->
+    <skip />
+    <!-- no translation found for ringtone_unknown (6888219771401173795) -->
+    <skip />
+    <!-- no translation found for wifi_available:one (8168012881468888470) -->
+    <!-- no translation found for wifi_available:other (4666122955807117718) -->
+    <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
+    <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
+    <!-- no translation found for select_character (3735110139249491726) -->
+    <skip />
+    <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
+    <skip />
+    <!-- no translation found for sms_control_title (2742400596989418394) -->
+    <skip />
+    <!-- no translation found for sms_control_message (3447126217666595989) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (8839660939359273650) -->
+    <skip />
+    <!-- no translation found for sms_control_no (909756849988183801) -->
+    <skip />
+    <!-- no translation found for date_time_set (2495199891239480952) -->
+    <skip />
+    <!-- no translation found for default_permission_group (7742780381379652409) -->
+    <skip />
+    <!-- no translation found for no_permissions (85461124044682315) -->
+    <skip />
+    <!-- no translation found for perms_hide (4145325555929151849) -->
+    <skip />
+    <!-- no translation found for perms_show_all (6040194843455403173) -->
+    <skip />
+    <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
+    <skip />
+    <!-- no translation found for usb_storage_title (8699631567051394409) -->
+    <skip />
+    <!-- no translation found for usb_storage_message (5344039189213308733) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
+    <skip />
+    <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
+    <skip />
+    <!-- no translation found for select_input_method (2658280517827502015) -->
+    <skip />
+    <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
+    <skip />
+    <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
+    <skip />
+    <!-- no translation found for candidates_style (7738463880139922176) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it-rIT/strings.xml b/core/res/res/values-it-rIT/strings.xml
deleted file mode 100644
index 412648d..0000000
--- a/core/res/res/values-it-rIT/strings.xml
+++ /dev/null
@@ -1,818 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="BaMmi">Blocco chiamate</string>
-  <string name="CLIRDefaultOffNextCallOff">Impostazioni predefinite ID chiamante su non limitato. Chiamata successiva: senza limitazioni</string>
-  <string name="CLIRDefaultOffNextCallOn">Impostazioni predefinite ID chiamante su non limitato. Chiamata successiva: con limitazioni</string>
-  <string name="CLIRDefaultOnNextCallOff">Impostazioni predefinite ID chiamante su limitato. Chiamata successiva: senza limitazioni</string>
-  <string name="CLIRDefaultOnNextCallOn">Impostazioni predefinite ID chiamante su limitato. Chiamata successiva: con limitazioni</string>
-  <string name="CLIRPermanent">Impossibile modificare l'impostazione dell'ID chiamante.</string>
-  <string name="CfMmi">Trasferimento chiamata</string>
-  <string name="ClipMmi">ID chiamante in ingresso</string>
-  <string name="ClirMmi">ID chiamante in uscita</string>
-  <string name="CwMmi">Chiamata in attesa</string>
-  <string name="Midnight">"Mezzanotte"</string>
-  <string name="Noon">"Pomeriggio"</string>
-  <string name="PinMmi">Cambio PIN</string>
-  <string name="PwdMmi">Cambio password</string>
-  <string name="VideoView_error_button">OK</string>
-  <string name="VideoView_error_text_unknown">Impossibile riprodurre il video.</string>
-  <string name="VideoView_error_title">Impossibile riprodurre il video</string>
-  <string name="abbrev_month">"<xliff:g id="format">%b</xliff:g>"</string>
-  <string name="abbrev_month_day">"<xliff:g id="format">%-d %b</xliff:g>"</string>
-  <string name="abbrev_month_day_year">"<xliff:g id="format">%-d %b %Y</xliff:g>"</string>
-  <string name="abbrev_month_year">"<xliff:g id="format">%b %Y</xliff:g>"</string>
-  <string name="activate_keyguard">Blocco schermo</string>
-  <string name="aerr_application">L'applicazione <xliff:g id="application">%1$s</xliff:g>
-        (processo <xliff:g id="process">%2$s</xliff:g>) è stata interrotta in maniera imprevista. Riprovare.</string>
-  <string name="aerr_process">Il processo <xliff:g id="process">%1$s</xliff:g> è
-        stata interrotto in maniera imprevista. Riprovare.</string>
-  <string name="aerr_title">Spiacenti.</string>
-  <string name="ago">fa</string>
-  <string name="alwaysUse">Utilizzare come impostazione predefinita per questa azione.</string>
-  <string name="am">"AM"</string>
-  <string name="anr_activity_application">L'attività <xliff:g id="activity">%1$s</xliff:g> (nell'applicazione <xliff:g id="application">%2$s</xliff:g>) non risponde.</string>
-  <string name="anr_activity_process">L'attività <xliff:g id="activity">%1$s</xliff:g> (nel processo <xliff:g id="process">%2$s</xliff:g>) non risponde.</string>
-  <string name="anr_application_process">L'applicazione <xliff:g id="application">%1$s</xliff:g> (nel processo <xliff:g id="process">%2$s</xliff:g>) non risponde.</string>
-  <string name="anr_process">Il processo <xliff:g id="process">%1$s</xliff:g> non risponde.</string>
-  <string name="anr_title">Spiacenti!</string>
-  <string name="badPin">Il vecchio PIN digitato non è corretto.</string>
-  <string name="badPuk">Il codice PUK digitato non è corretto.</string>
-  <string name="battery_low_percent_format">Meno di <xliff:g id="number">%d%%</xliff:g>
-    rimanente.</string>
-  <string name="battery_low_subtitle">Batteria quasi scarica:</string>
-  <string name="battery_low_title">Collegare il caricabatterie</string>
-  <string name="battery_status_charging">Sotto carica\u2026</string>
-  <string name="battery_status_text_percent_format">
-					<xliff:g id="number">%d%%</xliff:g>
-				</string>
-  <string name="before">Prima</string>
-  <string name="browserSavedFormData">Salvataggio dei dati del modulo completato.</string>
-  <string name="byteShort">B</string>
-  <string name="cancel">Annulla</string>
-  <string name="capital_off">OFF</string>
-  <string name="capital_on">ON</string>
-  <string name="cfReasonBusy">Trasferimento chiamata: Occupato</string>
-  <string name="cfReasonNR">Trasferimento chiamata: Non raggiungibile</string>
-  <string name="cfReasonNRy">Trasferimento chiamata: Nessuna risposta</string>
-  <string name="cfReasonUnconditional">Trasferimento chiamata: Sempre</string>
-  <string name="cfTemplateForwarded">{0}: {1}</string>
-  <string name="cfTemplateForwardedTime">{0}: {1} dopo {2} secondi</string>
-  <string name="cfTemplateNotForwarded">{0}: Non trasferita</string>
-  <string name="cfTemplateRegistered">{0}: Non trasferita</string>
-  <string name="cfTemplateRegisteredTime">{0}: Non trasferita</string>
-  <string name="chooseActivity">Selezionare un'azione</string>
-  <string name="clearDefaultHintMsg">Cancella impostazione predefinita in Impostazioni Home &gt; Applicazioni &gt; Gestisci applicazioni.</string>
-  <string name="compass_accuracy_banner">La bussola necessita di calibrazione</string>
-  <string name="compass_accuracy_notificaction_body">Scuotere delicatamente il telefono per eseguire la calibrazione.</string>
-  <string name="compass_accuracy_notificaction_title">Calibra bussola</string>
-  <string name="contentServiceSync">Sincronizza</string>
-  <string name="contentServiceSyncErrorNotificationDesc">Problemi nella sincronizzazione.</string>
-  <string name="contentServiceSyncNotificationDesc">Sincronizzazione in corso</string>
-  <string name="contentServiceSyncNotificationTitle">Sincronizza</string>
-  <string name="contentServiceTooManyDeletesNotificationDesc">Troppe eliminazioni di %s.</string>
-  <string name="contentServiceXmppAvailable">XMPP Attivo</string>
-  <string name="copy">Copia</string>
-  <string name="copyAll">Copia tutto</string>
-  <string name="copyUrl">Copia URL</string>
-  <string name="cut">Taglia</string>
-  <string name="cutAll">Taglia tutto</string>
-  <string name="daily">Giornaliero</string>
-  <string name="daily_format">h:mm aa</string>
-  <string name="date1_date2">"<xliff:g id="format">%2$s \u2013 %5$s</xliff:g>"</string>
-  <string name="date1_time1_date2_time2">"<xliff:g id="format">%2$s, %3$s \u2013 %5$s, %6$s</xliff:g>"</string>
-  <string name="date_picker_month">mese</string>
-  <string name="date_picker_set">Imposta</string>
-  <string name="date_range_separator">" \u2013 "</string>
-  <string name="date_time_set">Imposta</string>
-  <string name="day">giorno</string>
-  <string name="day_of_week_long_friday">Venerdì</string>
-  <string name="day_of_week_long_monday">Lunedì</string>
-  <string name="day_of_week_long_saturday">Sabato</string>
-  <string name="day_of_week_long_sunday">Domenica</string>
-  <string name="day_of_week_long_thursday">Giovedì</string>
-  <string name="day_of_week_long_tuesday">Martedì</string>
-  <string name="day_of_week_long_wednesday">Mercoledì</string>
-  <string name="day_of_week_medium_friday">Ven</string>
-  <string name="day_of_week_medium_monday">Lun</string>
-  <string name="day_of_week_medium_saturday">Sab</string>
-  <string name="day_of_week_medium_sunday">Dom</string>
-  <string name="day_of_week_medium_thursday">Gio</string>
-  <string name="day_of_week_medium_tuesday">Mar</string>
-  <string name="day_of_week_medium_wednesday">Mer</string>
-  <string name="day_of_week_short_friday">Ve</string>
-  <string name="day_of_week_short_monday">Lu</string>
-  <string name="day_of_week_short_saturday">S</string>
-  <string name="day_of_week_short_sunday">D</string>
-  <string name="day_of_week_short_thursday">G</string>
-  <string name="day_of_week_short_tuesday">M</string>
-  <string name="day_of_week_short_wednesday">Me</string>
-  <string name="day_of_week_shorter_friday">V</string>
-  <string name="day_of_week_shorter_monday">L</string>
-  <string name="day_of_week_shorter_saturday">S</string>
-  <string name="day_of_week_shorter_sunday">D</string>
-  <string name="day_of_week_shorter_thursday">G</string>
-  <string name="day_of_week_shorter_tuesday">M</string>
-  <string name="day_of_week_shorter_wednesday">M</string>
-  <string name="day_of_week_shortest_friday">F</string>
-  <string name="day_of_week_shortest_monday">M</string>
-  <string name="day_of_week_shortest_saturday">S</string>
-  <string name="day_of_week_shortest_sunday">D</string>
-  <string name="day_of_week_shortest_thursday">G</string>
-  <string name="day_of_week_shortest_tuesday">M</string>
-  <string name="day_of_week_shortest_wednesday">M</string>
-  <string name="days">giorni</string>
-  <string name="daysDurationFuturePlural">tra <xliff:g id="days">%d</xliff:g> giorni</string>
-  <string name="daysDurationPastPlural"><xliff:g id="days">%d</xliff:g> giorni fa</string>
-  <string name="debug">Debug</string>
-  <string name="defaultMsisdnAlphaTag">MSISDN1</string>
-  <string name="defaultVoiceMailAlphaTag">Posta vocale</string>
-  <string name="default_permission_group">Predefinito</string>
-  <string name="elapsed_time_short_format_h_mm_ss">
-					<xliff:g id="format">%1$d:%2$02d:%3$02d</xliff:g>
-				</string>
-  <string name="elapsed_time_short_format_mm_ss">
-					<xliff:g id="format">%1$02d:%2$02d</xliff:g>
-				</string>
-  <string name="ellipsis">\u2026</string>
-  <string name="emergency_call_dialog_call">Chiamata di emergenza</string>
-  <string name="emergency_call_dialog_cancel">Annulla</string>
-  <string name="emergency_call_dialog_number_for_display">Numero di emergenza</string>
-  <string name="emergency_call_dialog_text">Effettuare una chiamata di emergenza?</string>
-  <string name="emergency_call_number_uri">tel:112</string>
-  <string name="emptyPhoneNumber">(Nessun numero telefonico)</string>
-  <string name="every_weekday">"Ogni settimana (Lun\u2013Fri)"</string>
-  <string name="factorytest_failed">Test del produttore non riuscito</string>
-  <string name="factorytest_no_action">Impossibile trovare un pacchetto che fornisca l'azione
-        FACTORY_TEST.</string>
-  <string name="factorytest_not_system">L'azione FACTORY_TEST
-        è supportata solo per i pacchetti installati in /system/app.</string>
-  <string name="factorytest_reboot">Riavvia</string>
-  <string name="force_close">Forza chiusura</string>
-  <string name="friday">Venerdì</string>
-  <string name="gigabyteShort">GB</string>
-  <string name="global_action_lock">Blocco schermo</string>
-  <string name="global_action_power_off">Spegni</string>
-  <string name="global_action_silent_mode_off_status">Suono attivato</string>
-  <string name="global_action_silent_mode_on_status">Suono disattivato</string>
-  <string name="global_action_toggle_silent_mode">Modalità automatica</string>
-  <string name="global_actions">Opzioni telefono</string>
-  <string name="googlewebcontenthelper_loading">Caricamento in corso\u2026</string>
-  <string name="hour">ora</string>
-  <string name="hours">ore</string>
-  <string name="httpError">La pagina Web contiene un errore.</string>
-  <string name="httpErrorAuth">Impossibile completare l'autenticazione.</string>
-  <string name="httpErrorBadUrl">Impossibile aprire la pagina perché l'URL non è valido.</string>
-  <string name="httpErrorConnect">Impossibile stabilire una connessione con il server.</string>
-  <string name="httpErrorFailedSslHandshake">Impossibile stabilire una connessione sicura.</string>
-  <string name="httpErrorFile">Impossibile accedere al file.</string>
-  <string name="httpErrorFileNotFound">Impossibile trovare il file richiesto.</string>
-  <string name="httpErrorIO">Impossibile comunicare con il server. Riprovare più tardi.</string>
-  <string name="httpErrorLookup">Impossibile trovare l'URL.</string>
-  <string name="httpErrorOk">OK</string>
-  <string name="httpErrorProxyAuth">Impossibile completare l'autenticazione tramite il server proxy.</string>
-  <string name="httpErrorRedirectLoop">La pagina contiene troppi reindirizzamenti server.</string>
-  <string name="httpErrorTimeout">La connessione con il server è scaduta.</string>
-  <string name="httpErrorTooManyRequests">Troppe richieste in corso di elaborazione. Riprovare più tardi.</string>
-  <string name="httpErrorUnsupportedAuthScheme">Lo schema di autenticazione del sito non è supportato.</string>
-  <string name="httpErrorUnsupportedScheme">Il protocollo non è supportato.</string>
-  <string name="in">in</string>
-  <string name="invalidPin">Digitare un PIN compreso tra 4 e 8 numeri.</string>
-  <string name="keyguard_label_text">Per sbloccare premere Menu quindi 0.</string>
-  <string name="keyguard_password_emergency_instructions">Premere il pulsante di chiamata per effettuare una chiamata di emergenza.</string>
-  <string name="keyguard_password_enter_pin_code">Immettere il codice PIN:</string>
-  <string name="keyguard_password_instructions">Immettere la password o digitare un numero di emergenza.</string>
-  <string name="keyguard_password_wrong_pin_code">Codice PIN errato.</string>
-  <string name="kilobyteShort">KB</string>
-  <string name="lockscreen_carrier_default">(Nessun servizio)</string>
-  <string name="lockscreen_carrier_key">gsm.operator.alpha</string>
-  <string name="lockscreen_emergency_call">Chiamata di emergenza</string>
-  <string name="lockscreen_failed_attempts_almost_glogin">
-        Il codice di sblocco è stato immesso in maniera errata <xliff:g id="number">%d</xliff:g> volte.
-       Dopo <xliff:g id="number">%d</xliff:g> ulteriori tentativi non riusciti,
-       sarà necessario sbloccare il telefono tramite l'accesso Google.\n\n
-       Riprovare tra <xliff:g id="number">%d</xliff:g> secondi.
-    </string>
-  <string name="lockscreen_forgot_pattern_button_text">Password dimenticata?</string>
-  <string name="lockscreen_glogin_instructions">Per sbloccare,\neffettuare l'accesso con l'account Google:</string>
-  <string name="lockscreen_glogin_invalid_input">Nome utente o password non valida.</string>
-  <string name="lockscreen_glogin_password_hint">Password</string>
-  <string name="lockscreen_glogin_submit_button">Accedi</string>
-  <string name="lockscreen_glogin_too_many_attempts">Troppi tentativi di immissione codice!</string>
-  <string name="lockscreen_glogin_username_hint">Nome utente (e-mail)</string>
-  <string name="lockscreen_instructions_when_pattern_disabled">Premere Menu per sbloccare.</string>
-  <string name="lockscreen_instructions_when_pattern_enabled">Premere Menu per sbloccare o effettuare una chiamata di emergenza.</string>
-  <string name="lockscreen_low_battery">Collegare il caricabatterie.</string>
-  <string name="lockscreen_missing_sim_instructions">Inserire una scheda SIM.</string>
-  <string name="lockscreen_missing_sim_message">Nessuna scheda SIM nel telefono.</string>
-  <string name="lockscreen_missing_sim_message_short">Nessuna scheda SIM.</string>
-  <string name="lockscreen_network_locked_message">Rete bloccata</string>
-  <string name="lockscreen_pattern_correct">Corretto!</string>
-  <string name="lockscreen_pattern_instructions">Digitare il codice per sbloccare:</string>
-  <string name="lockscreen_pattern_wrong">Riprovare:</string>
-  <string name="lockscreen_plugged_in">Sotto carica (<xliff:g id="number">%d%%</xliff:g>)</string>
-  <string name="lockscreen_screen_locked">Blocco schermo</string>
-  <string name="lockscreen_sim_locked_message">La scheda SIM è bloccata.</string>
-  <string name="lockscreen_sim_puk_locked_instructions">Contattare il centro servizi.</string>
-  <string name="lockscreen_sim_puk_locked_message">La scheda SIM è bloccata con il codice PUK.</string>
-  <string name="lockscreen_sim_unlock_progress_dialog_message">Sblocco della scheda SIM in corso\u2026</string>
-  <string name="lockscreen_too_many_failed_attempts_countdown">Riprovare tra <xliff:g id="number">%d</xliff:g> secondi.</string>
-  <string name="lockscreen_too_many_failed_attempts_dialog_message">
-        Il codice di sblocco è stato digitato erroneamente <xliff:g id="number">%d</xliff:g> volte.
-        \n\nRiprovare tra <xliff:g id="number">%d</xliff:g> secondi.
-    </string>
-  <string name="lockscreen_too_many_failed_attempts_dialog_title">Avviso codice blocco</string>
-  <string name="low_internal_storage_view_text">Memoria del telefono insufficiente.</string>
-  <string name="low_internal_storage_view_title">Spazio insufficiente</string>
-  <string name="low_memory">La memoria del telefono è piena. Eliminare alcuni file per liberare spazio.</string>
-  <string name="me">Me</string>
-  <string name="megabyteShort">MB</string>
-  <string name="menu_delete_shortcut_label">elimina</string>
-  <string name="menu_enter_shortcut_label">enter</string>
-  <string name="menu_space_shortcut_label">spazio</string>
-  <string name="midnight">"Mezzanotte"</string>
-  <string name="minute">min</string>
-  <string name="minutes">min</string>
-  <string name="mismatchPin">Il codice PIN inserito è errato.</string>
-  <string name="mmiComplete">MMI completato.</string>
-  <string name="mmiError">Problema di connessione o codice MMI non valido.</string>
-  <string name="monday">Lunedì</string>
-  <string name="month">"<xliff:g id="format">%B</xliff:g>"</string>
-  <string name="month_day">"<xliff:g id="format">%-d %B</xliff:g>"</string>
-  <string name="month_day_year">"<xliff:g id="format">%-d %B %Y</xliff:g>"</string>
-  <string name="month_long_april">Aprile</string>
-  <string name="month_long_august">Agosto</string>
-  <string name="month_long_december">Dicembre</string>
-  <string name="month_long_february">Febbraio</string>
-  <string name="month_long_january">Gennaio</string>
-  <string name="month_long_july">Luglio</string>
-  <string name="month_long_june">Giugno</string>
-  <string name="month_long_march">Marzo</string>
-  <string name="month_long_may">Maggio</string>
-  <string name="month_long_november">Novembre</string>
-  <string name="month_long_october">Ottobre</string>
-  <string name="month_long_september">Settembre</string>
-  <string name="month_medium_april">Apr</string>
-  <string name="month_medium_august">Ago</string>
-  <string name="month_medium_december">Dic</string>
-  <string name="month_medium_february">Feb</string>
-  <string name="month_medium_january">Gen</string>
-  <string name="month_medium_july">Lug</string>
-  <string name="month_medium_june">Giu</string>
-  <string name="month_medium_march">Mar</string>
-  <string name="month_medium_may">Mag</string>
-  <string name="month_medium_november">Nov</string>
-  <string name="month_medium_october">Ott</string>
-  <string name="month_medium_september">Set</string>
-  <string name="month_shortest_april">A</string>
-  <string name="month_shortest_august">A</string>
-  <string name="month_shortest_december">D</string>
-  <string name="month_shortest_february">F</string>
-  <string name="month_shortest_january">G</string>
-  <string name="month_shortest_july">L</string>
-  <string name="month_shortest_june">G</string>
-  <string name="month_shortest_march">M</string>
-  <string name="month_shortest_may">M</string>
-  <string name="month_shortest_november">N</string>
-  <string name="month_shortest_october">O</string>
-  <string name="month_shortest_september">S</string>
-  <string name="month_year">"<xliff:g id="format">%B %Y</xliff:g>"</string>
-  <string name="monthly">Mensile</string>
-  <string name="monthly_format">g MMM</string>
-  <string name="more_item_label">Altro</string>
-  <string name="needPuk2">Digitare il codice PUK2 per sbloccare la scheda SIM.</string>
-  <string name="no">Annulla</string>
-  <string name="noApplications">Nessuna applicazione può eseguire questa azione.</string>
-  <string name="no_permissions">Nessuna autorizzazione richiesta</string>
-  <string name="no_recent_tasks">Nessuna applicazione recente.</string>
-  <string name="noon">"pomeriggio"</string>
-  <string name="numeric_date">"<xliff:g id="format">%d/%m/%Y</xliff:g>"</string>
-  <string name="numeric_date_notation">"<xliff:g id="format">%d/%m/%y</xliff:g>"</string>
-  <string name="numeric_md1_md2">"<xliff:g id="format">%3$s/%2$s \u2013 %8$s/%7$s</xliff:g>"</string>
-  <string name="numeric_md1_time1_md2_time2">"<xliff:g id="format">%3$s/%2$s, %5$s \u2013 %8$s/%7$s, %10$s</xliff:g>"</string>
-  <string name="numeric_mdy1_mdy2">"<xliff:g id="format">%3$s/%2$s/%4$s \u2013 %8$s/%7$s/%9$s</xliff:g>"</string>
-  <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="format">%3$s/%2$s/%4$s, %5$s \u2013 %8$s/%7$s/%9$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s %3$s/%2$s, %5$s \u2013 %6$s %8$s/%7$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %3$s/%2$s \u2013 %6$s, %8$s/%7$s</xliff:g>"</string>
-  <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s %3$s/%2$s/%4$s, %5$s \u2013 %6$s %8$s/%7$s/%9$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s %3$s/%2$s/%4$s \u2013 %6$s %8$s/%7$s/%9$s</xliff:g>"</string>
-  <string name="ok">OK</string>
-  <string name="oneMonthDurationPast">1 mese fa</string>
-  <string name="open_permission_deny">Non si dispone dell'autorizzazione per aprire questa pagina.</string>
-  <string name="passwordIncorrect">Password errata.</string>
-  <string name="paste">Incolla</string>
-  <string name="permdesc_accessCoarseLocation">Accede alle origini approssimative dell'ubicazione, quali il database in rete
-        del cellulare, per determinare l'ubicazione approssimativa del telefono, quando disponibile. Le applicazioni
-        nocive possono utilizzare questa autorizzazione per determinare l'ubicazione approssimativa dell'utente.</string>
-  <string name="permdesc_accessFineLocation">Accede alle origini accurate dell'ubicazione, ad esempio
-        il sistema GPS (Global Positioning System) sul telefono, quando disponibile.
-        Le applicazioni nocive possono utilizzare questa autorizzazione per determinare l'ubicazione dell'utente,
-        consumando ulteriormente la batteria.</string>
-  <string name="permdesc_accessLocationExtraCommands">Accede ai comandi del provider da altre posizione.
-        Le applicazioni nocive possono utilizzare questa per interferire con il funzionamento del GPS
-        o altre sorgenti ubicazione.</string>
-  <string name="permdesc_accessMockLocation">Crea sorgenti simulate dell'ubicazione a scopo di prova.
-        Le applicazioni nocive possono utilizzare questa autorizzazione per ignorare l'ubicazione e/o lo stato restituito dalle sorgenti reali dell'ubicazione
-,        ad esempio un segnale GPS o un fornitore di servizi di rete.</string>
-  <string name="permdesc_accessNetworkState">Consente ad un'applicazione di visualizzare
-      lo stato di tutte le reti.</string>
-  <string name="permdesc_accessSurfaceFlinger">Consente all'applicazione di utilizzare
-        le applicazioni base di SurfaceFlinger.</string>
-  <string name="permdesc_accessWifiState">Consente ad un'applicazione di visualizzare
-      le informazioni sullo stato Wi-Fi.</string>
-  <string name="permdesc_addSystemService">Consente all'applicazione di pubblicare
-        i propri servizi base del sistema. Le applicazioni nocive possono assumere il controllo
-        del sistema, e sottrarre o danneggiare i dati in esso contenuti.</string>
-  <string name="permdesc_batteryStats">Consente la modifica delle
-        statistiche raccolte sulla batteria. Non utilizzare per applicazioni normali.</string>
-  <string name="permdesc_bluetooth">Consente a un'applicazione di visualizzare
-      la configurazione del telefono locale Bluetooth e di effettuare e accettare connessioni
-      con i dispositivi accoppiati.</string>
-  <string name="permdesc_bluetoothAdmin">Consente a un'applicazione di configurare
-      il telefono locale Bluetooth e di rilevare ed eseguire accoppiamenti con i dispositivi
-      remoti.</string>
-  <string name="permdesc_brick">Consente all'applicazione di
-        disabilitare permanentemente l'intero telefono. Si tratta di un'autorizzazione molto rischiosa.</string>
-  <string name="permdesc_broadcastPackageRemoved">Consente a un'applicazione di
-        trasmettere una notifica quando viene rimosso un pacchetto di applicazioni.
-        Le applicazioni nocive possono utilizzare questa autorizzazione per interrompere tutte le altre applicazioni
-        in esecuzione.</string>
-  <string name="permdesc_broadcastSticky">Consente a un'applicazione di inviare
-        broadcast permanenti che rimangono anche dopo il termine del broadcast.
-        Le applicazioni nocive possono rallentare le prestazioni del telefono e renderlo instabile utilizzando
-        troppa memoria.</string>
-  <string name="permdesc_callPhone">Consente all'applicazione di chiamare
-        numeri telefonici senza interventi. Le applicazioni nocive possono
-        effettuare chiamate indesiderate a carico dell'utente. Si noti che ciò non
-        consente all'applicazione di effettuare chiamate a numeri di emergenza.</string>
-  <string name="permdesc_callPrivileged">Consente all'applicazione di effettuare chiamate a qualsiasi numero,
-        compresi numeri di emergenza senza alcun intervento. Le applicazioni nocive possono
-        effettuare chiamate inutili e illecite verso servizi di
- emergenza.</string>
-  <string name="permdesc_camera">Consente all'applicazione di scattare foto
-        con la fotocamera. In questo modo è sempre possibile raccogliere le immagini
-        visualizzate dalla fotocamera.</string>
-  <string name="permdesc_changeComponentState">Consente a un'applicazione di apportare modifiche a prescindere dal fatto che
-        il componente di un'altra applicazione sia abilitato o meno. Le applicazioni nocive possono utilizzare
-        questa autorizzazione per disabilitare le principali funzioni del telefono. Utilizzare con cautela l'autorizzazione poiché
-         è possibile che i componenti dell'applicazione si presentino in uno stato inutilizzabile, non uniforme o instabile.
-    </string>
-  <string name="permdesc_changeConfiguration">Consente a un'applicazione di
-        modificare la configurazione corrente, ad esempio le impostazioni internazionali o le dimensioni generali dei
-        caratteri.</string>
-  <string name="permdesc_changeNetworkState">Consente a un'applicazione di modificare
-     lo stato della connettività di rete.</string>
-  <string name="permdesc_changeWifiState">Consente a un'applicazione di connettersi
-      e disconnettersi dai punti di accesso Wi-Fi e apportare modifiche alle reti
-      Wi-Fi configurate.</string>
-  <string name="permdesc_checkinProperties">Consente l'accesso in lettura/scrittura
-        alle proprietà caricate dal servizio di controllo. Non utilizzare per applicazioni
-        normali.</string>
-  <string name="permdesc_clearAppCache">Consente a un'applicazione di liberare memoria nel telefono
-        eliminando i file nella directory della cache dell'applicazione. Normalmente l'accesso al processo del sistema
-        è molto limitato.</string>
-  <string name="permdesc_clearAppUserData">Consente a un'applicazione di cancellare i dati dell'utente.</string>
-  <string name="permdesc_createNetworkSockets">Consente a un'applicazione di
-      creare socket di rete.</string>
-  <string name="permdesc_deleteCacheFiles">Consente a un'applicazione di cancellare
-        i file nella cache.</string>
-  <string name="permdesc_deletePackages">Consente a un'applicazione di cancellare
-        i pacchetti Android. Le applicazioni nocive possono utilizzare questa funzione per cancellare importanti applicazioni.</string>
-  <string name="permdesc_devicePower">Consente all'applicazione di accendere o spegnere
-        il telefono.</string>
-  <string name="permdesc_diagnostic">Consente all'applicazione di leggere e scrivere su
-    qualsiasi risorsa posseduta dal gruppo diag; ad esempio, file in /dev. Questo potrebbe potenzialmente
-    avere effetti sulla stabilità e protezione del sistema. Deve essere utilizzato ESCLUSIVAMENTE
-    per diagnostiche specifiche dell'hardware da parte del costruttore o dell'operatore.</string>
-  <string name="permdesc_disableKeyguard">Consente a un'applicazione di disabilitare
-      il blocco tasti e tutte le password di sicurezza associate. Un esempio appropriato
-      è rappresentato dal telefono che disabilita il blocco tasti alla ricezione di una chiamata,
-      per riabilitarlo al termine della chiamata stessa.</string>
-  <string name="permdesc_dump">Consente all'applicazione di recuperare
-        o stato interno del sistema. Le applicazioni nocive possono recuperare
-        una vasta gamma di informazioni riservate e protette di cui normalmente non avrebbero
-        bisogno.</string>
-  <string name="permdesc_expandStatusBar">Consente all'applicazione di
-        espandere o comprimere la barra di stato.</string>
-  <string name="permdesc_factoryTest">Eseguire un test del produttore di basso livello,
-        consentendo l'accesso completo all'hardware del telefono. Disponibile solo quando
-        il telefono viene eseguito in modalità test del produttore.</string>
-  <string name="permdesc_flashlight">Consente all'applicazione di controllare
-        il flash.</string>
-  <string name="permdesc_forceBack">Consente a un'applicazione di forzare
-        la chiusura di tutte le attività in esecuzione in primo piano e tornare indietro.
-        Non utilizzarlo per le applicazioni normali.</string>
-  <string name="permdesc_fotaUpdate">Consente a un'applicazione di ricevere
-        le notifiche sugli aggiornamenti in sospeso del sistema e ne attiva
-        l'installazione. Le applicazioni nocive possono utilizzare questa funzionalità per danneggiare il sistema con aggiornamenti non autorizzati
-        o interferire in generale con il processo di
-        aggiornamento.</string>
-  <string name="permdesc_getAccounts">Consente a un'applicazione di ottenere
-      l'elenco degli account del telefono.</string>
-  <string name="permdesc_getPackageSize">Consente a un'applicazione di ricevere
-        il proprio codice, i dati e la dimensione della cache</string>
-  <string name="permdesc_getTasks">Consente a un'applicazione di ricevere
-        informazioni sui task in esecuzione attualmente e recentemente. Ciò può consentire
-        alle applicazioni nocive di rilevare informazioni riservate sulle altre applicazioni.</string>
-  <string name="permdesc_hardware_test">Consente all'applicazione di controllare le varie periferiche
-        per testare l'hardware.</string>
-  <string name="permdesc_injectEvents">Consente a un'applicazione di distribuire
-        i propri eventi di input (pressione dei tasti e così via) ad altre applicazioni. Le applicazioni nocive
-        possono utilizzare questa autorizzazione per prendere il controllo del telefono.</string>
-  <string name="permdesc_installPackages">Consente a un'applicazione di installare
-        pacchetti di Android nuovi o aggiornati. Le applicazioni nocive possono utilizzarla per aggiungere nuove applicazioni con
-        autorizzazioni più o meno efficaci.</string>
-  <string name="permdesc_internalSystemWindow">Consente la creazione di
-        finestre che devono essere utilizzate dall'interfaccia utente
-        del sistema interno. Non utilizzare per applicazioni normali.</string>
-  <string name="permdesc_locationUpdates">Consente di attivare/disattivare le notifiche
-        di aggiornamento della posizione dalla radio. Non utilizzare per applicazioni normali.</string>
-  <string name="permdesc_manageAppTokens">Consente alle applicazioni di
-        creare e gestire i propri token, aggirando il loro normale
-        Z-ordering. Non utilizzare mai per applicazioni normali.</string>
-  <string name="permdesc_masterClear">Consente a un'applicazione di ripristinare completamente
-        le impostazioni di fabbrica del sistema, cancellando tutti i dati,
-        la configurazione e le applicazioni installate.</string>
-  <string name="permdesc_modifyAudioSettings">Consente all'applicazione di modificare
-        le impostazioni audio globali ad esempio il volume e l'indirizzamento.</string>
-  <string name="permdesc_modifyPhoneState">Consente all'applicazione di controllare
-        le funzioni telefoniche del dispositivo. Un'applicazione con questa autorizzazione può scambiare le reti,
-        accendere o spegnere il telefono ed eseguire operazioni simili senza
-        notifiche.</string>
-  <string name="permdesc_mount_unmount_filesystems">Consente all'applicazione di montare e smontare
-        i file system per i dispositivi rimovibili.</string>
-  <string name="permdesc_persistentActivity">Consente a un'applicazione di rendere
-        permanenti alcuni suoi componenti in modo che il sistema non possa utilizzarli per altre
-        applicazioni.</string>
-  <string name="permdesc_processOutgoingCalls">Consente all'applicazione di
-        elaborare le chiamate in uscita e modificare il numero da comporre. Le applicazioni nocive
-        possono monitorare, reindirizzare o impedire le chiamate in uscita.</string>
-  <string name="permdesc_readCalendar">Consente a un'applicazione di leggere
-        tutti gli eventi del calendario memorizzati nel telefono. Le applicazioni nocive
-        possono utilizzare questa autorizzazione per inviare gli eventi ad altre persone.</string>
-  <string name="permdesc_readContacts">Consente a un'applicazione di leggere
-        tutti i contatti (indirizzi) memorizzati sul telefono. Le applicazioni nocive
-        possono utilizzare questa autorizzazione per inviare i dati ad altre persone.</string>
-  <string name="permdesc_readFrameBuffer">Consente all'applicazione di leggere
-        il contenuto del buffer del frame.</string>
-  <string name="permdesc_readInputState">Consente alle applicazioni di controllare
-        i tasti premuti anche durante l'interazione con un'altra applicazione (come
-        quando si digita una password). Non utilizzare mai per le normali applicazioni.</string>
-  <string name="permdesc_readLogs">Consente a un'applicazione di leggere dai
-        vari file di log del sistema. Ciò consente di rilevare le informazioni generali
-        sull'attuale indirizzo del telefono. Non dovrebbero contenere
-        informazioni personali o riservate.</string>
-  <string name="permdesc_readOwnerData">Consente a un'applicazione di leggere
-        i dati del proprietario del telefono memorizzati in quest'ultimo. Le applicazioni nocive
-        possono utilizzare questa autorizzazione per leggere i dati del proprietario del telefono.</string>
-  <string name="permdesc_readPhoneState">Consente all'applicazione di accedere alle funzioni telefoniche del dispositivo.
-        Un'applicazione con quest'autorizzazione può rilevare il numero di telefono,
-        se una chiamata è attiva, il numero dell'altro telefono connesso
-        e così via.</string>
-  <string name="permdesc_readSms">Consente all'applicazione di leggere
-      i messaggi SMS memorizzati sul telefono o sulla scheda SIM. Le applicazioni nocive
-      possono leggere i messaggi riservati.</string>
-  <string name="permdesc_readSyncSettings">Consente a un'applicazione di leggere le impostazioni di sincronizzazione,
-        ad esempio se la sincronizzazione per i contatti è abilitata.</string>
-  <string name="permdesc_readSyncStats">Consente a un'applicazione di leggere le statistiche di sincronizzazione, ad esempio
-        la cronologia delle sincronizzazioni avvenute.</string>
-  <string name="permdesc_reboot">Consente all'applicazione di
-        forzare il riavvio del telefono.</string>
-  <string name="permdesc_receiveBootCompleted">Consente a un'applicazione di
-        avviarsi automaticamente dopo l'avvio del sistema.
-        Ciò può prolungare l'avvio del telefono e rallentarne
-        il normale funzionamento a causa dell'esecuzione costante delle applicazioni.</string>
-  <string name="permdesc_receiveMms">Consente all'applicazione di ricevere
-      ed elaborare i messaggi MMS. Le applicazioni nocive possono monitorare i messaggi
-      o eliminarli automaticamente.</string>
-  <string name="permdesc_receiveSms">Consente all'applicazione di ricevere
-      ed elaborare i messaggi SMS. Le applicazioni nocive possono monitorare
-      i messaggi o eliminarli automaticamente.</string>
-  <string name="permdesc_receiveWapPush">Consente all'applicazione di ricevere
-      ed elaborare i messaggi WAP. Le applicazioni nocive possono monitorare
-      i messaggi o eliminarli automaticamente.</string>
-  <string name="permdesc_recordAudio">Consente all'applicazione di accedere
-        al percorso di registrazione audio.</string>
-  <string name="permdesc_reorderTasks">Consente a un'applicazione di spostare
-        i task in primo e in secondo piano. Le applicazioni nocive possono forzare
-        la propria visualizzazione in primo piano automaticamente.</string>
-  <string name="permdesc_restartPackages">Consente a un'applicazione di
-        riavviare forzatamente altre applicazioni.</string>
-  <string name="permdesc_runSetActivityWatcher">Consente a un'applicazione di
-        monitorare e controllare come il sistema avvia le attività.
-        Le applicazioni nocive possono compromettere completamente il sistema. Questa
-        autorizzazione è necessaria solo per lo sviluppo, mai per il normale utilizzo
-        del telefono.</string>
-  <string name="permdesc_sendSms">Consente all'applicazione di inviare messaggi
-      SMS. Le applicazioni nocive possono inviare messaggi senza
-       conferma a carico del proprietario del telefono.</string>
-  <string name="permdesc_setAlwaysFinish">Consente a un'applicazione
-        di controllare se le attività vengono sempre completate subito dopo essere andate in secondo piano.
-        Mai necessario per le applicazioni normali.</string>
-  <string name="permdesc_setAnimationScale">Consente all'applicazione di modificare
-        la velocità di animazione globale, ovvero rallentare o accelerare le animazioni, in qualsiasi momento.</string>
-  <string name="permdesc_setDebugApp">Consente a un'applicazione di attivare
-        il debug per un'altra applicazione. Le applicazioni nocive possono utilizzare
-        questa autorizzazione per interrompere le altre applicazioni.</string>
-  <string name="permdesc_setOrientation">Consente a un'applicazione di modificare
-        la rotazione dello schermo in qualsiasi momento. Mai necessario per
-        le normali applicazioni.</string>
-  <string name="permdesc_setPreferredApplications">Consente a un'applicazione di
-        modificare le applicazioni preferite. In questo modo le applicazioni nocive
-        possono modificare automaticamente le applicazioni in esecuzione, obbligandole
-        a raccogliere dati riservati.</string>
-  <string name="permdesc_setProcessForeground">Consente a un'applicazione di portare
-        in primo piano tutti i processi in esecuzione, in modo da non poterli interrompere.
-        Mai necessaria per le normali applicazioni.</string>
-  <string name="permdesc_setProcessLimit">Consente a un'applicazione
-        di controllare il numero massimo di processi in esecuzione. Mai
-        necessaria per le normali applicazioni.</string>
-  <string name="permdesc_setTimeZone">Consente a un'applicazione di
-        cambiare il fuso orario del telefono.</string>
-  <string name="permdesc_setWallpaper">Consente all'applicazione
-        di impostare lo sfondo del sistema.</string>
-  <string name="permdesc_setWallpaperHints">Consente all'applicazione
-        di impostare i suggerimenti sulle dimensioni dello sfondo del sistema.</string>
-  <string name="permdesc_signalPersistentProcesses">Consente all'applicazione di richiedere
-        che il segnale fornito venga inviato a tutti i processi permanenti.</string>
-  <string name="permdesc_statusBar">Consente all'applicazione di disabilitare
-        la barra di stato o di aggiungere o rimuovere le icone del sistema.</string>
-  <string name="permdesc_subscribedFeedsRead">Consente all'applicazione di visualizzare i dettagli in merito ai feed correntemente sincornizzati.</string>
-  <string name="permdesc_subscribedFeedsWrite">Consente all'applicazione di modificare 
-      i feed correntemente sincronizzati. Questo potrebbe consentire ad applicazioni nocive di 
-      cambiare i feed sincronizzati.</string>
-  <string name="permdesc_systemAlertWindow">Consente a un'applicazione di
-        mostrare le finestre di avviso del sistema. Le applicazioni nocive possono prendere il controllo
-        di tutto lo schermo del telefono.</string>
-  <string name="permdesc_vibrate">Consente all'applicazione di controllare
-        la vibrazione.</string>
-  <string name="permdesc_wakeLock">Consente all'applicazione di evitare che il telefono
-        entri in modalità standby.</string>
-  <string name="permdesc_writeApnSettings">Consente all'applicazione di modificare le impostazioni APN,
-        ad esempio Proxy e Porta si qualsiasi APN.</string>
-  <string name="permdesc_writeCalendar">Consente a un'applicazione di modificare
-        gli eventi del calendario memorizzati nel telefono. Le applicazioni nocive
-        possono utilizzare questa autorizzazione per cancellare o modificare i dati del calendario.</string>
-  <string name="permdesc_writeContacts">Consente a un'applicazione di modificare
-        i dati (indirizzo) dei contatti salvati sul telefono. Le applicazioni nocive
-        possono utilizzare questa autorizzazione per cancellare o modificare i dati del contatto.</string>
-  <string name="permdesc_writeGservices">Consente all'applicazione di modificare
-        i servizi mappa di Google. Non utilizzare per applicazioni normali.</string>
-  <string name="permdesc_writeOwnerData">Consente a un'applicazione di modificare i dati
-        del proprietario del telefono. Le applicazioni nocive
-        possono utilizzare questa autorizzazioni per cancellare o modificare i dati del proprietario.</string>
-  <string name="permdesc_writeSettings">Consente a un'applicazione di modificare i dati
-        delle impostazioni del sistema. Le applicazioni nocive possono danneggiare la configurazione
-        del sistema.</string>
-  <string name="permdesc_writeSms">Consente all'applicazione di scrivere
-      ai messaggi SMS memorizzati sul telefono o sulla scheda SIM. Le applicazioni
-      nocive possono eliminare i messaggi riservati.</string>
-  <string name="permdesc_writeSyncSettings">Consente a un'applicazione di modificare le impostazioni di sincronizzazione,
-        ad esempio se la sincronizzazione per i Contatti è abilitata.</string>
-  <string name="permgroupdesc_accounts">Accedere agli account di Google disponibili.</string>
-  <string name="permgroupdesc_costMoney">Consente alle applicazioni di eseguire queste operazioni
-        a carico dell'utente.</string>
-  <string name="permgroupdesc_developmentTools">Funzioni necessarie solo per gli
-        sviluppatori di applicazioni.</string>
-  <string name="permgroupdesc_hardwareControls">Accedere direttamente all'hardware della
-        cuffia.</string>
-  <string name="permgroupdesc_location">Monitorare l'ubicazione fisica</string>
-  <string name="permgroupdesc_messages">Leggere e scrivere i messaggi SMS,
-        e-mail e altri ancora.</string>
-  <string name="permgroupdesc_network">Consente alle applicazioni di accedere alle varie
-        funzioni di rete.</string>
-  <string name="permgroupdesc_personalInfo">Accedere direttamente ai contatti
-        e al calendario memorizzati nel telefono.</string>
-  <string name="permgroupdesc_phoneCalls">Monitorare, registrare ed elaborare
-        le telefonate.</string>
-  <string name="permgroupdesc_systemTools">Accesso di basso livello e controllo
-        del sistema.</string>
-  <string name="permgrouplab_accounts">Account Google</string>
-  <string name="permgrouplab_costMoney">Servizi a carico dell'utente</string>
-  <string name="permgrouplab_developmentTools">Strumenti di sviluppo</string>
-  <string name="permgrouplab_hardwareControls">Controlli hardware</string>
-  <string name="permgrouplab_location">Località</string>
-  <string name="permgrouplab_messages">Messaggi</string>
-  <string name="permgrouplab_network">Comunicazione di rete</string>
-  <string name="permgrouplab_personalInfo">Informazioni personali</string>
-  <string name="permgrouplab_phoneCalls">Chiamate telefoniche</string>
-  <string name="permgrouplab_systemTools">Strumenti del sistema</string>
-  <string name="permissions_format"><xliff:g id="perm_line1">%1$s</xliff:g>, <xliff:g id="perm_line2">%2$s</xliff:g></string>
-  <string name="permlab_accessCoarseLocation">Ubicazione (basata su rete) approssimativa</string>
-  <string name="permlab_accessFineLocation">Ubicazione (GPS) accurata</string>
-  <string name="permlab_accessLocationExtraCommands">accesso ai comandi del provider da altre posizione</string>
-  <string name="permlab_accessMockLocation">origini ubicazioni simulate a scopo di prova</string>
-  <string name="permlab_accessNetworkState">visualizza stato rete</string>
-  <string name="permlab_accessSurfaceFlinger">accesso SurfaceFlinger</string>
-  <string name="permlab_accessWifiState">visualizza stato Wi-Fi</string>
-  <string name="permlab_addSystemService">pubblica servizi basso livello</string>
-  <string name="permlab_batteryStats">modifica statistiche batteria</string>
-  <string name="permlab_bluetooth">crea connessioni Bluetooth</string>
-  <string name="permlab_bluetoothAdmin">amministrazione bluetooth</string>
-  <string name="permlab_brick">disabilita telefono permanentemente</string>
-  <string name="permlab_broadcastPackageRemoved">invia broadcast rimosso pacchetto</string>
-  <string name="permlab_broadcastSticky">invia broadcast permanente</string>
-  <string name="permlab_callPhone">chiama direttamente numeri di telefono</string>
-  <string name="permlab_callPrivileged">chiamare direttamente numeri di telefono</string>
-  <string name="permlab_camera">scatta foto</string>
-  <string name="permlab_changeComponentState">abilita o disabilita i componenti dell'applicazione</string>
-  <string name="permlab_changeConfiguration">modifica impostazioni IU</string>
-  <string name="permlab_changeNetworkState">cambia connettività di rete</string>
-  <string name="permlab_changeWifiState">cambia stato Wi-Fi</string>
-  <string name="permlab_checkinProperties">accesso alle proprietà di controllo</string>
-  <string name="permlab_clearAppCache">elimina tutti i dati della cache dell'applicazione</string>
-  <string name="permlab_clearAppUserData">elimina altri dati dell'applicazione</string>
-  <string name="permlab_createNetworkSockets">accesso completo a Internet</string>
-  <string name="permlab_deleteCacheFiles">elimina altra cache dell'applicazione</string>
-  <string name="permlab_deletePackages">elimina applicazioni</string>
-  <string name="permlab_devicePower">accendi o spegni telefono</string>
-  <string name="permlab_diagnostic">lettura/scrittura su risorse possedute tramite diag</string>
-  <string name="permlab_disableKeyguard">disabilita blocco tasti</string>
-  <string name="permlab_dump">recupera stato interno del sistema</string>
-  <string name="permlab_expandStatusBar">espandi/comprimi barra di stato</string>
-  <string name="permlab_factoryTest">esegui in modalità test del produttore</string>
-  <string name="permlab_flashlight">controlla flash</string>
-  <string name="permlab_forceBack">forza chiusura applicazione</string>
-  <string name="permlab_fotaUpdate">installa automaticamente aggiornamenti del sistema</string>
-  <string name="permlab_getAccounts">rileva account noti</string>
-  <string name="permlab_getPackageSize">misura spazio memoria applicazione</string>
-  <string name="permlab_getTasks">recupera applicazioni in esecuzione</string>
-  <string name="permlab_hardware_test">hardware di prova</string>
-  <string name="permlab_injectEvents">premere i tasti e i pulsanti di controllo</string>
-  <string name="permlab_installPackages">installa direttamente applicazioni</string>
-  <string name="permlab_internalSystemWindow">visualizza finestre non autorizzate</string>
-  <string name="permlab_locationUpdates">controllo notifiche aggiornamento posizione</string>
-  <string name="permlab_manageAppTokens">gestisci token applicazioni</string>
-  <string name="permlab_masterClear">ripristina valori predefiniti di fabbrica</string>
-  <string name="permlab_modifyAudioSettings">modifica impostazioni audio</string>
-  <string name="permlab_modifyPhoneState">modifica stato telefono</string>
-  <string name="permlab_mount_unmount_filesystems">monta e smonta file system</string>
-  <string name="permlab_persistentActivity">applicazione sempre in esecuzione</string>
-  <string name="permlab_processOutgoingCalls">intercetta chiamate in uscita</string>
-  <string name="permlab_readCalendar">leggi dati del calendario</string>
-  <string name="permlab_readContacts">leggi dati contatti</string>
-  <string name="permlab_readFrameBuffer">leggi buffer frame</string>
-  <string name="permlab_readInputState">registra contenuto immesso e azioni eseguite</string>
-  <string name="permlab_readLogs">leggi file log del sistema</string>
-  <string name="permlab_readOwnerData">leggi dati proprietario</string>
-  <string name="permlab_readPhoneState">leggi stato telefono</string>
-  <string name="permlab_readSms">leggi SMS o MMS</string>
-  <string name="permlab_readSyncSettings">leggi impostazioni di sincronizzazione</string>
-  <string name="permlab_readSyncStats">leggi statistiche di sincronizzazione</string>
-  <string name="permlab_reboot">forzare il riavvio del telefono</string>
-  <string name="permlab_receiveBootCompleted">avvia automaticamente all'avvio</string>
-  <string name="permlab_receiveMms">ricevi MMS</string>
-  <string name="permlab_receiveSms">ricevi SMS</string>
-  <string name="permlab_receiveWapPush">ricevi WAP</string>
-  <string name="permlab_recordAudio">registra audio</string>
-  <string name="permlab_reorderTasks">riordina applicazioni in esecuzione</string>
-  <string name="permlab_restartPackages">riavvia altre applicazioni</string>
-  <string name="permlab_runSetActivityWatcher">monitora e controlla tutto l'avvio dell'applicazione</string>
-  <string name="permlab_sendSms">invia messaggi SMS</string>
-  <string name="permlab_setAlwaysFinish">chiudi tutte le applicazioni in secondo piano</string>
-  <string name="permlab_setAnimationScale">modifica velocità di animazione globale</string>
-  <string name="permlab_setDebugApp">abilita debug applicazione</string>
-  <string name="permlab_setOrientation">cambia orientamento schermo</string>
-  <string name="permlab_setPreferredApplications">imposta applicazioni preferite</string>
-  <string name="permlab_setProcessForeground">impedisci interruzione</string>
-  <string name="permlab_setProcessLimit">limita numero di processi in esecuzione</string>
-  <string name="permlab_setTimeZone">imposta fuso orario</string>
-  <string name="permlab_setWallpaper">imposta sfondo</string>
-  <string name="permlab_setWallpaperHints">imposta suggerimenti dimensioni sfondo</string>
-  <string name="permlab_signalPersistentProcesses">invia segnali Linux ad applicazioni</string>
-  <string name="permlab_statusBar">disabilita o modifica barra di stato</string>
-  <string name="permlab_subscribedFeedsRead">leggere i feed sottoscritti</string>
-  <string name="permlab_subscribedFeedsWrite">scrivere i feed sottoscritti</string>
-  <string name="permlab_systemAlertWindow">visualizza avvisi a livello di sistema</string>
-  <string name="permlab_vibrate">controllo vibrazione</string>
-  <string name="permlab_wakeLock">impedisci standby telefono</string>
-  <string name="permlab_writeApnSettings">scrivere le impostazioni nome punto di accesso</string>
-  <string name="permlab_writeCalendar">scrivi dati calendario</string>
-  <string name="permlab_writeContacts">scrivi dati contatto</string>
-  <string name="permlab_writeGservices">modificare i servizi mappa di Google</string>
-  <string name="permlab_writeOwnerData">scrivi dati proprietario</string>
-  <string name="permlab_writeSettings">modifica impostazioni globali sistema</string>
-  <string name="permlab_writeSms">modifica SMS o MMS</string>
-  <string name="permlab_writeSyncSettings">scrivi impostazioni di sincronizzazione</string>
-  <string name="perms_hide">
-					<xliff:g ctype="bold">Nascondi</xliff:g>
-				</string>
-  <string name="perms_show_all">
-					<xliff:g ctype="bold">Mostra tutti</xliff:g>
-				</string>
-  <string name="petabyteShort">PB</string>
-  <string name="pm">"PM"</string>
-  <string name="power_dialog">Opzioni telefono</string>
-  <string name="power_off">Spegni</string>
-  <string name="prepend_shortcut_label">Menu+</string>
-  <string name="preposition_for_date">su %s</string>
-  <string name="preposition_for_time">a %s</string>
-  <string name="preposition_for_year">in %s</string>
-  <string name="ringtone_default">Suoneria predefinita</string>
-  <string name="ringtone_default_with_actual">Suoneria predefinita (<xliff:g id="actual_ringtone">%1$s</xliff:g>)</string>
-  <string name="ringtone_picker_title">Selezionare una suoneria</string>
-  <string name="ringtone_silent">Automatico</string>
-  <string name="ringtone_unknown">Suoneria sconosciuta</string>
-  <string name="safeMode">Modalità sicura</string>
-  <string name="same_month_md1_md2">"<xliff:g id="format">%3$s \u2013 %8$s %2$s </xliff:g>"</string>
-  <string name="same_month_md1_time1_md2_time2">"<xliff:g id="format">%3$s %2$s %5$s \u2013 %8$s %7$s %10$s</xliff:g>"</string>
-  <string name="same_month_mdy1_mdy2">"<xliff:g id="format">%3$s \u2013 %8$s %9$s %2$s</xliff:g>"</string>
-  <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="format">%3$s %2$s %4$s, %5$s \u2013 %8$s %7$s %9$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %3$s %2$s, %5$s \u2013 %6$s, %8$s %7$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s %3$s %2$s \u2013 %6$s %8$s %7$s</xliff:g>"</string>
-  <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %3$s %2$s %4$s, %5$s \u2013 %6$s, %8$s %7$s %9$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s %3$s %2$s %4$s \u2013 %6$s %8$s %7$s %9$s</xliff:g>"</string>
-  <string name="same_year_md1_md2">"<xliff:g id="format">%3$s %2$s \u2013 %8$s %7$s</xliff:g>"</string>
-  <string name="same_year_md1_time1_md2_time2">"<xliff:g id="format">%3$s %2$s, %5$s \u2013 %8$s %7$s, %10$s</xliff:g>"</string>
-  <string name="same_year_mdy1_mdy2">"<xliff:g id="format">%3$s %2$s \u2013 %8$s %7$s %9$s</xliff:g>"</string>
-  <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="format">%3$s %2$s %4$s, %5$s \u2013 %8$s %7$s %9$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s %3$s %2$s %5$s \u2013 %6$s, %8$s %7$s %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s %3$s %2$s \u2013 %6$s %8$s %7$s</xliff:g>"</string>
-  <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s %3$s %2$s %4$s, %5$s \u2013 %6$s %8$s %7$s %9$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %3$s %2$s \u2013 %6$s, %8$s %7$s %9$s</xliff:g>"</string>
-  <string name="saturday">Sabato</string>
-  <string name="save_password_label">Conferma</string>
-  <string name="save_password_message">Memorizzare la password nel browser?</string>
-  <string name="save_password_never">Mai</string>
-  <string name="save_password_notnow">Non adesso</string>
-  <string name="save_password_remember">Memorizza</string>
-  <string name="screen_lock">Blocco schermo</string>
-  <string name="screen_progress">In funzione\u2026</string>
-  <string name="search_go">Cerca</string>
-  <string name="second">sec</string>
-  <string name="seconds">sec</string>
-  <string name="selectAll">Seleziona tutto</string>
-  <string name="selectMenuLabel">Seleziona</string>
-  <string name="select_character">Selezionare il carattere da inserire</string>
-  <string name="sendText">Selezionare un'azione per il testo</string>
-  <string name="serviceClassData">Dati</string>
-  <string name="serviceClassDataAsync">Asinc</string>
-  <string name="serviceClassDataSync">Sincronizza</string>
-  <string name="serviceClassFAX">FAX</string>
-  <string name="serviceClassPAD">PAD</string>
-  <string name="serviceClassPacket">Pacchetto</string>
-  <string name="serviceClassSMS">SMS</string>
-  <string name="serviceClassVoice">Voce</string>
-  <string name="serviceDisabled">Il servizio è stato disabilitato.</string>
-  <string name="serviceEnabled">Il servizio è stato abilitato.</string>
-  <string name="serviceEnabledFor">Il servizio è stato abilitato per:</string>
-  <string name="serviceErased">Cancellazione completata.</string>
-  <string name="serviceNotProvisioned">Servizio non fornito.</string>
-  <string name="serviceRegistered">Registrazione completata.</string>
-  <string name="shutdown_confirm">Il telefono verrà spento.</string>
-  <string name="shutdown_progress">Spegnimento in corso\u2026</string>
-  <string name="silent_mode">Modalità automatica</string>
-  <string name="simAbsentLabel">Scheda SIM assente o inserita in maniera errata.</string>
-  <string name="simNetworkPersonalizationLabel">Scheda SIM non utilizzata in questo telefono.</string>
-  <string name="simPINLabel">PIN SIM necessario (e attualmente non supportato).</string>
-  <string name="simPUKLabel">PUK SIM necessario (e attualmente non supportato).</string>
-  <string name="sms_control_default_app_name">Applicazione sconosciuta</string>
-  <string name="sms_control_message">Sono in corso di invio numerosi messaggi SMS. Scegliere \"OK\" per continuare oppure \"Annulla\" per interrompere l'invio.</string>
-  <string name="sms_control_no">Annulla</string>
-  <string name="sms_control_title">Invio messaggi SMS in corso</string>
-  <string name="sms_control_yes">OK</string>
-  <string name="status_bar_applications_title">Applicazione</string>
-  <string name="status_bar_clear_all_button">Cancella notifiche</string>
-  <string name="status_bar_date_format">"<xliff:g id="format">MMMM g, aaaa</xliff:g>"</string>
-  <string name="status_bar_latest_events_title">Notifiche</string>
-  <string name="status_bar_no_notifications_title">Nessuna notifica</string>
-  <string name="status_bar_ongoing_events_title">In uscita</string>
-  <string name="status_bar_time_format">"<xliff:g id="format">h:mm AA</xliff:g>"</string>
-  <string name="sunday">Domenica</string>
-  <string name="terabyteShort">TB</string>
-  <string name="text_copied">Testo copiato negli Appunti.</string>
-  <string name="thursday">Giovedì</string>
-  <string name="time1_time2">"<xliff:g id="format">%1$s \u2013 %2$s</xliff:g>"</string>
-  <string name="time_date">"<xliff:g id="format">%1$s, %3$s</xliff:g>"</string>
-  <string name="time_picker_set">Imposta</string>
-  <string name="time_wday">"<xliff:g id="format">%1$s, %2$s</xliff:g>"</string>
-  <string name="time_wday_date">"<xliff:g id="format">%1$s, %2$s, %3$s</xliff:g>"</string>
-  <string name="today">Oggi</string>
-  <string name="tomorrow">Domani</string>
-  <string name="tuesday">Martedì</string>
-  <string name="turn_off_radio">Disattiva wireless</string>
-  <string name="turn_on_radio">Attiva wireless</string>
-  <string name="unknownName">(Sconosciuto)</string>
-  <string name="untitled">&lt;senza titolo&gt;</string>
-  <string name="volume_alarm">Volume allarme</string>
-  <string name="volume_call">Volume chiamata in ingresso</string>
-  <string name="volume_music">Volume musica/video</string>
-  <string name="volume_ringtone">Volume suoneria</string>
-  <string name="volume_unknown">Volume</string>
-  <string name="wait">Attendi</string>
-  <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="format">%1$s %2$s, %3$s \u2013 %4$s %5$s, %6$s</xliff:g>"</string>
-  <string name="wday1_date1_wday2_date2">"<xliff:g id="format">%1$s %2$s \u2013 %4$s %5$s</xliff:g>"</string>
-  <string name="wday_date">"<xliff:g id="format">%2$s %3$s</xliff:g>"</string>
-  <string name="wednesday">Mercoledì</string>
-  <string name="week">settimana</string>
-  <string name="weekly">"Settimanalmente il <xliff:g id="day">%s</xliff:g>"</string>
-  <string name="weekly_format">MMM g</string>
-  <string name="weeks">settimane</string>
-  <string name="whichApplication">Completa azione utilizzando</string>
-  <string name="year">anno</string>
-  <string name="yearly">Annualmente</string>
-  <string name="yearly_format">aaaa</string>
-  <string name="years">anni</string>
-  <string name="yes">OK</string>
-  <string name="yesterday">Ieri</string>
-</resources>
diff --git a/core/res/res/values-ja/arrays.xml b/core/res/res/values-ja/arrays.xml
new file mode 100644
index 0000000..f9c904b
--- /dev/null
+++ b/core/res/res/values-ja/arrays.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
new file mode 100644
index 0000000..b402c7f8
--- /dev/null
+++ b/core/res/res/values-ja/strings.xml
@@ -0,0 +1,699 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="byteShort">"B"</string>
+    <string name="kilobyteShort">"KB"</string>
+    <string name="megabyteShort">"MB"</string>
+    <string name="gigabyteShort">"GB"</string>
+    <string name="terabyteShort">"TB"</string>
+    <string name="petabyteShort">"PB"</string>
+    <string name="untitled">"&lt;無題&gt;"</string>
+    <string name="ellipsis">"…"</string>
+    <string name="emptyPhoneNumber">"(電話番号なし)"</string>
+    <string name="unknownName">"(不明)"</string>
+    <string name="defaultVoiceMailAlphaTag">"ボイスメール"</string>
+    <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+    <string name="mmiError">"接続に問題があるか、MMIコードが正しくありません。"</string>
+    <string name="serviceEnabled">"サービスが有効になりました。"</string>
+    <string name="serviceEnabledFor">"次のサービスが有効になりました:"</string>
+    <string name="serviceDisabled">"サービスが無効になりました。"</string>
+    <string name="serviceRegistered">"登録されました。"</string>
+    <string name="serviceErased">"消去されました。"</string>
+    <string name="passwordIncorrect">"パスワードが正しくありません。"</string>
+    <string name="mmiComplete">"MMIが完了しました。"</string>
+    <string name="badPin">"入力した古いPINは正しくありません。"</string>
+    <string name="badPuk">"入力したPUKは正しくありません。"</string>
+    <string name="mismatchPin">"入力したPINが一致しません。"</string>
+    <string name="invalidPin">"4~8桁の数字のPINを入力してください。"</string>
+    <!-- no translation found for needPuk (919668385956251611) -->
+    <skip />
+    <string name="needPuk2">"SIMカードのロック解除のためPUK2を入力します。"</string>
+    <string name="ClipMmi">"着信時の発信者番号"</string>
+    <string name="ClirMmi">"発信時の発信者番号"</string>
+    <string name="CfMmi">"電話の転送"</string>
+    <string name="CwMmi">"待機中の着信"</string>
+    <string name="BaMmi">"発信制限"</string>
+    <string name="PwdMmi">"パスワードの変更"</string>
+    <string name="PinMmi">"PINの変更"</string>
+    <string name="CLIRDefaultOnNextCallOn">"デフォルトでは発信者番号は非通知です。次の通話でも非通知です。"</string>
+    <string name="CLIRDefaultOnNextCallOff">"デフォルトでは発信者番号は非通知ですが、次の通話では通知されます。"</string>
+    <string name="CLIRDefaultOffNextCallOn">"デフォルトでは発信者番号は通知されますが、次の通話では非通知です。"</string>
+    <string name="CLIRDefaultOffNextCallOff">"デフォルトでは発信者番号は通知されます。次の通話でも通知されます。"</string>
+    <string name="serviceNotProvisioned">"サービスは提供されません。"</string>
+    <string name="CLIRPermanent">"発信者番号の設定は変更できません。"</string>
+    <string name="serviceClassVoice">"音声"</string>
+    <string name="serviceClassData">"データ"</string>
+    <string name="serviceClassFAX">"FAX"</string>
+    <string name="serviceClassSMS">"SMS"</string>
+    <string name="serviceClassDataAsync">"非同期"</string>
+    <string name="serviceClassDataSync">"同期"</string>
+    <string name="serviceClassPacket">"パケット"</string>
+    <string name="serviceClassPAD">"PAD"</string>
+    <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
+    <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+    <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g> (<xliff:g id="TIME_DELAY">{2}</xliff:g>秒後)"</string>
+    <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
+    <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
+    <string name="httpErrorOk">"OK"</string>
+    <string name="httpError">"ウェブページにエラーがあります。"</string>
+    <string name="httpErrorLookup">"URLが見つかりませんでした。"</string>
+    <string name="httpErrorUnsupportedAuthScheme">"このサイトの認証方式には対応していません。"</string>
+    <string name="httpErrorAuth">"認証できませんでした。"</string>
+    <string name="httpErrorProxyAuth">"プロキシサーバーを使用した認証に失敗しました。"</string>
+    <string name="httpErrorConnect">"サーバーに接続できませんでした。"</string>
+    <string name="httpErrorIO">"サーバーと通信できませんでした。しばらくしてからもう一度試してください。"</string>
+    <string name="httpErrorTimeout">"サーバーへの接続がタイムアウトになりました。"</string>
+    <string name="httpErrorRedirectLoop">"このページはサーバーのリダイレクトが多すぎます。"</string>
+    <string name="httpErrorUnsupportedScheme">"このプロトコルには対応していません。"</string>
+    <string name="httpErrorFailedSslHandshake">"安全な接続を確立できませんでした。"</string>
+    <string name="httpErrorBadUrl">"URLが無効なのでページを表示できませんでした。"</string>
+    <string name="httpErrorFile">"ファイルにアクセスできませんでした。"</string>
+    <string name="httpErrorFileNotFound">"要求されたファイルが見つかりませんでした。"</string>
+    <string name="httpErrorTooManyRequests">"処理中のリクエストが多すぎます。しばらくしてからもう一度試してください。"</string>
+    <string name="contentServiceSync">"同期"</string>
+    <string name="contentServiceSyncNotificationTitle">"同期"</string>
+    <string name="contentServiceTooManyDeletesNotificationDesc">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>での削除が多すぎます。"</string>
+    <string name="low_memory">"電話のメモリがいっぱいです。ファイルを削除してメモリを解放してください。"</string>
+    <string name="me">"自分"</string>
+    <string name="power_dialog">"携帯電話オプション"</string>
+    <string name="silent_mode">"マナーモード"</string>
+    <string name="turn_on_radio">"ワイヤレスをオン"</string>
+    <string name="turn_off_radio">"ワイヤレスオフ"</string>
+    <string name="screen_lock">"画面をロック"</string>
+    <string name="power_off">"電源オフ"</string>
+    <string name="shutdown_progress">"シャットダウン中..."</string>
+    <string name="shutdown_confirm">"携帯電話は停止されます。"</string>
+    <string name="no_recent_tasks">"最近使ったアプリケーションはありません。"</string>
+    <string name="global_actions">"携帯電話オプション"</string>
+    <string name="global_action_lock">"画面をロック"</string>
+    <string name="global_action_power_off">"電源オフ"</string>
+    <string name="global_action_toggle_silent_mode">"マナーモード"</string>
+    <string name="global_action_silent_mode_on_status">"音声オフ"</string>
+    <string name="global_action_silent_mode_off_status">"サウンド:オン"</string>
+    <string name="safeMode">"セーフモード"</string>
+    <string name="permgrouplab_costMoney">"料金の発生するサービス"</string>
+    <string name="permgroupdesc_costMoney">"料金の発生する操作をアプリケーションに許可します。"</string>
+    <string name="permgrouplab_messages">"送受信したメッセージ"</string>
+    <string name="permgroupdesc_messages">"SMS、メールなどのメッセージの読み書き"</string>
+    <string name="permgrouplab_personalInfo">"個人情報"</string>
+    <string name="permgroupdesc_personalInfo">"携帯電話に保存した連絡先とカレンダーに直接アクセス"</string>
+    <string name="permgrouplab_location">"現在地"</string>
+    <string name="permgroupdesc_location">"現在地を監視"</string>
+    <string name="permgrouplab_network">"ネットワーク通信"</string>
+    <string name="permgroupdesc_network">"ネットワークのさまざまな機能へのアクセスをアプリケーションに許可します。"</string>
+    <string name="permgrouplab_accounts">"Googleアカウント"</string>
+    <string name="permgroupdesc_accounts">"利用可能なGoogleアカウントへのアクセス"</string>
+    <string name="permgrouplab_hardwareControls">"ハードウェアの制御"</string>
+    <string name="permgroupdesc_hardwareControls">"ハンドセットのハードウェアへの直接アクセス"</string>
+    <string name="permgrouplab_phoneCalls">"電話の発信"</string>
+    <string name="permgroupdesc_phoneCalls">"通話の監視、記録、処理"</string>
+    <string name="permgrouplab_systemTools">"システムツール"</string>
+    <string name="permgroupdesc_systemTools">"システムの低レベルのアクセスと制御"</string>
+    <string name="permgrouplab_developmentTools">"開発ツール"</string>
+    <string name="permgroupdesc_developmentTools">"アプリケーションのデベロッパーにのみ必要な機能です。"</string>
+    <string name="permlab_statusBar">"ステータスバーを無効にしたり変更する"</string>
+    <string name="permdesc_statusBar">"ステータスバーを無効にしたり、システムアイコンを追加や削除することをアプリケーションに許可します。"</string>
+    <string name="permlab_expandStatusBar">"ステータスバーの拡大/縮小"</string>
+    <string name="permdesc_expandStatusBar">"ステータスバーの拡大や縮小をアプリケーションに許可します。"</string>
+    <string name="permlab_processOutgoingCalls">"発信の傍受"</string>
+    <string name="permdesc_processOutgoingCalls">"発信を処理して、ダイヤルする番号を変更することをアプリケーションに許可します。悪意のあるアプリケーションが発信を監視、転送、阻止する恐れがあります。"</string>
+    <string name="permlab_receiveSms">"SMSの受信"</string>
+    <string name="permdesc_receiveSms">"SMSメッセージの受信と処理をアプリケーションに許可します。悪意のあるアプリケーションがメッセージを監視したり、表示せずに削除する恐れがあります。"</string>
+    <string name="permlab_receiveMms">"MMSの受信"</string>
+    <string name="permdesc_receiveMms">"MMSメッセージの受信と処理をアプリケーションに許可します。悪意のあるアプリケーションがメッセージを監視したり、表示せずに削除する恐れがあります。"</string>
+    <string name="permlab_sendSms">"SMSメッセージの送信"</string>
+    <string name="permdesc_sendSms">"SMSメッセージの送信をアプリケーションに許可します。悪意のあるアプリケーションが確認なしでメッセージを送信し、料金が発生する恐れがあります。"</string>
+    <string name="permlab_readSms">"SMSやMMSの読み取り"</string>
+    <string name="permdesc_readSms">"携帯電話またはSIMカードに保存したSMSメッセージの読み取りをアプリケーションに許可します。悪意のあるアプリケーションが機密メッセージを読み取る恐れがあります。"</string>
+    <string name="permlab_writeSms">"SMSやMMSの編集"</string>
+    <string name="permdesc_writeSms">"携帯電話やSIMカードに保存したSMSメッセージへの書き込みをアプリケーションに許可します。悪意のあるアプリケーションがメッセージを削除する恐れがあります。"</string>
+    <string name="permlab_receiveWapPush">"WAPの受信"</string>
+    <string name="permdesc_receiveWapPush">"WAPメッセージの受信と処理をアプリケーションに許可します。悪意のあるアプリケーションがメッセージを監視したり、表示せずに削除する恐れがあります。"</string>
+    <string name="permlab_getTasks">"実行中のアプリケーションの取得"</string>
+    <string name="permdesc_getTasks">"現在実行中または最近実行したタスクに関する情報の取得をアプリケーションに許可します。悪意のあるアプリケーションが他のアプリケーションから非公開情報を取得する恐れがあります。"</string>
+    <string name="permlab_reorderTasks">"実行中のアプリケーションの順序の変更"</string>
+    <string name="permdesc_reorderTasks">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリケーションに許可します。悪意のあるアプリケーションが優先されて、コントロールできなくなる恐れがあります。"</string>
+    <string name="permlab_setDebugApp">"アプリケーションのデバッグを有効にする"</string>
+    <string name="permdesc_setDebugApp">"別のアプリケーションをデバッグモードにすることをアプリケーションに許可します。これにより悪意のあるアプリケーションが、別のアプリケーションを終了させる恐れがあります。"</string>
+    <string name="permlab_changeConfiguration">"UI設定の変更"</string>
+    <string name="permdesc_changeConfiguration">"ロケールや全体のフォントのサイズなど、現在の設定の変更をアプリケーションに許可します。"</string>
+    <string name="permlab_restartPackages">"他のアプリケーションの再起動"</string>
+    <string name="permdesc_restartPackages">"他のアプリケーションの強制的な再起動をアプリケーションに許可します。"</string>
+    <string name="permlab_setProcessForeground">"停止の阻止"</string>
+    <string name="permdesc_setProcessForeground">"フォアグラウンドでプロセスを実行して、終了できないようにすることをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
+    <string name="permlab_forceBack">"アプリケーションの強制終了"</string>
+    <string name="permdesc_forceBack">"フォアグラウンドで実行されている操作を強制終了して戻ることをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
+    <string name="permlab_dump">"システムの内部状態の取得"</string>
+    <string name="permdesc_dump">"システムの内部状態の取得をアプリケーションに許可します。悪意のあるアプリケーションが、通常は必要のない、広範囲にわたる非公開の機密情報を取得する恐れがあります。"</string>
+    <string name="permlab_addSystemService">"低レベルサービスの公開"</string>
+    <string name="permdesc_addSystemService">"独自の低レベルのシステムサービスを公開することをアプリケーションに許可します。悪意のあるアプリケーションがシステムを乗っ取って、データの盗用や破壊をする恐れがあります。"</string>
+    <string name="permlab_runSetActivityWatcher">"起動中のすべてのアプリケーションの監視と制御"</string>
+    <string name="permdesc_runSetActivityWatcher">"システムが起動する操作の監視と制御をアプリケーションに許可します。悪意のあるアプリケーションがシステムを完全に破壊する恐れがあります。この許可は開発にのみ必要で、携帯電話の通常の使用にはまったく必要ありません。"</string>
+    <string name="permlab_broadcastPackageRemoved">"パッケージが削除されたブロードキャストの配信"</string>
+    <string name="permdesc_broadcastPackageRemoved">"アプリケーションパッケージの削除の通知を配信することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、他の実行中のアプリケーションを強制終了する恐れがあります。"</string>
+    <string name="permlab_broadcastSmsReceived">"SMS受信ブロードキャストの配信"</string>
+    <string name="permdesc_broadcastSmsReceived">"SMSメッセージの受信通知の配信をアプリケーションに許可します。これにより悪意のあるアプリケーションが、受信SMSメッセージを偽造する恐れがあります。"</string>
+    <string name="permlab_broadcastWapPush">"WAP-PUSH受信ブロードキャストの配信"</string>
+    <string name="permdesc_broadcastWapPush">"WAP PUSHメッセージの受信の通知を配信することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、MMS受信メッセージを偽造したり、ウェブページのコンテンツを密かに改ざんする恐れがあります。"</string>
+    <string name="permlab_setProcessLimit">"実行中のプロセスの数を制限"</string>
+    <string name="permdesc_setProcessLimit">"実行するプロセス数の上限の制御をアプリケーションに許可します。通常のアプリケーションにはまったく必要ありません。"</string>
+    <string name="permlab_setAlwaysFinish">"バックグラウンドアプリケーションをすべて閉じる"</string>
+    <string name="permdesc_setAlwaysFinish">"バックグラウンドになり次第必ず操作を終了させるかどうかの制御をアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
+    <string name="permlab_fotaUpdate">"システムアップデートの自動インストール"</string>
+    <string name="permdesc_fotaUpdate">"保留中のシステムアップデートに関する通知を受信してインストールを開始することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、許可なく更新を行ってシステムを破壊したり、更新処理を妨害する恐れがあります。"</string>
+    <string name="permlab_batteryStats">"バッテリの統計の変更"</string>
+    <string name="permdesc_batteryStats">"収集されたバッテリの統計の変更を許可します。通常のアプリケーションでは使用しません。"</string>
+    <string name="permlab_internalSystemWindow">"未許可のウィンドウの表示"</string>
+    <string name="permdesc_internalSystemWindow">"内部システムのユーザーインターフェースで使用するためのウィンドウ作成を許可します。通常のアプリケーションでは使用しません。"</string>
+    <string name="permlab_systemAlertWindow">"システムレベルの警告の表示"</string>
+    <string name="permdesc_systemAlertWindow">"システムの警告ウィンドウをアプリケーションで表示できるようにします。悪意のあるアプリケーションが携帯電話の画面全体を偽装する恐れがあります。"</string>
+    <string name="permlab_setAnimationScale">"アニメーション全般の速度の変更"</string>
+    <string name="permdesc_setAnimationScale">"いつでもアニメーション全般の速度を変更する (アニメーションを速くまたは遅くする) ことをアプリケーションに許可します。"</string>
+    <string name="permlab_manageAppTokens">"アプリケーショントークンの管理"</string>
+    <string name="permdesc_manageAppTokens">"通常のZ-orderingを回避して、独自のトークンを作成、管理することをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
+    <string name="permlab_injectEvents">"キーを押してボタンをコントロール"</string>
+    <string name="permdesc_injectEvents">"入力イベント (キーを押すなど) を別のアプリケーションに伝えることをアプリケーションに許可します。これにより悪意のあるアプリケーションが、携帯電話を乗っ取る恐れがあります。"</string>
+    <string name="permlab_readInputState">"入力や操作の記録"</string>
+    <string name="permdesc_readInputState">"別のアプリケーションへの入力 (パスワードなど) でもキー入力を監視することをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
+    <!-- no translation found for permlab_bindInputMethod (3360064620230515776) -->
+    <skip />
+    <!-- no translation found for permdesc_bindInputMethod (3734838321027317228) -->
+    <skip />
+    <string name="permlab_setOrientation">"画面の向きの変更"</string>
+    <string name="permdesc_setOrientation">"いつでも画面の回転を変更することをアプリケーションに許可します。通常のアプリケーションにはまったく必要ありません。"</string>
+    <string name="permlab_signalPersistentProcesses">"Linuxのシグナルをアプリケーションに送信"</string>
+    <string name="permdesc_signalPersistentProcesses">"すべての永続プロセスへの指定の信号の送信要求をアプリケーションに許可します。"</string>
+    <string name="permlab_persistentActivity">"アプリケーションを常に実行する"</string>
+    <string name="permdesc_persistentActivity">"自身を部分的に永続させて、他のアプリケーション用にはその領域をシステムに使わせないようにすることをアプリケーションに許可します。"</string>
+    <string name="permlab_deletePackages">"アプリケーションの削除"</string>
+    <string name="permdesc_deletePackages">"Androidパッケージの削除をアプリケーションに許可します。これにより悪意のあるアプリケーションが、重要なアプリケーションを削除する恐れがあります。"</string>
+    <string name="permlab_clearAppUserData">"他のアプリケーションのデータを削除"</string>
+    <string name="permdesc_clearAppUserData">"ユーザーデータの消去をアプリケーションに許可します。"</string>
+    <string name="permlab_deleteCacheFiles">"他のアプリケーションのキャッシュを削除"</string>
+    <string name="permdesc_deleteCacheFiles">"キャッシュファイルの削除をアプリケーションに許可します。"</string>
+    <string name="permlab_getPackageSize">"アプリケーションのメモリ容量の計測"</string>
+    <string name="permdesc_getPackageSize">"アプリケーションのコード、データ、キャッシュのサイズを取得することを許可します。"</string>
+    <string name="permlab_installPackages">"アプリケーションを直接インストール"</string>
+    <string name="permdesc_installPackages">"Androidパッケージを新たにインストールまたは更新することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、勝手に強力な権限を持つ新しいアプリケーションを追加する恐れがあります。"</string>
+    <string name="permlab_clearAppCache">"アプリケーションキャッシュデータの削除"</string>
+    <string name="permdesc_clearAppCache">"アプリケーションのキャッシュディレクトリからファイルを削除して携帯電話のメモリを解放することをアプリケーションに許可します。通常、アクセスはシステムプロセスのみに制限されます。"</string>
+    <string name="permlab_readLogs">"システムログファイルの読み取り"</string>
+    <string name="permdesc_readLogs">"システムのさまざまなログファイルの読み取りをアプリケーションに許可します。これにより携帯電話の使用状況に関する全般情報が取得されますが、個人情報や非公開情報が含まれることはありません。"</string>
+    <string name="permlab_diagnostic">"diagが所有するリソースの読み書き"</string>
+    <string name="permdesc_diagnostic">"diagグループが所有するリソース (例、/dev内のファイル) への読み書きをアプリケーションに許可します。これはシステムの安定性とセキュリティに影響する恐れがあります。メーカーまたはオペレータによるハードウェア固有の診断以外には使用しないでください。"</string>
+    <string name="permlab_changeComponentState">"アプリケーションのコンポーネントを有効/無効にする"</string>
+    <!-- no translation found for permdesc_changeComponentState (4569107043246700630) -->
+    <skip />
+    <string name="permlab_setPreferredApplications">"優先アプリケーションの設定"</string>
+    <string name="permdesc_setPreferredApplications">"優先アプリケーションを変更することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、実行中のアプリケーションを密かに変更し、既存のアプリケーションになりすまして、非公開データを収集する恐れがあります。"</string>
+    <string name="permlab_writeSettings">"システム全般の設定の変更"</string>
+    <string name="permdesc_writeSettings">"システム設定データの変更をアプリケーションに許可します。悪意のあるアプリケーションがシステム設定を破壊する恐れがあります。"</string>
+    <!-- no translation found for permlab_writeSecureSettings (204676251876718288) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSecureSettings (4116616249170428132) -->
+    <skip />
+    <string name="permlab_writeGservices">"Googleサービスの地図の変更"</string>
+    <string name="permdesc_writeGservices">"Googleサービスマップの変更をアプリケーションに許可します。通常のアプリケーションでは使用しません。"</string>
+    <string name="permlab_receiveBootCompleted">"起動時に自動的に開始"</string>
+    <string name="permdesc_receiveBootCompleted">"システムの起動後に、自動的に起動することをアプリケーションに許可します。これにより携帯電話の起動に時間がかかるようになり、アプリケーションが常に実行されるために携帯電話の全体的な動作が遅くなります。"</string>
+    <string name="permlab_broadcastSticky">"stickyブロードキャストの配信"</string>
+    <string name="permdesc_broadcastSticky">"配信が終了してもメモリに残るようなstickyブロードキャストをアプリケーションに許可します。悪意のあるアプリケーションがメモリを使いすぎて、携帯電話の動作が遅くなったり、不安定になる恐れがあります。"</string>
+    <string name="permlab_readContacts">"連絡先データの読み取り"</string>
+    <string name="permdesc_readContacts">"携帯電話に保存した連絡先 (アドレス) データをアプリケーションですべて読み取れるようにします。これにより悪意のあるアプリケーションが、そのデータを他人に送信する恐れがあります。"</string>
+    <string name="permlab_writeContacts">"連絡先データの書き込み"</string>
+    <string name="permdesc_writeContacts">"携帯電話に保存した連絡先 (アドレス) データの変更をアプリケーションに許可します。これにより悪意のあるアプリケーションが、連絡先データを消去や変更する恐れがあります。"</string>
+    <string name="permlab_writeOwnerData">"所有者データの書き込み"</string>
+    <string name="permdesc_writeOwnerData">"携帯電話に保存した所有者のデータの変更をアプリケーションに許可します。これにより悪意のあるアプリケーションが、所有者のデータを消去や変更する恐れがあります。"</string>
+    <string name="permlab_readOwnerData">"所有者データの読み取り"</string>
+    <string name="permdesc_readOwnerData">"携帯電話に保存した所有者データの読み取りをアプリケーションに許可します。これにより悪意のあるアプリケーションが、所有者データを読み取る恐れがあります。"</string>
+    <string name="permlab_readCalendar">"カレンダーデータの読み取り"</string>
+    <string name="permdesc_readCalendar">"携帯電話に保存したカレンダーのイベントをアプリケーションですべて読み取れるようにします。悪意のあるアプリケーションではこれを利用して、カレンダーのイベントを他人に送信できます。"</string>
+    <string name="permlab_writeCalendar">"カレンダーデータの書き込み"</string>
+    <string name="permdesc_writeCalendar">"携帯電話に保存したカレンダーイベントの変更をアプリケーションに許可します。これにより悪意のあるアプリケーションが、カレンダーデータを消去や変更する恐れがあります。"</string>
+    <string name="permlab_accessMockLocation">"仮の位置情報でテスト"</string>
+    <string name="permdesc_accessMockLocation">"テスト用に仮の位置情報源を作成します。これにより悪意のあるアプリケーションが、GPS、ネットワークプロバイダなどから返される本当の位置情報や状況を改ざんする恐れがあります。"</string>
+    <string name="permlab_accessLocationExtraCommands">"位置情報プロバイダのその他のコマンドへのアクセス"</string>
+    <string name="permdesc_accessLocationExtraCommands">"位置情報プロバイダのその他のコマンドにアクセスします。これにより悪意のあるアプリケーションが、GPSなどの位置情報源の動作を妨害する恐れがあります。"</string>
+    <string name="permlab_accessFineLocation">"正確な (GPS) 位置"</string>
+    <string name="permdesc_accessFineLocation">"GPSなど、携帯電話の正確な位置情報源に、可能な場合アクセスします。これにより悪意のあるアプリケーションが、ユーザーの現在地を特定したり、バッテリの消費が増える恐れがあります。"</string>
+    <string name="permlab_accessCoarseLocation">"おおよその (ネットワーク情報による) 位置"</string>
+    <string name="permdesc_accessCoarseLocation">"セルラーネットワークデータベースなど、携帯電話のおおよその位置を特定する情報源が利用可能な場合にアクセスします。これにより悪意のあるアプリケーションが、ユーザーのおおよその位置を特定できる恐れがあります。"</string>
+    <string name="permlab_accessSurfaceFlinger">"SurfaceFlingerへのアクセス"</string>
+    <string name="permdesc_accessSurfaceFlinger">"SurfaceFlingerの低レベルの機能の使用をアプリケーションに許可します。"</string>
+    <string name="permlab_readFrameBuffer">"フレームバッファの読み取り"</string>
+    <string name="permdesc_readFrameBuffer">"フレームバッファの内容の読み取りと使用をアプリケーションに許可します。"</string>
+    <string name="permlab_modifyAudioSettings">"音声設定の変更"</string>
+    <string name="permdesc_modifyAudioSettings">"音量や転送などの音声全般の設定の変更をアプリケーションに許可します。"</string>
+    <string name="permlab_recordAudio">"録音"</string>
+    <string name="permdesc_recordAudio">"オーディオ録音パスへのアクセスをアプリケーションに許可します。"</string>
+    <string name="permlab_camera">"写真の撮影"</string>
+    <string name="permdesc_camera">"カメラで写真を撮ることをアプリケーションに許可します。これによりアプリケーションは、カメラに写る画像をいつでも収集できます。"</string>
+    <string name="permlab_brick">"携帯電話を永久に使用できなくする"</string>
+    <string name="permdesc_brick">"携帯電話全体を永続的に無効にすることをアプリケーションに許可します。この許可は非常に危険です。"</string>
+    <string name="permlab_reboot">"携帯電話の再起動"</string>
+    <string name="permdesc_reboot">"携帯電話の強制的な再起動をアプリケーションに許可します。"</string>
+    <string name="permlab_mount_unmount_filesystems">"ファイルシステムのマウントとマウント解除"</string>
+    <string name="permdesc_mount_unmount_filesystems">"リムーバブルメモリのファイルシステムのマウントとマウント解除をアプリケーションに許可します。"</string>
+    <string name="permlab_vibrate">"バイブレータの制御"</string>
+    <string name="permdesc_vibrate">"バイブレータのコントロールをアプリケーションに許可します。"</string>
+    <string name="permlab_flashlight">"ライトのコントロール"</string>
+    <string name="permdesc_flashlight">"ライトの制御をアプリケーションに許可します。"</string>
+    <string name="permlab_hardware_test">"ハードウェアのテスト"</string>
+    <string name="permdesc_hardware_test">"ハードウェアのテストのためにさまざまな周辺機器を制御することをアプリケーションに許可します。"</string>
+    <string name="permlab_callPhone">"電話番号に直接発信"</string>
+    <string name="permdesc_callPhone">"電話を自動でかけることをアプリケーションに許可します。悪意のあるアプリケーションが予想外の電話をかけて、料金が発生する恐れがあります。緊急電話番号への通話は許可しません。"</string>
+    <string name="permlab_callPrivileged">"あらゆる電話番号に直接発信"</string>
+    <string name="permdesc_callPrivileged">"緊急電話を含めてあらゆる電話番号に自動発信することをアプリケーションに許可します。悪意のあるアプリケーションが緊急サービスに不要かつ不正な通話をする恐れがあります。"</string>
+    <string name="permlab_locationUpdates">"位置の更新通知の制御"</string>
+    <string name="permdesc_locationUpdates">"無線通信からの位置更新通知を有効/無効にすることを許可します。通常のアプリケーションでは使用しません。"</string>
+    <string name="permlab_checkinProperties">"チェックインプロパティへのアクセス"</string>
+    <string name="permdesc_checkinProperties">"チェックインサービスがアップロードしたプロパティへの読み書きを許可します。通常のアプリケーションでは使用しません。"</string>
+    <string name="permlab_modifyPhoneState">"携帯電話の状態の変更"</string>
+    <string name="permdesc_modifyPhoneState">"携帯端末の電話機能のコントロールをアプリケーションに許可します。この許可を受けたアプリケーションは、ネットワークの切り替え、携帯電話の無線通信のオン/オフなどを通知せずに行うことができます。"</string>
+    <string name="permlab_readPhoneState">"携帯電話の状態の読み取り"</string>
+    <string name="permdesc_readPhoneState">"携帯端末の電話機能へのアクセスをアプリケーションに許可します。これを許可されたアプリケーションは、この携帯電話の電話番号、通話中かどうか、通話相手の電話番号などを特定できます。"</string>
+    <string name="permlab_wakeLock">"携帯電話をスリープ状態にしない"</string>
+    <string name="permdesc_wakeLock">"携帯電話をスリープ状態にしないようにすることをアプリケーションに許可します。"</string>
+    <string name="permlab_devicePower">"携帯電話の電源のオン/オフ"</string>
+    <string name="permdesc_devicePower">"携帯電話の電源のオン/オフをアプリケーションに許可します。"</string>
+    <string name="permlab_factoryTest">"出荷時試験モードでの実行"</string>
+    <string name="permdesc_factoryTest">"携帯電話のハードウェアへのアクセスを完全に許可して、低レベルのメーカーテストとして実行します。メーカーのテストモードで携帯電話を使用するときのみ利用できます。"</string>
+    <string name="permlab_setWallpaper">"壁紙の設定"</string>
+    <string name="permdesc_setWallpaper">"システムの壁紙の設定をアプリケーションに許可します。"</string>
+    <string name="permlab_setWallpaperHints">"壁紙サイズのヒントの設定"</string>
+    <string name="permdesc_setWallpaperHints">"システムの壁紙サイズのヒントの設定をアプリケーションに許可します。"</string>
+    <string name="permlab_masterClear">"システムを出荷時のデフォルトにリセット"</string>
+    <string name="permdesc_masterClear">"データ、設定、インストールしたアプリケーションをすべて消去して、完全に出荷時の設定にシステムをリセットすることをアプリケーションに許可します。"</string>
+    <string name="permlab_setTimeZone">"タイムゾーンの設定"</string>
+    <string name="permdesc_setTimeZone">"携帯電話のタイムゾーンの変更をアプリケーションに許可します。"</string>
+    <string name="permlab_getAccounts">"既知のアカウントの取得"</string>
+    <string name="permdesc_getAccounts">"携帯端末内にあるアカウントのリストの取得をアプリケーションに許可します。"</string>
+    <string name="permlab_accessNetworkState">"ネットワーク状態の表示"</string>
+    <string name="permdesc_accessNetworkState">"すべてのネットワーク状態の表示をアプリケーションに許可します。"</string>
+    <string name="permlab_createNetworkSockets">"インターネットへの完全なアクセス権"</string>
+    <string name="permdesc_createNetworkSockets">"ネットワークソケットの作成をアプリケーションに許可します。"</string>
+    <string name="permlab_writeApnSettings">"アクセスポイント名設定の書き込み"</string>
+    <string name="permdesc_writeApnSettings">"APNのプロキシやポートなどのAPN設定の変更をアプリケーションに許可します。"</string>
+    <string name="permlab_changeNetworkState">"ネットワーク接続の変更"</string>
+    <string name="permdesc_changeNetworkState">"ネットワークの接続状態の変更をアプリケーションに許可します。"</string>
+    <string name="permlab_accessWifiState">"Wi-Fi状態の表示"</string>
+    <string name="permdesc_accessWifiState">"Wi-Fi状態に関する情報の表示をアプリケーションに許可します。"</string>
+    <string name="permlab_changeWifiState">"Wi-Fi状態の変更"</string>
+    <string name="permdesc_changeWifiState">"Wi-Fiアクセスポイントへの接続や接続の切断、設定されたWi-Fiネットワークの変更をアプリケーションに許可します。"</string>
+    <string name="permlab_bluetoothAdmin">"Bluetoothの管理"</string>
+    <string name="permdesc_bluetoothAdmin">"ローカルのBluetooth電話を設定し、リモートデバイスを検出してペアに設定することをアプリケーションに許可します。"</string>
+    <string name="permlab_bluetooth">"Bluetooth接続の作成"</string>
+    <string name="permdesc_bluetooth">"ローカルBluetooth電話の設定を表示し、デバイスをペアとして設定して接続を承認することをアプリケーションに許可します。"</string>
+    <string name="permlab_disableKeyguard">"キーロックを無効にする"</string>
+    <string name="permdesc_disableKeyguard">"キーロックや関連するパスワードセキュリティを無効にすることをアプリケーションに許可します。正当な利用の例では、かかってきた電話を受信する際にキーロックを無効にし、通話の終了時にキーロックを有効にし直します。"</string>
+    <string name="permlab_readSyncSettings">"同期設定の読み取り"</string>
+    <string name="permdesc_readSyncSettings">"連絡先の同期が有効かどうかなど、同期設定の読み取りをアプリケーションに許可します。"</string>
+    <string name="permlab_writeSyncSettings">"同期設定の書き込み"</string>
+    <string name="permdesc_writeSyncSettings">"連絡先の同期が有効かどうかなど、同期設定の変更をアプリケーションに許可します。"</string>
+    <string name="permlab_readSyncStats">"同期統計の読み取り"</string>
+    <string name="permdesc_readSyncStats">"同期状態 (同期履歴など) の読み取りをアプリケーションに許可します。"</string>
+    <string name="permlab_subscribedFeedsRead">"登録したフィードの読み取り"</string>
+    <string name="permdesc_subscribedFeedsRead">"現在同期しているフィードの詳細の取得をアプリケーションに許可します。"</string>
+    <string name="permlab_subscribedFeedsWrite">"登録したフィードの書き込み"</string>
+    <string name="permdesc_subscribedFeedsWrite">"現在同期しているフィードの変更をアプリケーションに許可します。悪意のあるアプリケーションが同期フィードを変更する恐れがあります。"</string>
+    <!-- no translation found for phoneTypes:7 (9192514806975898961) -->
+    <!-- no translation found for emailAddressTypes:3 (2374913952870110618) -->
+    <!-- no translation found for postalAddressTypes:3 (4932682847595299369) -->
+    <!-- no translation found for imAddressTypes:3 (3145118944639869809) -->
+    <!-- no translation found for organizationTypes:2 (3455047468583965104) -->
+  <string-array name="imProtocols">
+    <item>"AIM"</item>
+    <item>"Windows Live"</item>
+    <item>"Yahoo"</item>
+    <item>"Skype"</item>
+    <item>"QQ"</item>
+    <item>"Googleトーク"</item>
+    <item>"ICQ"</item>
+    <item>"Jabber"</item>
+  </string-array>
+    <!-- no translation found for keyguard_password_enter_pin_code (3731488827218876115) -->
+    <skip />
+    <string name="keyguard_password_wrong_pin_code">"PINコードが正しくありません。"</string>
+    <string name="keyguard_label_text">"ロックを解除するには、Menu、0キーの順に押します。"</string>
+    <string name="emergency_call_dialog_number_for_display">"緊急電話番号"</string>
+    <string name="lockscreen_carrier_default">"(サービスなし)"</string>
+    <!-- no translation found for lockscreen_screen_locked (7288443074806832904) -->
+    <skip />
+    <string name="lockscreen_instructions_when_pattern_enabled">"Menuキーを押してロックを解除するか、緊急電話をかけます。"</string>
+    <string name="lockscreen_instructions_when_pattern_disabled">"ロックを解除するにはMenuキーを押します。"</string>
+    <!-- no translation found for lockscreen_pattern_instructions (7478703254964810302) -->
+    <skip />
+    <string name="lockscreen_emergency_call">"緊急電話"</string>
+    <string name="lockscreen_pattern_correct">"一致しました"</string>
+    <!-- no translation found for lockscreen_pattern_wrong (4817583279053112312) -->
+    <skip />
+    <string name="lockscreen_plugged_in">"充電中 (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+    <string name="lockscreen_low_battery">"充電してください。"</string>
+    <string name="lockscreen_missing_sim_message_short">"SIMカードがありません。"</string>
+    <string name="lockscreen_missing_sim_message">"SIMカードが携帯電話に挿入されていません。"</string>
+    <string name="lockscreen_missing_sim_instructions">"SIMカードを挿入してください。"</string>
+    <string name="lockscreen_network_locked_message">"ネットワークがロックされました"</string>
+    <string name="lockscreen_sim_puk_locked_message">"SIMカードはPUKでロックされています。"</string>
+    <string name="lockscreen_sim_puk_locked_instructions">"お客様サポートにお問い合わせください。"</string>
+    <string name="lockscreen_sim_locked_message">"SIMカードはロックされています。"</string>
+    <string name="lockscreen_sim_unlock_progress_dialog_message">"SIMカードのロックを解除中..."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message">"ロック解除のパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しく指定されていません。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度指定してください。"</string>
+    <string name="lockscreen_failed_attempts_almost_glogin">"指定したパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しくありません。あと<xliff:g id="NUMBER_1">%d</xliff:g>回指定に失敗すると、携帯電話のロックの解除にGoogleへのログインが必要になります。"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度指定してください。"</string>
+    <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g>秒後にもう一度試してください。"</string>
+    <string name="lockscreen_forgot_pattern_button_text">"パターンを忘れた場合"</string>
+    <string name="lockscreen_glogin_too_many_attempts">"パターンの指定回数が多すぎる"</string>
+    <!-- no translation found for lockscreen_glogin_instructions (7400120254204758548) -->
+    <skip />
+    <string name="lockscreen_glogin_username_hint">"ユーザー名 (メール)"</string>
+    <string name="lockscreen_glogin_password_hint">"パスワード"</string>
+    <string name="lockscreen_glogin_submit_button">"ログイン"</string>
+    <string name="lockscreen_glogin_invalid_input">"ユーザー名またはパスワードが正しくありません。"</string>
+    <string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
+    <!-- no translation found for hour_minute_ampm (7044207493989843593) -->
+    <skip />
+    <!-- no translation found for hour_minute_cap_ampm (5778825208801303756) -->
+    <skip />
+    <!-- no translation found for hour_ampm (7618670480400517084) -->
+    <skip />
+    <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+    <skip />
+    <string name="status_bar_clear_all_button">"通知を消去"</string>
+    <string name="status_bar_no_notifications_title">"通知なし"</string>
+    <string name="status_bar_ongoing_events_title">"継続中"</string>
+    <string name="status_bar_latest_events_title">"通知"</string>
+    <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+    <skip />
+    <string name="battery_status_charging">"充電中..."</string>
+    <string name="battery_low_title">"充電してください"</string>
+    <string name="battery_low_subtitle">"バッテリの残量が少なくなっています。"</string>
+    <string name="battery_low_percent_format">"残り<xliff:g id="NUMBER">%d%%</xliff:g>未満"</string>
+    <string name="factorytest_failed">"出荷時試験が失敗"</string>
+    <string name="factorytest_not_system">"FACTORY_TEST操作は、/system/appにインストールされたパッケージのみが対象です。"</string>
+    <string name="factorytest_no_action">"FACTORY_TEST操作を行うパッケージは見つかりませんでした。"</string>
+    <string name="factorytest_reboot">"再起動"</string>
+    <string name="save_password_label">"確認"</string>
+    <string name="save_password_message">"このパスワードをブラウザで保存しますか?"</string>
+    <string name="save_password_notnow">"今は保存しない"</string>
+    <string name="save_password_remember">"保存"</string>
+    <string name="save_password_never">"保存しない"</string>
+    <string name="open_permission_deny">"このページへのアクセスは許可されていません。"</string>
+    <string name="text_copied">"テキストがクリップボードにコピーされました。"</string>
+    <string name="more_item_label">"その他"</string>
+    <string name="prepend_shortcut_label">"Menu+"</string>
+    <string name="menu_space_shortcut_label">"Space"</string>
+    <string name="menu_enter_shortcut_label">"Enter"</string>
+    <string name="menu_delete_shortcut_label">"Del"</string>
+    <string name="search_go">"Search"</string>
+    <string name="today">"今日"</string>
+    <string name="yesterday">"昨日"</string>
+    <string name="tomorrow">"明日"</string>
+    <string name="oneMonthDurationPast">"1か月前"</string>
+    <string name="beforeOneMonthDurationPast">"1か月前"</string>
+  <plurals name="num_seconds_ago">
+    <item quantity="one">"1秒前"</item>
+    <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
+  </plurals>
+  <plurals name="num_minutes_ago">
+    <item quantity="one">"1分前"</item>
+    <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
+  </plurals>
+  <plurals name="num_hours_ago">
+    <item quantity="one">"1時間前"</item>
+    <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
+  </plurals>
+  <plurals name="num_days_ago">
+    <item quantity="one">"昨日"</item>
+    <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
+  </plurals>
+  <plurals name="in_num_seconds">
+    <item quantity="one">"1秒後"</item>
+    <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
+  </plurals>
+  <plurals name="in_num_minutes">
+    <item quantity="one">"1分後"</item>
+    <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
+  </plurals>
+  <plurals name="in_num_hours">
+    <item quantity="one">"1時間後"</item>
+    <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
+  </plurals>
+  <plurals name="in_num_days">
+    <item quantity="one">"明日"</item>
+    <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
+  </plurals>
+    <string name="preposition_for_date">"%s"</string>
+    <string name="preposition_for_time">"%s"</string>
+    <string name="preposition_for_year">"%s年"</string>
+    <string name="day">"日"</string>
+    <string name="days">"日"</string>
+    <string name="hour">"時間"</string>
+    <string name="hours">"時間"</string>
+    <string name="minute">"分"</string>
+    <string name="minutes">"分"</string>
+    <string name="second">"秒"</string>
+    <string name="seconds">"秒"</string>
+    <string name="week">"週間"</string>
+    <string name="weeks">"週間"</string>
+    <string name="year">"年"</string>
+    <string name="years">"年"</string>
+    <string name="sunday">"日曜"</string>
+    <string name="monday">"月曜"</string>
+    <string name="tuesday">"火曜"</string>
+    <string name="wednesday">"水曜"</string>
+    <string name="thursday">"木曜"</string>
+    <string name="friday">"金曜"</string>
+    <string name="saturday">"土曜"</string>
+    <string name="every_weekday">"平日の毎日 (月~金)"</string>
+    <string name="daily">"毎日"</string>
+    <string name="weekly">"毎週<xliff:g id="DAY">%s</xliff:g>"</string>
+    <string name="monthly">"毎月"</string>
+    <string name="yearly">"毎年"</string>
+    <string name="VideoView_error_title">"動画を再生できません"</string>
+    <string name="VideoView_error_text_unknown">"この動画は再生できません。"</string>
+    <string name="VideoView_error_button">"OK"</string>
+    <string name="am">"AM"</string>
+    <string name="pm">"PM"</string>
+    <string name="numeric_date">"<xliff:g id="YEAR">%Y</xliff:g>/<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="MONTH">%m</xliff:g>"</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%3$s</xliff:g>~<xliff:g id="DATE2">%5$s</xliff:g> (<xliff:g id="WEEKDAY2">%4$s</xliff:g>) <xliff:g id="TIME2">%6$s</xliff:g>"</string>
+    <string name="wday1_date1_wday2_date2">"<xliff:g id="DATE1">%2$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="DATE2">%5$s</xliff:g> (<xliff:g id="WEEKDAY2">%4$s</xliff:g>)"</string>
+    <string name="date1_time1_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g> <xliff:g id="TIME1">%3$s</xliff:g>~<xliff:g id="DATE2">%5$s</xliff:g> <xliff:g id="TIME2">%6$s</xliff:g>"</string>
+    <string name="date1_date2">"<xliff:g id="DATE1">%2$s</xliff:g>~<xliff:g id="DATE2">%5$s</xliff:g>"</string>
+    <string name="time1_time2">"<xliff:g id="TIME1">%1$s</xliff:g>~<xliff:g id="TIME2">%2$s</xliff:g>"</string>
+    <string name="time_wday_date">"<xliff:g id="DATE">%3$s</xliff:g> (<xliff:g id="WEEKDAY">%2$s</xliff:g>) <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+    <string name="wday_date">"<xliff:g id="DATE">%3$s</xliff:g> (<xliff:g id="WEEKDAY">%2$s</xliff:g>)"</string>
+    <string name="time_date">"<xliff:g id="DATE">%3$s</xliff:g> <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+    <string name="time_wday">"<xliff:g id="WEEKDAY">%2$s</xliff:g> <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+    <string name="full_date_month_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMMM</xliff:g><xliff:g id="DAY">dd</xliff:g>\'日\'"</string>
+    <string name="full_date_day_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMMM</xliff:g><xliff:g id="DAY">dd</xliff:g>\'日\'"</string>
+    <string name="medium_date_month_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMM</xliff:g><xliff:g id="DAY">dd</xliff:g>\'日\'"</string>
+    <string name="medium_date_day_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMM</xliff:g><xliff:g id="DAY">dd</xliff:g>\'日\'"</string>
+    <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
+    <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+    <string name="noon">"正午"</string>
+    <string name="Noon">"正午"</string>
+    <string name="midnight">"午前0時"</string>
+    <string name="Midnight">"午前0時"</string>
+    <!-- no translation found for month_day (5565829181417740906) -->
+    <skip />
+    <!-- no translation found for month (7026169712234774086) -->
+    <skip />
+    <string name="month_day_year">"<xliff:g id="YEAR">%Y</xliff:g>年<xliff:g id="MONTH">%B</xliff:g><xliff:g id="DAY">%-d</xliff:g>日"</string>
+    <!-- no translation found for month_year (9219019380312413367) -->
+    <skip />
+    <string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
+    <string name="date_and_time">"<xliff:g id="YEAR">%Y</xliff:g>年<xliff:g id="MONTH">%B</xliff:g><xliff:g id="DAY">%-d</xliff:g>日<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
+    <string name="same_year_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日"</string>
+    <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
+    <string name="same_year_mdy1_mdy2">"<xliff:g id="YEAR">%9$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日"</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR">%9$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
+    <string name="same_year_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日<xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日<xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日<xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日<xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>"</string>
+    <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g> (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
+    <string name="numeric_mdy1_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>"</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g> (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
+    <string name="numeric_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g> (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g> (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="DAY2">%8$s</xliff:g>日"</string>
+    <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
+    <string name="same_month_mdy1_mdy2">"<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="DAY2">%8$s</xliff:g>日"</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
+    <string name="same_month_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日<xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日<xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日<xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日<xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+    <string name="abbrev_month_day_year">"<xliff:g id="YEAR">%Y</xliff:g>年<xliff:g id="MONTH">%b</xliff:g><xliff:g id="DAY">%-d</xliff:g>日"</string>
+    <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+    <skip />
+    <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+    <skip />
+    <!-- no translation found for abbrev_month (3131032032850777433) -->
+    <skip />
+    <string name="day_of_week_long_sunday">"日曜"</string>
+    <string name="day_of_week_long_monday">"月曜"</string>
+    <string name="day_of_week_long_tuesday">"火曜"</string>
+    <string name="day_of_week_long_wednesday">"水曜"</string>
+    <string name="day_of_week_long_thursday">"木曜"</string>
+    <string name="day_of_week_long_friday">"金曜"</string>
+    <string name="day_of_week_long_saturday">"土曜"</string>
+    <string name="day_of_week_medium_sunday">"日"</string>
+    <string name="day_of_week_medium_monday">"月"</string>
+    <string name="day_of_week_medium_tuesday">"火"</string>
+    <string name="day_of_week_medium_wednesday">"水"</string>
+    <string name="day_of_week_medium_thursday">"木"</string>
+    <string name="day_of_week_medium_friday">"金"</string>
+    <string name="day_of_week_medium_saturday">"土"</string>
+    <string name="day_of_week_short_sunday">"日"</string>
+    <string name="day_of_week_short_monday">"月"</string>
+    <string name="day_of_week_short_tuesday">"火"</string>
+    <string name="day_of_week_short_wednesday">"水"</string>
+    <string name="day_of_week_short_thursday">"木"</string>
+    <string name="day_of_week_short_friday">"金"</string>
+    <string name="day_of_week_short_saturday">"土"</string>
+    <string name="day_of_week_shorter_sunday">"日"</string>
+    <string name="day_of_week_shorter_monday">"月"</string>
+    <string name="day_of_week_shorter_tuesday">"火"</string>
+    <string name="day_of_week_shorter_wednesday">"水"</string>
+    <string name="day_of_week_shorter_thursday">"木"</string>
+    <string name="day_of_week_shorter_friday">"金"</string>
+    <string name="day_of_week_shorter_saturday">"土"</string>
+    <string name="day_of_week_shortest_sunday">"日"</string>
+    <string name="day_of_week_shortest_monday">"月"</string>
+    <string name="day_of_week_shortest_tuesday">"火"</string>
+    <string name="day_of_week_shortest_wednesday">"水"</string>
+    <string name="day_of_week_shortest_thursday">"木"</string>
+    <string name="day_of_week_shortest_friday">"金"</string>
+    <string name="day_of_week_shortest_saturday">"土"</string>
+    <string name="month_long_january">"1月"</string>
+    <string name="month_long_february">"2月"</string>
+    <string name="month_long_march">"3月"</string>
+    <string name="month_long_april">"4月"</string>
+    <string name="month_long_may">"5月"</string>
+    <string name="month_long_june">"6月"</string>
+    <string name="month_long_july">"7月"</string>
+    <string name="month_long_august">"8月"</string>
+    <string name="month_long_september">"9月"</string>
+    <string name="month_long_october">"10月"</string>
+    <string name="month_long_november">"11月"</string>
+    <string name="month_long_december">"12月"</string>
+    <string name="month_medium_january">"1月"</string>
+    <string name="month_medium_february">"2月"</string>
+    <string name="month_medium_march">"3月"</string>
+    <string name="month_medium_april">"4月"</string>
+    <string name="month_medium_may">"5月"</string>
+    <string name="month_medium_june">"6月"</string>
+    <string name="month_medium_july">"7月"</string>
+    <string name="month_medium_august">"8月"</string>
+    <string name="month_medium_september">"9月"</string>
+    <string name="month_medium_october">"10月"</string>
+    <string name="month_medium_november">"11月"</string>
+    <string name="month_medium_december">"12月"</string>
+    <string name="month_shortest_january">"1"</string>
+    <string name="month_shortest_february">"2"</string>
+    <string name="month_shortest_march">"3"</string>
+    <string name="month_shortest_april">"4"</string>
+    <string name="month_shortest_may">"5"</string>
+    <string name="month_shortest_june">"6"</string>
+    <string name="month_shortest_july">"7"</string>
+    <string name="month_shortest_august">"8"</string>
+    <string name="month_shortest_september">"9"</string>
+    <string name="month_shortest_october">"10"</string>
+    <string name="month_shortest_november">"11"</string>
+    <string name="month_shortest_december">"12"</string>
+    <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+    <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+    <string name="selectAll">"すべて選択"</string>
+    <string name="cut">"切り取り"</string>
+    <string name="cutAll">"すべて切り取り"</string>
+    <string name="copy">"コピー"</string>
+    <string name="copyAll">"すべてコピー"</string>
+    <string name="paste">"貼り付け"</string>
+    <string name="copyUrl">"URLをコピー"</string>
+    <!-- no translation found for inputMethod (7673923508389094672) -->
+    <skip />
+    <!-- no translation found for editTextMenuTitle (1672989176958581452) -->
+    <skip />
+    <string name="low_internal_storage_view_title">"空き容量低下"</string>
+    <string name="low_internal_storage_view_text">"携帯電話の空き容量が少なくなっています。"</string>
+    <string name="ok">"OK"</string>
+    <string name="cancel">"キャンセル"</string>
+    <string name="yes">"OK"</string>
+    <string name="no">"キャンセル"</string>
+    <string name="capital_on">"オン"</string>
+    <string name="capital_off">"オフ"</string>
+    <string name="whichApplication">"操作の完了に使用"</string>
+    <string name="alwaysUse">"この操作にデフォルトで使用します。"</string>
+    <string name="clearDefaultHintMsg">"ホームの[設定]&gt;[アプリケーション]&gt;[アプリケーションを管理]で、デフォルトをクリアします。"</string>
+    <string name="chooseActivity">"操作の選択"</string>
+    <string name="noApplications">"この操作を実行するアプリケーションはありません。"</string>
+    <string name="aerr_title">"エラー"</string>
+    <string name="aerr_application">"アプリケーション<xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>プロセス) が予期せず停止しました。もう一度試してください。"</string>
+    <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>プロセスが予期せず停止しました。もう一度試してください。"</string>
+    <string name="anr_title">"エラー"</string>
+    <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g>操作 (アプリケーション<xliff:g id="APPLICATION">%2$s</xliff:g>) は応答していません。"</string>
+    <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g>操作 (プロセス:<xliff:g id="PROCESS">%2$s</xliff:g>) は応答していません。"</string>
+    <string name="anr_application_process">"アプリケーション<xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>プロセス) は応答していません。"</string>
+    <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>プロセスは応答していません。"</string>
+    <string name="force_close">"強制終了"</string>
+    <string name="wait">"待機"</string>
+    <string name="debug">"デバッグ"</string>
+    <string name="sendText">"テキストの操作の選択"</string>
+    <string name="volume_ringtone">"着信音の音量"</string>
+    <!-- no translation found for volume_music (5421651157138628171) -->
+    <skip />
+    <!-- no translation found for volume_music_hint_playing_through_bluetooth (9165984379394601533) -->
+    <skip />
+    <string name="volume_call">"着信音の音量"</string>
+    <!-- no translation found for volume_call_hint_playing_through_bluetooth (7750873841563910404) -->
+    <skip />
+    <string name="volume_alarm">"アラームの音量"</string>
+    <!-- no translation found for volume_notification (2422265656744276715) -->
+    <skip />
+    <string name="volume_unknown">"音量"</string>
+    <string name="ringtone_default">"デフォルトの着信音"</string>
+    <string name="ringtone_default_with_actual">"デフォルトの着信音 (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+    <string name="ringtone_silent">"無音"</string>
+    <!-- no translation found for ringtone_picker_title (3515143939175119094) -->
+    <skip />
+    <string name="ringtone_unknown">"不明の着信音"</string>
+  <plurals name="wifi_available">
+    <item quantity="one">"Wi-Fiネットワークが利用可能"</item>
+    <item quantity="other">"Wi-Fiネットワークが利用可能"</item>
+  </plurals>
+  <plurals name="wifi_available_detailed">
+    <item quantity="one">"Wi-Fiオープンネットワークが利用できます"</item>
+    <item quantity="other">"Wi-Fiオープンネットワークが利用できます"</item>
+  </plurals>
+    <!-- no translation found for select_character (3365550120617701745) -->
+    <skip />
+    <string name="sms_control_default_app_name">"不明なアプリケーション"</string>
+    <string name="sms_control_title">"SMSメッセージの送信中"</string>
+    <string name="sms_control_message">"大量のSMSメッセージが送信されます。送信するには[OK]、中止するには[キャンセル]を選択します。"</string>
+    <string name="sms_control_yes">"OK"</string>
+    <string name="sms_control_no">"キャンセル"</string>
+    <string name="date_time_set">"設定"</string>
+    <string name="default_permission_group">"デフォルト"</string>
+    <string name="no_permissions">"許可は必要ありません"</string>
+    <string name="perms_hide"><b>"隠す"</b></string>
+    <string name="perms_show_all"><b>"すべて表示"</b></string>
+    <string name="googlewebcontenthelper_loading">"読み込み中..."</string>
+    <string name="usb_storage_title">"USB接続"</string>
+    <string name="usb_storage_message">"USB経由で携帯電話をコンピュータに接続しました。コンピュータと携帯電話のSDカード間でファイルをコピーするには、[マウント]を選択します。"</string>
+    <string name="usb_storage_button_mount">"マウント"</string>
+    <string name="usb_storage_button_unmount">"マウントしない"</string>
+    <string name="usb_storage_error_message">"USBメモリにSDカードを使用する際に問題が発生しました。"</string>
+    <string name="usb_storage_notification_title">"USB接続"</string>
+    <string name="usb_storage_notification_message">"パソコンとの間でファイルをコピーします。"</string>
+    <!-- no translation found for select_input_method (2086499663193509436) -->
+    <skip />
+    <!-- no translation found for fast_scroll_alphabet (5433275485499039199) -->
+    <skip />
+    <!-- no translation found for fast_scroll_numeric_alphabet (4030170524595123610) -->
+    <skip />
+    <!-- no translation found for candidates_style (5248064431114273041) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc204-de/strings.xml b/core/res/res/values-mcc204-de/strings.xml
new file mode 100644
index 0000000..1b2f85b
--- /dev/null
+++ b/core/res/res/values-mcc204-de/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for locale_replacement (2972154133076909542) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc204-ja/strings.xml b/core/res/res/values-mcc204-ja/strings.xml
new file mode 100644
index 0000000..1b2f85b
--- /dev/null
+++ b/core/res/res/values-mcc204-ja/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for locale_replacement (2972154133076909542) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc204/arrays.xml b/core/res/res/values-mcc204/arrays.xml
new file mode 100644
index 0000000..7902a13
--- /dev/null
+++ b/core/res/res/values-mcc204/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<resources>
+
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_lat_lng">
+        <item>51589256</item>
+        <item>4774396</item>
+    </integer-array>
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_zoom">
+        <item>6</item>
+    </integer-array>
+
+</resources>
diff --git a/core/res/res/values-mcc204/strings.xml b/core/res/res/values-mcc204/strings.xml
new file mode 100644
index 0000000..c3fff3d
--- /dev/null
+++ b/core/res/res/values-mcc204/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2008, Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- A string used to replace %s in a URL to fill in the locale for countries  -->
+    <!-- whose locale we don't natively support.  A 0 length string triggers no replacement -->
+    <string name="locale_replacement">nl_nl</string>    
+</resources>
diff --git a/core/res/res/values-mcc230-de/strings.xml b/core/res/res/values-mcc230-de/strings.xml
new file mode 100644
index 0000000..46bdbda
--- /dev/null
+++ b/core/res/res/values-mcc230-de/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for locale_replacement (9011721823833053909) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc230-ja/strings.xml b/core/res/res/values-mcc230-ja/strings.xml
new file mode 100644
index 0000000..46bdbda
--- /dev/null
+++ b/core/res/res/values-mcc230-ja/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for locale_replacement (9011721823833053909) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc230/arrays.xml b/core/res/res/values-mcc230/arrays.xml
new file mode 100644
index 0000000..71c3ed6
--- /dev/null
+++ b/core/res/res/values-mcc230/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<resources>
+
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_lat_lng">
+        <item>50087811</item>
+        <item>14420460</item>
+    </integer-array>
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_zoom">
+        <item>6</item>
+    </integer-array>
+
+</resources>
diff --git a/core/res/res/values-mcc230/strings.xml b/core/res/res/values-mcc230/strings.xml
new file mode 100644
index 0000000..559b858
--- /dev/null
+++ b/core/res/res/values-mcc230/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2008, Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- A string used to replace %s in a URL to fill in the locale for countries  -->
+    <!-- whose locale we don't natively support.  A 0 length string triggers no replacement -->
+    <string name="locale_replacement">cs_cz</string>    
+</resources>
diff --git a/core/res/res/values-mcc232-de/strings.xml b/core/res/res/values-mcc232-de/strings.xml
new file mode 100644
index 0000000..0a20691
--- /dev/null
+++ b/core/res/res/values-mcc232-de/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for locale_replacement (166900303893651370) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc232-ja/strings.xml b/core/res/res/values-mcc232-ja/strings.xml
new file mode 100644
index 0000000..0a20691
--- /dev/null
+++ b/core/res/res/values-mcc232-ja/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for locale_replacement (166900303893651370) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc232/arrays.xml b/core/res/res/values-mcc232/arrays.xml
new file mode 100644
index 0000000..98458f8
--- /dev/null
+++ b/core/res/res/values-mcc232/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<resources>
+
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_lat_lng">
+        <item>48209206</item>
+        <item>16372778</item>
+    </integer-array>
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_zoom">
+        <item>6</item>
+    </integer-array>
+
+</resources>
diff --git a/core/res/res/values-mcc232/strings.xml b/core/res/res/values-mcc232/strings.xml
new file mode 100644
index 0000000..494770f
--- /dev/null
+++ b/core/res/res/values-mcc232/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2008, Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- A string used to replace %s in a URL to fill in the locale for countries  -->
+    <!-- whose locale we don't natively support.  A 0 length string triggers no replacement -->
+    <string name="locale_replacement">de_at</string>    
+</resources>
diff --git a/core/res/res/values-mcc234-de/strings.xml b/core/res/res/values-mcc234-de/strings.xml
new file mode 100644
index 0000000..44a7f03
--- /dev/null
+++ b/core/res/res/values-mcc234-de/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for locale_replacement (233769627858930762) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc234-ja/strings.xml b/core/res/res/values-mcc234-ja/strings.xml
new file mode 100644
index 0000000..44a7f03
--- /dev/null
+++ b/core/res/res/values-mcc234-ja/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for locale_replacement (233769627858930762) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc234/strings.xml b/core/res/res/values-mcc234/strings.xml
new file mode 100644
index 0000000..2e6a3f3
--- /dev/null
+++ b/core/res/res/values-mcc234/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2008, Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- A string used to replace %s in a URL to fill in the locale for countries  -->
+    <!-- whose locale we don't natively support.  A 0 length string triggers no replacement -->
+    <string name="locale_replacement">en_gb</string>    
+</resources>
diff --git a/core/res/res/values-mcc260/arrays.xml b/core/res/res/values-mcc260/arrays.xml
new file mode 100644
index 0000000..03447ab
--- /dev/null
+++ b/core/res/res/values-mcc260/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<resources>
+
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_lat_lng">
+        <item>59910761</item>
+        <item>10749092</item>
+    </integer-array>
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_zoom">
+        <item>5</item>
+    </integer-array>
+
+</resources>
diff --git a/core/res/res/values-mcc260/strings.xml b/core/res/res/values-mcc260/strings.xml
new file mode 100644
index 0000000..20c19dd
--- /dev/null
+++ b/core/res/res/values-mcc260/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2008, Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- A string used to replace %s in a URL to fill in the locale for countries  -->
+    <!-- whose locale we don't natively support.  A 0 length string triggers no replacement -->
+    <string name="locale_replacement">pl_pl</string>    
+</resources>
diff --git a/core/res/res/values-mcc262-de/strings.xml b/core/res/res/values-mcc262-de/strings.xml
new file mode 100644
index 0000000..fad4872
--- /dev/null
+++ b/core/res/res/values-mcc262-de/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for locale_replacement (273407696421660814) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc262-ja/strings.xml b/core/res/res/values-mcc262-ja/strings.xml
new file mode 100644
index 0000000..fad4872
--- /dev/null
+++ b/core/res/res/values-mcc262-ja/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for locale_replacement (273407696421660814) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-mcc262/arrays.xml b/core/res/res/values-mcc262/arrays.xml
new file mode 100644
index 0000000..955df7d
--- /dev/null
+++ b/core/res/res/values-mcc262/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<resources>
+
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_lat_lng">
+        <item>52372026</item>
+        <item>9735672</item>
+    </integer-array>
+    <!-- Do not translate. -->
+    <integer-array name="maps_starting_zoom">
+        <item>5</item>
+    </integer-array>
+
+</resources>
diff --git a/core/res/res/values-mcc262/strings.xml b/core/res/res/values-mcc262/strings.xml
new file mode 100644
index 0000000..8ca0e31
--- /dev/null
+++ b/core/res/res/values-mcc262/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2008, Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- A string used to replace %s in a URL to fill in the locale for countries  -->
+    <!-- whose locale we don't natively support.  A 0 length string triggers no replacement -->
+    <string name="locale_replacement">de_de</string>    
+</resources>
diff --git a/core/res/res/values-nl-rNL/strings.xml b/core/res/res/values-nl-rNL/strings.xml
index bca994b..1dc48bb 100644
--- a/core/res/res/values-nl-rNL/strings.xml
+++ b/core/res/res/values-nl-rNL/strings.xml
@@ -1,558 +1,905 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="BaMmi">Oproep blokkeren</string>
-  <string name="CLIRDefaultOffNextCallOff">ID-beperkingsstandaarden op onbeperkt. Volgend gesprek: niet beperkt</string>
-  <string name="CLIRDefaultOffNextCallOn">ID-beperkingsstandaarden op onbeperkt. Volgend gesprek: beperkt</string>
-  <string name="CLIRDefaultOnNextCallOff">ID-beperkingsstandaarden op beperkt. Volgend gesprek: niet beperkt</string>
-  <string name="CLIRDefaultOnNextCallOn">ID-beperkingsstandaarden op beperkt. Volgend gesprek: beperkt</string>
-  <string name="CLIRPermanent">ID-beperking ingesteld op permanente modus.</string>
-  <string name="CfMmi">Oproep doorschakelen</string>
-  <string name="ClipMmi">Nummerweergave inkomend gesprek</string>
-  <string name="ClirMmi">Nummerweergave uitgaand gesprek</string>
-  <string name="CwMmi">Gesprek in wachtstand</string>
-  <string name="Midnight">"Middernacht"</string>
-  <string name="Noon">"12 uur 'smiddags"</string>
-  <string name="PinMmi">Pincode wijzigen</string>
-  <string name="PwdMmi">Wachtwoord wijzigen</string>
-  <string name="VideoView_error_button">OK</string>
-  <string name="VideoView_error_text_unknown">Fout opgetreden bij afspelen van geselecteerde video.</string>
-  <string name="VideoView_error_title">Videoafspeelfout</string>
-  <string name="abbrev_month">"<xliff:g id="format">%b</xliff:g>"</string>
-  <string name="abbrev_month_day">"<xliff:g id="format">%-d %b</xliff:g>"</string>
-  <string name="abbrev_month_day_year">"<xliff:g id="format">%-d %b %Y</xliff:g>"</string>
-  <string name="abbrev_month_year">"<xliff:g id="format">%b %Y</xliff:g>"</string>
-  <string name="activate_keyguard">Toetsbescherming activeren</string>
-  <string name="ago">geleden</string>
-  <string name="alwaysUse">Deze toepassing altijd gebruiken voor deze toepassing</string>
-  <string name="am">"AM"</string>
-  <string name="battery_low_percent_format">Minder dan <xliff:g id="number">%d%%</xliff:g>
-    resterend</string>
-  <string name="battery_low_subtitle">Lage batterijstroom</string>
-  <string name="battery_low_title">Oplader verbinden</string>
-  <string name="battery_status_charging">Bezig met opladen\u2026</string>
-  <string name="battery_status_text_percent_format"><xliff:g id="number">%d%%</xliff:g></string>
-  <string name="before">Voor</string>
-  <string name="browserSavedFormData">Formuliergegevens opgeslagen</string>
-  <string name="byteShort">b</string>
-  <string name="cancel">Annuleren</string>
-  <string name="capital_off">UIT</string>
-  <string name="capital_on">AAN</string>
-  <string name="cfReasonBusy">Oproep doorschakelen bezig</string>
-  <string name="cfReasonNR">Oproep doorschakelen niet bereikbaar</string>
-  <string name="cfReasonNRy">Oproep doorschakelen geen antwoord</string>
-  <string name="cfReasonUnconditional">Oproep doorschakelen onvoorwaardelijk</string>
-  <string name="cfTemplateForwarded">{0}: {1}</string>
-  <string name="cfTemplateForwardedTime">{0}: {1} na {2} seconden</string>
-  <string name="cfTemplateNotForwarded">{0}: Niet doorgestuurd</string>
-  <string name="cfTemplateRegistered">{0}: Niet doorgestuurd ({1})</string>
-  <string name="cfTemplateRegisteredTime">{0}: Niet doorgestuurd ({1} na {2} seconden)</string>
-  <string name="chooseActivity">Een actie selecteren</string>
-  <string name="contentServiceSync">Sync</string>
-  <string name="contentServiceSyncNotificationDesc">Bezig met synchroniseren</string>
-  <string name="contentServiceSyncNotificationTitle">Sync</string>
-  <string name="contentServiceXmppAvailable">XMPP actief</string>
-  <string name="copy">Kopiëren</string>
-  <string name="copyUrl">URL kopiëren</string>
-  <string name="cut">Knippen</string>
-  <string name="daily">Elke dag</string>
-  <string name="daily_format">h:mm aa</string>
-  <string name="date1_date2">"<xliff:g id="format">%2$s \u2013 %5$s</xliff:g>"</string>
-  <string name="date1_time1_date2_time2">"<xliff:g id="format">%2$s, %3$s \u2013 %5$s, %6$s</xliff:g>"</string>
-  <string name="date_picker_set">Instellen</string>
-  <string name="date_range_separator">" \u2013 "</string>
-  <string name="day">dag</string>
-  <string name="day_of_week_long_friday">Vrijdag</string>
-  <string name="day_of_week_long_monday">Maandag</string>
-  <string name="day_of_week_long_saturday">Zaterdag</string>
-  <string name="day_of_week_long_sunday">Zondag</string>
-  <string name="day_of_week_long_thursday">Donderdag</string>
-  <string name="day_of_week_long_tuesday">Dinsdag</string>
-  <string name="day_of_week_long_wednesday">Woensdag</string>
-  <string name="day_of_week_medium_friday">Vri</string>
-  <string name="day_of_week_medium_monday">Maa</string>
-  <string name="day_of_week_medium_saturday">Zat</string>
-  <string name="day_of_week_medium_sunday">Zon</string>
-  <string name="day_of_week_medium_thursday">Don</string>
-  <string name="day_of_week_medium_tuesday">Din</string>
-  <string name="day_of_week_medium_wednesday">Woe</string>
-  <string name="day_of_week_short_friday">Vr</string>
-  <string name="day_of_week_short_monday">Ma</string>
-  <string name="day_of_week_short_saturday">Za</string>
-  <string name="day_of_week_short_sunday">Zo</string>
-  <string name="day_of_week_short_thursday">Do</string>
-  <string name="day_of_week_short_tuesday">Di</string>
-  <string name="day_of_week_short_wednesday">Wo</string>
-  <string name="day_of_week_shorter_friday">V</string>
-  <string name="day_of_week_shorter_monday">M</string>
-  <string name="day_of_week_shorter_saturday">Za</string>
-  <string name="day_of_week_shorter_sunday">Zo</string>
-  <string name="day_of_week_shorter_thursday">Do</string>
-  <string name="day_of_week_shorter_tuesday">Di</string>
-  <string name="day_of_week_shorter_wednesday">W</string>
-  <string name="day_of_week_shortest_friday">V</string>
-  <string name="day_of_week_shortest_monday">M</string>
-  <string name="day_of_week_shortest_saturday">Z</string>
-  <string name="day_of_week_shortest_sunday">Z</string>
-  <string name="day_of_week_shortest_thursday">Do</string>
-  <string name="day_of_week_shortest_tuesday">Di</string>
-  <string name="day_of_week_shortest_wednesday">W</string>
-  <string name="days">dagen</string>
-  <string name="daysDurationFuturePlural">over <xliff:g id="days">%d</xliff:g> dagen</string>
-  <string name="daysDurationPastPlural"><xliff:g id="days">%d</xliff:g> dagen geleden</string>
-  <string name="defaultMsisdnAlphaTag">Msisdn1</string>
-  <string name="defaultVoiceMailAlphaTag">Voicemail</string>
-  <string name="elapsed_time_short_format_h_mm_ss"><xliff:g id="format">%1$d:%2$02d:%3$02d</xliff:g></string>
-  <string name="elapsed_time_short_format_mm_ss"><xliff:g id="format">%1$02d:%2$02d</xliff:g></string>
-  <string name="ellipsis">\u2026</string>
-  <string name="emergency_call_dialog_call">Noodoproep</string>
-  <string name="emergency_call_dialog_cancel">Annuleren</string>
-  <string name="emergency_call_dialog_number_for_display">Alarmnummers</string>
-  <string name="emergency_call_dialog_text">Een alarmnummer bellen?</string>
-  <string name="emergency_call_number_uri">tel:112</string>
-  <string name="emptyPhoneNumber">(geen telefoonnummer)</string>
-  <string name="every_weekday">"Elke werkdag (Maa\u2013vri)"</string>
-  <string name="factorytest_failed">Fabriekstest mislukt</string>
-  <string name="factorytest_no_action">Geen pakket gevonden dat de handeling        FACTORY_TEST levert.</string>
-  <string name="factorytest_not_system">De handeling FACTORY_TEST
-        wordt alleen ondersteund voor pakketten die geïnstalleerd zijn in /system/app.</string>
-  <string name="factorytest_reboot">Opnieuw opstarten</string>
-  <string name="friday">Vrijdag</string>
-  <string name="gigabyteShort">Gb</string>
-  <string name="global_action_lock">Vergrendeling</string>
-  <string name="global_action_power_off">Uitschakelen</string>
-  <string name="global_action_silent_mode_off_status">Geluid staat AAN</string>
-  <string name="global_action_silent_mode_on_status">Geluid staat UIT</string>
-  <string name="global_action_toggle_silent_mode">Stille modus</string>
-  <string name="global_actions">Globale handelingen</string>
-  <string name="hour">uur</string>
-  <string name="hours">uur</string>
-  <string name="httpError">Onbekende fout</string>
-  <string name="httpErrorAuth">Verificatie mislukt</string>
-  <string name="httpErrorBadUrl">Ongeldige url</string>
-  <string name="httpErrorConnect">Verbinding maken met server mislukt</string>
-  <string name="httpErrorFailedSslHandshake">Uitvoeren van ssl-handshake mislukt</string>
-  <string name="httpErrorFile">Bestandfout</string>
-  <string name="httpErrorFileNotFound">Bestand niet gevonden</string>
-  <string name="httpErrorIO">Lezen van of schrijven naar server mislukt</string>
-  <string name="httpErrorLookup">Onbekende host</string>
-  <string name="httpErrorOk">OK</string>
-  <string name="httpErrorProxyAuth">Verificeren van proxyserver mislukt</string>
-  <string name="httpErrorRedirectLoop">Te veel omleidingen door server</string>
-  <string name="httpErrorTimeout">Time-out bij serververbinding</string>
-  <string name="httpErrorUnsupportedAuthScheme">Niet-ondersteund verificatieschema. Verificeren mislukt.</string>
-  <string name="httpErrorUnsupportedScheme">Protocol wordt niet ondersteund</string>
-  <string name="in">in</string>
-  <string name="keyguard_label_text">Om vrij te geven drukt u op Menu en vervolgens op 0.</string>
-  <string name="keyguard_password_emergency_instructions">Druk op de Beltoets om het alarmnummer te bellen.</string>
-  <string name="keyguard_password_enter_pin_code">Pincode invoeren</string>
-  <string name="keyguard_password_instructions">Voer een wachtwoord in of bel een alarmnummer.</string>
-  <string name="keyguard_password_wrong_pin_code">Onjuiste pincode!</string>
-  <string name="kilobyteShort">Kb</string>
-  <string name="lockscreen_carrier_default">(Geen service)</string>
-  <string name="lockscreen_carrier_key">gsm.operator.alpha</string>
-  <string name="lockscreen_emergency_call">Noodoproep</string>
-  <string name="lockscreen_instructions_when_pattern_disabled">Druk op Menu om vrij te geven</string>
-  <string name="lockscreen_instructions_when_pattern_enabled">Druk op Menu om vrij te geven of bel een alarmnummer</string>
-  <string name="lockscreen_low_battery">Oplader verbinden</string>
-  <string name="lockscreen_missing_sim_instructions">Voer een SIM-kaart in</string>
-  <string name="lockscreen_missing_sim_message">Geen SIM in toestel</string>
-  <string name="lockscreen_pattern_correct">Juist!</string>
-  <string name="lockscreen_pattern_instructions">Patroon tekenen om vrij te geven</string>
-  <string name="lockscreen_pattern_wrong">Verkeerd patroon! Nogmaals proberen</string>
-  <string name="lockscreen_plugged_in">Bezig met opladen (<xliff:g id="number">%d%%</xliff:g>)</string>
-  <string name="lockscreen_screen_locked">Schermblokkering</string>
-  <string name="lockscreen_too_many_failed_attempts_countdown">Probeer opnieuw over <xliff:g id="number">%d</xliff:g> seconden</string>
-  <string name="lockscreen_too_many_failed_attempts_dialog_message">
-        U heeft nu <xliff:g id="number">%d</xliff:g> mislukte pogingen om
-        het vrijgavepatroon correct te tekenen.\n
-        Probeer opnieuw over <xliff:g id="number">%d</xliff:g> seconden.
-    </string>
-  <string name="lockscreen_too_many_failed_attempts_dialog_title">Blokkeerpatroonwaarschuwing</string>
-  <string name="low_internal_storage_text">Weinig intern geheugen</string>
-  <string name="low_internal_storage_view_text">Toestel heeft weinig intern geheugen</string>
-  <string name="low_internal_storage_view_title">Weinig intern geheugen</string>
-  <string name="megabyteShort">Mb</string>
-  <string name="midnight">"middernacht"</string>
-  <string name="minute">minuut</string>
-  <string name="minutes">minuten</string>
-  <string name="mmiComplete">MMI voltooid</string>
-  <string name="mmiError">Netwerkfout of onjuiste MMI-code.</string>
-  <string name="monday">Maandag</string>
-  <string name="month">"<xliff:g id="format">%B</xliff:g>"</string>
-  <string name="month_day">"<xliff:g id="format">%-d %B</xliff:g>"</string>
-  <string name="month_day_year">"<xliff:g id="format">%-d %B %Y</xliff:g>"</string>
-  <string name="month_long_april">April</string>
-  <string name="month_long_august">Augustus</string>
-  <string name="month_long_december">December</string>
-  <string name="month_long_february">Februari</string>
-  <string name="month_long_january">Januari</string>
-  <string name="month_long_july">Juli</string>
-  <string name="month_long_june">Juni</string>
-  <string name="month_long_march">Maart</string>
-  <string name="month_long_may">Mei</string>
-  <string name="month_long_november">November</string>
-  <string name="month_long_october">Oktober</string>
-  <string name="month_long_september">September</string>
-  <string name="month_medium_april">apr</string>
-  <string name="month_medium_august">aug</string>
-  <string name="month_medium_december">dec</string>
-  <string name="month_medium_february">feb</string>
-  <string name="month_medium_january">jan</string>
-  <string name="month_medium_july">jul</string>
-  <string name="month_medium_june">jun</string>
-  <string name="month_medium_march">mrt</string>
-  <string name="month_medium_may">mei</string>
-  <string name="month_medium_november">nov</string>
-  <string name="month_medium_october">okt</string>
-  <string name="month_medium_september">sep</string>
-  <string name="month_shortest_april">A</string>
-  <string name="month_shortest_august">A</string>
-  <string name="month_shortest_december">D</string>
-  <string name="month_shortest_february">F</string>
-  <string name="month_shortest_january">J</string>
-  <string name="month_shortest_july">J</string>
-  <string name="month_shortest_june">J</string>
-  <string name="month_shortest_march">M</string>
-  <string name="month_shortest_may">M</string>
-  <string name="month_shortest_november">N</string>
-  <string name="month_shortest_october">O</string>
-  <string name="month_shortest_september">S</string>
-  <string name="month_year">"<xliff:g id="format">%B %Y</xliff:g>"</string>
-  <string name="monthly">Elke mnd</string>
-  <string name="monthly_format">d MMM</string>
-  <string name="more_item_label">Meer</string>
-  <string name="no">Annuleren</string>
-  <string name="noApplications">Geen toepassingen beschikbaar om        de handeling uit te voeren</string>
-  <string name="no_recent_tasks">Geen recente toepassingen</string>
-  <string name="noon">"12 uur 'smiddags"</string>
-  <string name="numeric_date">"<xliff:g id="format">%d/%m/%Y</xliff:g>"</string>
-  <string name="numeric_date_notation">"<xliff:g id="format">%d/%m/%y</xliff:g>"</string>
-  <string name="numeric_md1_md2">"<xliff:g id="format">%3$s/%2$s \u2013 %8$s/%7$s</xliff:g>"</string>
-  <string name="numeric_md1_time1_md2_time2">"<xliff:g id="format">%3$s/%2$s, %5$s \u2013 %8$s/%7$s, %10$s</xliff:g>"</string>
-  <string name="numeric_mdy1_mdy2">"<xliff:g id="format">%3$s/%2$s/%4$s \u2013 %8$s/%7$s/%9$s</xliff:g>"</string>
-  <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="format">%3$s/%2$s/%4$s, %5$s \u2013 %8$s/%7$s/%9$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s %3$s/%2$s, %5$s \u2013 %6$s %8$s/%7$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s %3$s/%2$s \u2013 %6$s %8$s/%7$s</xliff:g>"</string>
-  <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s %3$s/%2$s/%4$s, %5$s \u2013 %6$s %8$s/%7$s/%9$s, %10$s</xliff:g>"</string>
-  <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s %3$s/%2$s/%4$s \u2013 %6$s %8$s/%7$s/%9$s</xliff:g>"</string>
-  <string name="ok">OK</string>
-  <string name="open_permission_deny">U hebt geen toestemming om deze pagina te openen.</string>
-  <string name="passwordIncorrect">Ongeldig wachtwoord</string>
-  <string name="paste">Plakken</string>
-  <string name="permdesc_accessFineLocation">Open, indien beschikbaar, het Global
-        Positioning System op het toestel.
-        Verkeerde toepassingen kunnen dit gebruiken om te bepalen waar u
-        zich bevindt en extra batterijstroom verbruiken.</string>
-  <string name="permdesc_accessCoarseLocation">Gebruik, indien beschikbaar, een
-        netwerkdatabank om de locatie van het toestel te schatten. Verkeerde toepassingen
-        kunnen dit gebruiken om te schatten waar u zich bevindt.</string>
-  <string name="permdesc_accessPhoneInterface">Toepassingen mogen de interne
-        Telefooninterface openen. Is bij normale toepassingen nooit nodig.</string>
-  <string name="permdesc_accessSurfaceFlinger">Toepassingen mogen de        functies op laag niveau van SurfaceFlinger gebruiken.</string>
-  <string name="permdesc_addSystemService">Toepassingen mogen hun
-        eigen systeemdiensten van laag-niveau publiceren. Verkeerde toepassingen kunnen
-        het systeem kapen en gegevens erop beschadigen of stelen.</string>
-  <string name="permdesc_brick">Hiermee kan de toepassing de gehele
-        dienst permanent uitschakelen. Dit is erg gevaarlijk.</string>
-  <string name="permdesc_broadcastPackageRemoved">Hiermee kan een toepassing
-        een melding uitzenden met de mededeling dat een toepassingspakket is verwijderd.
-        Verkeerde toepassingen kunnen dit gebruiken om andere
-        actieve toepassingen te stoppen.</string>
-  <string name="permdesc_broadcastSticky">Hiermee kan een toepassing
-        plakuitzendingen versturen, die blijven hangen als de uitzending stopt.
-        Verkeerde toepassingen kunnen het toestel traag of instabiel maken
-        door te veel geheugengebruik te veroorzaken.</string>
-  <string name="permdesc_callPhone">Hiermee kunnen toepassingen
-        telefoonnummers bellen zonder uw tussenkomst. Verkeerde toepassingen
-        kunnen ongewilde gesprekken op uw telefoonrekening veroorzaken.</string>
-  <string name="permdesc_camera">Hiermee kunnen toepassingen
-        foto's maken met de camera. Hiermee kan de toepassing op elk moment de
-        beelden van de camera ophalen.</string>
-  <string name="permdesc_changeComponentState">Hiermee kan een toepassing veranderen of
-        een component van een andere toepassing wordt ingeschakeld of niet. Slechte toepassingen kunnen
-        dit gebruiken om belangrijke toestelfuncties uit te schakelen. Wees voorzichtig met het verlenen van
-        toestemmingen, omdat het mogelijk is dat toepassingscomponenten in een onbruikbare, inconsistente of instabiele toestand geraken.
-    </string>
-  <string name="permdesc_changeConfiguration">Hiermee kan een toepassing
-        de actuele configuratie veranderen, zoals de locatie of algemene
-        tekengrootte.</string>
-  <string name="permdesc_clearAppCache">Hiermee kan een toepassing toestelgeheugen
-        vrijmaken door bestanden uit de cachemap te verwijderen. Toegang wordt 
-        meestal beperkt tot systeemprocessen.</string>
-  <string name="permdesc_deleteCacheFiles">Hiermee kan een toepassing        cachebestanden verwijderen.</string>
-  <string name="permdesc_deletePackages">Hiermee kan een toepassing
-        Android-pakketten verwijderen. Slechte toepassingen kunnen dit misbruiken om belangrijke toepassingen te wissen.</string>
-  <string name="permdesc_devicePower">Hiermee kan de toepassing het        toestel in- of uitschakelen, of ingeschakeld laten.</string>
-  <string name="permdesc_dump">Hiermee kan een toepassingen
-        de interne toestand van het systeem opvragen. Verkeerde toepassingen kunnen
-        een diverse privé- en veiligheidsinformatie verkrijgen die ze
-        normaal gesproken niet nodig hebben.</string>
-  <string name="permdesc_factoryTest">Uitvoeren als een fabriekstest op laag
-        niveau, waardoor volledige toegang tot de toestelhardware gegeven is. Alleen beschikbaar
-        als een toestel in de fabriekstestmodus staat.</string>
-  <string name="permdesc_flashlight">Hiermee kan de toepassing de        flitser besturen.</string>
-  <string name="permdesc_forceBack">Hiermee kan een toepassing elke
-        activiteit die op de voorgrond staat sluiten en terugkeren.
-        Is bij normale toepassingen nooit nodig.</string>
-  <string name="permdesc_fotaUpdate">Hiermee kan een toepassing
-        meldingen ontvangen over systeemupdates die in behandeling zijn en hun installatie
-        in gang zetten. Slechte toepassingen kunnen dit misbruiken om het
-        te beschadigen met niet toegestane updates, of algemeen het updaten
-        te verstoren.</string>
-  <string name="permdesc_getTasks">Hiermee kan een toepassing
-        informatie ophalen over geactiveerde en recent geactiveerde taken. Verkeerde
-        toepassingen kunnen hierdoor
-        toegang krijgen tot privé-informatie over andere toepassingen.</string>
-  <string name="permdesc_hardware_test">Hiermee kan de toepassing diverse        randapparaten besturen met als doel het testen van de hardware.</string>
-  <string name="permdesc_injectEvents">Hiermee kan een toepassing
-        zijn eigen invoergebeurtenissen (toetsindrukken enz.) naar andere toepassingen sturen. Slechte
-        toepassingen kunnen dit misbruiken om controle over het toestel te krijgen.</string>
-  <string name="permdesc_installPackages">Hiermee kan een toepassing nieuwe Android-
-        pakketten installeren of updaten. Slechte toepassingen kunnen dit misbruiken om nieuwe
-        toepassingen met twijfelachtig verstrekkende rechten toe te voegen.</string>
-  <string name="permdesc_internalSystemWindow">Hiermee kunnen vensters
-        worden gemaakt die bedoeld zijn voor gebruik door het interne systeem
-        van de gebruikersinterface. Niet bedoeld voor normale toepassingen.</string>
-  <string name="permdesc_manageAppTokens">Hiermee kunnen toepassingen
-        hun eigen tokens maken, en zo de normale Z-ordening
-        buiten spel zetten. Is bij normale toepassingen nooit nodig.</string>
-  <string name="permdesc_masterClear">Hiermee kan een toepassing het
-        systeem volledig opnieuw instellen op fabrieksinstellingen, waardoor alle gegevens,
-        configuratie en geïnstalleerde toepassingen worden gewist.</string>
-  <string name="permdesc_modifyAudioSettings">Hiermee kan een toepassing        globale audioinstellingen aanpassen, zoals volume en route.</string>
-  <string name="permdesc_mount_unmount_filesystems">Hiermee kan de toepassing        bestandssystemen voor verwisselbaar geheugen koppelen en loskoppelen.</string>
-  <string name="permdesc_persistentActivity">Hiermee kan een toepassing
-        gedeeltes van zichzelf fixeren, zodat het systeem deze niet meer kan gebruiken voor andere
-        toepassingen.</string>
-  <string name="permdesc_raisedThreadPriority">Hiermee kan een toepassing
-        zgn raised thread priorities gebruiken, wat mogelijk invloed heeft op de reactiesnelheid van de
-        gebruikersinterface.</string>
-  <string name="permdesc_readContacts">Hiermee kan een toepassing alle
-        contactgegevens (adres) op het toestel lezen. Slechte toepassingen
-        kunnen dit misbruiken om uw gegevens naar andere personen te sturen.</string>
-  <string name="permdesc_readFrameBuffer">Hiermee kan een toepassing        de gegevens van de framebuffer lezen.</string>
-  <string name="permdesc_readInputState">Hiermee kunnen toepassingen de
-        toetsen zien die u indrukt, ook bij interactie met een andere toepassing (zoals
-        het invoeren van een wachtwoord). Is bij normale toepassingen nooit nodig.</string>
-  <string name="permdesc_readSms">Hiermee kan een toepassing
-      sms-berichten op telefoon of SIM-kaart lezen. Slechte toepassingen
-      kunnen vertrouwelijke berichten lezen.</string>
-  <string name="permdesc_receiveBootCompleted">Hiermee kan een toepassing
-        zichzelf starten zodra het systeem is opgestart.
-        Hierdoor kan het opstarten van het toestel langer duren en de
-        toepassing het toestel afremmen omdat het altijd is geactiveerd.</string>
-  <string name="permdesc_receiveMms">Hiermee kan een toepassing
-      multimediaberichten ontvangen en verwerken. Slechte toepassingen kunnen
-      uw berichten in de gaten houden of verwijderen zonder dat dit wordt aangegeven.</string>
-  <string name="permdesc_receiveSms">Hiermee kan een toepassing
-      tekstberichten ontvangen en verwerken. Slechte toepassingen kunnen
-      uw berichten in de gaten houden of verwijderen zonder dat dit wordt aangegeven.</string>
-  <string name="permdesc_receiveWapPush">Hiermee kan een toepassing
-      wap-berichten ontvangen en verwerken. Slechte toepassingen kunnen
-      uw berichten in de gaten houden of verwijderen zonder dat dit wordt aangegeven.</string>
-  <string name="permdesc_recordAudio">Hierdoor kan een toepassing        het opnamepad voor audio openen.</string>
-  <string name="permdesc_reorderTasks">Hiermee kan een toepassing
-        taken naar de voorgrond en achtergrond verplaatsen. Slechte toepassingen kunnen
-        zichzelf zonder tussenkomst naar de voorgrond forceren.</string>
-  <string name="permdesc_runInstrumentation">Hiermee kan een toepassing
-        zijn eigen instrumentatiecode invoegen in elke andere toepassing.
-        Slechte toepassingen kunnen zo het systeem in gevaar brengen. Deze
-        toepassing is alleen nodig voor ontwikkelingsdoeleinden, nooit voor normaal
-        gebruik van het toestel.</string>
-  <string name="permdesc_runSetActivityWatcher">Hiermee kan een toepassing
-        de wijze waarop het systeem activiteiten start in de gaten houden en besturen.
-        Slechte toepassingen kunnen zo het systeem in gevaar brengen. Deze
-        toepassing is alleen nodig voor ontwikkelingsdoeleinden, nooit voor normaal
-        gebruik van het toestel.</string>
-  <string name="permdesc_sendSms">Hiermee kan een toepassing
-      tekstberichten verzenden. Slechte toepassingen kunnen u op kosten jagen door
-      zonder toestemming berichten te verzenden.</string>
-  <string name="permdesc_setAlwaysFinish">Hiermee kan een toepassing
-        besturen of activiteiten altijd voltooid moeten zijn als ze
-        naar de achtergrond gaan. Nooit
-        nodig voor normale toepassingen.</string>
-  <string name="permdesc_setAnimationScale">Hiermee kan een toepassing op        elk moment de globale animatiesnelheid (snellere of tragere animaties) veranderen.</string>
-  <string name="permdesc_setDebugApp">Hiermee kan een toepassing
-        foutopsporing voor andere toepassingen inschakelen. Slechte toepassingen kunnen
-        dit misbruiken om andere toepassingen te stoppen.</string>
-  <string name="permdesc_setOrientation">Hiermee kan een toepassing op
-        elk moment de schermligging veranderen. Is bij normale toepassingen
-        nooit nodig.</string>
-  <string name="permdesc_setPreferredApplications">Hiermee kan een toepassing
-        uw voorkeurstoepassingen veranderen. Slechte toepassingen kunnen zo
-        stilletjes veranderen welke toepassingen gestart moeten worden, zodat
-        bestaande toepassingen privégegevens over u verzamelen.</string>
-  <string name="permdesc_setProcessLimit">Hiermee kan een toepassing
-        het maximumaantal geactiveerde processen besturen. Nooit
-        nodig voor normale toepassingen.</string>
-  <string name="permdesc_setWallpaper">Hiermee kan de toepassing        de systeemachtergrond instellen.</string>
-  <string name="permdesc_signalPersistentProcesses">Hiermee kan een toepassing verzoeken        dat het meegeleverde signaal naar alle aanhoudende processen wordt gestuurd.</string>
-  <string name="permdesc_statusBar">Hiermee kan een toepassing        de statusbalk en pictogrammen openen, sluiten of uitschakelen.</string>
-  <string name="permdesc_systemAlertWindow">Hiermee kan een toepassing
-        systeemmeldingen weergeven. Slechte toepassingen kunnen het
-        volledige toestelscherm overnemen.</string>
-  <string name="permdesc_vibrate">Hiermee kan de toepassing de        triller besturen.</string>
-  <string name="permdesc_writeContacts">Hiermee kan een toepassing alle
-        contactgegevens (adres) op het toestel aanpassen. Slechte
-        toepassingen kunnen dit misbruiken om contactgegevens te wissen of wijzigen.</string>
-  <string name="permdesc_writeSettings">Hiermee kan een toepassing de
-        instellingsgegevens van het systeem aanpassen. Slechte toepassingen kunnen de configuratie
-        van het systeem beschadigen.</string>
-  <string name="permdesc_writeSms">Hiermee kan een toepassing
-      sms-berichten op telefoon of SIM-kaart schrijven. Slechte toepassingen
-      kunnen berichten verwijderen.</string>
-  <string name="permlab_accessFineLocation">Toegang tot gps-locatie</string>
-  <string name="permlab_accessCoarseLocation">Toegang tot netwerklocatie</string>
-  <string name="permlab_accessPhoneInterface">Toegang tot telefooninterface</string>
-  <string name="permlab_accessSurfaceFlinger">Toegang tot SurfaceFlinger</string>
-  <string name="permlab_addSystemService">Systeemservice toevoegen</string>
-  <string name="permlab_brick">Toestel uitschakelen</string>
-  <string name="permlab_broadcastPackageRemoved">Uitzendpakket verwijderd</string>
-  <string name="permlab_broadcastSticky">Belangrijke uitzending</string>
-  <string name="permlab_callPhone">Telefoonnummers bellen</string>
-  <string name="permlab_camera">Camera</string>
-  <string name="permlab_changeComponentState">Toepassingscomponenten in- of uitschakelen</string>
-  <string name="permlab_changeConfiguration">Configuratie wijzigen</string>
-  <string name="permlab_clearAppCache">Cachegegevens van toepassing wissen</string>
-  <string name="permlab_deleteCacheFiles">Cachebestanden wissen</string>
-  <string name="permlab_deletePackages">Pakketten verwijderen</string>
-  <string name="permlab_devicePower">Toestel inschakelen</string>
-  <string name="permlab_dump">Systeemstatus dumpen</string>
-  <string name="permlab_factoryTest">Fabriekstest</string>
-  <string name="permlab_flashlight">Flitser</string>
-  <string name="permlab_forceBack">Terug forceren</string>
-  <string name="permlab_fotaUpdate">Installatie van systeemupdate</string>
-  <string name="permlab_getTasks">Taakinformatie verkrijgen</string>
-  <string name="permlab_hardware_test">Hardwaretest</string>
-  <string name="permlab_injectEvents">Invoergebeurtenissen invoegen</string>
-  <string name="permlab_installPackages">Pakketten installeren</string>
-  <string name="permlab_internalSystemWindow">Intern systeemvenster</string>
-  <string name="permlab_manageAppTokens">Toepassingstokens beheren</string>
-  <string name="permlab_masterClear">Volledige systeemreset</string>
-  <string name="permlab_modifyAudioSettings">Audioinstellingen wijzigen</string>
-  <string name="permlab_mount_unmount_filesystems">Bestandssystemen koppelen en losmaken</string>
-  <string name="permlab_persistentActivity">Aanhoudende handelingen</string>
-  <string name="permlab_raisedThreadPriority">Raised thread priorities</string>
-  <string name="permlab_readContacts">Contactgegevens lezen</string>
-  <string name="permlab_readFrameBuffer">Framebuffer lezen</string>
-  <string name="permlab_readInputState">Invoerstatus lezen</string>
-  <string name="permlab_readSms">Sms/mms-berichten lezen</string>
-  <string name="permlab_receiveBootCompleted">Uitvoeren bij opstarten</string>
-  <string name="permlab_receiveMms">Mms-berichten ontvangen</string>
-  <string name="permlab_receiveSms">Sms-berichten ontvangen</string>
-  <string name="permlab_receiveWapPush">Wap-berichten ontvangen</string>
-  <string name="permlab_recordAudio">Audio opnemen</string>
-  <string name="permlab_reorderTasks">Taken herschikken</string>
-  <string name="permlab_runInstrumentation">Instrumentatie uitvoeren</string>
-  <string name="permlab_runSetActivityWatcher">Activiteitenmonitor instellen</string>
-  <string name="permlab_sendSms">Sms-berichten verzenden</string>
-  <string name="permlab_setAlwaysFinish">Altijd voltooien instellen</string>
-  <string name="permlab_setAnimationScale">Animatieschaal instellen</string>
-  <string name="permlab_setDebugApp">Foutopsporing instellen</string>
-  <string name="permlab_setOrientation">Ligging instellen</string>
-  <string name="permlab_setPreferredApplications">Voorkeurstoepassingen instellen</string>
-  <string name="permlab_setProcessLimit">Proceslimiet instellen</string>
-  <string name="permlab_setWallpaper">Achtergrond instellen</string>
-  <string name="permlab_signalPersistentProcesses">Signaal naar aanhoudende processen</string>
-  <string name="permlab_statusBar">Statusbalk besturen</string>
-  <string name="permlab_systemAlertWindow">Systeemmeldingen</string>
-  <string name="permlab_vibrate">Triller</string>
-  <string name="permlab_writeContacts">Contactgegevens schrijven</string>
-  <string name="permlab_writeSettings">Systeeminstellingen schrijven</string>
-  <string name="permlab_writeSms">Sms/mms-berichten schrijven</string>
-  <string name="petabyteShort">Pb</string>
-  <string name="pm">"PM"</string>
-  <string name="power_dialog">Energieopties</string>
-  <string name="power_off">Uitschakelen</string>
-  <string name="prepend_shortcut_label">Menu+</string>
-  <string name="preposition_for_date">op %s</string>
-  <string name="preposition_for_time">bij %s</string>
-  <string name="preposition_for_year">in %s</string>
-  <string name="safeMode">Veilige modus</string>
-  <string name="same_month_md1_md2">"<xliff:g id="format">%2$s %3$s \u2013 %8$s</xliff:g>"</string>
-  <string name="same_month_md1_time1_md2_time2">"<xliff:g id="format">%3$s %2$s, %5$s \u2013 %8$s %7$s, %10$s</xliff:g>"</string>
-  <string name="same_month_mdy1_mdy2">"<xliff:g id="format">%3$s \u2013 %8$s %2$s, %9$s</xliff:g>"</string>
-  <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="format">%3$s %2$s %4$s, %5$s \u2013 %8$s %7$s %9$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s %3$s %2$s, %5$s \u2013 %6$s %8$s %7$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s %3$s %2$s \u2013 %6$s %8$s %7$s</xliff:g>"</string>
-  <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s %3$s %2$s %4$s, %5$s \u2013 %6$s %8$s %7$s %9$s, %10$s</xliff:g>"</string>
-  <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s %3$s %2$s %4$s \u2013 %6$s %8$s %7$s, %9$s</xliff:g>"</string>
-  <string name="same_year_md1_md2">"<xliff:g id="format">%3$s %2$s \u2013 %8$s %7$s</xliff:g>"</string>
-  <string name="same_year_md1_time1_md2_time2">"<xliff:g id="format">%3$s %2$s, %5$s \u2013 %8$s %7$s, %10$s</xliff:g>"</string>
-  <string name="same_year_mdy1_mdy2">"<xliff:g id="format">%3$s %2$s \u2013 %8$s %7$s, %9$s</xliff:g>"</string>
-  <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="format">%3$s %2$s %4$s, %5$s \u2013 %8$s %7$s %9$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s %3$s %2$s, %5$s \u2013 %6$s %8$s %7$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s %3$s %2$s \u2013 %6$s %8$s %7$s</xliff:g>"</string>
-  <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s %3$s %2$s %4$s, %5$s \u2013 %6$s %8$s %7$s %9$s, %10$s</xliff:g>"</string>
-  <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s %3$s %2$s \u2013 %6$s %8$s %7$s %9$s</xliff:g>"</string>
-  <string name="saturday">Zaterdag</string>
-  <string name="save_password_label">Bevestigen</string>
-  <string name="save_password_message">Wilt u dat de browser dit wachtwoord onthoudt?</string>
-  <string name="save_password_never">Nooit</string>
-  <string name="save_password_notnow">Niet nu</string>
-  <string name="save_password_remember">Onthouden</string>
-  <string name="screen_lock">Vergrendeling</string>
-  <string name="screen_progress">Bezig\u2026</string>
-  <string name="search_go">Ga naar</string>
-  <string name="second">seconde</string>
-  <string name="seconds">seconden</string>
-  <string name="selectAll">Alles selecteren</string>
-  <string name="selectMenuLabel">Selecteren</string>
-  <string name="sendText">Kiezen wat met de tekst gebeurt</string>
-  <string name="serviceClassData">Gegevens</string>
-  <string name="serviceClassDataAsync">Async</string>
-  <string name="serviceClassDataSync">Sync</string>
-  <string name="serviceClassFAX">FAX</string>
-  <string name="serviceClassPAD">PAD</string>
-  <string name="serviceClassPacket">Pakket</string>
-  <string name="serviceClassSMS">SMS</string>
-  <string name="serviceClassVoice">Spraak</string>
-  <string name="serviceDisabled">Service uitgeschakeld</string>
-  <string name="serviceEnabled">Service ingeschakeld</string>
-  <string name="serviceEnabledFor">Service ingeschakeld voor:</string>
-  <string name="serviceErased">Wissen gelukt</string>
-  <string name="serviceNotProvisioned">Service niet opgenomen.</string>
-  <string name="serviceRegistered">Registratie gelukt</string>
-  <string name="silent_mode">Stille modus</string>
-  <string name="simAbsentLabel">SIM ontbreekt of onjuist geplaatst</string>
-  <string name="simNetworkPersonalizationLabel">SIM kan niet op dit toestel worden gebruikt</string>
-  <string name="simPINLabel">SIM-pincode nodig (en momenteel niet ondersteund)</string>
-  <string name="simPUKLabel">SIM-PUK-code nodig (en momenteel niet ondersteund)</string>
-  <string name="status_bar_applications_title">Toepassing</string>
-  <string name="status_bar_date_format">"<xliff:g id="format">d MMMM yyyy</xliff:g>"</string>
-  <string name="status_bar_latest_events_title">Nieuwste gebeurtenissen</string>
-  <string name="status_bar_no_notifications_title">Meldingen</string>
-  <string name="status_bar_ongoing_events_title">Actueel</string>
-  <string name="status_bar_time_format">"<xliff:g id="format">h:mm AA</xliff:g>"</string>
-  <string name="sunday">Zondag</string>
-  <string name="terabyteShort">Tb</string>
-  <string name="thursday">Donderdag</string>
-  <string name="time1_time2">"<xliff:g id="format">%1$s \u2013 %2$s</xliff:g>"</string>
-  <string name="time_date">"<xliff:g id="format">%1$s, %3$s</xliff:g>"</string>
-  <string name="time_picker_set">Instellen</string>
-  <string name="time_wday">"<xliff:g id="format">%2$s %1$s</xliff:g>"</string>
-  <string name="time_wday_date">"<xliff:g id="format">%2$s %1$s %3$s</xliff:g>"</string>
-  <string name="today">Vandaag</string>
-  <string name="tomorrow">Morgen</string>
-  <string name="tuesday">Dinsdag</string>
-  <string name="turn_off_radio">Radio uitschakelen</string>
-  <string name="turn_on_radio">Radio uitschakelen</string>
-  <string name="unknownName">(onbekend)</string>
-  <string name="untitled">&lt;Naamloos&gt;</string>
-  <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="format">%1$s %2$s, %3$s \u2013 %4$s %5$s, %6$s</xliff:g>"</string>
-  <string name="wday1_date1_wday2_date2">"<xliff:g id="format">%1$s %2$s \u2013 %4$s %5$s</xliff:g>"</string>
-  <string name="wday_date">"<xliff:g id="format">%2$s %3$s</xliff:g>"</string>
-  <string name="web_user_agent">Mozilla/5.0 (Linux; U; Android 0.6; en)
-        AppleWebKit/525.10+ (KHTML, zoals Gecko) Versie/3.0.4 Mobile Safari/523.12.2</string>
-  <string name="wednesday">Woensdag</string>
-  <string name="week">week</string>
-  <string name="weekly">"Wekelijks op <xliff:g id="day">%s</xliff:g>"</string>
-  <string name="weekly_format">d MMM</string>
-  <string name="weeks">weken</string>
-  <string name="whichApplication">Welke toepassing wilt u gebruiken?</string>
-  <string name="yearly">Elk jaar</string>
-  <string name="yearly_format">yyyy</string>
-  <string name="yes">OK</string>
-  <string name="yesterday">Gisteren</string>
+    <string name="byteShort">"b"</string>
+    <string name="kilobyteShort">"Kb"</string>
+    <string name="megabyteShort">"Mb"</string>
+    <string name="gigabyteShort">"Gb"</string>
+    <string name="terabyteShort">"Tb"</string>
+    <string name="petabyteShort">"Pb"</string>
+    <string name="untitled">"&lt;Naamloos&gt;"</string>
+    <string name="ellipsis">"…"</string>
+    <string name="emptyPhoneNumber">"(geen telefoonnummer)"</string>
+    <string name="unknownName">"(onbekend)"</string>
+    <string name="defaultVoiceMailAlphaTag">"Voicemail"</string>
+    <string name="defaultMsisdnAlphaTag">"Msisdn1"</string>
+    <string name="mmiError">"Netwerkfout of onjuiste MMI-code."</string>
+    <string name="serviceEnabled">"Service ingeschakeld"</string>
+    <string name="serviceEnabledFor">"Service ingeschakeld voor:"</string>
+    <string name="serviceDisabled">"Service uitgeschakeld"</string>
+    <string name="serviceRegistered">"Registratie gelukt"</string>
+    <string name="serviceErased">"Wissen gelukt"</string>
+    <string name="passwordIncorrect">"Ongeldig wachtwoord"</string>
+    <string name="mmiComplete">"MMI voltooid"</string>
+    <!-- no translation found for badPin (5103184589972647739) -->
+    <skip />
+    <!-- no translation found for badPuk (2200634943393540609) -->
+    <skip />
+    <!-- no translation found for mismatchPin (5055729703806180857) -->
+    <skip />
+    <!-- no translation found for invalidPin (6201854814319326475) -->
+    <skip />
+    <!-- no translation found for needPuk (4788728144863892764) -->
+    <skip />
+    <!-- no translation found for needPuk2 (7056908944942451033) -->
+    <skip />
+    <string name="ClipMmi">"Nummerweergave inkomend gesprek"</string>
+    <string name="ClirMmi">"Nummerweergave uitgaand gesprek"</string>
+    <string name="CfMmi">"Oproep doorschakelen"</string>
+    <string name="CwMmi">"Gesprek in wachtstand"</string>
+    <string name="BaMmi">"Oproep blokkeren"</string>
+    <string name="PwdMmi">"Wachtwoord wijzigen"</string>
+    <string name="PinMmi">"Pincode wijzigen"</string>
+    <string name="CLIRDefaultOnNextCallOn">"ID-beperkingsstandaarden op beperkt. Volgend gesprek: beperkt"</string>
+    <string name="CLIRDefaultOnNextCallOff">"ID-beperkingsstandaarden op beperkt. Volgend gesprek: niet beperkt"</string>
+    <string name="CLIRDefaultOffNextCallOn">"ID-beperkingsstandaarden op onbeperkt. Volgend gesprek: beperkt"</string>
+    <string name="CLIRDefaultOffNextCallOff">"ID-beperkingsstandaarden op onbeperkt. Volgend gesprek: niet beperkt"</string>
+    <string name="serviceNotProvisioned">"Service niet opgenomen."</string>
+    <string name="CLIRPermanent">"ID-beperking ingesteld op permanente modus."</string>
+    <string name="serviceClassVoice">"Spraak"</string>
+    <string name="serviceClassData">"Gegevens"</string>
+    <string name="serviceClassFAX">"FAX"</string>
+    <string name="serviceClassSMS">"SMS"</string>
+    <string name="serviceClassDataAsync">"Async"</string>
+    <string name="serviceClassDataSync">"Sync"</string>
+    <string name="serviceClassPacket">"Pakket"</string>
+    <string name="serviceClassPAD">"PAD"</string>
+    <string name="cfTemplateNotForwarded">"{0}: Niet doorgestuurd"</string>
+    <string name="cfTemplateForwarded">"{0}: {1}"</string>
+    <string name="cfTemplateForwardedTime">"{0}: {1} na {2} seconden"</string>
+    <string name="cfTemplateRegistered">"{0}: Niet doorgestuurd ({1})"</string>
+    <string name="cfTemplateRegisteredTime">"{0}: Niet doorgestuurd ({1} na {2} seconden)"</string>
+    <string name="httpErrorOk">"OK"</string>
+    <string name="httpError">"Onbekende fout"</string>
+    <string name="httpErrorLookup">"Onbekende host"</string>
+    <string name="httpErrorUnsupportedAuthScheme">"Niet-ondersteund verificatieschema. Verificeren mislukt."</string>
+    <string name="httpErrorAuth">"Verificatie mislukt"</string>
+    <string name="httpErrorProxyAuth">"Verificeren van proxyserver mislukt"</string>
+    <string name="httpErrorConnect">"Verbinding maken met server mislukt"</string>
+    <string name="httpErrorIO">"Lezen van of schrijven naar server mislukt"</string>
+    <string name="httpErrorTimeout">"Time-out bij serververbinding"</string>
+    <string name="httpErrorRedirectLoop">"Te veel omleidingen door server"</string>
+    <string name="httpErrorUnsupportedScheme">"Protocol wordt niet ondersteund"</string>
+    <string name="httpErrorFailedSslHandshake">"Uitvoeren van ssl-handshake mislukt"</string>
+    <string name="httpErrorBadUrl">"Ongeldige url"</string>
+    <string name="httpErrorFile">"Bestandfout"</string>
+    <string name="httpErrorFileNotFound">"Bestand niet gevonden"</string>
+    <!-- no translation found for httpErrorTooManyRequests (3764334538393544875) -->
+    <skip />
+    <string name="contentServiceSync">"Sync"</string>
+    <string name="contentServiceSyncNotificationTitle">"Sync"</string>
+    <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8477597194404210723) -->
+    <skip />
+    <!-- no translation found for low_memory (4191592786596642367) -->
+    <skip />
+    <!-- no translation found for me (4616693653158602117) -->
+    <skip />
+    <string name="power_dialog">"Energieopties"</string>
+    <string name="silent_mode">"Stille modus"</string>
+    <string name="turn_on_radio">"Radio uitschakelen"</string>
+    <string name="turn_off_radio">"Radio uitschakelen"</string>
+    <string name="screen_lock">"Vergrendeling"</string>
+    <string name="power_off">"Uitschakelen"</string>
+    <!-- no translation found for shutdown_progress (3735034517335251808) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm (699224922526414097) -->
+    <skip />
+    <string name="no_recent_tasks">"Geen recente toepassingen"</string>
+    <string name="global_actions">"Globale handelingen"</string>
+    <string name="global_action_lock">"Vergrendeling"</string>
+    <string name="global_action_power_off">"Uitschakelen"</string>
+    <string name="global_action_toggle_silent_mode">"Stille modus"</string>
+    <string name="global_action_silent_mode_on_status">"Geluid staat UIT"</string>
+    <string name="global_action_silent_mode_off_status">"Geluid staat AAN"</string>
+    <string name="safeMode">"Veilige modus"</string>
+    <!-- no translation found for permgrouplab_costMoney (904087853776533085) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_costMoney (4662370555643969515) -->
+    <skip />
+    <!-- no translation found for permgrouplab_messages (2984053976424233925) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_messages (2129093134354989379) -->
+    <skip />
+    <!-- no translation found for permgrouplab_personalInfo (4548406335021507392) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_personalInfo (8499310823817958034) -->
+    <skip />
+    <!-- no translation found for permgrouplab_location (8535677827151907069) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_location (2341662219604651887) -->
+    <skip />
+    <!-- no translation found for permgrouplab_network (3597781730625751831) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_network (8332572695347918340) -->
+    <skip />
+    <!-- no translation found for permgrouplab_accounts (8631201594657951893) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_accounts (443982868906396781) -->
+    <skip />
+    <!-- no translation found for permgrouplab_hardwareControls (5074512938567152139) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_hardwareControls (8772503144945278440) -->
+    <skip />
+    <!-- no translation found for permgrouplab_phoneCalls (7096448531266882376) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_phoneCalls (6703873478653366233) -->
+    <skip />
+    <!-- no translation found for permgrouplab_systemTools (1840847965111633430) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_systemTools (2810337951496685271) -->
+    <skip />
+    <!-- no translation found for permgrouplab_developmentTools (692844635256963358) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_developmentTools (5253915519857796400) -->
+    <skip />
+    <string name="permlab_statusBar">"Statusbalk besturen"</string>
+    <string name="permdesc_statusBar">"Hiermee kan een toepassing de statusbalk en pictogrammen openen, sluiten of uitschakelen."</string>
+    <!-- no translation found for permlab_expandStatusBar (6382500803293284173) -->
+    <skip />
+    <!-- no translation found for permdesc_expandStatusBar (90953162060681436) -->
+    <skip />
+    <!-- no translation found for permlab_processOutgoingCalls (786316295241100144) -->
+    <skip />
+    <!-- no translation found for permdesc_processOutgoingCalls (1655242138991854396) -->
+    <skip />
+    <string name="permlab_receiveSms">"Sms-berichten ontvangen"</string>
+    <string name="permdesc_receiveSms">"Hiermee kan een toepassing tekstberichten ontvangen en verwerken. Slechte toepassingen kunnen uw berichten in de gaten houden of verwijderen zonder dat dit wordt aangegeven."</string>
+    <string name="permlab_receiveMms">"Mms-berichten ontvangen"</string>
+    <string name="permdesc_receiveMms">"Hiermee kan een toepassing multimediaberichten ontvangen en verwerken. Slechte toepassingen kunnen uw berichten in de gaten houden of verwijderen zonder dat dit wordt aangegeven."</string>
+    <string name="permlab_sendSms">"Sms-berichten verzenden"</string>
+    <string name="permdesc_sendSms">"Hiermee kan een toepassing tekstberichten verzenden. Slechte toepassingen kunnen u op kosten jagen door zonder toestemming berichten te verzenden."</string>
+    <string name="permlab_readSms">"Sms/mms-berichten lezen"</string>
+    <string name="permdesc_readSms">"Hiermee kan een toepassing sms-berichten op telefoon of SIM-kaart lezen. Slechte toepassingen kunnen vertrouwelijke berichten lezen."</string>
+    <string name="permlab_writeSms">"Sms/mms-berichten schrijven"</string>
+    <string name="permdesc_writeSms">"Hiermee kan een toepassing sms-berichten op telefoon of SIM-kaart schrijven. Slechte toepassingen kunnen berichten verwijderen."</string>
+    <string name="permlab_receiveWapPush">"Wap-berichten ontvangen"</string>
+    <string name="permdesc_receiveWapPush">"Hiermee kan een toepassing wap-berichten ontvangen en verwerken. Slechte toepassingen kunnen uw berichten in de gaten houden of verwijderen zonder dat dit wordt aangegeven."</string>
+    <string name="permlab_getTasks">"Taakinformatie verkrijgen"</string>
+    <string name="permdesc_getTasks">"Hiermee kan een toepassing informatie ophalen over geactiveerde en recent geactiveerde taken. Verkeerde toepassingen kunnen hierdoor toegang krijgen tot privé-informatie over andere toepassingen."</string>
+    <string name="permlab_reorderTasks">"Taken herschikken"</string>
+    <string name="permdesc_reorderTasks">"Hiermee kan een toepassing taken naar de voorgrond en achtergrond verplaatsen. Slechte toepassingen kunnen zichzelf zonder tussenkomst naar de voorgrond forceren."</string>
+    <string name="permlab_setDebugApp">"Foutopsporing instellen"</string>
+    <string name="permdesc_setDebugApp">"Hiermee kan een toepassing foutopsporing voor andere toepassingen inschakelen. Slechte toepassingen kunnen dit misbruiken om andere toepassingen te stoppen."</string>
+    <string name="permlab_changeConfiguration">"Configuratie wijzigen"</string>
+    <string name="permdesc_changeConfiguration">"Hiermee kan een toepassing de actuele configuratie veranderen, zoals de locatie of algemene tekengrootte."</string>
+    <!-- no translation found for permlab_restartPackages (5836367540766044606) -->
+    <skip />
+    <!-- no translation found for permdesc_restartPackages (1764965996765573321) -->
+    <skip />
+    <!-- no translation found for permlab_setProcessForeground (4860990420780868638) -->
+    <skip />
+    <!-- no translation found for permdesc_setProcessForeground (3795477299954784360) -->
+    <skip />
+    <string name="permlab_forceBack">"Terug forceren"</string>
+    <string name="permdesc_forceBack">"Hiermee kan een toepassing elke activiteit die op de voorgrond staat sluiten en terugkeren. Is bij normale toepassingen nooit nodig."</string>
+    <string name="permlab_dump">"Systeemstatus dumpen"</string>
+    <string name="permdesc_dump">"Hiermee kan een toepassingen de interne toestand van het systeem opvragen. Verkeerde toepassingen kunnen een diverse privé- en veiligheidsinformatie verkrijgen die ze normaal gesproken niet nodig hebben."</string>
+    <string name="permlab_addSystemService">"Systeemservice toevoegen"</string>
+    <string name="permdesc_addSystemService">"Toepassingen mogen hun eigen systeemdiensten van laag-niveau publiceren. Verkeerde toepassingen kunnen het systeem kapen en gegevens erop beschadigen of stelen."</string>
+    <string name="permlab_runSetActivityWatcher">"Activiteitenmonitor instellen"</string>
+    <string name="permdesc_runSetActivityWatcher">"Hiermee kan een toepassing de wijze waarop het systeem activiteiten start in de gaten houden en besturen. Slechte toepassingen kunnen zo het systeem in gevaar brengen. Deze toepassing is alleen nodig voor ontwikkelingsdoeleinden, nooit voor normaal gebruik van het toestel."</string>
+    <string name="permlab_broadcastPackageRemoved">"Uitzendpakket verwijderd"</string>
+    <string name="permdesc_broadcastPackageRemoved">"Hiermee kan een toepassing een melding uitzenden met de mededeling dat een toepassingspakket is verwijderd. Verkeerde toepassingen kunnen dit gebruiken om andere actieve toepassingen te stoppen."</string>
+    <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
+    <skip />
+    <string name="permlab_setProcessLimit">"Proceslimiet instellen"</string>
+    <string name="permdesc_setProcessLimit">"Hiermee kan een toepassing het maximumaantal geactiveerde processen besturen. Nooit nodig voor normale toepassingen."</string>
+    <string name="permlab_setAlwaysFinish">"Altijd voltooien instellen"</string>
+    <string name="permdesc_setAlwaysFinish">"Hiermee kan een toepassing besturen of activiteiten altijd voltooid moeten zijn als ze naar de achtergrond gaan. Nooit nodig voor normale toepassingen."</string>
+    <string name="permlab_fotaUpdate">"Installatie van systeemupdate"</string>
+    <string name="permdesc_fotaUpdate">"Hiermee kan een toepassing meldingen ontvangen over systeemupdates die in behandeling zijn en hun installatie in gang zetten. Slechte toepassingen kunnen dit misbruiken om het te beschadigen met niet toegestane updates, of algemeen het updaten te verstoren."</string>
+    <!-- no translation found for permlab_batteryStats (1598947993704535568) -->
+    <skip />
+    <!-- no translation found for permdesc_batteryStats (6247598531831307989) -->
+    <skip />
+    <string name="permlab_internalSystemWindow">"Intern systeemvenster"</string>
+    <string name="permdesc_internalSystemWindow">"Hiermee kunnen vensters worden gemaakt die bedoeld zijn voor gebruik door het interne systeem van de gebruikersinterface. Niet bedoeld voor normale toepassingen."</string>
+    <string name="permlab_systemAlertWindow">"Systeemmeldingen"</string>
+    <string name="permdesc_systemAlertWindow">"Hiermee kan een toepassing systeemmeldingen weergeven. Slechte toepassingen kunnen het volledige toestelscherm overnemen."</string>
+    <string name="permlab_setAnimationScale">"Animatieschaal instellen"</string>
+    <string name="permdesc_setAnimationScale">"Hiermee kan een toepassing op elk moment de globale animatiesnelheid (snellere of tragere animaties) veranderen."</string>
+    <string name="permlab_manageAppTokens">"Toepassingstokens beheren"</string>
+    <string name="permdesc_manageAppTokens">"Hiermee kunnen toepassingen hun eigen tokens maken, en zo de normale Z-ordening buiten spel zetten. Is bij normale toepassingen nooit nodig."</string>
+    <string name="permlab_injectEvents">"Invoergebeurtenissen invoegen"</string>
+    <string name="permdesc_injectEvents">"Hiermee kan een toepassing zijn eigen invoergebeurtenissen (toetsindrukken enz.) naar andere toepassingen sturen. Slechte toepassingen kunnen dit misbruiken om controle over het toestel te krijgen."</string>
+    <string name="permlab_readInputState">"Invoerstatus lezen"</string>
+    <string name="permdesc_readInputState">"Hiermee kunnen toepassingen de toetsen zien die u indrukt, ook bij interactie met een andere toepassing (zoals het invoeren van een wachtwoord). Is bij normale toepassingen nooit nodig."</string>
+    <string name="permlab_setOrientation">"Ligging instellen"</string>
+    <string name="permdesc_setOrientation">"Hiermee kan een toepassing op elk moment de schermligging veranderen. Is bij normale toepassingen nooit nodig."</string>
+    <string name="permlab_signalPersistentProcesses">"Signaal naar aanhoudende processen"</string>
+    <string name="permdesc_signalPersistentProcesses">"Hiermee kan een toepassing verzoeken dat het meegeleverde signaal naar alle aanhoudende processen wordt gestuurd."</string>
+    <string name="permlab_persistentActivity">"Aanhoudende handelingen"</string>
+    <string name="permdesc_persistentActivity">"Hiermee kan een toepassing gedeeltes van zichzelf fixeren, zodat het systeem deze niet meer kan gebruiken voor andere toepassingen."</string>
+    <string name="permlab_deletePackages">"Pakketten verwijderen"</string>
+    <string name="permdesc_deletePackages">"Hiermee kan een toepassing Android-pakketten verwijderen. Slechte toepassingen kunnen dit misbruiken om belangrijke toepassingen te wissen."</string>
+    <!-- no translation found for permlab_clearAppUserData (3858185484601410171) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppUserData (7233537744753081136) -->
+    <skip />
+    <string name="permlab_deleteCacheFiles">"Cachebestanden wissen"</string>
+    <string name="permdesc_deleteCacheFiles">"Hiermee kan een toepassing cachebestanden verwijderen."</string>
+    <!-- no translation found for permlab_getPackageSize (6743556676630447973) -->
+    <skip />
+    <!-- no translation found for permdesc_getPackageSize (2893996655828539776) -->
+    <skip />
+    <string name="permlab_installPackages">"Pakketten installeren"</string>
+    <string name="permdesc_installPackages">"Hiermee kan een toepassing nieuwe Android- pakketten installeren of updaten. Slechte toepassingen kunnen dit misbruiken om nieuwe toepassingen met twijfelachtig verstrekkende rechten toe te voegen."</string>
+    <string name="permlab_clearAppCache">"Cachegegevens van toepassing wissen"</string>
+    <string name="permdesc_clearAppCache">"Hiermee kan een toepassing toestelgeheugen vrijmaken door bestanden uit de cachemap te verwijderen. Toegang wordt meestal beperkt tot systeemprocessen."</string>
+    <!-- no translation found for permlab_readLogs (6653488552442991707) -->
+    <skip />
+    <!-- no translation found for permdesc_readLogs (356352685800884319) -->
+    <skip />
+    <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
+    <skip />
+    <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
+    <skip />
+    <string name="permlab_changeComponentState">"Toepassingscomponenten in- of uitschakelen"</string>
+    <string name="permdesc_changeComponentState">"Hiermee kan een toepassing veranderen of een component van een andere toepassing wordt ingeschakeld of niet. Slechte toepassingen kunnen dit gebruiken om belangrijke toestelfuncties uit te schakelen. Wees voorzichtig met het verlenen van toestemmingen, omdat het mogelijk is dat toepassingscomponenten in een onbruikbare, inconsistente of instabiele toestand geraken."</string>
+    <string name="permlab_setPreferredApplications">"Voorkeurstoepassingen instellen"</string>
+    <string name="permdesc_setPreferredApplications">"Hiermee kan een toepassing uw voorkeurstoepassingen veranderen. Slechte toepassingen kunnen zo stilletjes veranderen welke toepassingen gestart moeten worden, zodat bestaande toepassingen privégegevens over u verzamelen."</string>
+    <string name="permlab_writeSettings">"Systeeminstellingen schrijven"</string>
+    <string name="permdesc_writeSettings">"Hiermee kan een toepassing de instellingsgegevens van het systeem aanpassen. Slechte toepassingen kunnen de configuratie van het systeem beschadigen."</string>
+    <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
+    <skip />
+    <!-- no translation found for permlab_writeGservices (296370685945777755) -->
+    <skip />
+    <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
+    <skip />
+    <string name="permlab_receiveBootCompleted">"Uitvoeren bij opstarten"</string>
+    <string name="permdesc_receiveBootCompleted">"Hiermee kan een toepassing zichzelf starten zodra het systeem is opgestart. Hierdoor kan het opstarten van het toestel langer duren en de toepassing het toestel afremmen omdat het altijd is geactiveerd."</string>
+    <string name="permlab_broadcastSticky">"Belangrijke uitzending"</string>
+    <string name="permdesc_broadcastSticky">"Hiermee kan een toepassing plakuitzendingen versturen, die blijven hangen als de uitzending stopt. Verkeerde toepassingen kunnen het toestel traag of instabiel maken door te veel geheugengebruik te veroorzaken."</string>
+    <string name="permlab_readContacts">"Contactgegevens lezen"</string>
+    <string name="permdesc_readContacts">"Hiermee kan een toepassing alle contactgegevens (adres) op het toestel lezen. Slechte toepassingen kunnen dit misbruiken om uw gegevens naar andere personen te sturen."</string>
+    <string name="permlab_writeContacts">"Contactgegevens schrijven"</string>
+    <string name="permdesc_writeContacts">"Hiermee kan een toepassing alle contactgegevens (adres) op het toestel aanpassen. Slechte toepassingen kunnen dit misbruiken om contactgegevens te wissen of wijzigen."</string>
+    <!-- no translation found for permlab_writeOwnerData (8036840529708535113) -->
+    <skip />
+    <!-- no translation found for permdesc_writeOwnerData (5873447528845878348) -->
+    <skip />
+    <!-- no translation found for permlab_readOwnerData (1847040178513733757) -->
+    <skip />
+    <!-- no translation found for permdesc_readOwnerData (7563299529149214764) -->
+    <skip />
+    <!-- no translation found for permlab_readCalendar (2111238731453410895) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (4408253940601239114) -->
+    <skip />
+    <!-- no translation found for permlab_writeCalendar (7518052789370653396) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCalendar (8057304232140147596) -->
+    <skip />
+    <!-- no translation found for permlab_accessMockLocation (321094551062270213) -->
+    <skip />
+    <!-- no translation found for permdesc_accessMockLocation (3651565866471419739) -->
+    <skip />
+    <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
+    <skip />
+    <string name="permlab_accessFineLocation">"Toegang tot gps-locatie"</string>
+    <string name="permdesc_accessFineLocation">"Open, indien beschikbaar, het Global Positioning System op het toestel. Verkeerde toepassingen kunnen dit gebruiken om te bepalen waar u zich bevindt en extra batterijstroom verbruiken."</string>
+    <string name="permlab_accessCoarseLocation">"Toegang tot netwerklocatie"</string>
+    <string name="permdesc_accessCoarseLocation">"Gebruik, indien beschikbaar, een netwerkdatabank om de locatie van het toestel te schatten. Verkeerde toepassingen kunnen dit gebruiken om te schatten waar u zich bevindt."</string>
+    <string name="permlab_accessSurfaceFlinger">"Toegang tot SurfaceFlinger"</string>
+    <string name="permdesc_accessSurfaceFlinger">"Toepassingen mogen de functies op laag niveau van SurfaceFlinger gebruiken."</string>
+    <string name="permlab_readFrameBuffer">"Framebuffer lezen"</string>
+    <string name="permdesc_readFrameBuffer">"Hiermee kan een toepassing de gegevens van de framebuffer lezen."</string>
+    <string name="permlab_modifyAudioSettings">"Audioinstellingen wijzigen"</string>
+    <string name="permdesc_modifyAudioSettings">"Hiermee kan een toepassing globale audioinstellingen aanpassen, zoals volume en route."</string>
+    <string name="permlab_recordAudio">"Audio opnemen"</string>
+    <string name="permdesc_recordAudio">"Hierdoor kan een toepassing het opnamepad voor audio openen."</string>
+    <string name="permlab_camera">"Camera"</string>
+    <!-- unknown placeholder BREAK in permdesc_camera -->
+    <skip />
+    <string name="permlab_brick">"Toestel uitschakelen"</string>
+    <string name="permdesc_brick">"Hiermee kan de toepassing de gehele dienst permanent uitschakelen. Dit is erg gevaarlijk."</string>
+    <!-- no translation found for permlab_reboot (8844650672567077423) -->
+    <skip />
+    <!-- no translation found for permdesc_reboot (4704919552870918328) -->
+    <skip />
+    <string name="permlab_mount_unmount_filesystems">"Bestandssystemen koppelen en losmaken"</string>
+    <string name="permdesc_mount_unmount_filesystems">"Hiermee kan de toepassing bestandssystemen voor verwisselbaar geheugen koppelen en loskoppelen."</string>
+    <string name="permlab_vibrate">"Triller"</string>
+    <string name="permdesc_vibrate">"Hiermee kan de toepassing de triller besturen."</string>
+    <string name="permlab_flashlight">"Flitser"</string>
+    <string name="permdesc_flashlight">"Hiermee kan de toepassing de flitser besturen."</string>
+    <string name="permlab_hardware_test">"Hardwaretest"</string>
+    <string name="permdesc_hardware_test">"Hiermee kan de toepassing diverse randapparaten besturen met als doel het testen van de hardware."</string>
+    <string name="permlab_callPhone">"Telefoonnummers bellen"</string>
+    <string name="permdesc_callPhone">"Hiermee kunnen toepassingen telefoonnummers bellen zonder uw tussenkomst. Verkeerde toepassingen kunnen ongewilde gesprekken op uw telefoonrekening veroorzaken."</string>
+    <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
+    <skip />
+    <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
+    <skip />
+    <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
+    <skip />
+    <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
+    <skip />
+    <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
+    <skip />
+    <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
+    <skip />
+    <!-- no translation found for permlab_modifyPhoneState (7791696535097912313) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyPhoneState (6352405226410454770) -->
+    <skip />
+    <!-- no translation found for permlab_readPhoneState (7320082586621086653) -->
+    <skip />
+    <!-- no translation found for permdesc_readPhoneState (8004450067066407969) -->
+    <skip />
+    <!-- no translation found for permlab_wakeLock (1591164750935072136) -->
+    <skip />
+    <!-- no translation found for permdesc_wakeLock (160471538196734936) -->
+    <skip />
+    <string name="permlab_devicePower">"Toestel inschakelen"</string>
+    <string name="permdesc_devicePower">"Hiermee kan de toepassing het toestel in- of uitschakelen, of ingeschakeld laten."</string>
+    <string name="permlab_factoryTest">"Fabriekstest"</string>
+    <string name="permdesc_factoryTest">"Uitvoeren als een fabriekstest op laag niveau, waardoor volledige toegang tot de toestelhardware gegeven is. Alleen beschikbaar als een toestel in de fabriekstestmodus staat."</string>
+    <string name="permlab_setWallpaper">"Achtergrond instellen"</string>
+    <string name="permdesc_setWallpaper">"Hiermee kan de toepassing de systeemachtergrond instellen."</string>
+    <!-- no translation found for permlab_setWallpaperHints (4192438316932517807) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaperHints (738757439960921674) -->
+    <skip />
+    <string name="permlab_masterClear">"Volledige systeemreset"</string>
+    <string name="permdesc_masterClear">"Hiermee kan een toepassing het systeem volledig opnieuw instellen op fabrieksinstellingen, waardoor alle gegevens, configuratie en geïnstalleerde toepassingen worden gewist."</string>
+    <!-- no translation found for permlab_setTimeZone (477196167239548690) -->
+    <skip />
+    <!-- no translation found for permdesc_setTimeZone (8564892020460841198) -->
+    <skip />
+    <!-- no translation found for permlab_getAccounts (2764070033402295170) -->
+    <skip />
+    <!-- no translation found for permdesc_getAccounts (1203491378748649898) -->
+    <skip />
+    <!-- no translation found for permlab_accessNetworkState (2032916924886010827) -->
+    <skip />
+    <!-- no translation found for permdesc_accessNetworkState (7081329402551195933) -->
+    <skip />
+    <!-- no translation found for permlab_createNetworkSockets (4706698319966917864) -->
+    <skip />
+    <!-- no translation found for permdesc_createNetworkSockets (2580337178778551792) -->
+    <skip />
+    <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
+    <skip />
+    <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
+    <skip />
+    <!-- no translation found for permlab_changeNetworkState (2710779001260856872) -->
+    <skip />
+    <!-- no translation found for permdesc_changeNetworkState (8076109230787022270) -->
+    <skip />
+    <!-- no translation found for permlab_accessWifiState (3613679494230374297) -->
+    <skip />
+    <!-- no translation found for permdesc_accessWifiState (8226508433563326925) -->
+    <skip />
+    <!-- no translation found for permlab_changeWifiState (6043889338995432957) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWifiState (7829372845909567994) -->
+    <skip />
+    <!-- no translation found for permlab_bluetoothAdmin (5513286736585647334) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (1838208497914347365) -->
+    <skip />
+    <!-- no translation found for permlab_bluetooth (6378797624765639115) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetooth (8592386018922265273) -->
+    <skip />
+    <!-- no translation found for permlab_disableKeyguard (4574886811903233903) -->
+    <skip />
+    <!-- no translation found for permdesc_disableKeyguard (815972646344251271) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncSettings (8818819977141505127) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncSettings (8454705401908767847) -->
+    <skip />
+    <!-- no translation found for permlab_writeSyncSettings (4514911143753152941) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSyncSettings (7630627689635091836) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncStats (5748337739678952863) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncStats (582551457321957183) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
+    <skip />
+    <!-- no translation found for phoneTypes:0 (6070018634209800981) -->
+    <!-- no translation found for phoneTypes:1 (1514509689885965711) -->
+    <!-- no translation found for phoneTypes:2 (497473201754095234) -->
+    <!-- no translation found for phoneTypes:3 (5554432614281047787) -->
+    <!-- no translation found for phoneTypes:4 (2222084401110150993) -->
+    <!-- no translation found for phoneTypes:5 (2290007103906353121) -->
+    <!-- no translation found for phoneTypes:6 (6930783706213719251) -->
+    <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
+    <!-- no translation found for emailAddressTypes:0 (1540640638077615417) -->
+    <!-- no translation found for emailAddressTypes:1 (4252853367575831977) -->
+    <!-- no translation found for emailAddressTypes:2 (7158046581744435718) -->
+    <!-- no translation found for emailAddressTypes:3 (3625034471181268169) -->
+    <!-- no translation found for postalAddressTypes:0 (5732960259696659380) -->
+    <!-- no translation found for postalAddressTypes:1 (7132240704786130285) -->
+    <!-- no translation found for postalAddressTypes:2 (1317604357745852817) -->
+    <!-- no translation found for postalAddressTypes:3 (1582953598462826702) -->
+    <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
+    <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
+    <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
+    <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
+    <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
+    <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
+    <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
+    <!-- no translation found for imProtocols:0 (3318725788774688043) -->
+    <!-- no translation found for imProtocols:1 (1787713387022932886) -->
+    <!-- no translation found for imProtocols:2 (6751174158442316516) -->
+    <!-- no translation found for imProtocols:3 (1151283347465052653) -->
+    <!-- no translation found for imProtocols:4 (2157980008878817934) -->
+    <!-- no translation found for imProtocols:5 (7836237460308230767) -->
+    <!-- no translation found for imProtocols:6 (1180789904462172516) -->
+    <!-- no translation found for imProtocols:7 (21955111672779862) -->
+    <string name="keyguard_password_enter_pin_code">"Pincode invoeren"</string>
+    <string name="keyguard_password_wrong_pin_code">"Onjuiste pincode!"</string>
+    <string name="keyguard_label_text">"Om vrij te geven drukt u op Menu en vervolgens op 0."</string>
+    <string name="emergency_call_dialog_number_for_display">"Alarmnummers"</string>
+    <string name="lockscreen_carrier_default">"(Geen service)"</string>
+    <string name="lockscreen_screen_locked">"Schermblokkering"</string>
+    <string name="lockscreen_instructions_when_pattern_enabled">"Druk op Menu om vrij te geven of bel een alarmnummer"</string>
+    <string name="lockscreen_instructions_when_pattern_disabled">"Druk op Menu om vrij te geven"</string>
+    <string name="lockscreen_pattern_instructions">"Patroon tekenen om vrij te geven"</string>
+    <string name="lockscreen_emergency_call">"Noodoproep"</string>
+    <string name="lockscreen_pattern_correct">"Juist!"</string>
+    <string name="lockscreen_pattern_wrong">"Verkeerd patroon! Nogmaals proberen"</string>
+    <string name="lockscreen_plugged_in">"Bezig met opladen (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+    <string name="lockscreen_low_battery">"Oplader verbinden"</string>
+    <!-- no translation found for lockscreen_missing_sim_message_short (5051192587315492957) -->
+    <skip />
+    <string name="lockscreen_missing_sim_message">"Geen SIM in toestel"</string>
+    <string name="lockscreen_missing_sim_instructions">"Voer een SIM-kaart in"</string>
+    <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_message (1005803622871256359) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_instructions (5033160098036646955) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_locked_message (7398401200962556379) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (5939537246164692076) -->
+    <skip />
+    <!-- unknown placeholder BREAK in lockscreen_too_many_failed_attempts_dialog_message -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (1569017295989454551) -->
+    <skip />
+    <string name="lockscreen_too_many_failed_attempts_countdown">"Probeer opnieuw over <xliff:g id="NUMBER">%d</xliff:g> seconden"</string>
+    <!-- no translation found for lockscreen_forgot_pattern_button_text (4219994639843985488) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_too_many_attempts (7504679498838839295) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_instructions (6542400673357252011) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_username_hint (6378418320242015111) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_password_hint (3224230234042131153) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_submit_button (5562051040043760034) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
+    <skip />
+    <!-- unknown placeholder FORMAT in status_bar_time_format -->
+    <skip />
+    <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
+    <skip />
+    <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
+    <skip />
+    <!-- no translation found for hour_ampm (7665432130905376251) -->
+    <skip />
+    <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
+    <skip />
+    <!-- no translation found for status_bar_clear_all_button (2202004591253243750) -->
+    <skip />
+    <string name="status_bar_no_notifications_title">"Meldingen"</string>
+    <string name="status_bar_ongoing_events_title">"Actueel"</string>
+    <string name="status_bar_latest_events_title">"Nieuwste gebeurtenissen"</string>
+    <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g>"</string>
+    <string name="battery_status_charging">"Bezig met opladen…"</string>
+    <string name="battery_low_title">"Oplader verbinden"</string>
+    <string name="battery_low_subtitle">"Lage batterijstroom"</string>
+    <string name="battery_low_percent_format">"Minder dan <xliff:g id="NUMBER">%d%%</xliff:g> resterend"</string>
+    <string name="factorytest_failed">"Fabriekstest mislukt"</string>
+    <string name="factorytest_not_system">"De handeling FACTORY_TEST wordt alleen ondersteund voor pakketten die geïnstalleerd zijn in /system/app."</string>
+    <string name="factorytest_no_action">"Geen pakket gevonden dat de handeling FACTORY_TEST levert."</string>
+    <string name="factorytest_reboot">"Opnieuw opstarten"</string>
+    <string name="save_password_label">"Bevestigen"</string>
+    <string name="save_password_message">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
+    <string name="save_password_notnow">"Niet nu"</string>
+    <string name="save_password_remember">"Onthouden"</string>
+    <string name="save_password_never">"Nooit"</string>
+    <string name="open_permission_deny">"U hebt geen toestemming om deze pagina te openen."</string>
+    <!-- no translation found for text_copied (6106873823411904723) -->
+    <skip />
+    <string name="more_item_label">"Meer"</string>
+    <string name="prepend_shortcut_label">"Menu+"</string>
+    <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
+    <skip />
+    <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
+    <skip />
+    <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
+    <skip />
+    <string name="search_go">"Ga naar"</string>
+    <string name="today">"Vandaag"</string>
+    <string name="yesterday">"Gisteren"</string>
+    <string name="tomorrow">"Morgen"</string>
+    <!-- no translation found for oneMonthDurationPast (3402179395240209557) -->
+    <skip />
+    <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
+    <skip />
+    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
+    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
+    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
+    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
+    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
+    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
+    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
+    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
+    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
+    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
+    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
+    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
+    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
+    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
+    <!-- no translation found for in_num_days:one (5608475533104443893) -->
+    <!-- no translation found for in_num_days:other (3827193006163842267) -->
+    <string name="preposition_for_date">"op %s"</string>
+    <string name="preposition_for_time">"bij %s"</string>
+    <string name="preposition_for_year">"in %s"</string>
+    <string name="day">"dag"</string>
+    <string name="days">"dagen"</string>
+    <string name="hour">"uur"</string>
+    <string name="hours">"uur"</string>
+    <string name="minute">"minuut"</string>
+    <string name="minutes">"minuten"</string>
+    <string name="second">"seconde"</string>
+    <string name="seconds">"seconden"</string>
+    <string name="week">"week"</string>
+    <string name="weeks">"weken"</string>
+    <!-- no translation found for year (8024790425994085153) -->
+    <skip />
+    <!-- no translation found for years (8592090054773244417) -->
+    <skip />
+    <string name="sunday">"Zondag"</string>
+    <string name="monday">"Maandag"</string>
+    <string name="tuesday">"Dinsdag"</string>
+    <string name="wednesday">"Woensdag"</string>
+    <string name="thursday">"Donderdag"</string>
+    <string name="friday">"Vrijdag"</string>
+    <string name="saturday">"Zaterdag"</string>
+    <string name="every_weekday">"Elke werkdag (Maa–vri)"</string>
+    <string name="daily">"Elke dag"</string>
+    <string name="weekly">"Wekelijks op <xliff:g id="DAY">%s</xliff:g>"</string>
+    <string name="monthly">"Elke mnd"</string>
+    <string name="yearly">"Elk jaar"</string>
+    <string name="VideoView_error_title">"Videoafspeelfout"</string>
+    <string name="VideoView_error_text_unknown">"Fout opgetreden bij afspelen van geselecteerde video."</string>
+    <string name="VideoView_error_button">"OK"</string>
+    <string name="am">"AM"</string>
+    <string name="pm">"PM"</string>
+    <!-- unknown placeholder FORMAT in numeric_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in wday1_date1_time1_wday2_date2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in wday1_date1_wday2_date2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in date1_time1_date2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in date1_date2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time1_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time_wday_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in wday_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time_date -->
+    <skip />
+    <!-- unknown placeholder FORMAT in time_wday -->
+    <skip />
+    <!-- no translation found for full_date_month_first (6011143962222283357) -->
+    <skip />
+    <!-- no translation found for full_date_day_first (8621594762705478189) -->
+    <skip />
+    <!-- no translation found for medium_date_month_first (48990963718825728) -->
+    <skip />
+    <!-- no translation found for medium_date_day_first (2898992016440387123) -->
+    <skip />
+    <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
+    <skip />
+    <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
+    <skip />
+    <string name="noon">"12 uur \'smiddags"</string>
+    <string name="Noon">"12 uur \'smiddags"</string>
+    <string name="midnight">"middernacht"</string>
+    <string name="Midnight">"Middernacht"</string>
+    <!-- unknown placeholder FORMAT in month_day -->
+    <skip />
+    <!-- unknown placeholder FORMAT in month -->
+    <skip />
+    <!-- unknown placeholder FORMAT in month_day_year -->
+    <skip />
+    <!-- unknown placeholder FORMAT in month_year -->
+    <skip />
+    <!-- no translation found for time_of_day (8375993139317154157) -->
+    <skip />
+    <!-- no translation found for date_and_time (9197690194373107109) -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_md1_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_md1_wday2_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_mdy1_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_wday2_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_md1_time1_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_md1_time1_wday2_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_mdy1_time1_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_time1_wday2_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_md1_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_md1_wday2_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_mdy1_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_wday2_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_md1_time1_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_md1_time1_wday2_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_mdy1_time1_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_time1_wday2_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_md1_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_md1_wday2_md2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_mdy1_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_wday2_mdy2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_md1_time1_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_md1_time1_wday2_md2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_mdy1_time1_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_time1_wday2_mdy2_time2 -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month_day_year -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month_year -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month_day -->
+    <skip />
+    <!-- unknown placeholder FORMAT in abbrev_month -->
+    <skip />
+    <string name="day_of_week_long_sunday">"Zondag"</string>
+    <string name="day_of_week_long_monday">"Maandag"</string>
+    <string name="day_of_week_long_tuesday">"Dinsdag"</string>
+    <string name="day_of_week_long_wednesday">"Woensdag"</string>
+    <string name="day_of_week_long_thursday">"Donderdag"</string>
+    <string name="day_of_week_long_friday">"Vrijdag"</string>
+    <string name="day_of_week_long_saturday">"Zaterdag"</string>
+    <string name="day_of_week_medium_sunday">"Zon"</string>
+    <string name="day_of_week_medium_monday">"Maa"</string>
+    <string name="day_of_week_medium_tuesday">"Din"</string>
+    <string name="day_of_week_medium_wednesday">"Woe"</string>
+    <string name="day_of_week_medium_thursday">"Don"</string>
+    <string name="day_of_week_medium_friday">"Vri"</string>
+    <string name="day_of_week_medium_saturday">"Zat"</string>
+    <string name="day_of_week_short_sunday">"Zo"</string>
+    <string name="day_of_week_short_monday">"Ma"</string>
+    <string name="day_of_week_short_tuesday">"Di"</string>
+    <string name="day_of_week_short_wednesday">"Wo"</string>
+    <string name="day_of_week_short_thursday">"Do"</string>
+    <string name="day_of_week_short_friday">"Vr"</string>
+    <string name="day_of_week_short_saturday">"Za"</string>
+    <string name="day_of_week_shorter_sunday">"Zo"</string>
+    <string name="day_of_week_shorter_monday">"M"</string>
+    <string name="day_of_week_shorter_tuesday">"Di"</string>
+    <string name="day_of_week_shorter_wednesday">"W"</string>
+    <string name="day_of_week_shorter_thursday">"Do"</string>
+    <string name="day_of_week_shorter_friday">"V"</string>
+    <string name="day_of_week_shorter_saturday">"Za"</string>
+    <string name="day_of_week_shortest_sunday">"Z"</string>
+    <string name="day_of_week_shortest_monday">"M"</string>
+    <string name="day_of_week_shortest_tuesday">"Di"</string>
+    <string name="day_of_week_shortest_wednesday">"W"</string>
+    <string name="day_of_week_shortest_thursday">"Do"</string>
+    <string name="day_of_week_shortest_friday">"V"</string>
+    <string name="day_of_week_shortest_saturday">"Z"</string>
+    <string name="month_long_january">"Januari"</string>
+    <string name="month_long_february">"Februari"</string>
+    <string name="month_long_march">"Maart"</string>
+    <string name="month_long_april">"April"</string>
+    <string name="month_long_may">"Mei"</string>
+    <string name="month_long_june">"Juni"</string>
+    <string name="month_long_july">"Juli"</string>
+    <string name="month_long_august">"Augustus"</string>
+    <string name="month_long_september">"September"</string>
+    <string name="month_long_october">"Oktober"</string>
+    <string name="month_long_november">"November"</string>
+    <string name="month_long_december">"December"</string>
+    <string name="month_medium_january">"jan"</string>
+    <string name="month_medium_february">"feb"</string>
+    <string name="month_medium_march">"mrt"</string>
+    <string name="month_medium_april">"apr"</string>
+    <string name="month_medium_may">"mei"</string>
+    <string name="month_medium_june">"jun"</string>
+    <string name="month_medium_july">"jul"</string>
+    <string name="month_medium_august">"aug"</string>
+    <string name="month_medium_september">"sep"</string>
+    <string name="month_medium_october">"okt"</string>
+    <string name="month_medium_november">"nov"</string>
+    <string name="month_medium_december">"dec"</string>
+    <string name="month_shortest_january">"J"</string>
+    <string name="month_shortest_february">"F"</string>
+    <string name="month_shortest_march">"M"</string>
+    <string name="month_shortest_april">"A"</string>
+    <string name="month_shortest_may">"M"</string>
+    <string name="month_shortest_june">"J"</string>
+    <string name="month_shortest_july">"J"</string>
+    <string name="month_shortest_august">"A"</string>
+    <string name="month_shortest_september">"S"</string>
+    <string name="month_shortest_october">"O"</string>
+    <string name="month_shortest_november">"N"</string>
+    <string name="month_shortest_december">"D"</string>
+    <!-- unknown placeholder FORMAT in elapsed_time_short_format_mm_ss -->
+    <skip />
+    <!-- unknown placeholder FORMAT in elapsed_time_short_format_h_mm_ss -->
+    <skip />
+    <string name="selectAll">"Alles selecteren"</string>
+    <string name="cut">"Knippen"</string>
+    <!-- no translation found for cutAll (4474519683293791451) -->
+    <skip />
+    <string name="copy">"Kopiëren"</string>
+    <!-- no translation found for copyAll (4777548804630476932) -->
+    <skip />
+    <string name="paste">"Plakken"</string>
+    <string name="copyUrl">"URL kopiëren"</string>
+    <!-- no translation found for inputMethod (7911866729148111492) -->
+    <skip />
+    <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
+    <skip />
+    <string name="low_internal_storage_view_title">"Weinig intern geheugen"</string>
+    <string name="low_internal_storage_view_text">"Toestel heeft weinig intern geheugen"</string>
+    <string name="ok">"OK"</string>
+    <string name="cancel">"Annuleren"</string>
+    <string name="yes">"OK"</string>
+    <string name="no">"Annuleren"</string>
+    <string name="capital_on">"AAN"</string>
+    <string name="capital_off">"UIT"</string>
+    <string name="whichApplication">"Welke toepassing wilt u gebruiken?"</string>
+    <string name="alwaysUse">"Deze toepassing altijd gebruiken voor deze toepassing"</string>
+    <!-- no translation found for clearDefaultHintMsg (5742432113023174321) -->
+    <skip />
+    <string name="chooseActivity">"Een actie selecteren"</string>
+    <string name="noApplications">"Geen toepassingen beschikbaar om de handeling uit te voeren"</string>
+    <!-- no translation found for aerr_title (2654390351574026098) -->
+    <skip />
+    <!-- no translation found for aerr_application (4917288809565116720) -->
+    <skip />
+    <!-- no translation found for aerr_process (1273819861108073461) -->
+    <skip />
+    <!-- no translation found for anr_title (3305935690891435915) -->
+    <skip />
+    <!-- no translation found for anr_activity_application (1653036325679156678) -->
+    <skip />
+    <!-- no translation found for anr_activity_process (2674027618362070465) -->
+    <skip />
+    <!-- no translation found for anr_application_process (2163656674970221928) -->
+    <skip />
+    <!-- no translation found for anr_process (7747550780123472160) -->
+    <skip />
+    <!-- no translation found for force_close (9020954128872810669) -->
+    <skip />
+    <!-- no translation found for wait (7973775702304037058) -->
+    <skip />
+    <!-- no translation found for debug (857932504764728770) -->
+    <skip />
+    <string name="sendText">"Kiezen wat met de tekst gebeurt"</string>
+    <!-- no translation found for volume_ringtone (4121694816346562058) -->
+    <skip />
+    <!-- no translation found for volume_music (4869950240104717493) -->
+    <skip />
+    <!-- no translation found for volume_call (5723421277753250395) -->
+    <skip />
+    <!-- no translation found for volume_alarm (2752102730973081294) -->
+    <skip />
+    <!-- no translation found for volume_unknown (6908187627672375742) -->
+    <skip />
+    <!-- no translation found for ringtone_default (2873893375149093475) -->
+    <skip />
+    <!-- no translation found for ringtone_default_with_actual (5474076151665761913) -->
+    <skip />
+    <!-- no translation found for ringtone_silent (7477159279081654685) -->
+    <skip />
+    <!-- no translation found for ringtone_picker_title (7055241890764367884) -->
+    <skip />
+    <!-- no translation found for ringtone_unknown (6888219771401173795) -->
+    <skip />
+    <!-- no translation found for wifi_available:one (8168012881468888470) -->
+    <!-- no translation found for wifi_available:other (4666122955807117718) -->
+    <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
+    <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
+    <!-- no translation found for select_character (3735110139249491726) -->
+    <skip />
+    <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
+    <skip />
+    <!-- no translation found for sms_control_title (2742400596989418394) -->
+    <skip />
+    <!-- no translation found for sms_control_message (3447126217666595989) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (8839660939359273650) -->
+    <skip />
+    <!-- no translation found for sms_control_no (909756849988183801) -->
+    <skip />
+    <!-- no translation found for date_time_set (2495199891239480952) -->
+    <skip />
+    <!-- no translation found for default_permission_group (7742780381379652409) -->
+    <skip />
+    <!-- no translation found for no_permissions (85461124044682315) -->
+    <skip />
+    <!-- no translation found for perms_hide (4145325555929151849) -->
+    <skip />
+    <!-- no translation found for perms_show_all (6040194843455403173) -->
+    <skip />
+    <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
+    <skip />
+    <!-- no translation found for usb_storage_title (8699631567051394409) -->
+    <skip />
+    <!-- no translation found for usb_storage_message (5344039189213308733) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
+    <skip />
+    <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
+    <skip />
+    <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
+    <skip />
+    <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
+    <skip />
+    <!-- no translation found for select_input_method (2658280517827502015) -->
+    <skip />
+    <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
+    <skip />
+    <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
+    <skip />
+    <!-- no translation found for candidates_style (7738463880139922176) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 4f40a27..9f2c840 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -19,7 +19,7 @@
 -->
 <resources>
 
-    <!-- These are all of the drawable resources that should be preloaded by
+    <!-- Do not translate. These are all of the drawable resources that should be preloaded by
          the zygote process before it starts forking application processes. -->
     <array name="preloaded_drawables">
         <item>@drawable/scrollbar_handle_vertical</item>
@@ -87,15 +87,17 @@
         
     </array>
     
+    <!-- Do not translate. -->
     <integer-array name="maps_starting_lat_lng">
         <item>36149777</item>
         <item>-95993398</item>
     </integer-array>
+    <!-- Do not translate. -->
     <integer-array name="maps_starting_zoom">
         <item>3</item>
     </integer-array>
 
-    <!-- Defines the slots for the right-hand side icons.  That is to say, the
+    <!-- Do not translate. Defines the slots for the right-hand side icons.  That is to say, the
          icons in the status bar that are not notifications. -->
     <string-array name="status_bar_icon_order">
         <item>clock</item>
@@ -111,5 +113,6 @@
         <item>gps</item>
         <item>sync_active</item>
         <item>sync_failing</item>
+        <item>ime</item>
     </string-array>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6c96cc2..a60845b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -32,6 +32,10 @@
         <attr name="disabledAlpha" format="float" />
         <!-- Default background dim amount when a menu, dialog, or something similar pops up. -->
         <attr name="backgroundDimAmount" format="float" />
+        <!-- Control whether dimming behind the window is enabled.  The default
+             theme does not set this value, meaning it is based on whether the
+             window is floating. -->
+        <attr name="backgroundDimEnabled" format="boolean" />
 
         <!-- =========== -->
         <!-- Text styles -->
@@ -93,6 +97,12 @@
         <!-- Text color, typeface, size, and style for the text inside of a button. -->
         <attr name="textAppearanceButton" format="reference" />
         
+        <!-- A styled string, specifying the style to be used for showing
+             inline candidate text when composing with an input method.  The
+             text itself will be ignored, but the style spans will be applied
+             to the candidate text as it is edited. -->
+        <attr name="candidatesTextStyleSpans" format="reference|string" />
+        
         <!-- Drawable to use for check marks -->
         <attr name="textCheckMark" format="reference" />
         <attr name="textCheckMarkInverse" format="reference" />
@@ -205,6 +215,52 @@
              {@link android.R.styleable#WindowAnimation}. -->
         <attr name="windowAnimationStyle" format="reference" />
     
+        <!-- Defines the default soft input state that this window would
+             like when it is displayed. -->
+        <attr name="windowSoftInputMode">
+            <!-- Not specified, use what the system thinks is best.  This
+                 is the default. -->
+            <flag name="stateUnspecified" value="0" />
+            <!-- Leave the soft input window as-is, in whatever state it
+                 last was. -->
+            <flag name="stateUnchanged" value="1" />
+            <!-- Don't display the soft input area, there is no reason to
+                 do so on this window. -->
+            <flag name="stateHidden" value="2" />
+            <!-- Make the soft input area visible when this window is
+                 first displayed. -->
+            <flag name="stateFirstVisible" value="3" />
+            <!-- The soft input area should always be displayed while in this
+                 window. -->
+            <flag name="stateVisible" value="4" />
+            
+            <!-- The window resize/pan adjustment has not been specified,
+                 the system will automatically select between resize and pan
+                 modes, depending
+                 on whether the content of the window has any layout views
+                 that can scroll their contents.  If there is such a view,
+                 then the window will be resized, with the assumption being
+                 that the resizeable area can be reduced to make room for
+                 the input UI. -->
+            <flag name="adjustUnspecified" value="0x00" />
+            <!-- Always resize the window: the content area of the window is
+                 reduced to make room for the soft input area. -->
+            <flag name="adjustResize" value="0x10" />
+            <!-- Don't resize the window to make room for the soft input area;
+                 instead pan the contents of the window as focus moves inside
+                 of it so that the user can see what they are typing.  This is
+                 generally less desireable than panning because the user may
+                 need to close the input area to get at and interact with
+                 parts of the window. -->
+            <flag name="adjustPan" value="0x20" />
+        </attr>
+
+        <!-- Flag allowing you to disable the preview animation for a window.
+             The default value is false; if set to true, the system can never
+             use the window's theme to show a preview of it before your
+             actual instance is shown to the user. -->
+        <attr name="windowDisablePreview" format="boolean" />
+        
         <!-- ============ -->
         <!-- Alert Dialog styles -->
         <!-- ============ -->
@@ -284,6 +340,8 @@
         <attr name="spinnerStyle" format="reference" />
         <!-- Default Star style. -->
         <attr name="starStyle" format="reference" />
+        <!-- Buttonless Star style. -->
+        <attr name="starStyleButtonless" format="reference" />
         <!-- Default TabWidget style. -->
         <attr name="tabWidgetStyle" format="reference" />
         <!-- Default TextView style. -->
@@ -370,6 +428,111 @@
         <enum name="start" value="1" />
         <enum name="middle" value="2" />
         <enum name="end" value="3" />
+        <enum name="marquee" value="4" />
+    </attr>
+    <!-- The type of data being placed in a text field, used to help an
+         input method decide how to let the user enter text.  The constants
+         here correspond to those defined by
+         {@link android.text.InputType}.  Generally you can select
+         a single value, though some can be combined together as
+         indicated.  Setting this attribute to anything besides
+         <var>none</var> also implies that the text is editable. -->
+    <attr name="inputType">
+        <!-- There is no content type.  The text is not editable. -->
+        <flag name="none" value="0x00000000" />
+        <!-- Just plain old text.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_NORMAL}. -->
+        <flag name="text" value="0x00000001" />
+        <!-- Can be combined with <var>text</var> and its variations to
+             request captilization of all characters.  Corresponds to
+             {@link android.text.InputType#TYPE_TEXT_FLAG_CAP_CHARACTERS}. -->
+        <flag name="textCapCharacters" value="0x00001001" />
+        <!-- Can be combined with <var>text</var> and its variations to
+             request captilization of the first character of every word.  Corresponds to
+             {@link android.text.InputType#TYPE_TEXT_FLAG_CAP_WORDS}. -->
+        <flag name="textCapWords" value="0x00002001" />
+        <!-- Can be combined with <var>text</var> and its variations to
+             request captilization of the first character of every sentence.  Corresponds to
+             {@link android.text.InputType#TYPE_TEXT_FLAG_CAP_SENTENCES}. -->
+        <flag name="textCapSentences" value="0x00004001" />
+        <!-- Can be combined with <var>text</var> and its variations to
+             request auto-correction of texting being input.  Corresponds to
+             {@link android.text.InputType#TYPE_TEXT_FLAG_AUTO_CORRECT}. -->
+        <flag name="textAutoCorrect" value="0x00008001" />
+        <!-- Can be combined with <var>text</var> and its variations to
+             specify that this field will be doing its own auto-completion and
+             talking with the input method appropriately.  Corresponds to
+             {@link android.text.InputType#TYPE_TEXT_FLAG_AUTO_COMPLETE}. -->
+        <flag name="textAutoComplete" value="0x00010001" />
+        <!-- Can be combined with <var>text</var> and its variations to
+             allow multiple lines of text in the field.  Corresponds to
+             {@link android.text.InputType#TYPE_TEXT_FLAG_MULTI_LINE}. -->
+        <flag name="textMultiLine" value="0x00020001" />
+        <!-- Text that will be used as a URI.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_URI}. -->
+        <flag name="textUri" value="0x00000011" />
+        <!-- Text that will be used as an e-mail address.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_EMAIL_ADDRESS}. -->
+        <flag name="textEmailAddress" value="0x00000021" />
+        <!-- Text that is being supplied as the subject of an e-mail.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_EMAIL_SUBJECT}. -->
+        <flag name="textEmailSubject" value="0x00000031" />
+        <!-- Text that is being supplied as the content of an e-mail.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_EMAIL_CONTENT}. -->
+        <flag name="textEmailContent" value="0x00000041" />
+        <!-- Text that is the name of a person.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_PERSON_NAME}. -->
+        <flag name="textPersonName" value="0x00000051" />
+        <!-- Text that is being supplied as a postal mailing address.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_POSTAL_ADDRESS}. -->
+        <flag name="textPostalAddress" value="0x00000061" />
+        <!-- Text that is a password.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_PASSWORD}. -->
+        <flag name="textPassword" value="0x00000071" />
+        <!-- Text that will be used for a web search.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_WEB_SEARCH}. -->
+        <flag name="textWebSearch" value="0x00000081" />
+        <!-- Text that is being supplied as text in a web form.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_WEB_EDIT_TEXT}. -->
+        <flag name="textWebEditText" value="0x00000091" />
+        <!-- A numeric only field.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_NUMBER}. -->
+        <flag name="number" value="0x00000002" />
+        <!-- Can be combined with <var>number</var> and its other options to
+             allow a signed number.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_NUMBER} |
+             {@link android.text.InputType#TYPE_NUMBER_FLAG_SIGNED}. -->
+        <flag name="numberSigned" value="0x00001002" />
+        <!-- Can be combined with <var>number</var> and its other options to
+             allow a decimal (fractional) number.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_NUMBER} |
+             {@link android.text.InputType#TYPE_NUMBER_FLAG_DECIMAL}. -->
+        <flag name="numberDecimal" value="0x00002002" />
+        <!-- For entering a phone number.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_PHONE}. -->
+        <flag name="phone" value="0x00000003" />
+        <!-- For entering a date and time.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_DATETIME} |
+             {@link android.text.InputType#TYPE_DATETIME_VARIATION_NORMAL}. -->
+        <flag name="datetime" value="0x00000004" />
+        <!-- For entering a date.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_DATETIME} |
+             {@link android.text.InputType#TYPE_DATETIME_VARIATION_DATE}. -->
+        <flag name="date" value="0x00000014" />
+        <!-- For entering a time.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_DATETIME} |
+             {@link android.text.InputType#TYPE_DATETIME_VARIATION_TIME}. -->
+        <flag name="time" value="0x00000024" />
     </attr>
 
     <!-- A coordinate in the X dimension. -->
@@ -400,6 +563,16 @@
         <flag name="center" value="0x11" />
         <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
         <flag name="fill" value="0x77" />
+        <!-- Additional option that can be set to have the top and/or bottom edges of
+             the child clipped to its container's bounds.
+             The clip will be based on the vertical gravity: a top gravity will clip the bottom
+             edge, a bottom gravity will clip the top edge, and neither will clip both edges. -->
+        <flag name="clip_vertical" value="0x80" />
+        <!-- Additional option that can be set to have the left and/or right edges of
+             the child clipped to its container's bounds.
+             The clip will be based on the horizontal gravity: a left gravity will clip the right
+             edge, a right gravity will clip the left edge, and neither will clip both edges. -->
+        <flag name="clip_horizontal" value="0x08" />
     </attr>
 
     <!-- Controls whether links such as urls and email addresses are
@@ -447,6 +620,16 @@
         <flag name="center" value="0x11" />
         <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
         <flag name="fill" value="0x77" />
+        <!-- Additional option that can be set to have the top and/or bottom edges of
+             the child clipped to its container's bounds.
+             The clip will be based on the vertical gravity: a top gravity will clip the bottom
+             edge, a bottom gravity will clip the top edge, and neither will clip both edges. -->
+        <flag name="clip_vertical" value="0x80" />
+        <!-- Additional option that can be set to have the left and/or right edges of
+             the child clipped to its container's bounds.
+             The clip will be based on the horizontal gravity: a left gravity will clip the right
+             edge, a right gravity will clip the left edge, and neither will clip both edges. -->
+        <flag name="clip_horizontal" value="0x08" />
     </attr>
 
     <!-- Standard orientation constant. -->
@@ -550,6 +733,12 @@
         <enum name="KEYCODE_MENU" value="82" />
         <enum name="KEYCODE_NOTIFICATION" value="83" />
         <enum name="KEYCODE_SEARCH" value="84" />
+        <enum name="KEYCODE_PLAYPAUSE" value="85" />
+        <enum name="KEYCODE_STOP" value="86" />
+        <enum name="KEYCODE_NEXTSONG" value="87" />
+        <enum name="KEYCODE_PREVIOUSSONG" value="88" />
+        <enum name="KEYCODE_REWIND" value="89" />
+        <enum name="KEYCODE_FORWARD" value="90" />
     </attr>
 
     <!-- ***************************************************************** -->
@@ -571,7 +760,11 @@
         <attr name="windowIsFloating" />
         <attr name="windowIsTranslucent" />
         <attr name="windowAnimationStyle" />
+        <attr name="windowSoftInputMode" />
+        <attr name="windowDisablePreview" />
         <attr name="textColor" />
+        <attr name="backgroundDimEnabled" />
+        <attr name="backgroundDimAmount" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -968,6 +1161,22 @@
         <attr name="layout_marginBottom" format="dimension"  />
     </declare-styleable>
 
+    <!-- Use <code>input-method</code> as the root tag of the XML resource that
+         describes an
+         {@link android.view.inputmethod.InputMethod} service, which is
+         referenced from its
+         {@link android.view.inputmethod.InputMethod#SERVICE_META_DATA}
+         meta-data entry.  Described here are the attributes that can be
+         included in that tag. -->
+    <declare-styleable name="InputMethod">
+        <!-- Component name of an activity that allows the user to modify
+             the settings for this input method. -->
+        <attr name="settingsActivity" format="string" />
+        <!-- Set to true in all of the configurations for which this input
+             method should be considered an option as the default. -->
+        <attr name="isDefault" format="boolean" />
+    </declare-styleable>
+    
     <!-- =============================== -->
     <!-- Widget package class attributes -->
     <!-- =============================== -->
@@ -1005,6 +1214,18 @@
         <!-- Indicates that this list will always be drawn on top of solid, single-color
              opaque background. This allows the list to optimize drawing. -->
         <attr name="cacheColorHint" format="color" />
+        <!-- Enables the fast scroll thumb that can be dragged to quickly scroll through 
+             the list. -->
+        <attr name="fastScrollEnabled" format="boolean" />
+        <!-- When set to true, the list will use a more refined calculation
+             method based on the pixels height of the items visible on screen. This
+             property is set to true by default but should be set to false if your adapter
+             will display items of varying heights. When this property is set to true and
+             your adapter displays items of varying heights, the scrollbar thumb will
+             change size as the user scrolls through the list. When set to fale, the list
+             will use only the number of items in the adapter and the number of items visible
+             on screen to determine the scrollbar's properties. -->
+        <attr name="smoothScrollbar" format="boolean" />
     </declare-styleable>
     <declare-styleable name="AbsSpinner">
         <!-- Reference to an array resource that will populate the Spinner.  For static content,
@@ -1067,6 +1288,16 @@
             <flag name="center" value="0x11" />
             <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
             <flag name="fill" value="0x77" />
+            <!-- Additional option that can be set to have the top and/or bottom edges of
+                 the child clipped to its container's bounds.
+                 The clip will be based on the vertical gravity: a top gravity will clip the bottom
+                 edge, a bottom gravity will clip the top edge, and neither will clip both edges. -->
+            <flag name="clip_vertical" value="0x80" />
+            <!-- Additional option that can be set to have the left and/or right edges of
+                 the child clipped to its container's bounds.
+                 The clip will be based on the horizontal gravity: a left gravity will clip the right
+                 edge, a right gravity will clip the left edge, and neither will clip both edges. -->
+            <flag name="clip_horizontal" value="0x08" />
         </attr>
         <!-- Determines whether to measure all children or just those in 
              the VISIBLE or INVISIBLE state when measuring. Defaults to false. -->
@@ -1108,6 +1339,7 @@
             <enum name="none" value="0"/>
             <enum name="spacingWidth" value="1" />
             <enum name="columnWidth" value="2" />
+            <enum name="spacingWidthUniform" value="3" />
         </attr>
         <attr name="columnWidth" format="dimension" />
         <attr name="numColumns" format="integer" min="0">
@@ -1204,6 +1436,12 @@
             <!-- The list allows multiple choices -->
             <enum name="multipleChoice" value="2" />
         </attr>
+        <!-- When set to false, the ListView will not draw the divider after each header view.
+             The default value is true. -->
+        <attr name="headerDividersEnabled" format="boolean" />
+        <!-- When set to false, the ListView will not draw the divider before each footer view.
+             The default value is true. -->
+        <attr name="footerDividersEnabled" format="boolean" />
     </declare-styleable>
     <declare-styleable name="MenuView">
         <!-- Default appearance of menu item text. -->
@@ -1228,6 +1466,8 @@
         <attr name="maxRows" format="integer" />
         <!-- Defines the maximum number of items per row. -->
         <attr name="maxItemsPerRow" format="integer" />
+        <!-- Defines the maximum number of items to show. -->
+        <attr name="maxItems" format="integer" />
         <!-- 'More' icon -->
         <attr name="moreIcon" format="reference" />
     </declare-styleable>
@@ -1407,21 +1647,25 @@
         <attr name="minEms" format="integer" min="0" />
         <!-- Makes the TextView be at least this many pixels wide -->
         <attr name="minWidth" />
-        <!-- Vertical gravity (top, center_vertical, bottom) when the text
-             is smaller than the view. -->
+        <!-- Specifies how to align the text by the view's x and/or y axis 
+             when the text is smaller than the view. -->
         <attr name="gravity" />
         <!-- Whether the text is allowed to be wider than the view (and
              therefore can be scrolled horizontally). -->
         <attr name="scrollHorizontally" format="boolean" />
         <!-- Whether the characters of the field are displayed as
-             password dots instead of themselves. -->
+             password dots instead of themselves.
+             {@deprecated Use inputType instead.} -->
         <attr name="password" format="boolean" />
         <!-- Constrains the text to a single horizontally scrolling line
              instead of letting it wrap onto multiple lines, and advances
              focus instead of inserting a newline when you press the
-             enter key. -->
+             enter key.  Note: for editable text views, it is better
+             to set this using the textMultiLine flag in inputType;
+             if both this and inputType are supplied, the input
+             type overrides the value here. -->
         <attr name="singleLine" format="boolean" />
-        <!-- Deprecated: use state_enabled instead. -->
+        <!-- {@deprecated Use state_enabled instead.} -->
         <attr name="enabled" format="boolean" />
         <!-- If the text is selectable, select it all when the view takes
              focus instead of moving the cursor to the start or end. -->
@@ -1446,7 +1690,8 @@
              to be found. -->
         <attr name="linksClickable" format="boolean" />
         <!-- If set, specifies that this TextView has a numeric input method.
-             The default is false. -->
+             The default is false.
+             {@deprecated Use inputType instead.} -->
         <attr name="numeric">
             <!-- Input is numeric. -->
             <flag name="integer" value="0x01" />
@@ -1462,15 +1707,17 @@
              The default is false. -->
         <attr name="digits" format="string" />
         <!-- If set, specifies that this TextView has a phone number input
-             method.
-             The default is false. -->
+             method. The default is false.
+             {@deprecated Use inputType instead.} -->
         <attr name="phoneNumber" format="boolean" />
         <!-- If set, specifies that this TextView should use the specified
-             input method (specified by fully-qualified class name). -->
+             input method (specified by fully-qualified class name).
+             {@deprecated Use inputType instead.} -->
         <attr name="inputMethod" format="string" />
         <!-- If set, specifies that this TextView has a textual input method
              and should automatically capitalize what the user types.
-             The default is "none". -->
+             The default is "none".
+             {@deprecated Use inputType instead.} -->
         <attr name="capitalize">
             <!-- Don't automatically capitalize anything. -->
             <enum name="none" value="0" />
@@ -1483,12 +1730,14 @@
         </attr>
         <!-- If set, specifies that this TextView has a textual input method
              and automatically corrects some common spelling errors.
-             The default is "false". -->
+             The default is "false".
+             {@deprecated Use inputType instead.} -->
         <attr name="autoText" format="boolean" />
         <!-- If set, specifies that this TextView has an input method.
              It will be a textual one unless it has otherwise been specified.
              For TextView, this is false by default.  For EditText, it is
-             true by default. -->
+             true by default.
+             {@deprecated Use inputType instead.} -->
         <attr name="editable" format="boolean" />
         <!-- If set, the text view will include its current complete text
              inside of its frozen icicle in addition to meta-data such as
@@ -1517,6 +1766,34 @@
         <attr name="lineSpacingExtra" format="dimension" />
         <!-- Extra spacing between lines of text, as a multiplier. -->
         <attr name="lineSpacingMultiplier" format="float" />
+        <!-- The number of times to repeat the marquee animation. Only applied if the 
+             TextView has marquee enabled. -->
+        <attr name="marqueeRepeatLimit" format="integer">
+            <!-- Indicates that marquee should repeat indefinitely  -->
+            <enum name="marquee_forever" value="-1" />
+        </attr>
+        <attr name="inputType" />
+        <!-- An addition content type description to supply to the input
+             method attached to the text view, which is private to the
+             implementation of the input method.  This simply fills in
+             the {@link android.view.inputmethod.EditorInfo#privateContentType
+             EditorInfo.privateContentType} field when the input
+             method is connected. -->
+        <attr name="editorPrivateContentType" format="string" />
+        <!-- Reference to an
+             {@link android.R.styleable#InputExtras &lt;input-extras&gt;}
+             XML resource containing additional data to
+             supply to an input method, which is private to the implementation
+             of the input method.  This simply fills in
+             the {@link android.view.inputmethod.EditorInfo#extras
+             EditorInfo.extras} field when the input
+             method is connected. -->
+        <attr name="editorExtras" format="reference" />
+    </declare-styleable>
+    <!-- An <code>input-extras</code> is a container for extra data to supply to
+         an input method.  Contains
+         one more more {@link #Extra <extra>} tags.  -->
+    <declare-styleable name="InputExtras">
     </declare-styleable>
     <declare-styleable name="AutoCompleteTextView">
         <!-- Defines the hint displayed in the drop down menu. -->
@@ -1527,7 +1804,12 @@
          completion suggestions are displayed in a drop down menu. -->
         <attr name="completionThreshold" format="integer" min="1" />
         <!-- Selector in a drop down list. -->
-        <attr name="dropDownSelector" format="reference|color" />        
+        <attr name="dropDownSelector" format="reference|color" />
+        <!-- Amount of pixels by which the drop down should be offset vertically. -->
+        <attr name="dropDownVerticalOffset" format="dimension" />
+        <!-- Amount of pixels by which the drop down should be offset horizontally. -->
+        <attr name="dropDownHorizontalOffset" format="dimension" />
+        <attr name="inputType" />
     </declare-styleable>
     <declare-styleable name="PopupWindow">
         <attr name="popupBackground" format="reference|color" />
@@ -1568,7 +1850,7 @@
         </attr>
     </declare-styleable>
 
-    <!-- SlidingDrawer specific attributes. These attribtues are used to configure
+    <!-- SlidingDrawer specific attributes. These attributes are used to configure
          a SlidingDrawer from XML. -->
     <declare-styleable name="SlidingDrawer">
         <!-- Identifier for the child that represents the drawer's handle. -->
@@ -1581,6 +1863,10 @@
         <attr name="bottomOffset" format="dimension"  />
         <!-- Extra offset for the handle at the top of the SlidingDrawer. -->
         <attr name="topOffset" format="dimension"  />
+        <!-- Indicates whether the drawer can be opened/closed by a single tap
+             on the handle.  (If false, the user must drag or fling, or click
+             using the trackball, to open/close the drawer.)  Default is true. -->
+        <attr name="allowSingleTap" format="boolean" />
         <!-- Indicates whether the drawer should be opened/closed with an animation
              when the user clicks the handle. Default is true. -->
         <attr name="animateOnClick" format="boolean" />
@@ -1864,6 +2150,16 @@
             <flag name="center" value="0x11" />
             <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
             <flag name="fill" value="0x77" />
+            <!-- Additional option that can be set to have the top and/or bottom edges of
+                 the child clipped to its container's bounds.
+                 The clip will be based on the vertical gravity: a top gravity will clip the bottom
+                 edge, a bottom gravity will clip the top edge, and neither will clip both edges. -->
+            <flag name="clip_vertical" value="0x80" />
+            <!-- Additional option that can be set to have the left and/or right edges of
+                 the child clipped to its container's bounds.
+                 The clip will be based on the horizontal gravity: a left gravity will clip the right
+                 edge, a right gravity will clip the left edge, and neither will clip both edges. -->
+            <flag name="clip_horizontal" value="0x08" />
         </attr>
         <!-- Reference to a drawable resource to draw with the specified scale. -->
         <attr name="drawable" />
@@ -2175,7 +2471,7 @@
         <!-- If supplied, this string will be displayed as the text of the "Search" button.
           <i>Optional attribute.</i> -->
         <attr name="searchButtonText" format="string" />
-
+        
         <!-- Additional features are controlled by mode bits in this field.  Omitting
             this field, or setting to zero, provides default behavior.  <i>Optional attribute.</i> 
         -->
@@ -2522,5 +2818,101 @@
         </attr>
     </declare-styleable>
 
+    <declare-styleable name="KeyboardView">
+        <!-- Default KeyboardView style. -->
+        <attr name="keyboardViewStyle" format="reference" />
+
+        <!-- Image for the key. This image needs to be a StateListDrawable, with the following
+             possible states: normal, pressed, checkable, checkable+pressed, checkable+checked,
+             checkable+checked+pressed. -->
+        <attr name="keyBackground" format="reference" />
+
+        <!-- Size of the text for character keys. -->
+        <attr name="keyTextSize" format="dimension" />
+
+        <!-- Size of the text for custom keys with some text and no icon. -->
+        <attr name="labelTextSize" format="dimension" />
+
+        <!-- Color to use for the label in a key -->
+        <attr name="keyTextColor" format="color" />
+
+        <!-- Layout resource for key press feedback.-->
+        <attr name="keyPreviewLayout" format="reference" />
+
+        <!-- Vertical offset of the key press feedback from the key. -->
+        <attr name="keyPreviewOffset" format="dimension" />
+
+        <!-- Height of the key press feedback popup. -->
+        <attr name="keyPreviewHeight" format="dimension" />
+
+        <!-- Amount to offset the touch Y coordinate by, for bias correction. -->
+        <attr name="verticalCorrection" format="dimension" />
+
+        <!-- Layout resource for popup keyboards -->
+        <attr name="popupLayout" format="reference" />
+    </declare-styleable>
+    
+    <declare-styleable name="KeyboardViewPreviewState">
+        <!-- State for {@link android.inputmethodservice.KeyboardView KeyboardView} 
+                key preview background -->
+        <attr name="state_long_pressable" format="boolean" />
+    </declare-styleable>
+
+    <declare-styleable name="Keyboard">
+        <!-- Default width of a key, in pixels or percentage of display width -->
+        <attr name="keyWidth" format="dimension|fraction" />
+        <!-- Default height of a key, in pixels or percentage of display width -->
+        <attr name="keyHeight" format="dimension|fraction" />
+        <!-- Default horizontal gap between keys -->
+        <attr name="horizontalGap" format="dimension|fraction" />
+        <!-- Default vertical gap between rows of keys -->
+        <attr name="verticalGap" format="dimension|fraction" />
+    </declare-styleable>
+
+    <declare-styleable name="Keyboard_Row">
+        <!-- Row edge flags-->
+        <attr name="rowEdgeFlags">
+            <!-- Row is anchored to the top of the keyboard -->
+            <flag name="top" value="4" />
+            <!-- Row is anchored to the bottom of the keyboard -->
+            <flag name="bottom" value="8" />
+        </attr>
+        <!-- Mode of the keyboard. If the mode doesn't match the
+             requested keyboard mode, the row will be skipped -->
+        <attr name="keyboardMode" format="reference" />
+    </declare-styleable>
+
+    <declare-styleable name="Keyboard_Key">
+        <!-- The unicode value or comma-separated values that this key outputs -->
+        <attr name="codes" format="integer|string" />
+        <!-- The XML keyboard layout of any popup keyboard -->
+        <attr name="popupKeyboard" format="reference" />
+        <!-- The characters to display in the popup keyboard -->
+        <attr name="popupCharacters" format="string" />
+        <!-- Key edge flags -->
+        <attr name="keyEdgeFlags">
+            <!-- Key is anchored to the left of the keyboard -->
+            <flag name="left" value="1" />
+            <!-- Key is anchored to the right of the keyboard -->
+            <flag name="right" value="2" />
+        </attr>
+        <!-- Whether this is a modifier key such as Alt or Shift -->
+        <attr name="isModifier" format="boolean" />
+        <!-- Whether this is a toggle key -->
+        <attr name="isSticky" format="boolean" />
+        <!-- Whether long-pressing on this key will make it repeat -->
+        <attr name="isRepeatable" format="boolean" />
+        <!-- The icon to show in the popup preview -->
+        <attr name="iconPreview" format="reference" />
+        <!-- The string of characters to output when this key is pressed -->
+        <attr name="keyOutputText" format="string" />
+        <!-- The label to display on the key -->
+        <attr name="keyLabel" format="string" />
+        <!-- The icon to display on the key instead of the label -->
+        <attr name="keyIcon" format="reference" />
+        <!-- Mode of the keyboard. If the mode doesn't match the
+             requested keyboard mode, the key will be skipped -->
+        <attr name="keyboardMode" />
+    </declare-styleable>
 </resources>
 
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 7f47182..e2151410 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -299,6 +299,12 @@
          be dropped as described here. -->
     <attr name="clearTaskOnLaunch" format="boolean" />
     
+    <!-- Specify whether an activity should be kept in its history stack.
+         If this attribute is set, then as soon as the user navigates away
+         from the activity it will be finished and they will no longer be
+         able to return to it. -->
+    <attr name="noHistory" format="boolean" />
+    
     <!-- Specify whether an acitivty's task state should always be maintained
          by the system, or if it is allowed to reset the task to its initial
          state in certain situations.
@@ -520,6 +526,37 @@
          functional test. -->
     <attr name="functionalTest" format="boolean" />
 
+    <!-- The touch screen type used by an application. -->
+    <attr name="reqTouchScreen">
+        <enum name="undefined" value="0" />
+        <enum name="notouch" value="1" />
+        <enum name="stylus" value="2" />
+        <enum name="finger" value="3" />
+    </attr>
+
+    <!-- The input method preferred by an application. -->
+    <attr name="reqKeyboardType">
+        <enum name="undefined" value="0" />
+        <enum name="nokeys" value="1" />
+        <enum name="qwerty" value="2" />
+        <enum name="twelvekey" value="3" />
+    </attr>
+
+    <!-- Application's requirement for a hard keyboard -->
+    <attr name="reqHardKeyboard" format="boolean" />
+
+    <!-- The navigation device preferred by an application. -->
+    <attr name="reqNavigation">
+        <enum name="undefined" value="0" />
+        <enum name="nonav" value="1" />
+        <enum name="dpad" value="2" />
+        <enum name="trackball" value="3" />
+        <enum name="wheel" value="4" />
+    </attr>
+
+    <!-- Application's requirement for five way navigation -->
+    <attr name="reqFiveWayNav" format="boolean" />
+
     <!-- The <code>manifest</code> tag is the root of an
          <code>AndroidManifest.xml</code> file,
          describing the contents of an Android package (.apk) file.  One
@@ -535,6 +572,7 @@
          {@link #AndroidManifestPermissionTree permission-tree},
          {@link #AndroidManifestUsesSdk uses-sdk},
          {@link #AndroidManifestUsesPermission uses-permission},
+         {@link #AndroidManifestUsesConfiguration uses-configuration},
          {@link #AndroidManifestApplication application},
          {@link #AndroidManifestInstrumentation instrumentation}.  -->
     <declare-styleable name="AndroidManifest">
@@ -682,7 +720,25 @@
         system permissions}. -->
         <attr name="name" />
     </declare-styleable>
-    
+
+    <!-- The <code>uses-configuration</code> tag specifies
+         a specific hardware configuration value used by the application.
+         For example an application might specify that it requires
+         a physical keyboard or a particular navigation method like
+         trackball. Multiple such attribute values can be specified by the
+         application.
+
+         <p>This appears as a child tag of the root
+         {@link #AndroidManifest manifest} tag. -->
+    <declare-styleable name="AndroidManifestUsesConfiguration" parent="AndroidManifest">
+        <!-- The type of touch screen used by an application. -->
+        <attr name="reqTouchScreen" />
+        <attr name="reqKeyboardType" />
+        <attr name="reqHardKeyboard" />
+        <attr name="reqNavigation" />
+        <attr name="reqFiveWayNav" />
+    </declare-styleable>
+
     <!-- The <code>uses-sdk</code> tag describes the SDK features that the
          containing package must be running on to operate correctly.
          
@@ -858,6 +914,7 @@
         <attr name="allowTaskReparenting" />
         <attr name="finishOnTaskLaunch" />
         <attr name="clearTaskOnLaunch" />
+        <attr name="noHistory" />
         <attr name="alwaysRetainTaskState" />
         <attr name="stateNotNeeded" />
         <attr name="excludeFromRecents" />
@@ -867,6 +924,10 @@
              component specific values). -->
         <attr name="enabled" />
         <attr name="exported" />
+        <!-- Specify the default soft-input mode for the main window of
+             this activity.  A value besides "unspecified" here overrides
+             any value in the theme. -->
+        <attr name="windowSoftInputMode" />
     </declare-styleable>
     
     <!-- The <code>activity-alias</code> tag declares a new
@@ -1066,7 +1127,7 @@
     
     <!-- Declaration of an {@link android.content.Intent} object in XML.  May
          also include zero or more {@link #IntentCategory <category> and
-         {@link #IntentExtra <extra>} tags. -->
+         {@link #Extra <extra>} tags. -->
     <declare-styleable name="Intent">
         <!-- The action name to assign to the Intent, as per
             {@link android.content.Intent#setAction Intent.setAction()}. -->
@@ -1092,9 +1153,9 @@
         <attr name="name" />
     </declare-styleable>
     
-    <!-- An extra data value to place in the Intent, as per
-            {@link android.content.Intent#putExtra Intent.putExtra()}. -->
-    <declare-styleable name="IntentExtra" parent="Intent">
+    <!-- An extra data value to place into a an extra/name value pair held
+            in a Bundle, as per {@link android.os.Bundle}. -->
+    <declare-styleable name="Extra" parent="Intent">
         <!-- Required name of the extra data. -->
         <attr name="name" />
         <!-- Concrete value to put for this named extra data. -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 1b80179..59f3a8f 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -58,6 +58,8 @@
     <drawable name="editbox_dropdown_dark_frame">@drawable/editbox_dropdown_background_dark</drawable>
     <drawable name="editbox_dropdown_light_frame">@drawable/editbox_dropdown_background</drawable>
     
+    <drawable name="input_method_fullscreen_background">#ffffffff</drawable>
+    
     <!-- For date picker widget -->
     <drawable name="selected_day_background">#ff0092f4</drawable>
   
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 72e149b..e58cae4 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -50,4 +50,16 @@
   <item type="id" name="button1" />
   <item type="id" name="button2" />
   <item type="id" name="button3" />
+  <item type="id" name="extractArea" />
+  <item type="id" name="candidatesArea" />
+  <item type="id" name="inputArea" />
+  <item type="id" name="inputExtractEditText" />
+  <item type="id" name="selectAll" />
+  <item type="id" name="cut" />
+  <item type="id" name="copy" />
+  <item type="id" name="paste" />
+  <item type="id" name="copyUrl" />
+  <item type="id" name="inputMethod" />
+  <item type="id" name="keyboardView" />
+  <item type="id" name="button_close" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9189622..dadf3ce 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -19,17 +19,17 @@
      *************************************************************** -->
 <resources>
 
-    <!-- We don't want to publish private symbols in android.R as part of the
-         SDK.  Instead, put them here. -->
-    <private-symbols package="com.android.internal" />
+  <!-- We don't want to publish private symbols in android.R as part of the
+       SDK.  Instead, put them here. -->
+  <private-symbols package="com.android.internal" />
     
-    <!-- AndroidManifest.xml attributes. -->
-    <eat-comment />
+  <!-- AndroidManifest.xml attributes. -->
+  <eat-comment />
 
 <!-- ===============================================================
-     Resource set for version 1.0 of the platform.
+     Resources for version 1 of the platform.
      =============================================================== -->
-    <eat-comment />
+  <eat-comment />
 
   <public type="attr" name="theme" id="0x01010000" />
   <public type="attr" name="label" id="0x01010001" />
@@ -572,7 +572,7 @@
   <public type="attr" name="listChoiceIndicatorMultiple" id="0x0101021a" />    
   <public type="attr" name="versionCode" id="0x0101021b" />
   <public type="attr" name="versionName" id="0x0101021c" />
-
+  
   <public type="id" name="background" id="0x01020000" />
   <public type="id" name="checkbox" id="0x01020001" />
   <public type="id" name="content" id="0x01020002" />
@@ -601,7 +601,7 @@
   <public type="id" name="button1" id="0x01020019" />
   <public type="id" name="button2" id="0x0102001a" />
   <public type="id" name="button3" id="0x0102001b" />
-
+  
   <public type="style" name="Animation" id="0x01030000" />
   <public type="style" name="Animation.Activity" id="0x01030001" />
   <public type="style" name="Animation.Dialog" id="0x01030002" />
@@ -916,7 +916,7 @@
   <public type="layout" name="select_dialog_item" id="0x01090011" />
   <public type="layout" name="select_dialog_singlechoice" id="0x01090012" />
   <public type="layout" name="select_dialog_multichoice" id="0x01090013" />
-        
+  
   <public type="anim" name="fade_in" id="0x010a0000" />
   <public type="anim" name="fade_out" id="0x010a0001" />
   <public type="anim" name="slide_in_left" id="0x010a0002" />
@@ -925,5 +925,117 @@
   <public type="anim" name="accelerate_interpolator" id="0x010a0005" />
   <public type="anim" name="decelerate_interpolator" id="0x010a0006" />
 
+<!-- ===============================================================
+     Resources added in version 2 of the platform.
+     =============================================================== -->
+  <eat-comment />
+  
+  <public type="attr" name="marqueeRepeatLimit" id="0x0101021d" />
+  
+<!-- ===============================================================
+     Resources added in version 3 of the platform.
+     =============================================================== -->
+  <eat-comment />
 
+  <public type="attr" name="backgroundDimEnabled" id="0x0101021f" />
+  <public type="attr" name="inputType" id="0x01010220" />
+  <public type="attr" name="isDefault" id="0x01010221" />
+  <public type="attr" name="windowDisablePreview" id="0x01010222" />
+  <public type="attr" name="editorPrivateContentType" id="0x01010223" />
+  <public type="attr" name="editorExtras" id="0x01010224" />
+  <public type="attr" name="settingsActivity" id="0x01010225" />
+  <public type="attr" name="fastScrollEnabled" id="0x01010226" />
+  <public type="attr" name="reqTouchScreen" id="0x01010227" />
+  <public type="attr" name="reqKeyboardType" id="0x01010228" />
+  <public type="attr" name="reqHardKeyboard" id="0x01010229" />
+  <public type="attr" name="reqNavigation" id="0x0101022a" />
+  <public type="attr" name="windowSoftInputMode" id="0x0101022b" />
+  <public type="attr" name="starStyleButtonless" id="0x0101022c" />
+  <public type="attr" name="noHistory" id="0x0101022d" />
+  <public type="attr" name="headerDividersEnabled" id="0x0101022e" />
+  <public type="attr" name="footerDividersEnabled" id="0x0101022f" />
+  <public type="attr" name="candidatesTextStyleSpans" id="0x01010230" />
+  <public type="attr" name="smoothScrollbar" id="0x01010231" />
+  <public type="attr" name="reqFiveWayNav" id="0x01010232" />
+  <public type="attr" name="keyBackground" id="0x01010233" />
+  <public type="attr" name="keyTextSize" id="0x01010234" />
+  <public type="attr" name="labelTextSize" id="0x01010235" />
+  <public type="attr" name="keyTextColor" id="0x01010236" />
+  <public type="attr" name="keyPreviewLayout" id="0x01010237" />
+  <public type="attr" name="keyPreviewOffset" id="0x01010238" />
+  <public type="attr" name="keyPreviewHeight" id="0x01010239" />
+  <public type="attr" name="verticalCorrection" id="0x01010240" />
+  <public type="attr" name="popupLayout" id="0x01010241" />
+  <public type="attr" name="state_long_pressable" id="0x01010242" />
+  <public type="attr" name="keyWidth" id="0x01010243" />
+  <public type="attr" name="keyHeight" id="0x01010244" />
+  <public type="attr" name="horizontalGap" id="0x01010245" />
+  <public type="attr" name="verticalGap" id="0x01010246" />
+  <public type="attr" name="rowEdgeFlags" id="0x01010247" />
+  <public type="attr" name="codes" id="0x01010248" />
+  <public type="attr" name="popupKeyboard" id="0x01010249" />
+  <public type="attr" name="popupCharacters" id="0x0101024a" />
+  <public type="attr" name="keyEdgeFlags" id="0x0101024b" />
+  <public type="attr" name="isModifier" id="0x0101024c" />
+  <public type="attr" name="isSticky" id="0x0101024d" />
+  <public type="attr" name="isRepeatable" id="0x0101024e" />
+  <public type="attr" name="iconPreview" id="0x0101024f" />
+  <public type="attr" name="keyOutputText" id="0x01010250" />
+  <public type="attr" name="keyLabel" id="0x01010251" />
+  <public type="attr" name="keyIcon" id="0x01010252" />
+  <public type="attr" name="keyboardMode" id="0x01010253" />
+
+  <!-- The part of the UI shown by an
+       {@link android.inputmethodservice.InputMethodService} that contains the
+       views for interacting with the user in extraction mode. -->
+  <public type="id" name="extractArea" id="0x0102001c" />
+
+  <!-- The part of the UI shown by an
+       {@link android.inputmethodservice.InputMethodService} that contains the
+       views for displaying candidates for what the user has entered. -->
+  <public type="id" name="candidatesArea" id="0x0102001d" />
+
+  <!-- The part of the UI shown by an
+       {@link android.inputmethodservice.InputMethodService} that contains the
+       views for entering text using the screen. -->
+  <public type="id" name="inputArea" id="0x0102001e" />
+
+  <!-- Context menu ID for the "Select All" menu item to select all text
+       in a text view. -->
+  <public type="id" name="selectAll" id="0x0102001f" />
+  <!-- Context menu ID for the "Cut" menu item to copy and delete the currently
+       selected (or all) text in a text view to the clipboard. -->
+  <public type="id" name="cut" id="0x01020020" />
+  <!-- Context menu ID for the "Copy" menu item to copy the currently
+       selected (or all) text in a text view to the clipboard. -->
+  <public type="id" name="copy" id="0x01020021" />
+  <!-- Context menu ID for the "Paste" menu item to copy the current contents
+       of the clipboard into the text view. -->
+  <public type="id" name="paste" id="0x01020022" />
+  <!-- Context menu ID for the "Copy URL" menu item to copy the currently
+       selected URL from the text view to the clipboard. -->
+  <public type="id" name="copyUrl" id="0x01020023" />
+  <!-- Context menu ID for the "Input Method" menu item to being up the
+       input method picker dialog, allowing the user to switch to another
+       input method. -->
+  <public type="id" name="inputMethod" id="0x01020024" />
+  <!-- View ID of the text editor inside of an extracted text layout. -->
+  <public type="id" name="inputExtractEditText" id="0x01020025" />
+
+  <!-- View ID of the {@link android.inputmethodservice.KeyboardView} within
+        an input method's input area. -->
+  <public type="id" name="keyboardView" id="0x01020026" />
+  <!-- View ID of a {@link android.view.View} to close a popup keyboard -->
+  <public type="id" name="button_close" id="0x01020027" />
+
+  <public type="style" name="Theme.InputMethod" id="0x01030054" />
+  <public type="style" name="Theme.NoDisplay" id="0x01030055" />
+  <public type="style" name="Animation.InputMethod" id="0x01030056" />
+  <public type="style" name="Widget.KeyboardView" id="0x01030057" />
+  
+  <public type="drawable" name="ic_btn_search" id="0x0108009e" />
+  <public type="drawable" name="ic_dialog_menu_generic" id="0x010800a0" />
 </resources>
+
+
+
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bec3bc8..d92fd5f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -18,17 +18,25 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Abbreviations for different units of information and computer storage -->
-    <!-- used by android.content.Formatter.formatFileSize -->
+    <!-- Suffix added to a number to signify size in bytes. -->
     <string name="byteShort">B</string>
+    <!-- Suffix added to a number to signify size in kilobytes. -->
     <string name="kilobyteShort">KB</string>
+    <!-- Suffix added to a number to signify size in megabytes. -->
     <string name="megabyteShort">MB</string>
+    <!-- Suffix added to a number to signify size in gigabytes. -->
     <string name="gigabyteShort">GB</string>
+    <!-- Suffix added to a number to signify size in terabytes. -->
     <string name="terabyteShort">TB</string>
+    <!-- Suffix added to a number to signify size in petabytes. -->
     <string name="petabyteShort">PB</string>
 
-    <string name="selectMenuLabel">Select</string>
+    <!-- Used in Contacts for a field that has no label and in Note Pad
+         for a note with no name. -->
     <string name="untitled">&lt;untitled&gt;</string>
+
+    <!-- Used to replace a range of characters in text that is too wide
+         for the space allocated to it. -->
     <string name="ellipsis">\u2026</string>
 
     <!-- How to display the lack of a phone number -->
@@ -37,62 +45,92 @@
     <!-- How to display the lack of a name -->
     <string name="unknownName">(Unknown)</string>
 
-    <string name="screen_progress">Working\u2026</string>
-
     <!-- What the UI should display for "voice mail" unless overridden by the SIM-->
     <string name="defaultVoiceMailAlphaTag">Voicemail</string>
 
     <!-- What the UI should display for "Msisdn" unless overridden by the SIM-->
     <string name="defaultMsisdnAlphaTag">MSISDN1</string>
 
-    <!-- For GsmMmiCode.java -->
+    <!-- For GsmMmiCode.java --> <skip />
+    <!-- Displayed when the user dialed an MMI code whose function
+         could not be performed. This will be displayed in a toast. -->
     <string name="mmiError">Connection problem or invalid MMI code.</string>
+    <!-- Displayed when a phone feature such as call barring was activated. -->
     <string name="serviceEnabled">Service was enabled.</string>
+    <!-- Displayed in front of the list of a set of service classes
+         (voice, data, fax, etc.) that were enabled. -->
     <string name="serviceEnabledFor">Service was enabled for:</string>
+    <!-- Displayed when a phone feature such as call forwarding was deactivated. -->
     <string name="serviceDisabled">Service has been disabled.</string>
+    <!-- Displayed when a phone property such as a SIM password was registered. -->
     <string name="serviceRegistered">Registration was successful.</string>
+    <!-- Displayed when a phone property such as a SIM password was erased. -->
     <string name="serviceErased">Erasure was successful.</string>
+    <!-- Displayed when a SIM password was entered incorrectly. -->
     <string name="passwordIncorrect">Incorrect password.</string>
+    <!-- Displayed when a phone feature triggered by an MMI code is complete. -->
     <string name="mmiComplete">MMI complete.</string>
+    <!-- Displayed when a SIM PIN password is entered incorrectly. -->
     <string name="badPin">The old PIN you typed is not correct.</string>
+    <!-- Displayed when a SIM PUK password is entered incorrectly. -->
     <string name="badPuk">The PUK you typed is not correct.</string>
+    <!-- Displayed when SIM PIN passwords are entered inconsistently. -->
     <string name="mismatchPin">The PINs you entered do not match.</string>
+    <!-- Displayed when a SIM PIN password is too long or too short. -->
     <string name="invalidPin">Type a PIN that is 4 to 8 numbers.</string>
+    <!-- Displayed to prompt the user to type the PUK password to unlock
+         the SIM card. -->
+    <string name="needPuk">Your SIM card is PUK-locked. Type the PUK code to unlock it.</string>
     <string name="needPuk2">Type PUK2 to unblock SIM card.</string>
 
+    <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
     <string name="ClipMmi">Incoming Caller ID</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
     <string name="ClirMmi">Outgoing Caller ID</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling call forwarding. -->
     <string name="CfMmi">Call forwarding</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling call waiting. -->
     <string name="CwMmi">Call waiting</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling call barring. -->
     <string name="BaMmi">Call barring</string>
+    <!-- Displayed as the title for a success/failure report changing the SIM password. -->
     <string name="PwdMmi">Password change</string>
+    <!-- Displayed as the title for a success/failure report changing the SIM PIN. -->
     <string name="PinMmi">PIN change</string>
 
+    <!-- Displayed to confirm to the user that caller ID will be restricted on the next call as usual. -->
     <string name="CLIRDefaultOnNextCallOn">Caller ID defaults to restricted. Next call: Restricted</string>
+    <!-- Displayed to confirm to the user that caller ID will be not restricted on the next call even though it usually is. -->
     <string name="CLIRDefaultOnNextCallOff">Caller ID defaults to restricted. Next call: Not restricted</string>
+    <!-- Displayed to confirm to the user that caller ID will not be restricted on the next call but usually is. -->
     <string name="CLIRDefaultOffNextCallOn">Caller ID defaults to not restricted. Next call: Restricted</string>
+    <!-- Displayed to confirm to the user that caller ID will not be restricted on the next call or in general. -->
     <string name="CLIRDefaultOffNextCallOff">Caller ID defaults to not restricted. Next call: Not restricted</string>
 
 
+    <!-- Displayed to tell the user that caller ID is not provisioned for their SIM. -->
     <string name="serviceNotProvisioned">Service not provisioned.</string>
+    <!-- Displayed to tell the user that they cannot change the caller ID setting. -->
     <string name="CLIRPermanent">The caller ID setting cannot be changed.</string>
 
-    <!-- Mappings between TS 27.007 +CFCC/+CLCK "service classes" and human-readable strings-->
+    <!-- Mappings between TS 27.007 +CFCC/+CLCK "service classes" and human-readable strings--> <skip />
+    <!-- Example: Service was enabled for: Voice, Data -->
     <string name="serviceClassVoice">Voice</string>
+    <!-- Example: Service was enabled for: Voice, Data -->
     <string name="serviceClassData">Data</string>
+    <!-- Example: Service was enabled for: Voice, FAX -->
     <string name="serviceClassFAX">FAX</string>
+    <!-- Example: Service was enabled for: Voice, SMS -->
     <string name="serviceClassSMS">SMS</string>
+    <!-- Meaning: asynchronous data.  Example: Service was enabled for: Voice, Async -->
     <string name="serviceClassDataAsync">Async</string>
+    <!-- Meaning: synchronous data.  Example: Service was enabled for: Voice, Async -->
     <string name="serviceClassDataSync">Sync</string>
+    <!-- Meaning: packet data.  Example: Service was enabled for: Voice, Packet -->
     <string name="serviceClassPacket">Packet</string>
+    <!-- Meaning: unknown.  Example: Service was enabled for: Voice, PAD -->
     <string name="serviceClassPAD">PAD</string>
 
-    <string name="cfReasonUnconditional">Call forwarding - Always</string>
-    <string name="cfReasonBusy">Call forwarding - Busy</string>
-    <string name="cfReasonNRy">Call forwarding - No reply</string>
-    <string name="cfReasonNR">Call forwarding - Not reachable</string>
-
-
     <!--
         {0} is one of "bearerServiceCode*"
         {1} is dialing number
@@ -100,597 +138,850 @@
 
         cfTemplateRegistered and cfTemplateRegisteredTime mean that a phone number
         has been set but forwarding is not on.
-    -->
-    <string name="cfTemplateNotForwarded">{0}: Not forwarded</string>
-    <string name="cfTemplateForwarded">{0}: {1}</string>
-    <string name="cfTemplateForwardedTime">{0}: {1} after {2} seconds</string>
-    <string name="cfTemplateRegistered">{0}: Not forwarded</string>
-    <string name="cfTemplateRegisteredTime">{0}: Not forwarded</string>
+    --> <skip />
+    <!-- Displayed when the call forwarding query was not able to be forwarded. -->
+    <string name="cfTemplateNotForwarded"><xliff:g id="bearer_service_code">{0}</xliff:g>: Not forwarded</string>
+    <!-- Displayed when the call forwarding query was forwarded. -->
+    <string name="cfTemplateForwarded"><xliff:g id="bearer_service_code">{0}</xliff:g>: <xliff:g id="dialing_number">{1}</xliff:g></string>
+    <!-- Displayed when the call forwarding query will be forwarded after some time. -->
+    <string name="cfTemplateForwardedTime"><xliff:g id="bearer_service_code">{0}</xliff:g>: <xliff:g id="dialing_number">{1}</xliff:g> after <xliff:g id="time_delay">{2}</xliff:g> seconds</string>
+    <!-- Displayed when the call forwarding query was set but forwarding is not enabled. -->
+    <string name="cfTemplateRegistered"><xliff:g id="bearer_service_code">{0}</xliff:g>: Not forwarded</string>
+    <!-- Displayed when the call forwarding query was set but forwarding is not enabled. -->
+    <string name="cfTemplateRegisteredTime"><xliff:g id="bearer_service_code">{0}</xliff:g>: Not forwarded</string>
 
-    <string name="simAbsentLabel">SIM card absent or incorrectly inserted.</string>
-    <string name="simPINLabel">SIM PIN required (and presently unsupported).</string>
-    <string name="simPUKLabel">SIM PUK required (and presently unsupported).</string>
-    <string name="simNetworkPersonalizationLabel">SIM card cannot be used on this phone.</string>
-
-    <!-- BrowserFrame strings -->
-    <string name="browserSavedFormData">Saved form data.</string>
-
-    <!-- android.net.http Error strings -->
+    <!-- android.net.http Error strings --> <skip />
+    <!-- Displayed when a web request was successful. -->
     <string name="httpErrorOk">OK</string>
+    <!-- Displayed when a web request failed because we don't know the exact reason. -->
     <string name="httpError">The Web page contains an error.</string>
+    <!-- Displayed when a web request failed because the URL could not be found. -->
     <string name="httpErrorLookup">The URL could not be found.</string>
+    <!-- Displayed when a web request failed because the site's authentication scheme is not supported by us. -->
     <string name="httpErrorUnsupportedAuthScheme">The site authentication scheme is not supported.</string>
+    <!-- Displayed when a web request failed because the authentication failed. -->
     <string name="httpErrorAuth">Authentication was unsuccessful.</string>
+    <!-- Displayed when a web request failed because the authentication with the proxy failed. -->
     <string name="httpErrorProxyAuth">Authentication via the proxy server was unsuccessful.</string>
+    <!-- Displayed when a web request failed because there was a connection error. -->
     <string name="httpErrorConnect">The connection to the server was unsuccessful.</string>
+    <!-- Displayed when a web request failed because there was an input or output error. -->
     <string name="httpErrorIO">The server failed to communicate. Try again later.</string>
+    <!-- Displayed when a web request failed because the request timed out -->
     <string name="httpErrorTimeout">The connection to the server timed out.</string>
+    <!-- Displayed when a web request failed because the site tried to redirect us one too many times -->
     <string name="httpErrorRedirectLoop">The page contains too many server redirects.</string>
+    <!-- Displayed when a web request failed because the protocol of the server is not supported. -->
     <string name="httpErrorUnsupportedScheme">The protocol is not supported.</string>
+    <!-- Displayed when a web request failed because the a secure connection couldn't be made to the server.-->
     <string name="httpErrorFailedSslHandshake">A secure connection could not be established.</string>
+    <!-- Displayed when a web request failed because the URL isn't in a valid form. -->
     <string name="httpErrorBadUrl">The page could not be opened because the URL is invalid.</string>
+    <!-- Displayed when a request failed because we failed to open the file. -->
     <string name="httpErrorFile">The file could not be accessed.</string>
+    <!-- Displayed when a request failed because the file wasn't found. -->
     <string name="httpErrorFileNotFound">The requested file was not found.</string>
+    <!-- Displayed when a request failed because there are too many requests right now. -->
     <string name="httpErrorTooManyRequests">Too many requests are being processed. Try again later.</string>
 
-    <!-- Sync notifications -->
+    <!-- Sync notifications --> <skip />
+    <!-- A notification is shown when there is a sync error.  This is the text that will scroll through the notification bar (will be seen by the user as he uses another application). -->
     <string name="contentServiceSync">Sync</string>
-    <string name="contentServiceXmppAvailable">XMPP Active</string>
+    <!-- A notification is shown when there is a sync error.  This is the title of the notification.  It will be seen in the pull-down notification tray. -->
     <string name="contentServiceSyncNotificationTitle">Sync</string>
-    <string name="contentServiceSyncNotificationDesc">Syncing</string>
-    <string name="contentServiceTooManyDeletesNotificationDesc">Too many %s deletes.</string>
-    <string name="contentServiceSyncErrorNotificationDesc">Sync is experiencing problems.</string>
+    <!-- A notification is shown when there is a sync error.  This is the message of the notification.  It describes the error, in this case is there were too many deletes. The argument is the type of content, for example Gmail or Calendar. It will be seen in the pull-down notification tray. -->
+    <string name="contentServiceTooManyDeletesNotificationDesc">Too many <xliff:g id="content_type">%s</xliff:g> deletes.</string>
 
-    <!-- Low memory Toast -->
+    <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
     <string name="low_memory">Phone storage is full! Delete some files to free space.</string>
 
-    <!-- Display name of local number -->
+
+    <!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
     <string name="me">Me</string>
 
-    <!-- Power Dialog -->
-
+    <!-- Power Dialog --> <skip />
+    <!-- Title for the Phone Options dialog to lock the screen, turn off the phone etc. -->
     <string name="power_dialog">Phone options</string>
-    <string name="activate_keyguard">Screen lock</string>
+    <!-- Button to turn on silent mode, within the Phone Options dialog -->
     <string name="silent_mode">Silent mode</string>
+    <!-- Button to turn on the radio, within the Phone Options dialog -->
     <string name="turn_on_radio">Turn on wireless</string>
+    <!-- Button to turn off the radio, within the Phone Options dialog -->
     <string name="turn_off_radio">Turn off wireless</string>
+    <!-- Button to lock the screen, within the Phone Options dialog -->
     <string name="screen_lock">Screen lock</string>
+    <!-- Button to turn off the phone, within the Phone Options dialog -->
     <string name="power_off">Power off</string>
 
-    <!-- Shutdown Progress Dialog -->
+    <!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. -->
     <string name="shutdown_progress">Shutting down\u2026</string>
 
-    <!-- Shutdown Confirmation Dialog -->
+    <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the phone, there will be a confirmation dialog.  This is the message. -->
     <string name="shutdown_confirm">Your phone will shut down.</string>
 
     <!-- Recent Tasks dialog -->
     <string name="no_recent_tasks">No recent applications.</string>
 
-    <!-- Global Actions Dialog -->
-
+    <!-- Title of the Global Actions Dialog -->
     <string name="global_actions">Phone options</string>
 
-    <!-- label for item that locks the phone in the global actions dialog -->
+    <!-- label for item that locks the phone in the phone options dialog -->
     <string name="global_action_lock">Screen lock</string>
 
-    <!-- label for item that turns off power in global actions dialog -->
+    <!-- label for item that turns off power in phone options dialog -->
     <string name="global_action_power_off">Power off</string>
 
-    <!-- label for item that enables silent mode in global actions dialog -->
+    <!-- label for item that enables silent mode in phone options dialog -->
     <string name="global_action_toggle_silent_mode">Silent mode</string>
 
-    <!-- status message in global actions dialog for when silent mode is enabled -->
+    <!-- status message in phone options dialog for when silent mode is enabled -->
     <string name="global_action_silent_mode_on_status">Sound is OFF</string>
 
-    <!-- status message in global actions dialog for when silent mode is disabled -->
+    <!-- status message in phone options dialog for when silent mode is disabled -->
     <string name="global_action_silent_mode_off_status">Sound is ON</string>
 
-    <!-- Activity Manager -->
+    <!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
     <string name="safeMode">Safe mode</string>
 
-    <!--  Permission Groups -->
-
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_costMoney">Services that cost you money</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_costMoney">Allow applications to do things
         that can cost you money.</string>
 
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_messages">Your messages</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_messages">Read and write your SMS,
         e-mail, and other messages.</string>
 
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_personalInfo">Your personal information</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_personalInfo">Direct access to your contacts
         and calendar stored on the phone.</string>
 
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_location">Your location</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_location">Monitor your physical location</string>
 
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_network">Network communication</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_network">Allow applications to access
         various network features.</string>
 
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_accounts">Your Google accounts</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_accounts">Access the available Google accounts.</string>
 
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_hardwareControls">Hardware controls</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_hardwareControls">Direct access to hardware on
         the handset.</string>
 
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_phoneCalls">Phone calls</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_phoneCalls">Monitor, record, and process
         phone calls.</string>
 
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_systemTools">System tools</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_systemTools">Lower-level access and control
         of the system.</string>
 
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_developmentTools">Development tools</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_developmentTools">Features only needed for
         application developers.</string>
 
     <!--  Permissions -->
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_statusBar">disable or modify status bar</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_statusBar">Allows application to disable
         the status bar or add and remove system icons.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_expandStatusBar">expand/collapse status bar</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_expandStatusBar">Allows application to
         expand or collapse the status bar.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_processOutgoingCalls">intercept outgoing calls</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_processOutgoingCalls">Allows application to
         process outgoing calls and change the number to be dialed.  Malicious
         applications may monitor, redirect, or prevent outgoing calls.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_receiveSms">receive SMS</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_receiveSms">Allows application to receive
       and process SMS messages. Malicious applications may monitor
       your messages or delete them without showing them to you.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_receiveMms">receive MMS</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_receiveMms">Allows application to receive
       and process MMS messages. Malicious applications may monitor
       your messages or delete them without showing them to you.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_sendSms">send SMS messages</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_sendSms">Allows application to send SMS
       messages. Malicious applications may cost you money by sending
       messages without your confirmation.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readSms">read SMS or MMS</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readSms">Allows application to read
       SMS messages stored on your phone or SIM card. Malicious applications
       may read your confidential messages.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeSms">edit SMS or MMS</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeSms">Allows application to write
       to SMS messages stored on your phone or SIM card. Malicious applications
       may delete your messages.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_receiveWapPush">receive WAP</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_receiveWapPush">Allows application to receive
       and process WAP messages. Malicious applications may monitor
       your messages or delete them without showing them to you.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_getTasks">retrieve running applications</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getTasks">Allows application to retrieve
         information about currently and recently running tasks. May allow
         malicious applications to discover private information about other applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_reorderTasks">reorder running applications</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_reorderTasks">Allows an application to move
         tasks to the foreground and background. Malicious applications can force
         themselves to the front without your control.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setDebugApp">enable application debugging</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setDebugApp">Allows an application to turn
         on debugging for another application. Malicious applications can use this
         to kill other applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_changeConfiguration">change your UI settings</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_changeConfiguration">Allows an application to
         change the current configuration, such as the locale or overall font
         size.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_restartPackages">restart other applications</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_restartPackages">Allows an application to
         forcibly restart other applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setProcessForeground">keep from being stopped</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setProcessForeground">Allows an application to make
-        any process run in the foreground, so it can't be killed.
+        any process run in the foreground, so it can\'t be killed.
         Should never be needed for normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_forceBack">force application to close</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_forceBack">Allows an application to force any
         activity that is in the foreground to close and go back.
         Should never be needed for normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_dump">retrieve system internal state</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_dump">Allows application to retrieve
         internal state of the system. Malicious applications may retrieve
         a wide variety of private and secure information that they should
         never normally need.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_addSystemService">publish low-level services</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_addSystemService">Allows application to publish
         its own low-level system services. Malicious applications may hijack
         the system, and steal or corrupt any data on it.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_runSetActivityWatcher">monitor and control all application launching</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_runSetActivityWatcher">Allows an application to
         monitor and control how the system launches activities.
         Malicious applications may completely compromise the system. This
         permission is only needed for development, never for normal
         phone usage.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_broadcastPackageRemoved">send package removed broadcast</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_broadcastPackageRemoved">Allows an application to
         broadcast a notification that an application package has been removed.
         Malicious applications may use this to kill any other running
         application.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_broadcastSmsReceived">send SMS-received broadcast</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_broadcastSmsReceived">Allows an application to
+        broadcast a notification that an SMS message has been received.
+        Malicious applications may use this to forge incoming SMS messages.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_broadcastWapPush">send WAP-PUSH-received broadcast</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_broadcastWapPush">Allows an application to
+        broadcast a notification that a WAP PUSH message has been received.
+        Malicious applications may use this to forge MMS message receipt or to
+        silently replace the content of any web page with malicious variants.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setProcessLimit">limit number of running processes</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setProcessLimit">Allows an application
         to control the maximum number of processes that will run. Never
         needed for normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setAlwaysFinish">make all background applications close</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setAlwaysFinish">Allows an application
         to control whether activities are always finished as soon as they
         go to the background. Never needed for normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_fotaUpdate">automatically install system updates</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_fotaUpdate">Allows an application to receive
         notifications about pending system updates and trigger their
         installation. Malicious applications may use this to corrupt the system
         with unauthorized updates, or generally interfere with the update
         process.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_batteryStats">modify battery statistics</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_batteryStats">Allows the modification of
         collected battery statistics. Not for use by normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_internalSystemWindow">display unauthorized windows</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_internalSystemWindow">Allows the creation of
         windows that are intended to be used by the internal system
         user interface. Not for use by normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_systemAlertWindow">display system-level alerts</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_systemAlertWindow">Allows an application to
         show system alert windows. Malicious applications can take over the
         entire screen of the phone.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setAnimationScale">modify global animation speed</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setAnimationScale">Allows an application to change
         the global animation speed (faster or slower animations) at any time.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_manageAppTokens">manage application tokens</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_manageAppTokens">Allows applications to
         create and manage their own tokens, bypassing their normal
         Z-ordering. Should never be needed for normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_injectEvents">press keys and control buttons</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_injectEvents">Allows an application to deliver
         its own input events (key presses, etc.) to other applications. Malicious
         applications can use this to take over the phone.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readInputState">record what you type and actions you take</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readInputState">Allows applications to watch the
         keys you press even when interacting with another application (such
         as entering a password). Should never be needed for normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindInputMethod">bind to an input method</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindInputMethod">Allows the holder to bind to the top-level
+        interface of an input method. Should never be needed for normal applications.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setOrientation">change screen orientation</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setOrientation">Allows an application to change
         the rotation of the screen at any time. Should never be needed for
         normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_signalPersistentProcesses">send Linux signals to applications</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_signalPersistentProcesses">Allows application to request that the
         supplied signal be sent to all persistent processes.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_persistentActivity">make application always run</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_persistentActivity">Allows an application to make
-        parts of itself persistent, so the system can't use it for other
+        parts of itself persistent, so the system can\'t use it for other
         applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_deletePackages">delete applications</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_deletePackages">Allows an application to delete
         Android packages. Malicious applications can use this to delete important applications.</string>
 
-    <string name="permlab_clearAppUserData">delete other application's data</string>
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_clearAppUserData">delete other applications\' data</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_clearAppUserData">Allows an application to clear user data.</string>
-    <string name="permlab_deleteCacheFiles">delete other application's cache</string>
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_deleteCacheFiles">delete other applications\' caches</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_deleteCacheFiles">Allows an application to delete
         cache files.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_getPackageSize">measure application storage space</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getPackageSize">Allows an application to retrieve
         its code, data, and cache sizes</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_installPackages">directly install applications</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_installPackages">Allows an application to install new or updated
         Android packages. Malicious applications can use this to add new applications with arbitrarily
         powerful permissions.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_clearAppCache">delete all application cache data</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_clearAppCache">Allows an application to free phone storage
         by deleting files in application cache directory. Access is very
         restricted usually to system process.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readLogs">read system log files</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readLogs">Allows an application to read from the
-        system's various log files.  This allows it to discover general
+        system\'s various log files.  This allows it to discover general
         information about what you are doing with the phone, but they should
         not contain any personal or private information.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_diagnostic">read/write to resources owned by diag</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_diagnostic">Allows an application to read and write to
     any resource owned by the diag group; for example, files in /dev. This could
     potentially affect system stability and security. This should be ONLY be used
     for hardware-specific diagnostics by the manufacturer or operator.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_changeComponentState">enable or disable application components</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_changeComponentState">Allows an application to change whether a
         component of another application is enabled or not. Malicious applications can use this
         to disable important phone capabilities. Care must be used with permission, as it is
-        possible to get application components into an unusable, inconsistant, or unstable state.
+        possible to get application components into an unusable, inconsistent, or unstable state.
     </string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setPreferredApplications">set preferred applications</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setPreferredApplications">Allows an application to
         modify your preferred applications. This can allow malicious applications
         to silently change the applications that are run, spoofing your
         existing applications to collect private data from you.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeSettings">modify global system settings</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeSettings">Allows an application to modify the
-        system's settings data. Malicious applications can corrupt your system's
+        system\'s settings data. Malicious applications can corrupt your system\'s
         configuration.</string>
 
+    <string name="permlab_writeSecureSettings">modify secure system settings</string>
+    <string name="permdesc_writeSecureSettings">Allows an application to modify the
+        system's secure settings data. Not for use by normal applications.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeGservices">modify the Google services map</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeGservices">Allows an application to modify the
         Google services map.  Not for use by normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_receiveBootCompleted">automatically start at boot</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_receiveBootCompleted">Allows an application to
         have itself started as soon as the system has finished booting.
         This can make it take longer to start the phone and allow the
         application to slow down the overall phone by always running.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_broadcastSticky">send sticky broadcast</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_broadcastSticky">Allows an application to send
         sticky broadcasts, which remain after the broadcast ends.
         Malicious applications can make the phone slow or unstable by causing it
         to use too much memory.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readContacts">read contact data</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readContacts">Allows an application to read all
         of the contact (address) data stored on your phone. Malicious applications
         can use this to send your data to other people.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeContacts">write contact data</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeContacts">Allows an application to modify the
         contact (address) data stored on your phone. Malicious
         applications can use this to erase or modify your contact data.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeOwnerData">write owner data</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeOwnerData">Allows an application to modify the
         phone owner data stored on your phone. Malicious
         applications can use this to erase or modify owner data.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readOwnerData">read owner data</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readOwnerData">Allows an application read the
         phone owner data stored on your phone. Malicious
         applications can use this to read phone owner data.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readCalendar">read calendar data</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readCalendar">Allows an application to read all
         of the calendar events stored on your phone. Malicious applications
         can use this to send your calendar events to other people.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeCalendar">write calendar data</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeCalendar">Allows an application to modify the
         calendar events stored on your phone. Malicious
         applications can use this to erase or modify your calendar data.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessMockLocation">mock location sources for testing</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessMockLocation">Create mock location sources for testing.
         Malicious applications can use this to override the location and/or status returned by real
         location sources such as GPS or Network providers.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessLocationExtraCommands">access extra location provider commands</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessLocationExtraCommands">Access extra location provider commands.
         Malicious applications could use this to interfere with the operation of the GPS
         or other location sources.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessFineLocation">fine (GPS) location</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessFineLocation">Access fine location sources such as the
         Global Positioning System on the phone, where available.
         Malicious applications can use this to determine where you are, and may
         consume additional battery power.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessCoarseLocation">coarse (network-based) location</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessCoarseLocation">Access coarse location sources such as the cellular
         network database to determine an approximate phone location, where available. Malicious
         applications can use this to determine approximately where you are.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessSurfaceFlinger">access SurfaceFlinger</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessSurfaceFlinger">Allows application to use
         SurfaceFlinger low-level features.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readFrameBuffer">read frame buffer</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readFrameBuffer">Allows application to use
         read the content of the frame buffer.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_modifyAudioSettings">change your audio settings</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_modifyAudioSettings">Allows application to modify
         global audio settings such as volume and routing.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_recordAudio">record audio</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_recordAudio">Allows application to access
         the audio record path.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_camera">take pictures</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_camera">Allows application to take pictures
         with the camera. This allows the application at any time to collect
         images the camera is seeing.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_brick">permanently disable phone</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_brick">Allows the application to
         disable the entire phone permanently. This is very dangerous.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_reboot">force phone reboot</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_reboot">Allows the application to
         force the phone to reboot.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_mount_unmount_filesystems">mount and unmount filesystems</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_mount_unmount_filesystems">Allows the application to mount and
         unmount filesystems for removable storage.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_vibrate">control vibrator</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_vibrate">Allows the application to control
         the vibrator.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_flashlight">control flashlight</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_flashlight">Allows the application to control
         the flashlight.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_hardware_test">test hardware</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_hardware_test">Allows the application to control
         various peripherals for the purpose of hardware testing.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_callPhone">directly call phone numbers</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_callPhone">Allows the application to call
         phone numbers without your intervention. Malicious applications may
         cause unexpected calls on your phone bill. Note that this does not
         allow the application to call emergency numbers.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_callPrivileged">directly call any phone numbers</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_callPrivileged">Allows the application to call
         any phone number, including emergency numbers, without your intervention.
         Malicious applications may place unnecessary and illegal calls to emergency
         services.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_locationUpdates">control location update notifications</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_locationUpdates">Allows enabling/disabling location
         update notifications from the radio.  Not for use by normal applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_checkinProperties">access checkin properties</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_checkinProperties">Allows read/write access to
         properties uploaded by the checkin service.  Not for use by normal
         applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_modifyPhoneState">modify phone state</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_modifyPhoneState">Allows the application to control the
         phone features of the device. An application with this permission can switch
         networks, turn the phone radio on and off and the like without ever notifying
         you.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readPhoneState">read phone state</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readPhoneState">Allows the application to access the phone
         features of the device.  An application with this permission can determine the phone
         number of this phone, whether a call is active, the number that call is connected to
         and the like.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock">prevent phone from sleeping</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_wakeLock">Allows an application to prevent
         the phone from going to sleep.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_devicePower">power phone on or off</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_devicePower">Allows the application to turn the
         phone on or off.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_factoryTest">run in factory test mode</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_factoryTest">Run as a low-level manufacturer test,
         allowing complete access to the phone hardware. Only available
         when a phone is running in manufacturer test mode.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setWallpaper">set wallpaper</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setWallpaper">Allows the application
         to set the system wallpaper.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setWallpaperHints">set wallpaper size hints</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setWallpaperHints">Allows the application
         to set the system wallpaper size hints.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_masterClear">reset system to factory defaults</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_masterClear">Allows an application to completely
         reset the system to its factory settings, erasing all data,
         configuration, and installed applications.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setTimeZone">set time zone</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setTimeZone">Allows an application to change
-        the phone's time zone.</string>
+        the phone\'s time zone.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_getAccounts">discover known accounts</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getAccounts">Allows an application to get
       the list of accounts known by the phone.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessNetworkState">view network state</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessNetworkState">Allows an application to view
       the state of all networks.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_createNetworkSockets">full Internet access</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_createNetworkSockets">Allows an application to
       create network sockets.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeApnSettings">write Access Point Name settings</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeApnSettings">Allows an application to modify the APN
         settings, such as Proxy and Port of any APN.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_changeNetworkState">change network connectivity</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_changeNetworkState">Allows an application to change
       the state network connectivity.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessWifiState">view Wi-Fi state</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessWifiState">Allows an application to view
       the information about the state of Wi-Fi.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_changeWifiState">change Wi-Fi state</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_changeWifiState">Allows an application to connect
       to and disconnect from Wi-Fi access points, and to make changes to
       configured Wi-Fi networks.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bluetoothAdmin">bluetooth administration</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetoothAdmin">Allows an application to configure
       the local Bluetooth phone, and to discover and pair with remote
       devices.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bluetooth">create Bluetooth connections</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetooth">Allows an application to view
       configuration of the local Bluetooth phone, and to make and accept
       connections with paired devices.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_disableKeyguard">disable keylock</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_disableKeyguard">Allows an application to disable
       the keylock and any associated password security. A legitimate example of
       this is the phone disabling the keylock when receiving an incoming phone call,
       then re-enabling the keylock when the call is finished.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readSyncSettings">read sync settings</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readSyncSettings">Allows an application to read the sync settings,
         such as whether sync is enabled for Contacts.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeSyncSettings">write sync settings</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeSyncSettings">Allows an application to modify the sync
         settings, such as whether sync is enabled for Contacts.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readSyncStats">read sync statistics</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readSyncStats">Allows an application to read the sync stats; e.g., the
         history of syncs that have occurred.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_subscribedFeedsRead">read subscribed feeds</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_subscribedFeedsRead">Allows an application to get details about the currently synced feeds.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_subscribedFeedsWrite">write subscribed feeds</string>
-    <string name="permdesc_subscribedFeedsWrite">Allows an application to modify 
-      your currently synced feeds. This could allow a malicious application to 
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_subscribedFeedsWrite">Allows an application to modify
+      your currently synced feeds. This could allow a malicious application to
       change your synced feeds.</string>
 
-    <!-- Phone number types from android.provider.Contacts -->
+    <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
+    <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
     <string-array name="phoneTypes">
-        <!-- The order of these is important, don't reorder without changing Contacts.java -->
         <item>Home</item>
         <item>Mobile</item>
         <item>Work</item>
@@ -698,48 +989,47 @@
         <item>Home Fax</item>
         <item>Pager</item>
         <item>Other</item>
-        <item>Custom\u2026</item>
+        <item>Custom</item>
     </string-array>
 
-    <!-- Email address types from android.provider.Contacts -->
+    <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
+    <!-- Email address types from android.provider.Contacts. This could be used when adding a new e-mail address for a contact, for example. -->
     <string-array name="emailAddressTypes">
-        <!-- The order of these is important, don't reorder without changing Contacts.java -->
         <item>Home</item>
         <item>Work</item>
         <item>Other</item>
-        <item>Custom\u2026</item>
+        <item>Custom</item>
     </string-array>
 
-    <!-- Phone number types from android.provider.Contacts -->
+    <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
+    <!-- Postal address types from android.provider.Contacts. This could be used when adding a new address for a contact, for example. -->
     <string-array name="postalAddressTypes">
-        <!-- The order of these is important, don't reorder without changing Contacts.java -->
         <item>Home</item>
         <item>Work</item>
         <item>Other</item>
-        <item>Custom\u2026</item>
+        <item>Custom</item>
     </string-array>
 
-    <!-- IM types from android.provider.Contacts -->
+    <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
+    <!-- Instant Messenger ID types from android.provider.Contacts. This could be used when adding a new IM for a contact, for example. -->
     <string-array name="imAddressTypes">
-        <!-- The order of these is important, don't reorder without changing Contacts.java -->
         <item>Home</item>
         <item>Work</item>
         <item>Other</item>
-        <item>Custom\u2026</item>
+        <item>Custom</item>
     </string-array>
 
-    <!-- Organization types from android.provider.Contacts -->
+    <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
+    <!-- Organization types from android.provider.Contacts. This could be used when adding a new organization for a contact, for example. -->
     <string-array name="organizationTypes">
-        <!-- The order of these is important, don't reorder without changing Contacts.java -->
-        <item>Home</item>
         <item>Work</item>
         <item>Other</item>
-        <item>Custom\u2026</item>
+        <item>Custom</item>
     </string-array>
 
-    <!-- IM protocols from android.provider.Contacts -->
+    <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
+    <!-- Instant Message protocols/providers from android.provider.Contacts -->
     <string-array name="imProtocols">
-        <!-- The order of these is important, don't reorder without changing Contacts.java -->
         <item>AIM</item>
         <item>Windows Live</item>
         <item>Yahoo</item>
@@ -752,56 +1042,56 @@
 
     <!-- Instructions telling the user to enter their pin to unlock the keyguard.
          Displayed in one line in a large font.  -->
-    <string name="keyguard_password_enter_pin_code">Enter PIN code:</string>
+    <string name="keyguard_password_enter_pin_code">Enter PIN code</string>
 
     <!-- Instructions telling the user that they entered the wrong pin while trying
          to unlock the keyguard.  Displayed in one line in a large font.  -->
     <string name="keyguard_password_wrong_pin_code">Incorrect PIN code!</string>
 
+    <!-- Instructions telling the user how to unlock the phone. -->
     <string name="keyguard_label_text">To unlock, press Menu then 0.</string>
 
-    <string name="keyguard_password_emergency_instructions">Press the Call button to make an emergency call.</string>
-    <string name="keyguard_password_instructions">Enter passcode or dial emergency number.</string>
-
-    <!-- Emergency call strings.  -->
-    <string name="emergency_call_dialog_text">Make an emergency call?</string>
-    <string name="emergency_call_dialog_cancel">Cancel</string>
-    <string name="emergency_call_dialog_call">Emergency call</string>
+    <!-- This can be used in any application wanting to disable the text "Emergency number" -->
     <string name="emergency_call_dialog_number_for_display">Emergency number</string>
-    <string name="emergency_call_number_uri">tel:112</string>
 
     <!--
        *** touch based lock / unlock ***
-                                          -->
-    <!-- the key used to look up the carrier name from system properties -->
-    <string name="lockscreen_carrier_key">gsm.operator.alpha</string>
+                                          --> <skip />
 
-    <!-- the default display if there is no carrier (no service) -->
+    <!-- On the keyguard screen, it shows the carrier the phone is connected to.  This is displayed if the phone is not connected to a carrier.-->
     <string name="lockscreen_carrier_default">(No service)</string>
 
-    <string name="lockscreen_screen_locked">Screen locked</string>
+    <!-- Shown in the lock screen to tell the user that the screen is locked. -->
+    <string name="lockscreen_screen_locked">Screen locked.</string>
 
     <!-- when pattern lock is enabled, tell them about the emergency dial -->
     <string name="lockscreen_instructions_when_pattern_enabled">Press Menu to unlock or place emergency call.</string>
 
-    <!-- when pattern lock is disabled, only tell them to press menu to unlock -->
+    <!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock.  This is shown in small font at the bottom. -->
     <string name="lockscreen_instructions_when_pattern_disabled">Press Menu to unlock.</string>
 
-    <string name="lockscreen_pattern_instructions">Draw pattern to unlock:</string>
+    <!-- On the unlock pattern screen, shown at the top of the unlock screen to tell the user what to do. Below this text is the place for theu ser to draw the pattern. -->
+    <string name="lockscreen_pattern_instructions">Draw pattern to unlock</string>
+    <!-- Button at the bottom of the unlock screen to make an emergency call. -->
     <string name="lockscreen_emergency_call">Emergency call</string>
+    <!-- Shown to confirm that the user entered their lock pattern correctly. -->
     <string name="lockscreen_pattern_correct">Correct!</string>
-    <string name="lockscreen_pattern_wrong">Sorry, try again:</string>
+    <!-- On the unlock pattern screen, shown when the user enters the wrong lock pattern and must try again. -->
+    <string name="lockscreen_pattern_wrong">Sorry, try again</string>
 
     <!-- When the lock screen is showing and the phone plugged in, show the current
-         charge %-->
+         charge %.  -->
     <string name="lockscreen_plugged_in">Charging (<xliff:g id="number">%d%%</xliff:g>)</string>
 
     <!-- When the lock screen is showing and the battery is low, warn user to plug
          in the phone soon. -->
     <string name="lockscreen_low_battery">Connect your charger.</string>
 
+    <!-- Shown in the lock screen when there is no SIM card. -->
     <string name="lockscreen_missing_sim_message_short">No SIM card.</string>
+    <!-- Shown in the lock screen when there is no SIM card. -->
     <string name="lockscreen_missing_sim_message">No SIM card in phone.</string>
+    <!-- Shown in the lock screen to ask the user to insert a SIM card. -->
     <string name="lockscreen_missing_sim_instructions">Please insert a SIM card.</string>
 
 
@@ -813,25 +1103,25 @@
     <!-- When the user enters a wrong sim pin too many times, it becomes
          PUK locked (Pin Unlock Kode) -->
     <string name="lockscreen_sim_puk_locked_message">SIM card is PUK-locked.</string>
+    <!-- Shown in the lock screen when the SIM has become PUK locked and the user must call customer care to unlock it. -->
     <string name="lockscreen_sim_puk_locked_instructions">Please contact Customer Care.</string>
 
+    <!-- Shown in the lock screen to tell the user that their SIM is locked and they must unlock it. -->
     <string name="lockscreen_sim_locked_message">SIM card is locked.</string>
 
-    <!-- When the user enters a sim unlock code, it takes a little while to check
+    <!-- For the unlock screen, When the user enters a sim unlock code, it takes a little while to check
          whether it is valid, and to unlock the sim if it is valid.  we display a
-         progress dialog in the meantime -->
+         progress dialog in the meantime.  this is the emssage. -->
     <string name="lockscreen_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
 
-    <string name="lockscreen_too_many_failed_attempts_dialog_title">Lock pattern warning</string>
-
-    <!-- Information message shown in dialog when user has too many failed attempts -->
+    <!-- For the unlock screen, Information message shown in dialog when user has too many failed attempts -->
     <string name="lockscreen_too_many_failed_attempts_dialog_message">
         You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
         \n\nPlease try again in <xliff:g id="number">%d</xliff:g> seconds.
     </string>
 
-    <!-- Information message shown in dialog when user is almost at the limit
-         where they will be locked out and have to use their google login -->
+    <!-- For the unlock screen, Information message shown in dialog when user is almost at the limit
+         where they will be locked out and may have to enter an alternate username/password to unlock the phone -->
     <string name="lockscreen_failed_attempts_almost_glogin">
         You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
        After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
@@ -839,28 +1129,41 @@
        Please try again in <xliff:g id="number">%d</xliff:g> seconds.
     </string>
 
-    <!-- Countdown message shown while user is waiting to try again after too many
+    <!-- On the unlock screen, countdown message shown while user is waiting to try again after too many
          failed attempts -->
     <string name="lockscreen_too_many_failed_attempts_countdown">Try again in <xliff:g id="number">%d</xliff:g> seconds.</string>
 
-    <!-- Message shown on button that appears once it's apparent the user may have forgotten
+    <!-- On the unlock screen, message shown on button that appears once it's apparent the user may have forgotten
          their lock gesture -->
     <string name="lockscreen_forgot_pattern_button_text">Forgot pattern?</string>
 
-    <!-- glogin unlock screen -->
+    <!-- Title of the unlock screen that uses your Google login and password -->
     <string name="lockscreen_glogin_too_many_attempts">Too many pattern attempts!</string>
-    <string name="lockscreen_glogin_instructions">To unlock,\nsign in with your Google account:</string>
+    <!-- In the unlock screen, message telling the user that they need to use their Google login and password to unlock the phone -->
+    <string name="lockscreen_glogin_instructions">To unlock,\nsign in with your Google account</string>
+    <!-- Hint caption for the username field when unlocking the phone using login and password -->
     <string name="lockscreen_glogin_username_hint">Username (email)</string>
+    <!-- Hint caption for the password field when unlocking the phone using login and password -->
     <string name="lockscreen_glogin_password_hint">Password</string>
+    <!-- Button to try to unlock the phone using username and password -->
     <string name="lockscreen_glogin_submit_button">Sign in</string>
+    <!-- Displayed to the user when unlocking the phone with a username and password fails. -->
     <string name="lockscreen_glogin_invalid_input">Invalid username or password.</string>
 
-    <string name="date_picker_set">Set</string>
-    <string name="date_picker_month">month</string>
-    <string name="time_picker_set">Set</string>
+    <!-- A format string for 12-hour time of day (example: "12:30 PM"). -->
+    <string name="status_bar_time_format">"<xliff:g id="hour" example="12">h</xliff:g>:<xliff:g id="minute" example="30">mm</xliff:g> <xliff:g id="ampm" example="AM">AA</xliff:g>"</string>
 
-    <string name="status_bar_date_format">"<xliff:g id="format">MMMM d, yyyy</xliff:g>"</string>
-    <string name="status_bar_time_format">"<xliff:g id="format">h:mm AA</xliff:g>"</string>
+    <!-- A format string for 12-hour time of day, with lower-case "am" or "pm" (example: "12:30pm"). -->
+    <string name="hour_minute_ampm">"<xliff:g id="hour" example="12">%-l</xliff:g>:<xliff:g id="minute" example="30">%M</xliff:g><xliff:g id="ampm" example="am">%P</xliff:g>"</string>
+
+    <!-- A format string for 12-hour time of day, with capital "AM" or "PM" (example: "12:30PM"). -->
+    <string name="hour_minute_cap_ampm">"<xliff:g id="hour" example="12">%-l</xliff:g>:<xliff:g id="minute" example="30">%M</xliff:g><xliff:g id="ampm" example="AM">%p</xliff:g>"</string>
+
+    <!-- A format string for 12-hour time of day, just the hour, not the minute, with lower-case "am" or "pm" (example: "3pm"). -->
+    <string name="hour_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="pm">%P</xliff:g>"</string>
+
+    <!-- A format string for 12-hour time of day, just the hour, not the minute, with capital "AM" or "PM" (example: "3PM"). -->
+    <string name="hour_cap_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="PM">%p</xliff:g>"</string>
 
     <!-- The text for the button in the notification window-shade that clears
          all of the currently visible notifications. -->
@@ -879,120 +1182,198 @@
          the status bar.  Recently received text messsages (SMS), emails, calendar alerts, etc. -->
     <string name="status_bar_latest_events_title">Notifications</string>
 
-    <!-- The label for column of application icons in the opened version of the status bar -->
-    <string name="status_bar_applications_title">Application</string>
-
     <!-- The big percent text in the middle of the battery icon that appears when you plug in
          the charger. -->
-    <string name="battery_status_text_percent_format"><xliff:g id="number">%d%%</xliff:g></string>
+    <string name="battery_status_text_percent_format"><xliff:g id="number" example="50">%d</xliff:g><xliff:g id="percent" example="%">%%</xliff:g></string>
 
     <!-- The big percent text in the middle of the battery icon that appears when you plug in
-         the charger. -->
+         the charger. This indicates the current status of the battery.  -->
     <string name="battery_status_charging">Charging\u2026</string>
 
-    <!-- The title of the low battery alert. -->
+    <!-- When the battery is low, this is displayed to the user in a dialog.  The title of the low battery alert. -->
     <string name="battery_low_title">Please connect charger</string>
 
-    <!-- The subtitle of the low battery alert. -->
+    <!-- When the battery is low, this is displayed to the user in a dialog. The subtitle of the low battery alert. -->
     <string name="battery_low_subtitle">The battery is getting low:</string>
 
-    <!-- A message that appears when the battery level is getting low. -->
+    <!-- A message that appears when the battery level is getting low in a dialog.  This is appened to the subtitle of the low battery alert. -->
     <string name="battery_low_percent_format">less than <xliff:g id="number">%d%%</xliff:g>
     remaining.</string>
 
 
+    <!-- Title of the alert when something went wrong in the factory test. -->
     <string name="factorytest_failed">Factory test failed</string>
+    <!-- Error message displayed when a non-system application tries to start a factory test. -->
     <string name="factorytest_not_system">The FACTORY_TEST action
         is only supported for packages installed in /system/app.</string>
+    <!-- Error message displayed when the factory test could not be started. -->
     <string name="factorytest_no_action">No package was found that provides the
         FACTORY_TEST action.</string>
+    <!-- Button to restart the device after the factory test. -->
     <string name="factorytest_reboot">Reboot</string>
 
-    <!-- WebView User Agent -->
+    <!-- Do not translate.  WebView User Agent string -->
     <string name="web_user_agent"><xliff:g id="x">Mozilla/5.0 (Linux; U; Android %s)
-        AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2</xliff:g></string>
+        AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1</xliff:g></string>
 
-    <!-- WebView save password dialog -->
+    <!-- Title of the WebView save password dialog.  If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. -->
     <string name="save_password_label">Confirm</string>
+    
+    <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Text in the save password dialog, asking if the browser should remember a password. -->
     <string name="save_password_message">Do you want the browser to remember this password?</string>
+    <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying not to remember this password. -->
     <string name="save_password_notnow">Not now</string>
+    <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying to remember this password. -->
     <string name="save_password_remember">Remember</string>
-    <!-- should be "Never for this site". But it is too long, use "Never" instead -->
+    <!-- Button in the save password dialog, saying never to remember this password. This should be short. Should be "Never for this site". But it is too long, use "Never" instead -->
     <string name="save_password_never">Never</string>
 
-    <!-- WebView permission -->
+    <!-- Displayed to the user when they do not have permission to open a particular web page. -->
     <string name="open_permission_deny">You do not have permission to open this page.</string>
-    
-    <!-- WebView copy text-->
+
+    <!-- Displayed to the user to confirm that they have copied text from a web page to the clipboard. -->
     <string name="text_copied">Text copied to clipboard.</string>
 
+    <!-- Menu item displayed at the end of a menu to allow users to see another page worth of menu items. This is shown on any app's menu as long as the app has too many items in the menu.-->
     <string name="more_item_label">More</string>
+    <!-- Prepended to the shortcut for a menu item to indicate that the user should hold the MENU button together with the shortcut to invoke the item. For example, if the shortcut to open a new tab in browser is MENU and B together, then this would be prepended to the letter "B" -->
     <string name="prepend_shortcut_label">Menu+</string>
+    <!-- Displayed in place of the regular shortcut letter when a menu item has Menu+space for the shortcut. -->
     <string name="menu_space_shortcut_label">space</string>
+    <!-- Displayed in place of the regular shortcut letter when a menu item has Menu+enter for the shortcut. -->
     <string name="menu_enter_shortcut_label">enter</string>
+    <!-- Displayed in place of the regular shortcut letter when a menu item has Menu+delete for the shortcut. -->
     <string name="menu_delete_shortcut_label">delete</string>
 
-    <!-- Strings used for search bar -->
+    <!-- Strings used for search bar --><skip />
+    
+    <!-- This is the default button label in the system-wide search UI. 
+         It is also used by the home screen's search "widget". It should be short -->
     <string name="search_go">Search</string>
 
-    <!-- Strings used to display the date -->
+    <!-- String used to display the date. This is shown instead of a date if the date is today's date. -->
     <string name="today">Today</string>
-    <string name="before">Before</string>
+    <!-- String used to display the date. This is shown instead of a date if the date is yesterday's date. -->
     <string name="yesterday">Yesterday</string>
+    <!-- String used to display the date. This is shown instead of a date if the date is tomorrow's date. -->
     <string name="tomorrow">Tomorrow</string>
-    <string name="ago">ago</string>
-    <string name="in">in</string>
-    <string name="daysDurationFuturePlural">in <xliff:g id="days">%d</xliff:g> days</string>
-    <string name="daysDurationPastPlural"><xliff:g id="days">%d</xliff:g> days ago</string>
+    <!-- String used to display the date. This is the string to say something happened 1 month ago. -->
     <string name="oneMonthDurationPast">1 month ago</string>
+    <!-- String used to display the date. This is the string to say something happened more than 1 month ago. -->
+    <string name="beforeOneMonthDurationPast">Before 1 month ago</string>
 
-    <!-- Prepositions for dates ("on May 29", "in 2008", "at 2:33am") -->
+    <!-- This is used to express that something occurred some number of seconds in the past (e.g., 5 seconds ago). -->
+    <plurals name="num_seconds_ago">
+        <item quantity="one">1 second ago</item>
+        <item quantity="other"><xliff:g id="count">%d</xliff:g> seconds ago</item>
+    </plurals>
+
+    <!-- This is used to express that something occurred some number of minutes in the past (e.g., 5 minutes ago). -->
+    <plurals name="num_minutes_ago">
+        <item quantity="one">1 minute ago</item>
+        <item quantity="other"><xliff:g id="count">%d</xliff:g> minutes ago</item>
+    </plurals>
+
+    <!-- This is used to express that something occurred some number of hours in the past (e.g., 5 hours ago). -->
+    <plurals name="num_hours_ago">
+        <item quantity="one">1 hour ago</item>
+        <item quantity="other"><xliff:g id="count">%d</xliff:g> hours ago</item>
+    </plurals>
+
+    <!-- This is used to express that something occurred some number of days in the past (e.g., 5 days ago). -->
+    <plurals name="num_days_ago">
+        <item quantity="one">yesterday</item>
+        <item quantity="other"><xliff:g id="count">%d</xliff:g> days ago</item>
+    </plurals>
+
+    <!-- This is used to express that something will occur some number of seconds in the future (e.g., in 5 seconds). -->
+    <plurals name="in_num_seconds">
+        <item quantity="one">in 1 second</item>
+        <item quantity="other">in <xliff:g id="count">%d</xliff:g> seconds</item>
+    </plurals>
+
+    <!-- This is used to express that something will occur some number of minutes in the future (e.g., in 5 minutes). -->
+    <plurals name="in_num_minutes">
+        <item quantity="one">in 1 minute</item>
+        <item quantity="other">in <xliff:g id="count">%d</xliff:g> minutes</item>
+    </plurals>
+
+    <!-- This is used to express that something will occur some number of hours in the future (e.g., in 5 hours). -->
+    <plurals name="in_num_hours">
+        <item quantity="one">in 1 hour</item>
+        <item quantity="other">in <xliff:g id="count">%d</xliff:g> hours</item>
+    </plurals>
+
+    <!-- This is used to express that something will occur some number of days in the future (e.g., in 5 days). -->
+    <plurals name="in_num_days">
+        <item quantity="one">tomorrow</item>
+        <item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
+    </plurals>
+
+    <!-- String used to display the date. Preposition for date display ("on May 29") -->
     <string name="preposition_for_date">on %s</string>
+    <!-- String used to display the date. Preposition for time display ("at 2:33am") -->
     <string name="preposition_for_time">at %s</string>
+    <!-- String used to display the date. Preposition for year display ("in 2008") -->
     <string name="preposition_for_year">in %s</string>
 
+    <!-- Appened to express the value is this unit of time: singular day -->
     <string name="day">day</string>
+    <!-- Appened to express the value is this unit of time: plural days -->
     <string name="days">days</string>
+    <!-- Appened to express the value is this unit of time: singular hour -->
     <string name="hour">hour</string>
+    <!-- Appened to express the value is this unit of time: plural hours -->
     <string name="hours">hours</string>
+    <!-- Appened to express the value is this unit of time: singular minute -->
     <string name="minute">min</string>
+    <!-- Appened to express the value is this unit of time: plural minutes -->
     <string name="minutes">mins</string>
+    <!-- Appened to express the value is this unit of time. -->
     <string name="second">sec</string>
+    <!-- Appened to express the value is this unit of time. -->
     <string name="seconds">secs</string>
+    <!-- Appened to express the value is this unit of time. -->
     <string name="week">week</string>
+    <!-- Appened to express the value is this unit of time. -->
     <string name="weeks">weeks</string>
+    <!-- Appened to express the value is this unit of time. -->
     <string name="year">year</string>
+    <!-- Appened to express the value is this unit of time. -->
     <string name="years">years</string>
 
+    <!-- Used in the list of which days of the week a calendar event recurrs on -->
     <string name="sunday">Sunday</string>
+    <!-- Used in the list of which days of the week a calendar event recurrs on -->
     <string name="monday">Monday</string>
+    <!-- Used in the list of which days of the week a calendar event recurrs on -->
     <string name="tuesday">Tuesday</string>
+    <!-- Used in the list of which days of the week a calendar event recurrs on -->
     <string name="wednesday">Wednesday</string>
+    <!-- Used in the list of which days of the week a calendar event recurrs on -->
     <string name="thursday">Thursday</string>
+    <!-- Used in the list of which days of the week a calendar event recurrs on -->
     <string name="friday">Friday</string>
+    <!-- Used in the list of which days of the week a calendar event recurrs on -->
     <string name="saturday">Saturday</string>
 
-    <!-- Date formats for single line display mode -->
-    <string name="daily_format">h:mm aa</string>
-    <string name="weekly_format">MMM d</string>
-    <string name="monthly_format">MMM d</string>
-    <string name="yearly_format">yyyy</string>
-
-    <!-- TODO
-        Maybe the "mon-fri" part should be parameterized? That is, it should be something like
-        "%1$s \u2013 %2$s" and then the code that uses this resource can substitute in the local
-        3-letter abbreviation.
-    -->
+    <!-- Calendar spinner item, to select that an event recurs every weekday. -->
     <string name="every_weekday">"Every weekday (Mon\u2013Fri)"</string>
+    <!-- Calendar spinner item, to select that an event recurs every day. -->
     <string name="daily">Daily</string>
+    <!-- Calendar spinner item, to select that an event recurs every week on a particular day of the week. -->
     <string name="weekly">"Weekly on <xliff:g id="day">%s</xliff:g>"</string>
+    <!-- Calendar spinner item, to select that an event recurs every month. -->
     <string name="monthly">Monthly</string>
+    <!-- Calendar spinner item, to select that an event recurs every year. -->
     <string name="yearly">Yearly</string>
 
 
-    <!-- Errors for android.widget.VideoView -->
+    <!-- Title for error alert when a video cannot be played.  it can be used by any app. -->
     <string name="VideoView_error_title">Cannot play video</string>
+    <!-- Text for error alert when a video cannot be played. it can be used by any app. -->
     <string name="VideoView_error_text_unknown">Sorry, this video cannot be played.</string>
+    <!-- Button to close error alert when a video cannot be played -->
     <string name="VideoView_error_button">OK</string>
 
 
@@ -1003,360 +1384,238 @@
     <string name="pm">"PM"</string>
 
 
-    <!-- Example: "12/31/2007" -->
-    <string name="numeric_date">"<xliff:g id="format">%m/%d/%Y</xliff:g>"</string>
+    <!-- Numeric form of the day. Example: "12/31/2007" -->
+    <string name="numeric_date">"<xliff:g id="month" example="12">%m</xliff:g>/<xliff:g id="day" example="31">%d</xliff:g>/<xliff:g id="year" example="2008">%Y</xliff:g>"</string>
 
-    <!-- Example: "Mon, Dec 31, 2007, 8am - Tue, Jan 1, 2008, 5pm" -->
-    <!--   1: "Mon" -->
-    <!--   2: "Dec 31, 2007" -->
-    <!--   3: "8am" -->
-    <!--   4: "Tue" -->
-    <!--   5: "Jan 1, 2008" -->
-    <!--   6: "5pm" -->
-    <!-- or: "Friday, November 30, 8am - Thursday, December 6, 5pm" -->
-    <!--   1: "Friday" -->
-    <!--   2: "November 30" -->
-    <!--   3: "8am" -->
-    <!--   4: "Thursday" -->
-    <!--   5: "December 6" -->
-    <!--   6: "5pm" -->
-    <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="format">%1$s, %2$s, %3$s \u2013 %4$s, %5$s, %6$s</xliff:g>"</string>
+    <!-- Format indicating a range of time, from a time on one day to a time on another day. 
+         Example: "Mon, Dec 31, 2007, 8am - Tue, Jan 1, 2008, 5pm" -->
+    <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="weekday1" example="Monday">%1$s</xliff:g>, <xliff:g id="date1" example="December 31, 2007">%2$s</xliff:g>, <xliff:g id="time1" example="8am">%3$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Tuesday">%4$s</xliff:g>, <xliff:g id="date2" example="January 1, 2008">%5$s</xliff:g>, <xliff:g id="time2" example="5pm">%6$s</xliff:g>"</string>
 
-    <!-- Example: "Mon, Dec 31, 2007 - Tue, Jan 1, 2008" -->
-    <!--   1: "Mon" -->
-    <!--   2: "Dec 31, 2007" -->
-    <!--   4: "Tue" -->
-    <!--   5: "Jan 1, 2008" -->
-    <!-- or: "Friday, November 30 - Thursday, December 6" -->
-    <!--   1: "Friday" -->
-    <!--   2: "November 30" -->
-    <!--   4: "Thursday" -->
-    <!--   5: "December 6" -->
-    <string name="wday1_date1_wday2_date2">"<xliff:g id="format">%1$s, %2$s \u2013 %4$s, %5$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates, from one date to another.
+         Example: "Mon, Dec 31, 2007 - Tue, Jan 1, 2008" -->
+    <string name="wday1_date1_wday2_date2">"<xliff:g id="weekday1" example="Monday">%1$s</xliff:g>, <xliff:g id="date1" example="Dec 31, 2007">%2$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Thursday">%4$s</xliff:g>, <xliff:g id="date2" example="Jan 1, 2008">%5$s</xliff:g>"</string>
 
-    <!-- Example: "Dec 31, 2007, 8am - Jan 1, 2008, 5pm" -->
-    <!--   2: "Dec 31, 2007" -->
-    <!--   3: "8am" -->
-    <!--   5: "Jan 1, 2008" -->
-    <!--   6: "5pm" -->
-    <!-- or: "November 30, 8am - December 6, 5pm" -->
-    <!--   2: "November 30" -->
-    <!--   3: "8am" -->
-    <!--   5: "December 6" -->
-    <!--   6: "5pm" -->
-    <string name="date1_time1_date2_time2">"<xliff:g id="format">%2$s, %3$s \u2013 %5$s, %6$s</xliff:g>"</string>
+    <!-- Format indicating a range of time, from a time on one day to a time on another day. 
+         Example: "Dec 31, 2007, 8am - Jan 1, 2008, 5pm" -->
+    <string name="date1_time1_date2_time2">"<xliff:g id="date1" example="Dec 31, 2007">%2$s</xliff:g>, <xliff:g id="time1" example="8am">%3$s</xliff:g> \u2013 <xliff:g id="date2" example="Jan 1, 2008">%5$s</xliff:g>, <xliff:g id="time2" example="5pm">%6$s</xliff:g>"</string>
 
-    <!-- Example: "Dec 31, 2007 - Jan 1, 2008" -->
-    <!--   2: "Dec 31, 2007" -->
-    <!--   5: "Jan 1, 2008" -->
-    <!-- or: "November 30 - December 6" -->
-    <!--   2: "November 30" -->
-    <!--   5: "December 6" -->
-    <string name="date1_date2">"<xliff:g id="format">%2$s \u2013 %5$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates, from one date to another.
+         Example: "Dec 31, 2007 - Jan 1, 2008" -->
+    <string name="date1_date2">"<xliff:g id="date1" example="Dec 31, 2007">%2$s</xliff:g> \u2013 <xliff:g id="date2" example="Jan 1, 2008">%5$s</xliff:g>"</string>
 
-    <!-- Example: "10:00 - 11:00 am" -->
-    <!--   1: "10:00" -->
-    <!--   2: "11:00 am" -->
-    <!-- or: "10:00 am - 2:00 pm" -->
-    <!--   1: "10:00 am" -->
-    <!--   2: "2:00 pm" -->
-    <!-- or: "10:00 - 14:00" -->
-    <!--   1: "10:00" -->
-    <!--   2: "14:00" -->
-    <string name="time1_time2">"<xliff:g id="format">%1$s \u2013 %2$s</xliff:g>"</string>
+    <!-- Format indicating a range of times, from one time to another.
+         Example: "10:00 - 11:00 am" -->
+    <string name="time1_time2">"<xliff:g id="time1" example="10:00">%1$s</xliff:g> \u2013 <xliff:g id="time2" example="11:00">%2$s</xliff:g>"</string>
 
-    <!-- Example: "8:00 - 11:00 am, Mon, Dec 31, 2007" -->
-    <!--   1: "8:00 - 11:00 am" -->
-    <!--   2: "Mon" -->
-    <!--   3: "Dec 31, 2007" -->
-    <string name="time_wday_date">"<xliff:g id="format">%1$s, %2$s, %3$s</xliff:g>"</string>
+    <!-- Format indicating a range of times on a particular date.
+         Example: "8:00 - 11:00 am, Mon, Dec 31, 2007" -->
+    <string name="time_wday_date">"<xliff:g id="time_range" example="8:00 - 11:00 am">%1$s</xliff:g>, <xliff:g id="weekday" example="Mon">%2$s</xliff:g>, <xliff:g id="date" example="Dec 31, 2007">%3$s</xliff:g>"</string>
 
-    <!-- Example: "Mon, Dec 31, 2007" -->
-    <!--   2: "Mon" -->
-    <!--   3: "Dec 31, 2007" -->
-    <string name="wday_date">"<xliff:g id="format">%2$s, %3$s</xliff:g>"</string>
+    <!-- Format indicating a weekday and date.
+         Example: "Mon, Dec 31, 2007" -->
+    <string name="wday_date">"<xliff:g id="weekday" example="Monday">%2$s</xliff:g>, <xliff:g id="date" example="Dec 31, 2007">%3$s</xliff:g>"</string>
 
-    <!-- Example: "8:00 - 11:00 am, Dec 31, 2007" -->
-    <!--   1: "8:00 - 11:00 am" -->
-    <!--   3: "Dec 31, 2007" -->
-    <string name="time_date">"<xliff:g id="format">%1$s, %3$s</xliff:g>"</string>
+    <!-- Format indicating a range of times on a particular date.
+         Example: "8:00 - 11:00 am, Dec 31, 2007" -->
+    <string name="time_date">"<xliff:g id="time_range" example="8:00 - 11:00 am">%1$s</xliff:g>, <xliff:g id="date" example="Dec 31, 2007">%3$s</xliff:g>"</string>
 
-    <!-- Example: "8:00 - 11:00 am, Mon" -->
-    <!--   1: "8:00 - 11:00 am" -->
-    <!--   2: "Mon" -->
-    <string name="time_wday">"<xliff:g id="format">%1$s, %2$s</xliff:g>"</string>
+    <!-- Format indicating a range of times on a particular day of the week.
+         Example: "8:00 - 11:00 am, Mon" -->
+    <string name="time_wday">"<xliff:g id="time_range" example="8:00 - 11:00 am">%1$s</xliff:g>, <xliff:g id="weekday" example="Mon">%2$s</xliff:g>"</string>
 
+    <!-- Date format string used in contexts where the user has said they
+         want the month first, as used in the USA, with the month fully
+         spelled out.  You can remove the comma or add a period,
+         or make other punctuation changes appropriate for your locale.
+         If you need to add letters, put apostrophes around them to keep
+         them from being interpreted as format characters. -->
+    <string name="full_date_month_first"><xliff:g id="month" example="December">MMMM</xliff:g> <xliff:g id="day" example="31">dd</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
+
+    <!-- Date format string used in contexts where the user has said they
+         want the day of the month first, as used in Europe, with the month
+         fully spelled out.  You can remove the comma or add a period,
+         or make other punctuation changes appropriate for your locale.
+         If you need to add letters, put apostrophes around them to keep
+         them from being interpreted as format characters. -->
+    <string name="full_date_day_first"><xliff:g id="day" example="31">dd</xliff:g> <xliff:g id="month" example="December">MMMM</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
+
+    <!-- Date format string used in contexts where the user has said they
+         want the month first, as used in the USA, with the month
+         abbreviated.  You can remove the comma or add a period,
+         or make other punctuation changes appropriate for your locale.
+         If you need to add letters, put apostrophes around them to keep
+         them from being interpreted as format characters. -->
+    <string name="medium_date_month_first"><xliff:g id="month" example="Dec.">MMM</xliff:g> <xliff:g id="day" example="31">dd</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
+
+    <!-- Date format string used in contexts where the user has said they
+         want the day of the month first, as used in Europe, with the month
+         abbreviated.  You can remove the comma or add a period,
+         or make other punctuation changes appropriate for your locale.
+         If you need to add letters, put apostrophes around them to keep
+         them from being interpreted as format characters. -->
+    <string name="medium_date_day_first"><xliff:g id="day" example="31">dd</xliff:g> <xliff:g id="month" example="December">MMM</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
+
+    <!-- Time format string used in the status bar when the user has said they
+         want a 12-hour clock with AM and PM.
+         You can remove the colon
+         or make other punctuation changes appropriate for your locale.
+         If you need to add letters, put apostrophes around them to keep
+         them from being interpreted as format characters. -->
+    <string name="twelve_hour_time_format"><xliff:g id="hour" example="11">h</xliff:g>:<xliff:g id="minute" example="59">mm</xliff:g> <xliff:g id="ampm" example="AM">a</xliff:g></string>
+
+    <!-- Time format string used in the status bar when the user has said they
+         want a 24-hour clock.
+         You can remove the colon
+         or make other punctuation changes appropriate for your locale.
+         If you need to add letters, put apostrophes around them to keep
+         them from being interpreted as format characters. -->
+    <string name="twenty_four_hour_time_format"><xliff:g id="hour" example="23">H</xliff:g>:<xliff:g id="minute" example="59">mm</xliff:g></string>
+
+    <!-- Quoted name for 12pm, lowercase -->
     <string name="noon">"noon"</string>
+    <!-- Quoted name for 12pm, uppercase first letter -->
     <string name="Noon">"Noon"</string>
+    <!-- Quoted name for 12am, lowercase -->
     <string name="midnight">"midnight"</string>
+    <!-- Quoted name for 12am, uppercase first letter -->
     <string name="Midnight">"Midnight"</string>
 
-    <!-- Example: "October 9" -->
-    <string name="month_day">"<xliff:g id="format">%B %-d</xliff:g>"</string>
+    <!-- Date format for month and day of month.
+         Example: "October 9". -->
+    <string name="month_day">"<xliff:g id="month" example="October">%B</xliff:g> <xliff:g id="day" example="9">%-d</xliff:g>"</string>
 
-    <!-- Example: "October" -->
-    <string name="month">"<xliff:g id="format">%B</xliff:g>"</string>
+    <!-- Date format for month alone.
+         Example: "October" -->
+    <string name="month">"<xliff:g id="month" example="October">%B</xliff:g>"</string>
 
-    <!-- Example: "October 9, 2007" -->
-    <string name="month_day_year">"<xliff:g id="format">%B %-d, %Y</xliff:g>"</string>
+    <!-- Date format for month, day, and year.
+         Example: "October 9, 2007" -->
+    <string name="month_day_year">"<xliff:g id="month" example="October">%B</xliff:g> <xliff:g id="day" example="9">%-d</xliff:g>, <xliff:g id="year" example="2007">%Y</xliff:g>"</string>
 
-    <!-- Example: "October 2007" -->
-    <string name="month_year">"<xliff:g id="format">%B %Y</xliff:g>"</string>
+    <!-- Date format for month and year.
+         Example: "October 2007" -->
+    <string name="month_year">"<xliff:g id="month" example="October">%B</xliff:g> <xliff:g id="year" example="2007">%Y</xliff:g>"</string>
 
-    <!-- Example: "Oct 31 - Nov 3" -->
-    <!--   2: "Oct" -->
-    <!--   3: "31" -->
-    <!--   7: "Nov" -->
-    <!--   8: "3" -->
-    <string name="same_year_md1_md2">"<xliff:g id="format">%2$s %3$s \u2013 %7$s %8$s</xliff:g>"</string>
+    <!-- A format string for 24-hour time of day (example "23:59"). -->
+    <string name="time_of_day">"<xliff:g id="hour" example="23">%H</xliff:g>:<xliff:g id="minute" example="59">%M</xliff:g>:<xliff:g id="second" example="59">%S</xliff:g>"</string>
 
-    <!-- Example: "Wed, Oct 31 - Sat, Nov 3" -->
-    <!--   1: "Wed" -->
-    <!--   2: "Oct" -->
-    <!--   3: "31" -->
-    <!--   6: "Sat" -->
-    <!--   7: "Nov" -->
-    <!--   8: "3" -->
-    <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %2$s %3$s \u2013 %6$s, %7$s %8$s</xliff:g>"</string>
+    <!-- Format string for date and 24-hour time of day.
+         Example: 23:59:15 Jan 31 2008 -->
+    <string name="date_and_time">"<xliff:g id="hour" example="23">%H</xliff:g>:<xliff:g id="minute" example="59">%M</xliff:g>:<xliff:g id="second" example="59">%S</xliff:g> <xliff:g id="month" example="Jan">%B</xliff:g> <xliff:g id="day" example="31">%-d</xliff:g>, <xliff:g id="year" example="2008">%Y</xliff:g>"</string>
 
-    <!-- Example: "Oct 31 - Nov 3, 2007" -->
-    <!--   2: "Oct" -->
-    <!--   3: "31" -->
-    <!--   7: "Nov" -->
-    <!--   8: "3" -->
-    <!--   9: "2007" -->
-    <string name="same_year_mdy1_mdy2">"<xliff:g id="format">%2$s %3$s \u2013 %7$s %8$s, %9$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates in the same year.
+         Example: "Oct 31 - Nov 3" -->
+    <string name="same_year_md1_md2">"<xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>"</string>
 
-    <!-- Example: "Wed, Oct 31 - Sat, Nov 3, 2007" -->
-    <!--   1: "Wed" -->
-    <!--   2: "Oct" -->
-    <!--   3: "31" -->
-    <!--   6: "Sat" -->
-    <!--   7: "Nov" -->
-    <!--   8: "3" -->
-    <!--   9: "2007" -->
-    <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %2$s %3$s \u2013 %6$s, %7$s %8$s, %9$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates in the same year, with weekday.
+         Example: "Wed, Oct 31 - Sat, Nov 3" -->
+    <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>"</string>
 
-    <!-- Example: "Oct 31, 8:00am - Nov 3, 5:00pm" -->
-    <!--   2: "Oct" -->
-    <!--   3: "31" -->
-    <!--   5: "8:00am" -->
-    <!--   7: "Nov" -->
-    <!--   8: "3" -->
-    <!--  10: "5:00pm" -->
-    <string name="same_year_md1_time1_md2_time2">"<xliff:g id="format">%2$s %3$s, %5$s \u2013 %7$s %8$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates in the same year.
+         Example: "Oct 31 - Nov 3, 2007" -->
+    <string name="same_year_mdy1_mdy2">"<xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="year" example="2007">%9$s</xliff:g>"</string>
 
-    <!-- Example: "Wed, Oct 31, 8:00am - Sat, Nov 3, 5:00pm" -->
-    <!--   1: "Wed" -->
-    <!--   2: "Oct" -->
-    <!--   3: "31" -->
-    <!--   5: "8:00am" -->
-    <!--   6: "Sat" -->
-    <!--   7: "Nov" -->
-    <!--   8: "3" -->
-    <!--  10: "5:00pm" -->
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %5$s \u2013 %6$s, %7$s %8$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates in the same year, with weekdays.
+         Example: "Wed, Oct 31 - Sat, Nov 3, 2007" -->
+    <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="year" example="2007">%9$s</xliff:g>"</string>
 
-    <!-- Example: "Oct 31, 2007, 8:00am - Nov 3, 2007, 5:00pm" -->
-    <!--   2: "Oct" -->
-    <!--   3: "31" -->
-    <!--   4: "2007" -->
-    <!--   5: "8:00am" -->
-    <!--   7: "Nov" -->
-    <!--   8: "3" -->
-    <!--   9: "2007" -->
-    <!--  10: "5:00pm" -->
-    <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="format">%2$s %3$s, %4$s, %5$s \u2013 %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of time from a time on one day to a time on another.
+         Example: "Oct 31, 8:00am - Nov 3, 5:00pm" -->
+    <string name="same_year_md1_time1_md2_time2">"<xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
 
-    <!-- Example: "Wed, Oct 31, 2007, 8:00am - Sat, Nov 3, 2007, 5:00pm" -->
-    <!--   1: "Wed" -->
-    <!--   2: "Oct" -->
-    <!--   3: "31" -->
-    <!--   4: "2007" -->
-    <!--   5: "8:00am" -->
-    <!--   6: "Sat" -->
-    <!--   7: "Nov" -->
-    <!--   8: "3" -->
-    <!--   9: "2007" -->
-    <!--  10: "5:00pm" -->
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %4$s, %5$s \u2013 %6$s, %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of time from a time on one day to a time on another, with weekdays.
+         Example: "Wed, Oct 31, 8:00am - Sat, Nov 3, 5:00pm" -->
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id ="time2" example="5:00pm">%10$s</xliff:g>"</string>
+
+    <!-- Format indicating a range of time from a time on one day to a time on another, with years and weekdays.
+         Example: "Oct 31, 2007, 8:00am - Nov 3, 2007, 5:00pm" -->
+    <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="year1" example="2007">%4$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="year2" example="2007">%9$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
+
+    <!-- Format indicating a range of time from a time on one day to a time on another.
+     Example: "Wed, Oct 31, 2007, 8:00am - Sat, Nov 3, 2007, 5:00pm" -->
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="year1" example="2007">%4$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="year2" example="2007">%9$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
 
 
-    <!-- Example: "10/31 - 11/3" -->
-    <!--   2: "10" -->
-    <!--   3: "31" -->
-    <!--   7: "11" -->
-    <!--   8: "3" -->
-    <string name="numeric_md1_md2">"<xliff:g id="format">%2$s/%3$s \u2013 %7$s/%8$s</xliff:g>"</string>
+    <!-- Format indicating a range of (numeric) dates.
+          Example: "10/31 - 11/3" -->
+    <string name="numeric_md1_md2">"<xliff:g id="month1" example="10">%2$s</xliff:g>/<xliff:g id="day1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="month2" example="11">%7$s</xliff:g>/<xliff:g id="day2" example="30">%8$s</xliff:g>"</string>
 
-    <!-- Example: "Wed, 10/31 - Sat, 11/3" -->
-    <!--   1: "Wed" -->
-    <!--   2: "10" -->
-    <!--   3: "31" -->
-    <!--   6: "Sat" -->
-    <!--   7: "11" -->
-    <!--   8: "3" -->
-    <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %2$s/%3$s \u2013 %6$s, %7$s/%8$s</xliff:g>"</string>
+    <!-- Format indicating a range of (numeric) dates.
+          Example: "Wed, 10/31 - Sat, 11/3" -->
+    <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="10">%2$s</xliff:g>/<xliff:g id="day1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="11">%7$s</xliff:g>/<xliff:g id="day2" example="30">%8$s</xliff:g>"</string>
 
-    <!-- Example: "10/31/2007 - 11/3/2007" -->
-    <!--   2: "10" -->
-    <!--   3: "31" -->
-    <!--   4: "2007" -->
-    <!--   7: "11" -->
-    <!--   8: "3" -->
-    <!--   9: "2007" -->
-    <string name="numeric_mdy1_mdy2">"<xliff:g id="format">%2$s/%3$s/%4$s \u2013 %7$s/%8$s/%9$s</xliff:g>"</string>
+    <!-- Format indicating a range of (numeric) dates.
+          Example: "10/31/2007 - 11/3/2007" -->
+    <string name="numeric_mdy1_mdy2">"<xliff:g id="month1" example="10">%2$s</xliff:g>/<xliff:g id="day1" example="31">%3$s</xliff:g>/<xliff:g id="year1" example="2007">%4$s</xliff:g> \u2013 <xliff:g id="month2" example="11">%7$s</xliff:g>/<xliff:g id="day2" example="30">%8$s</xliff:g>/<xliff:g id="year2" example="2007">%9$s</xliff:g>"</string>
 
-    <!-- Example: "Wed, 10/31/2007 - Sat, 11/3/2007" -->
-    <!--   1: "Wed" -->
-    <!--   2: "10" -->
-    <!--   3: "31" -->
-    <!--   4: "2007" -->
-    <!--   6: "Sat" -->
-    <!--   7: "11" -->
-    <!--   8: "3" -->
-    <!--   9: "2007" -->
-    <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %2$s/%3$s/%4$s \u2013 %6$s, %7$s/%8$s/%9$s</xliff:g>"</string>
+    <!-- Format indicating a range of (numeric) dates.
+          Example: "Wed, 10/31/2007 - Sat, 11/3/2007" -->
+    <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="10">%2$s</xliff:g>/<xliff:g id="day1" example="31">%3$s</xliff:g>/<xliff:g id="year1" example="2007">%4$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="11">%7$s</xliff:g>/<xliff:g id="day2" example="30">%8$s</xliff:g>/<xliff:g id="year2" example="2007">%9$s</xliff:g>"</string>
 
-    <!-- Example: "10/31, 8:00am - 11/3, 5:00pm" -->
-    <!--   2: "10" -->
-    <!--   3: "31" -->
-    <!--   5: "8:00am" -->
-    <!--   7: "11" -->
-    <!--   8: "3" -->
-    <!--  10: "5:00pm" -->
-    <string name="numeric_md1_time1_md2_time2">"<xliff:g id="format">%2$s/%3$s, %5$s \u2013 %7$s/%8$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of (numeric) dates and times.
+          Example: "10/31, 8:00am - 11/3, 5:00pm" -->
+    <string name="numeric_md1_time1_md2_time2">"<xliff:g id="month1" example="10">%2$s</xliff:g>/<xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="month2" example="11">%7$s</xliff:g>/<xliff:g id="day2" example="30">%8$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
 
-    <!-- Example: "Wed, 10/31, 8:00am - Sat, 11/3, 5:00pm" -->
-    <!--   1: "Wed" -->
-    <!--   2: "10" -->
-    <!--   3: "31" -->
-    <!--   5: "8:00am" -->
-    <!--   6: "Sat" -->
-    <!--   7: "11" -->
-    <!--   8: "3" -->
-    <!--  10: "5:00pm" -->
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %2$s/%3$s, %5$s \u2013 %6$s, %7$s/%8$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of (numeric) dates and times.
+          Example: "Wed, 10/31, 8:00am - Sat, 11/3, 5:00pm" -->
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="10">%2$s</xliff:g>/<xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="11">%7$s</xliff:g>/<xliff:g id="day2" example="30">%8$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
 
-    <!-- Example: "10/31/2007, 8:00am - 11/3/2007, 5:00pm" -->
-    <!--   2: "10" -->
-    <!--   3: "31" -->
-    <!--   4: "2007" -->
-    <!--   5: "8:00am" -->
-    <!--   7: "11" -->
-    <!--   8: "3" -->
-    <!--   9: "2007" -->
-    <!--  10: "5:00pm" -->
-    <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="format">%2$s/%3$s/%4$s, %5$s \u2013 %7$s/%8$s/%9$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of (numeric) dates and times.
+          Example: "10/31/2007, 8:00am - 11/3/2007, 5:00pm"  -->
+    <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="month1" example="10">%2$s</xliff:g>/<xliff:g id="day1" example="31">%3$s</xliff:g>/<xliff:g id="year1" example="2007">%4$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="month2" example="11">%7$s</xliff:g>/<xliff:g id="day2" example="30">%8$s</xliff:g>/<xliff:g id="year2" example="2007">%9$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
 
-    <!-- Example: "Wed, 10/31/2007, 8:00am - Sat, 11/3/2007, 5:00pm" -->
-    <!--   1: "Wed" -->
-    <!--   2: "10" -->
-    <!--   3: "31" -->
-    <!--   4: "2007" -->
-    <!--   5: "8:00am" -->
-    <!--   6: "Sat" -->
-    <!--   7: "11" -->
-    <!--   8: "3" -->
-    <!--   9: "2007" -->
-    <!--  10: "5:00pm" -->
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %2$s/%3$s/%4$s, %5$s \u2013 %6$s, %7$s/%8$s/%9$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of (numeric) dates and times.
+          Example: "Wed, 10/31/2007, 8:00am - Sat, 11/3/2007, 5:00pm" -->
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="10">%2$s</xliff:g>/<xliff:g id="day1" example="31">%3$s</xliff:g>/<xliff:g id="year1" example="2007">%4$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="11">%7$s</xliff:g>/<xliff:g id="day2" example="30">%8$s</xliff:g>/<xliff:g id="year2" example="2007">%9$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
 
 
-    <!-- Example: "Oct 9 - 10" -->
-    <!--   2: "Oct" -->
-    <!--   3: "9" -->
-    <!--   8: "10" -->
-    <string name="same_month_md1_md2">"<xliff:g id="format">%2$s %3$s \u2013 %8$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates.
+          Example: "Oct 9 - 10" -->
+    <string name="same_month_md1_md2">"<xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="day2" example="3">%8$s</xliff:g>"</string>
 
-    <!-- Example: "Tue, Oct 9 - Wed, Oct 10" -->
-    <!--   1: "Tue" -->
-    <!--   2: "Oct" -->
-    <!--   3: "9" -->
-    <!--   6: "Wed" -->
-    <!--   7: "Oct" -->
-    <!--   8: "10" -->
-    <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="format">%1$s, %2$s %3$s \u2013 %6$s, %7$s %8$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates.
+          Example: "Tue, Oct 9 - Wed, Oct 10"  -->
+    <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>"</string>
 
-    <!-- Example: "Oct 9 - 10, 2007" -->
-    <!--   2: "Oct" -->
-    <!--   3: "9" -->
-    <!--   8: "10" -->
-    <!--   9: "2007" -->
-    <string name="same_month_mdy1_mdy2">"<xliff:g id="format">%2$s %3$s \u2013 %8$s, %9$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates.
+          Example: "Oct 9 - 10, 2007" -->
+    <string name="same_month_mdy1_mdy2">"<xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="year2" example="2007">%9$s</xliff:g>"</string>
 
-    <!-- Example: "Tue, Oct 9, 2007 - Wed, Oct 10, 2007" -->
-    <!--   1: "Tue" -->
-    <!--   2: "Oct" -->
-    <!--   3: "9" -->
-    <!--   4: "2007" -->
-    <!--   6: "Wed" -->
-    <!--   7: "Oct" -->
-    <!--   8: "10" -->
-    <!--   9: "2007" -->
-    <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="format">%1$s, %2$s %3$s, %4$s \u2013 %6$s, %7$s %8$s, %9$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates.
+          Example: "Tue, Oct 9, 2007 - Wed, Oct 10, 2007"  -->
+    <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="year1" example="2007">%4$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="year2" example="2007">%9$s</xliff:g>"</string>
 
-    <!-- Example: "Oct 9, 8:00am - Oct 10, 5:00pm" -->
-    <!--   2: "Oct" -->
-    <!--   3: "9" -->
-    <!--   5: "8:00am" -->
-    <!--   7: "Oct" -->
-    <!--   8: "10" -->
-    <!--  10: "5:00pm" -->
-    <string name="same_month_md1_time1_md2_time2">"<xliff:g id="format">%2$s %3$s, %5$s \u2013 %7$s %8$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates and times.
+          Example: "Oct 9, 8:00am - Oct 10, 5:00pm"  -->
+    <string name="same_month_md1_time1_md2_time2">"<xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
 
-    <!-- Example: "Tue, Oct 9, 8:00am - Wed, Oct 10, 5:00pm" -->
-    <!--   1: "Tue" -->
-    <!--   2: "Oct" -->
-    <!--   3: "9" -->
-    <!--   5: "8:00am" -->
-    <!--   6: "Wed" -->
-    <!--   7: "Oct" -->
-    <!--   8: "10" -->
-    <!--  10: "5:00pm" -->
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %5$s \u2013 %6$s, %7$s %8$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates and times.
+          Example: "Tue, Oct 9, 8:00am - Wed, Oct 10, 5:00pm"  -->
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
 
-    <!-- Example: "Oct 9, 2007, 8:00am - Oct 10, 2007, 5:00pm" -->
-    <!--   2: "Oct" -->
-    <!--   3: "9" -->
-    <!--   4: "2007" -->
-    <!--   5: "8:00am" -->
-    <!--   7: "Oct" -->
-    <!--   8: "10" -->
-    <!--   9: "2007" -->
-    <!--  10: "5:00pm" -->
-    <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="format">%2$s %3$s, %4$s, %5$s \u2013 %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates and times.
+          Example: "Oct 9, 2007, 8:00am - Oct 10, 2007, 5:00pm"  -->
+    <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="year1" example="2007">%4$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="year2" example="2007">%9$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
 
-    <!-- Example: "Tue, Oct 9, 2007, 8:00am - Wed, Oct 10, 2007, 5:00pm" -->
-    <!--   1: "Tue" -->
-    <!--   2: "Oct" -->
-    <!--   3: "9" -->
-    <!--   4: "2007" -->
-    <!--   5: "8:00am" -->
-    <!--   6: "Wed" -->
-    <!--   7: "Oct" -->
-    <!--   8: "10" -->
-    <!--   9: "2007" -->
-    <!--  10: "5:00pm" -->
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="format">%1$s, %2$s %3$s, %4$s, %5$s \u2013 %6$s, %7$s %8$s, %9$s, %10$s</xliff:g>"</string>
+    <!-- Format indicating a range of dates and times.
+          Example: "Tue, Oct 9, 2007, 8:00am - Wed, Oct 10, 2007, 5:00pm" -->
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="weekday1" example="Wed">%1$s</xliff:g>, <xliff:g id="month1" example="Oct">%2$s</xliff:g> <xliff:g id="day1" example="31">%3$s</xliff:g>, <xliff:g id="year1" example="2007">%4$s</xliff:g>, <xliff:g id="time1" example="8:00am">%5$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Sat">%6$s</xliff:g>, <xliff:g id="month2" example="Nov">%7$s</xliff:g> <xliff:g id="day2" example="3">%8$s</xliff:g>, <xliff:g id="year2" example="2007">%9$s</xliff:g>, <xliff:g id="time2" example="5:00pm">%10$s</xliff:g>"</string>
 
-    <!-- Example: "Oct 9, 2007" -->
-    <string name="abbrev_month_day_year">"<xliff:g id="format">%b %-d, %Y</xliff:g>"</string>
+    <!-- Format string for abbreviated month, day, and year.
+         Example: "Oct 9, 2007" -->
+    <string name="abbrev_month_day_year">"<xliff:g id="month" example="Oct">%b</xliff:g> <xliff:g id="day" example="9">%-d</xliff:g>, <xliff:g id="year" example="2007">%Y</xliff:g>"</string>
 
-    <!-- Example: "Oct 2007" -->
-    <string name="abbrev_month_year">"<xliff:g id="format">%b %Y</xliff:g>"</string>
+    <!-- Format string for abbreviated month and year.
+         Example: "Oct 2007" -->
+    <string name="abbrev_month_year">"<xliff:g id="month" example="Oct">%b</xliff:g> <xliff:g id="year" example="2007">%Y</xliff:g>"</string>
 
-    <!-- Example: "Oct 9" -->
-    <string name="abbrev_month_day">"<xliff:g id="format">%b %-d</xliff:g>"</string>
+    <!-- Format string for abbreviated month and day.
+         Example: "Oct 9" -->
+    <string name="abbrev_month_day">"<xliff:g id="month" example="Oct">%b</xliff:g> <xliff:g id="day" example="31">%-d</xliff:g>"</string>
 
-    <!-- Example: "Oct" -->
-    <string name="abbrev_month">"<xliff:g id="format">%b</xliff:g>"</string>
-
-    <!-- Example: the dash in Tue, Oct 9, 2007, 8:00am - Wed, Oct 10, 2007, 5:00pm -->
-    <string name="date_range_separator">" \u2013 "</string>
-
-    <!-- Example: "10/09/2007" -->
-    <string name="numeric_date_notation">"<xliff:g id="format">%m/%d/%y</xliff:g>"</string>
+    <!-- Format string for abbreviated month alone.
+         Example: "Oct" -->
+    <string name="abbrev_month">"<xliff:g id="month" example="Oct">%b</xliff:g>"</string>
 
     <!-- The full spelled out version of the day of the week. -->
     <string name="day_of_week_long_sunday">Sunday</string>
@@ -1649,138 +1908,203 @@
          In US English: "D" stands for December. -->
     <string name="month_shortest_december">D</string>
 
-    <!-- Format string for times like "01:23" -->
-    <string name="elapsed_time_short_format_mm_ss"><xliff:g id="format">%1$02d:%2$02d</xliff:g></string>
+    <!-- Format string for durations like "01:23" (1 minute, 23 seconds) -->
+    <string name="elapsed_time_short_format_mm_ss"><xliff:g id="minutes" example="1">%1$02d</xliff:g>:<xliff:g id="seconds" example="23">%2$02d</xliff:g></string>
 
-    <!-- Format string for times like "1:43:33" -->
-    <string name="elapsed_time_short_format_h_mm_ss"><xliff:g id="format">%1$d:%2$02d:%3$02d</xliff:g></string>
+    <!-- Format string for times like "1:43:33" (1 hour, 43 minutes, 33 seconds) -->
+    <string name="elapsed_time_short_format_h_mm_ss"><xliff:g id="hours" example="1">%1$d</xliff:g>:<xliff:g id="minutes" example="43">%2$02d</xliff:g>:<xliff:g id="seconds" example="33">%3$02d</xliff:g></string>
 
-    <!-- EditText context menu -->
+    <!-- Item on EditText context menu. This action is used to select all text in the edit field. -->
     <string name="selectAll">Select all</string>
 
-    <!-- EditText context menu -->
+    <!-- Item on EditText context menu.  This action is used to cut selected the text into the clipboard.  -->
     <string name="cut">Cut</string>
 
-    <!-- EditText context menu -->
+    <!-- Item on EditText context menu. This action is used to cut all the text into the clipboard. -->
     <string name="cutAll">Cut all</string>
 
-    <!-- EditText context menu -->
+    <!-- Item on EditText context menu. This action is used to cut selected the text into the clipboard. -->
     <string name="copy">Copy</string>
 
-    <!-- EditText context menu -->
+    <!-- Item on EditText context menu. This action is used to copy all the text into the clipboard. -->
     <string name="copyAll">Copy all</string>
 
-    <!-- EditText context menu -->
+    <!-- Item on EditText context menu. This action is used t o paste from the clipboard into the eidt field -->
     <string name="paste">Paste</string>
 
-    <!-- EditText context menu -->
+    <!-- Item on EditText context menu. This action is used to copy a URL from the edit field into the clipboard. -->
     <string name="copyUrl">Copy URL</string>
 
-    <!-- Low internal storage error dialog properties title of extended view -->
+    <!-- EditText context menu -->
+    <string name="inputMethod">Input Method</string>
+
+    <!-- Title for EditText context menu -->
+    <string name="editTextMenuTitle">Edit text</string>
+
+    <!-- If the device is getting low on internal storage, a notification is shown to the user.  This is the title of that notification. -->
     <string name="low_internal_storage_view_title">Low on space</string>
-    <!-- Low internal storage error dialog properties text displayed in extended view -->
+    <!-- If the device is getting low on internal storage, a notification is shown to the user.  This is the message of that notification. -->
     <string name="low_internal_storage_view_text">Phone storage space is getting low.</string>
 
     <!-- Preference framework strings. -->
     <string name="ok">OK</string>
+    <!-- Preference framework strings. -->
     <string name="cancel">Cancel</string>
+    <!-- Preference framework strings. -->
     <string name="yes">OK</string>
+    <!-- Preference framework strings. -->
     <string name="no">Cancel</string>
 
-    <!-- IndicatorButton -->
+    <!-- Default text for a button that can be toggled on and off. -->
     <string name="capital_on">ON</string>
+    <!-- Default text for a button that can be toggled on and off. -->
     <string name="capital_off">OFF</string>
 
     <!-- Title of intent resolver dialog when selecting an application to run. -->
     <string name="whichApplication">Complete action using</string>
-    <!-- Option to always use the selected Intent resolution in the future. -->
+    <!-- Option to always use the selected application resolution in the future. See the "Complete action using" dialog title-->
     <string name="alwaysUse">Use by default for this action.</string>
-    <!-- Text displayed when the user selects the check box for setting default application-->
+    <!-- Text displayed when the user selects the check box for setting default application.  See the "Use by default for this action" check box. -->
     <string name="clearDefaultHintMsg">Clear default in Home Settings &gt; Applications &gt; Manage applications.</string>
-    <!-- Default title for the activity chooser, when one is not given. -->
+    <!-- Default title for the activity chooser, when one is not given. Android allows multiple activities to perform an action.  for example, there may be many ringtone pickers installed.  A dialog is shown to the user allowing him to pick which activity should be used.  This is the title. -->
     <string name="chooseActivity">Select an action</string>
     <!-- Text to display when there are no activities found to display in the
-         activity chooser. -->
+         activity chooser. See the "Select an action" title. -->
     <string name="noApplications">No applications can perform this action.</string>
+    <!-- Title of the alert when an application has crashed. -->
     <string name="aerr_title">Sorry!</string>
+    <!-- Text of the alert that is displayed when an application is not responding. -->
     <string name="aerr_application">The application <xliff:g id="application">%1$s</xliff:g>
         (process <xliff:g id="process">%2$s</xliff:g>) has stopped unexpectedly. Please try again.</string>
+    <!-- Text of the alert that is displayed when an application has crashed. -->
     <string name="aerr_process">The process <xliff:g id="process">%1$s</xliff:g> has
         stopped unexpectedly. Please try again.</string>
+    <!-- Title of the alert when an application is not responding. -->
     <string name="anr_title">Sorry!</string>
+    <!-- Text of the alert that is displayed when an application is not responding. -->
     <string name="anr_activity_application">Activity <xliff:g id="activity">%1$s</xliff:g> (in application <xliff:g id="application">%2$s</xliff:g>) is not responding.</string>
+    <!-- Text of the alert that is displayed when an application is not responding. -->
     <string name="anr_activity_process">Activity <xliff:g id="activity">%1$s</xliff:g> (in process <xliff:g id="process">%2$s</xliff:g>) is not responding.</string>
+    <!-- Text of the alert that is displayed when an application is not responding. -->
     <string name="anr_application_process">Application <xliff:g id="application">%1$s</xliff:g> (in process <xliff:g id="process">%2$s</xliff:g>) is not responding.</string>
+    <!-- Text of the alert that is displayed when an application is not responding. -->
     <string name="anr_process">Process <xliff:g id="process">%1$s</xliff:g> is not responding.</string>
+    <!-- Button allowing the user to close an application that is not responding. This will kill the application. -->
     <string name="force_close">Force close</string>
+    <!-- Button allowing the user to choose to wait for an application that is not responding to become responsive again. -->
     <string name="wait">Wait</string>
+    <!-- Button allowing a developer to connect a debugger to an application that is not responding. -->
     <string name="debug">Debug</string>
 
     <!-- Displayed in the title of the chooser for things to do with text that
-         is to be sent to another application. -->
+         is to be sent to another application. For example, I can send text through SMS or IM.  A dialog with those choices would be shown, and this would be the title. -->
     <string name="sendText">Select an action for text</string>
 
-    <!-- Volume strings -->
+    <!-- Title of the dialog where the user is adjusting the phone ringer volume -->
     <string name="volume_ringtone">Ringer volume</string>
-    <string name="volume_music">Music/video volume</string>
+    <!-- Title of the dialog where the user is adjusting the music volume -->
+    <string name="volume_music">Media volume</string>
+    <!-- Hint shown in the volume toast to inform the user that the media audio is playing through Bluetooth. -->
+    <string name="volume_music_hint_playing_through_bluetooth">Playing through Bluetooth</string>
+    <!-- Title of the dialog where the user is adjusting the phone call volume -->
     <string name="volume_call">In-call volume</string>
+    <!-- Hint shown in the volume toast to inform the user that the in-call audio is playing through Bluetooth. -->
+    <string name="volume_call_hint_playing_through_bluetooth">Playing through Bluetooth</string>
+    <!-- Title of the dialog where the user is adjusting the audio volume for alarms -->
     <string name="volume_alarm">Alarm volume</string>
+    <!-- Title of the dialog where the user is adjusting the audio volume for notifications -->
+    <string name="volume_notification">Notification volume</string>
+    <!-- Title of the dialog where the user is adjusting the general audio volume -->
     <string name="volume_unknown">Volume</string>
 
-    <!-- Ringtone picker strings -->
+    <!-- Ringtone picker strings --> <skip />
+    <!-- Choice in the ringtone picker.  If chosen, the default ringtone will be used. -->
     <string name="ringtone_default">Default ringtone</string>
+    <!-- Choice in the ringtone picker.  If chosen, the default ringtone will be used. This fills in the actual ringtone's title into the message. -->
     <string name="ringtone_default_with_actual">Default ringtone (<xliff:g id="actual_ringtone">%1$s</xliff:g>)</string>
+    <!-- Choice in the ringtone picker.  If chosen, there will be silence instead of a ringtone played. -->
     <string name="ringtone_silent">Silent</string>
-    <string name="ringtone_picker_title">Select a ringtone</string>
+    <!-- The title of the ringtone picker dialog. -->
+    <string name="ringtone_picker_title">Ringtones</string>
+    <!-- If there is ever a ringtone set for some setting, but that ringtone can no longer be resolved, t his is shown instead.  For example, if the ringtone was on a SD card and it had been removed, this woudl be shown for ringtones on that SD card. -->
     <string name="ringtone_unknown">Unknown ringtone</string>
 
-    <!-- Wi-Fi strings -->
+    <!-- A notification is shown when there are open wireless networks nearby.  This is the notification's title. -->
     <plurals name="wifi_available">
         <item quantity="one">Wi-Fi network available</item>
         <item quantity="other">Wi-Fi networks available</item>
     </plurals>
+    <!-- A notification is shown when there are open wireless networks nearby.  This is the notification's message. -->
     <plurals name="wifi_available_detailed">
         <item quantity="one">Open Wi-Fi network available</item>
         <item quantity="other">Open Wi-Fi networks available</item>
     </plurals>
 
-    <!-- Character picker strings -->
-    <string name="select_character">Select character to insert</string>
+    <!-- Name of the dialog that lets the user choose an accented character to insert -->
+    <string name="select_character">Insert character</string>
 
-    <!-- SMS per-application rate control Dialog -->
+    <!-- SMS per-application rate control Dialog --> <skip />
+    <!-- See SMS_DIALOG.  This is shown if the current application's name cannot be figuerd out. -->
     <string name="sms_control_default_app_name">Unknown application</string>
+    <!-- SMS_DIALOG: An SMS dialog is shown if an application tries to send too many SMSes.  This is the title of that dialog. -->
     <string name="sms_control_title">Sending SMS messages</string>
+    <!-- See SMS_DIALOG.  This is the message shown in that dialog. -->
     <string name="sms_control_message">A large number of SMS messages are being sent. Select \"OK\" to continue, or \"Cancel\" to stop sending.</string>
+    <!-- See SMS_DIALOG.  This is a button choice to allow sending the SMSes. -->
     <string name="sms_control_yes">OK</string>
+    <!-- See SMS_DIALOG.  This is a button choice to disallow sending the SMSes.. -->
     <string name="sms_control_no">Cancel</string>
 
-    <!-- Date/Time Picker strings -->
+    <!-- Name of the button in the date/time picker to accept the date/time change -->
     <string name="date_time_set">Set</string>
 
-    <!-- SensorService strings -->
-    <string name="compass_accuracy_banner">Compass requires calibration</string>
-    <string name="compass_accuracy_notificaction_title">Calibrate compass</string>
-    <string name="compass_accuracy_notificaction_body">Shake phone gently to calibrate.</string>
     <!-- Security Permissions strings-->
+    <!-- The default permission group for any permissions that have not explicitly set a group. -->
     <string name="default_permission_group">Default</string>
+    <!-- Do not translate. -->
     <string name="permissions_format"><xliff:g id="perm_line1">%1$s</xliff:g>, <xliff:g id="perm_line2">%2$s</xliff:g></string>
+    <!-- Shown for an application when it doesn't require any permission grants. -->
     <string name="no_permissions">No permissions required</string>
+    <!-- When installing an application, the less-dangerous permissions are hidden.  If the user showed those, this is the text to hide them again.  -->
     <string name="perms_hide"><b>Hide</b></string>
+    <!-- When installing an application, the less-dangerous permissions are hidden.  This is the text to show those. -->
     <string name="perms_show_all"><b>Show all</b></string>
 
+    <!-- Shown when there is content loading from the internet into a dialog. -->
     <string name="googlewebcontenthelper_loading">Loading\u2026</string>
 
     <!-- USB storage dialog strings -->
     <!-- This is the label for the activity, and should never be visible to the user. -->
-    <string name="usb_storage_activity_label">USB storage dialog</string>
+    <!-- See USB_STORAGE.  USB_STORAGE_DIALOG:  After the user selects the notification, a dialog is shown asking if he wants to mount.  This is the title. -->
     <string name="usb_storage_title">USB connected</string>
+    <!-- See USB_STORAGE.    This is the message. -->
     <string name="usb_storage_message">You have connected your phone to your computer via USB. Select \"Mount\" if you want to copy files between your computer and your phone\'s SD card.</string>
+    <!-- See USB_STORAGE.    This is the button text to mount the phone on the computer. -->
     <string name="usb_storage_button_mount">Mount</string>
+    <!-- See USB_STORAGE.   This is the button text to ignore the plugging in of the phone.. -->
     <string name="usb_storage_button_unmount">Don\'t mount</string>
+    <!-- See USB_STORAGE_DIALOG.  IF there was an error mounting, this is hte text. --> 
     <string name="usb_storage_error_message">There is a problem using your SD card for USB storage.</string>
+    <!-- USB_STORAGE: When the user connects the phone to a computer via USB, we show a notification asking if he wnats to share files across.  This is the title -->
     <string name="usb_storage_notification_title">USB connected</string>
+    <!-- See USB_STORAGE. This is the message. -->
     <string name="usb_storage_notification_message">Select to copy files to/from your computer.</string>
 
+    <!-- Used to replace %s in urls retreived from the signin server with locales.  For Some        -->
+    <!-- devices we don't support all the locales we ship to and need to replace the '%s' with a    -->
+    <!-- locale string based on mcc values.  By default (0-length string) we don't replace the %s   -->
+    <!-- at all and later replace it with a locale string based on the users chosen locale          -->
+    <!-- DO NOT TRANSLATE -->
+    <string name="locale_replacement">""</string>
+
+    <!-- Title of the pop-up dialog in which the user switches input method components. -->
+    <string name="select_input_method">Select Input Method</string>
+    
+    <string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
+    <string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
+    
+    <string name="candidates_style"><font fgcolor="#ff000000"
+            bgcolor="#ff8080ff"><u>candidates</u>u></font></string>
 </resources>
 
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index dede6c1..19eb2c6 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -70,6 +70,8 @@
 
     <!-- Standard animations for a non-full-screen window or activity. -->
     <style name="Animation.Dialog">
+        <item name="windowEnterAnimation">@anim/dialog_enter</item>
+        <item name="windowExitAnimation">@anim/dialog_exit</item>
     </style>
 
     <!-- Standard animations for a translucent window or activity. -->
@@ -111,6 +113,20 @@
         <item name="windowExitAnimation">@anim/shrink_fade_out_from_bottom</item>
     </style>
 
+    <!-- Window animations that are applied to input method overlay windows.
+         {@hide Pending API council approval} -->
+    <style name="Animation.InputMethod">
+        <item name="windowEnterAnimation">@anim/input_method_enter</item>
+        <item name="windowExitAnimation">@anim/input_method_exit</item>
+    </style>
+
+    <!-- Window animations that are applied to the search bar overlay window.
+         {@hide Pending API council approval} -->
+    <style name="Animation.SearchBar">
+        <item name="windowEnterAnimation">@anim/search_bar_enter</item>
+        <item name="windowExitAnimation">@anim/search_bar_exit</item>
+    </style>
+
     <!-- Status Bar Styles -->
 
     <style name="TextAppearance.StatusBarTitle">
@@ -171,6 +187,11 @@
         <item name="android:button">@android:drawable/btn_star</item>
     </style>
 
+    <style name="Widget.CompoundButton.StarButtonless">
+        <item name="android:background">@android:drawable/btn_star_label_background</item>
+        <item name="android:button">@android:drawable/btn_star_buttonless</item>
+    </style>
+
     <style name="Widget.Button.Toggle">
         <item name="android:background">@android:drawable/btn_toggle_bg</item>
         <item name="android:textOn">@android:string/capital_on</item>
@@ -309,6 +330,8 @@
         <item name="android:completionThreshold">2</item>
         <item name="android:dropDownSelector">@android:drawable/list_selector_background</item>
         <item name="android:popupBackground">@android:drawable/spinner_dropdown_background</item>
+        <item name="android:dropDownVerticalOffset">-8px</item>
+        <item name="android:dropDownHorizontalOffset">2px</item>
     </style>
 
     <style name="Widget.Spinner">
@@ -378,6 +401,8 @@
 
     <style name="Widget.TabWidget">
         <item name="android:textAppearance">@style/TextAppearance.Widget.TabWidget</item>
+        <item name="ellipsize">marquee</item>
+        <item name="singleLine">true</item>
     </style>
 
     <style name="Widget.Gallery">
@@ -586,5 +611,17 @@
         <item name="android:showSilent">true</item>
         <item name="android:showDefault">true</item>
     </style>
-    
+
+    <style name="Widget.KeyboardView" parent="android:Widget">
+        <item name="android:background">@android:drawable/keyboard_background</item>
+        <item name="android:keyBackground">@android:drawable/btn_keyboard_key</item>
+        <item name="android:keyTextSize">22sp</item>
+        <item name="android:keyTextColor">#FFFFFFFF</item>
+        <item name="android:keyPreviewLayout">@android:layout/keyboard_key_preview</item>
+        <item name="android:keyPreviewOffset">-12dp</item>
+        <item name="android:keyPreviewHeight">80dp</item>
+        <item name="android:labelTextSize">14sp</item>
+        <item name="android:popupLayout">@android:layout/keyboard_popup_keyboard</item>
+        <item name="android:verticalCorrection">-10dip</item>
+    </style>
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 810b5f3..72367f8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -60,6 +60,8 @@
         
         <item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item>
         
+        <item name="candidatesTextStyleSpans">@android:string/candidates_style</item>
+        
         <item name="textCheckMark">@android:drawable/indicator_check_mark_dark</item>
         <item name="textCheckMarkInverse">@android:drawable/indicator_check_mark_light</item>
 
@@ -104,6 +106,7 @@
         <item name="windowTitleSize">25dip</item>
         <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>
+        <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
 
         <!-- Dialog attributes -->
         <item name="alertDialogStyle">@android:style/AlertDialog</item>
@@ -149,6 +152,7 @@
         <item name="scrollViewStyle">@android:style/Widget.ScrollView</item>
         <item name="spinnerStyle">@android:style/Widget.Spinner</item>
         <item name="starStyle">@android:style/Widget.CompoundButton.Star</item>
+        <item name="starStyleButtonless">@android:style/Widget.CompoundButton.StarButtonless</item>
         <item name="tabWidgetStyle">@android:style/Widget.TabWidget</item>
         <item name="textViewStyle">@android:style/Widget.TextView</item>
         <item name="webViewStyle">@android:style/Widget.WebView</item>
@@ -156,6 +160,7 @@
         <item name="spinnerDropDownItemStyle">@android:style/Widget.DropDownItem.Spinner</item>
         <item name="spinnerItemStyle">@android:style/Widget.TextView.SpinnerItem</item>
         <item name="dropDownHintAppearance">@android:style/TextAppearance.Widget.DropDownHint</item>
+        <item name="keyboardViewStyle">@android:style/Widget.KeyboardView</item>
         
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
@@ -172,13 +177,13 @@
     
     <!-- Variant of the default (dark) theme with no title bar -->
     <style name="Theme.NoTitleBar">
-        <item name="windowNoTitle">true</item>
+        <item name="android:windowNoTitle">true</item>
     </style>
     
     <!-- Variant of the default (dark) theme that has no title bar and
          fills the entire screen -->
     <style name="Theme.NoTitleBar.Fullscreen">
-        <item name="windowFullscreen">true</item>
+        <item name="android:windowFullscreen">true</item>
     </style>
     
     <!-- Theme for a light background with dark text on top.  Set your activity
@@ -216,13 +221,13 @@
     
     <!-- Variant of the light theme with no title bar -->
     <style name="Theme.Light.NoTitleBar">
-        <item name="windowNoTitle">true</item>
+        <item name="android:windowNoTitle">true</item>
     </style>
 
     <!-- Variant of the light theme that has no title bar and
          fills the entire screen -->
     <style name="Theme.Light.NoTitleBar.Fullscreen">
-        <item name="windowFullscreen">true</item>
+        <item name="android:windowFullscreen">true</item>
     </style>
     
     <!-- Special variation on the default theme that ensures the background is
@@ -230,41 +235,50 @@
          media players.   If you want the normal (dark background) theme
          do <em>not<em> use this, use {@link #Theme}. -->
     <style name="Theme.Black">
-        <item name="windowBackground">@android:color/black</item>
-        <item name="colorBackground">@android:color/black</item>
+        <item name="android:windowBackground">@android:color/black</item>
+        <item name="android:colorBackground">@android:color/black</item>
     </style>
     
     <!-- Variant of the black theme with no title bar -->
     <style name="Theme.Black.NoTitleBar">
-        <item name="windowNoTitle">true</item>
+        <item name="android:windowNoTitle">true</item>
     </style>
 
     <!-- Variant of the black theme that has no title bar and
          fills the entire screen -->
     <style name="Theme.Black.NoTitleBar.Fullscreen">
-        <item name="windowFullscreen">true</item>
+        <item name="android:windowFullscreen">true</item>
     </style>
     
     <!-- Default theme for translucent activities, that is windows that allow you
          to see through them to the windows behind.  This sets up the translucent
          flag and appropriate animations for your windows.  -->
     <style name="Theme.Translucent">
-        <item name="windowBackground">@android:color/transparent</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
     </style>
 
     <!-- Variant of the translucent theme with no title bar -->
     <style name="Theme.Translucent.NoTitleBar">
-        <item name="windowNoTitle">true</item>
+        <item name="android:windowNoTitle">true</item>
     </style>
 
     <!-- Variant of the translucent theme that has no title bar and
          fills the entire screen -->
     <style name="Theme.Translucent.NoTitleBar.Fullscreen">
-        <item name="windowFullscreen">true</item>
+        <item name="android:windowFullscreen">true</item>
     </style>
     
+    <!-- Default theme for activities that don't actually display a UI; that
+         is, they finish themselves before being resumed.  -->
+    <style name="Theme.NoDisplay">
+        <item name="android:windowBackground">@null</item>
+        <item name="android:windowIsTranslucent">false</item>
+        <item name="android:windowAnimationStyle">@null</item>
+        <item name="android:windowDisablePreview">@null</item>
+    </style>
+
     <!-- Default theme for dialog windows and activities, which is used by the
          {@link android.app.Dialog} class.  This changes the window to be
          floating (not fill the entire screen), and puts a frame around its
@@ -277,6 +291,7 @@
         <item name="android:windowIsFloating">true</item>
         <item name="android:windowContentOverlay">@android:drawable/panel_separator</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+        <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
     </style>
 
     <!-- Default theme for alert dialog windows, which is used by the
@@ -289,6 +304,29 @@
         <item name="windowContentOverlay">@drawable/panel_separator</item>
     </style>
     
+    <!-- Default theme for dialog windows and activities, which is used by the
+         {@link android.app.Dialog} class.  This changes the window to be
+         floating (not fill the entire screen), and puts a frame around its
+         contents.  You can set this theme on an activity if you would like to
+         make an activity that looks like a Dialog. -->
+    <style name="Theme.InputMethod" parent="Theme.Light.NoTitleBar">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowFrame">@null</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:backgroundDimEnabled">false</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.InputMethod</item>
+    </style>
+
+    <!-- Theme for the search input bar. -->
+    <style name="Theme.SearchBar" parent="Theme.Translucent.NoTitleBar">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowFrame">@null</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.SearchBar</item>
+    </style>
+
     <!-- Menu Themes -->
     <eat-comment />
 
@@ -301,6 +339,7 @@
         <item name="android:verticalDivider">@android:drawable/divider_vertical_bright</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.OptionsPanel</item>
         <item name="android:moreIcon">@android:drawable/ic_menu_more</item>
+        <item name="android:background">@null</item>
     </style>
 
     <style name="Theme.ExpandedMenu">
@@ -308,6 +347,7 @@
         <item name="android:itemTextAppearance">?android:attr/textAppearanceLargeInverse</item>
         <item name="android:listViewStyle">@android:style/Widget.ListView.Menu</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.OptionsPanel</item>
+        <item name="android:background">@null</item>
     </style>
 
     <!-- @hide -->
diff --git a/core/res/res/xml/autotext.xml b/core/res/res/xml/autotext.xml
index 64d3dc8..4c02a00 100644
--- a/core/res/res/xml/autotext.xml
+++ b/core/res/res/xml/autotext.xml
@@ -74,6 +74,7 @@
     <word src="fidn">find</word>
     <word src="fora">for a</word>
     <word src="freind">friend</word>
+    <word src="friday">Friday</word>
     <word src="hadbeen">had been</word>
     <word src="hadnt">hadn't</word>
     <word src="haev">have</word>
@@ -110,6 +111,7 @@
     <word src="maam">ma'am</word>
     <word src="mkae">make</word>
     <word src="mkaes">makes</word>
+    <word src="monday">Monday</word>
     <word src="mustnt">mustn't</word>
     <word src="neednt">needn't</word>
     <word src="oclock">o'clock</word>
@@ -127,6 +129,7 @@
     <word src="recieving">receiving</word>
     <word src="saidthat">said that</word>
     <word src="saidthe">said the</word>
+    <word src="saturday">Saturday</word>
     <word src="seh">she</word>
     <word src="shant">shan't</word>
     <word src="she'">she'll</word>
@@ -135,6 +138,7 @@
     <word src="shouldent">shouldn't</word>
     <word src="shouldnt">shouldn't</word>
     <word src="shouldve">should've</word>
+    <word src="sunday">Sunday</word>
     <word src="tahn">than</word>
     <word src="taht">that</word>
     <word src="teh">the</word>
@@ -149,11 +153,14 @@
     <word src="theyve">they've</word>
     <word src="thier">their</word>
     <word src="thsi">this</word>
+    <word src="thursday">Thursday</word>
     <word src="tothe">to the</word>
+    <word src="tuesday">Tuesday</word>
     <word src="UnitedStates">United States</word>
     <word src="unitedstates">United States</word>
     <word src="visavis">vis-a-vis</word>
     <word src="wasnt">wasn't</word>
+    <word src="wednesday">Wednesday</word>
     <word src="wierd">weird</word>
     <word src="wel">we'll</word>
     <word src="wer">we're</word>
diff --git a/core/res/res/xml/time_zones_by_country.xml b/core/res/res/xml/time_zones_by_country.xml
index 5755124..2d3e3fe 100644
--- a/core/res/res/xml/time_zones_by_country.xml
+++ b/core/res/res/xml/time_zones_by_country.xml
@@ -17,25 +17,78 @@
 */
 -->
 <timezones>
+    <!-- ANDORRA, 1:00 -->
+
     <timezone code="ad">Europe/Andorra</timezone>
+
+    <!-- UNITED ARAB EMIRATES, 4:00 -->
+
     <timezone code="ae">Asia/Dubai</timezone>
+
+    <!-- AFGHANISTAN, 4:30 -->
+
     <timezone code="af">Asia/Kabul</timezone>
+
+    <!-- ANTIGUA AND BARBUDA, -4:00 -->
+
     <timezone code="ag">America/Antigua</timezone>
+
+    <!-- ANGUILLA, -4:00 -->
+
     <timezone code="ai">America/Anguilla</timezone>
+
+    <!-- ALBANIA, 1:00 -->
+
     <timezone code="al">Europe/Tirane</timezone>
+
+    <!-- ARMENIA, 4:00 -->
+
     <timezone code="am">Asia/Yerevan</timezone>
+
+    <!-- NETHERLANDS ANTILLES, -4:00 -->
+
     <timezone code="an">America/Curacao</timezone>
+
+    <!-- ANGOLA, 1:00 -->
+
     <timezone code="ao">Africa/Luanda</timezone>
+
+    <!-- ANTARCTICA, 12:00 -->
+
     <timezone code="aq">Antarctica/McMurdo</timezone>
     <timezone code="aq">Antarctica/South_Pole</timezone>
-    <timezone code="aq">Antarctica/Rothera</timezone>
-    <timezone code="aq">Antarctica/Palmer</timezone>
-    <timezone code="aq">Antarctica/Mawson</timezone>
-    <timezone code="aq">Antarctica/Davis</timezone>
-    <timezone code="aq">Antarctica/Casey</timezone>
-    <timezone code="aq">Antarctica/Vostok</timezone>
+
+    <!-- ANTARCTICA, 10:00 -->
+
     <timezone code="aq">Antarctica/DumontDUrville</timezone>
+
+    <!-- ANTARCTICA, 8:00 -->
+
+    <timezone code="aq">Antarctica/Casey</timezone>
+
+    <!-- ANTARCTICA, 7:00 -->
+
+    <timezone code="aq">Antarctica/Davis</timezone>
+
+    <!-- ANTARCTICA, 6:00 -->
+
+    <timezone code="aq">Antarctica/Mawson</timezone>
+    <timezone code="aq">Antarctica/Vostok</timezone>
+
+    <!-- ANTARCTICA, 3:00 -->
+
     <timezone code="aq">Antarctica/Syowa</timezone>
+
+    <!-- ANTARCTICA, -3:00 -->
+
+    <timezone code="aq">Antarctica/Rothera</timezone>
+
+    <!-- ANTARCTICA, -4:00 -->
+
+    <timezone code="aq">Antarctica/Palmer</timezone>
+
+    <!-- ARGENTINA, -3:00 -->
+
     <timezone code="ar">America/Argentina/Buenos_Aires</timezone>
     <timezone code="ar">America/Argentina/Cordoba</timezone>
     <timezone code="ar">America/Argentina/Jujuy</timezone>
@@ -46,371 +99,1207 @@
     <timezone code="ar">America/Argentina/Mendoza</timezone>
     <timezone code="ar">America/Argentina/Rio_Gallegos</timezone>
     <timezone code="ar">America/Argentina/Ushuaia</timezone>
+
+    <!-- AMERICAN SAMOA, -11:00 -->
+
     <timezone code="as">Pacific/Pago_Pago</timezone>
+
+    <!-- AUSTRIA, 1:00 -->
+
     <timezone code="at">Europe/Vienna</timezone>
-    <timezone code="au">Australia/Lord_Howe</timezone>
+
+    <!-- AUSTRALIA, 10:00 -->
+
+    <timezone code="au">Australia/Sydney</timezone>
+    <timezone code="au">Australia/Melbourne</timezone>
+    <timezone code="au">Australia/Brisbane</timezone>
     <timezone code="au">Australia/Hobart</timezone>
     <timezone code="au">Australia/Currie</timezone>
-    <timezone code="au">Australia/Melbourne</timezone>
-    <timezone code="au">Australia/Sydney</timezone>
-    <timezone code="au">Australia/Broken_Hill</timezone>
-    <timezone code="au">Australia/Brisbane</timezone>
     <timezone code="au">Australia/Lindeman</timezone>
+
+    <!-- AUSTRALIA, 10:30 -->
+
+    <timezone code="au">Australia/Lord_Howe</timezone>
+
+    <!-- AUSTRALIA, 9:30 -->
+
     <timezone code="au">Australia/Adelaide</timezone>
+    <timezone code="au">Australia/Broken_Hill</timezone>
     <timezone code="au">Australia/Darwin</timezone>
+
+    <!-- AUSTRALIA, 8:00 -->
+
     <timezone code="au">Australia/Perth</timezone>
+
+    <!-- AUSTRALIA, 8:45 -->
+
     <timezone code="au">Australia/Eucla</timezone>
+
+    <!-- ARUBA, -4:00 -->
+
     <timezone code="aw">America/Aruba</timezone>
+
+    <!-- ALAND ISLANDS, 2:00 -->
+
     <timezone code="ax">Europe/Mariehamn</timezone>
+
+    <!-- AZERBAIJAN, 4:00 -->
+
     <timezone code="az">Asia/Baku</timezone>
+
+    <!-- BOSNIA AND HERZEGOVINA, 1:00 -->
+
     <timezone code="ba">Europe/Sarajevo</timezone>
+
+    <!-- BARBADOS, -4:00 -->
+
     <timezone code="bb">America/Barbados</timezone>
+
+    <!-- BANGLADESH, 6:00 -->
+
     <timezone code="bd">Asia/Dhaka</timezone>
+
+    <!-- BELGIUM, 1:00 -->
+
     <timezone code="be">Europe/Brussels</timezone>
+
+    <!-- BURKINA FASO, 0:00 -->
+
     <timezone code="bf">Africa/Ouagadougou</timezone>
+
+    <!-- BULGARIA, 2:00 -->
+
     <timezone code="bg">Europe/Sofia</timezone>
+
+    <!-- BAHRAIN, 3:00 -->
+
     <timezone code="bh">Asia/Bahrain</timezone>
+
+    <!-- BURUNDI, 2:00 -->
+
     <timezone code="bi">Africa/Bujumbura</timezone>
+
+    <!-- BENIN, 1:00 -->
+
     <timezone code="bj">Africa/Porto-Novo</timezone>
+
+    <!-- BERMUDA, -4:00 -->
+
     <timezone code="bm">Atlantic/Bermuda</timezone>
+
+    <!-- BRUNEI DARUSSALAM, 8:00 -->
+
     <timezone code="bn">Asia/Brunei</timezone>
+
+    <!-- BOLIVIA, -4:00 -->
+
     <timezone code="bo">America/La_Paz</timezone>
+
+    <!-- BRAZIL, -2:00 -->
+
     <timezone code="br">America/Noronha</timezone>
+
+    <!-- BRAZIL, -3:00 -->
+
+    <timezone code="br">America/Sao_Paulo</timezone>
     <timezone code="br">America/Belem</timezone>
     <timezone code="br">America/Fortaleza</timezone>
     <timezone code="br">America/Recife</timezone>
     <timezone code="br">America/Araguaina</timezone>
     <timezone code="br">America/Maceio</timezone>
     <timezone code="br">America/Bahia</timezone>
-    <timezone code="br">America/Sao_Paulo</timezone>
+
+    <!-- BRAZIL, -4:00 -->
+
+    <timezone code="br">America/Manaus</timezone>
     <timezone code="br">America/Campo_Grande</timezone>
     <timezone code="br">America/Cuiaba</timezone>
     <timezone code="br">America/Porto_Velho</timezone>
     <timezone code="br">America/Boa_Vista</timezone>
-    <timezone code="br">America/Manaus</timezone>
     <timezone code="br">America/Eirunepe</timezone>
     <timezone code="br">America/Rio_Branco</timezone>
+
+    <!-- BAHAMAS, -5:00 -->
+
     <timezone code="bs">America/Nassau</timezone>
+
+    <!-- BHUTAN, 6:00 -->
+
     <timezone code="bt">Asia/Thimphu</timezone>
+
+    <!-- BOTSWANA, 2:00 -->
+
     <timezone code="bw">Africa/Gaborone</timezone>
+
+    <!-- BELARUS, 2:00 -->
+
     <timezone code="by">Europe/Minsk</timezone>
+
+    <!-- BELIZE, -6:00 -->
+
     <timezone code="bz">America/Belize</timezone>
+
+    <!-- CANADA, -3:30 -->
+
     <timezone code="ca">America/St_Johns</timezone>
+
+    <!-- CANADA, -4:00 -->
+
     <timezone code="ca">America/Halifax</timezone>
     <timezone code="ca">America/Glace_Bay</timezone>
     <timezone code="ca">America/Moncton</timezone>
     <timezone code="ca">America/Goose_Bay</timezone>
     <timezone code="ca">America/Blanc-Sablon</timezone>
-    <timezone code="ca">America/Montreal</timezone>
+
+    <!-- CANADA, -5:00 -->
+
     <timezone code="ca">America/Toronto</timezone>
+    <timezone code="ca">America/Montreal</timezone>
     <timezone code="ca">America/Nipigon</timezone>
     <timezone code="ca">America/Thunder_Bay</timezone>
     <timezone code="ca">America/Iqaluit</timezone>
     <timezone code="ca">America/Pangnirtung</timezone>
     <timezone code="ca">America/Resolute</timezone>
     <timezone code="ca">America/Atikokan</timezone>
-    <timezone code="ca">America/Rankin_Inlet</timezone>
+
+    <!-- CANADA, -6:00 -->
+
     <timezone code="ca">America/Winnipeg</timezone>
-    <timezone code="ca">America/Rainy_River</timezone>
-    <timezone code="ca">America/Cambridge_Bay</timezone>
     <timezone code="ca">America/Regina</timezone>
+    <timezone code="ca">America/Rankin_Inlet</timezone>
+    <timezone code="ca">America/Rainy_River</timezone>
     <timezone code="ca">America/Swift_Current</timezone>
+
+    <!-- CANADA, -7:00 -->
+
     <timezone code="ca">America/Edmonton</timezone>
+    <timezone code="ca">America/Cambridge_Bay</timezone>
     <timezone code="ca">America/Yellowknife</timezone>
     <timezone code="ca">America/Inuvik</timezone>
     <timezone code="ca">America/Dawson_Creek</timezone>
+
+    <!-- CANADA, -8:00 -->
+
     <timezone code="ca">America/Vancouver</timezone>
     <timezone code="ca">America/Whitehorse</timezone>
     <timezone code="ca">America/Dawson</timezone>
+
+    <!-- COCOS (KEELING) ISLANDS, 6:30 -->
+
     <timezone code="cc">Indian/Cocos</timezone>
-    <timezone code="cd">Africa/Kinshasa</timezone>
+
+    <!-- CONGO, THE DEMOCRATIC REPUBLIC OF THE, 2:00 -->
+
     <timezone code="cd">Africa/Lubumbashi</timezone>
+
+    <!-- CONGO, THE DEMOCRATIC REPUBLIC OF THE, 1:00 -->
+
+    <timezone code="cd">Africa/Kinshasa</timezone>
+
+    <!-- CENTRAL AFRICAN REPUBLIC, 1:00 -->
+
     <timezone code="cf">Africa/Bangui</timezone>
+
+    <!-- CONGO, 1:00 -->
+
     <timezone code="cg">Africa/Brazzaville</timezone>
+
+    <!-- SWITZERLAND, 1:00 -->
+
     <timezone code="ch">Europe/Zurich</timezone>
+
+    <!-- COTE D'IVOIRE, 0:00 -->
+
     <timezone code="ci">Africa/Abidjan</timezone>
+
+    <!-- COOK ISLANDS, -10:00 -->
+
     <timezone code="ck">Pacific/Rarotonga</timezone>
+
+    <!-- CHILE, -4:00 -->
+
     <timezone code="cl">America/Santiago</timezone>
+
+    <!-- CHILE, -6:00 -->
+
     <timezone code="cl">Pacific/Easter</timezone>
+
+    <!-- CAMEROON, 1:00 -->
+
     <timezone code="cm">Africa/Douala</timezone>
+
+    <!-- CHINA, 8:00 -->
+
     <timezone code="cn">Asia/Shanghai</timezone>
     <timezone code="cn">Asia/Harbin</timezone>
     <timezone code="cn">Asia/Chongqing</timezone>
     <timezone code="cn">Asia/Urumqi</timezone>
     <timezone code="cn">Asia/Kashgar</timezone>
+
+    <!-- COLOMBIA, -5:00 -->
+
     <timezone code="co">America/Bogota</timezone>
+
+    <!-- COSTA RICA, -6:00 -->
+
     <timezone code="cr">America/Costa_Rica</timezone>
+
+    <!-- CUBA, -5:00 -->
+
     <timezone code="cu">America/Havana</timezone>
+
+    <!-- CAPE VERDE, -1:00 -->
+
     <timezone code="cv">Atlantic/Cape_Verde</timezone>
+
+    <!-- CHRISTMAS ISLAND, 7:00 -->
+
     <timezone code="cx">Indian/Christmas</timezone>
+
+    <!-- CYPRUS, 2:00 -->
+
     <timezone code="cy">Asia/Nicosia</timezone>
+
+    <!-- CZECH REPUBLIC, 1:00 -->
+
     <timezone code="cz">Europe/Prague</timezone>
+
+    <!-- GERMANY, 1:00 -->
+
     <timezone code="de">Europe/Berlin</timezone>
+
+    <!-- DJIBOUTI, 3:00 -->
+
     <timezone code="dj">Africa/Djibouti</timezone>
+
+    <!-- DENMARK, 1:00 -->
+
     <timezone code="dk">Europe/Copenhagen</timezone>
+
+    <!-- DOMINICA, -4:00 -->
+
     <timezone code="dm">America/Dominica</timezone>
+
+    <!-- DOMINICAN REPUBLIC, -4:00 -->
+
     <timezone code="do">America/Santo_Domingo</timezone>
+
+    <!-- ALGERIA, 1:00 -->
+
     <timezone code="dz">Africa/Algiers</timezone>
+
+    <!-- ECUADOR, -5:00 -->
+
     <timezone code="ec">America/Guayaquil</timezone>
+
+    <!-- ECUADOR, -6:00 -->
+
     <timezone code="ec">Pacific/Galapagos</timezone>
+
+    <!-- ESTONIA, 2:00 -->
+
     <timezone code="ee">Europe/Tallinn</timezone>
+
+    <!-- EGYPT, 2:00 -->
+
     <timezone code="eg">Africa/Cairo</timezone>
+
+    <!-- WESTERN SAHARA, 0:00 -->
+
     <timezone code="eh">Africa/El_Aaiun</timezone>
+
+    <!-- ERITREA, 3:00 -->
+
     <timezone code="er">Africa/Asmara</timezone>
+
+    <!-- SPAIN, 1:00 -->
+
     <timezone code="es">Europe/Madrid</timezone>
     <timezone code="es">Africa/Ceuta</timezone>
+
+    <!-- SPAIN, 0:00 -->
+
     <timezone code="es">Atlantic/Canary</timezone>
+
+    <!-- ETHIOPIA, 3:00 -->
+
     <timezone code="et">Africa/Addis_Ababa</timezone>
+
+    <!-- FINLAND, 2:00 -->
+
     <timezone code="fi">Europe/Helsinki</timezone>
+
+    <!-- FIJI, 12:00 -->
+
     <timezone code="fj">Pacific/Fiji</timezone>
+
+    <!-- FALKLAND ISLANDS (MALVINAS), -4:00 -->
+
     <timezone code="fk">Atlantic/Stanley</timezone>
-    <timezone code="fm">Pacific/Truk</timezone>
+
+    <!-- MICRONESIA, FEDERATED STATES OF, 11:00 -->
+
     <timezone code="fm">Pacific/Ponape</timezone>
     <timezone code="fm">Pacific/Kosrae</timezone>
+
+    <!-- MICRONESIA, FEDERATED STATES OF, 10:00 -->
+
+    <timezone code="fm">Pacific/Truk</timezone>
+
+    <!-- FAROE ISLANDS, 0:00 -->
+
     <timezone code="fo">Atlantic/Faroe</timezone>
+
+    <!-- FRANCE, 1:00 -->
+
     <timezone code="fr">Europe/Paris</timezone>
+
+    <!-- GABON, 1:00 -->
+
     <timezone code="ga">Africa/Libreville</timezone>
+
+    <!-- UNITED KINGDOM, 0:00 -->
+
     <timezone code="gb">Europe/London</timezone>
+
+    <!-- GRENADA, -4:00 -->
+
     <timezone code="gd">America/Grenada</timezone>
+
+    <!-- GEORGIA, 4:00 -->
+
     <timezone code="ge">Asia/Tbilisi</timezone>
+
+    <!-- FRENCH GUIANA, -3:00 -->
+
     <timezone code="gf">America/Cayenne</timezone>
+
+    <!-- GUERNSEY, 0:00 -->
+
     <timezone code="gg">Europe/Guernsey</timezone>
+
+    <!-- GHANA, 0:00 -->
+
     <timezone code="gh">Africa/Accra</timezone>
+
+    <!-- GIBRALTAR, 1:00 -->
+
     <timezone code="gi">Europe/Gibraltar</timezone>
-    <timezone code="gl">America/Godthab</timezone>
+
+    <!-- GREENLAND, 0:00 -->
+
     <timezone code="gl">America/Danmarkshavn</timezone>
+
+    <!-- GREENLAND, -1:00 -->
+
     <timezone code="gl">America/Scoresbysund</timezone>
+
+    <!-- GREENLAND, -3:00 -->
+
+    <timezone code="gl">America/Godthab</timezone>
+
+    <!-- GREENLAND, -4:00 -->
+
     <timezone code="gl">America/Thule</timezone>
+
+    <!-- GAMBIA, 0:00 -->
+
     <timezone code="gm">Africa/Banjul</timezone>
+
+    <!-- GUINEA, 0:00 -->
+
     <timezone code="gn">Africa/Conakry</timezone>
+
+    <!-- GUADELOUPE, -4:00 -->
+
     <timezone code="gp">America/Guadeloupe</timezone>
+
+    <!-- EQUATORIAL GUINEA, 1:00 -->
+
     <timezone code="gq">Africa/Malabo</timezone>
+
+    <!-- GREECE, 2:00 -->
+
     <timezone code="gr">Europe/Athens</timezone>
+
+    <!-- SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS, -2:00 -->
+
     <timezone code="gs">Atlantic/South_Georgia</timezone>
+
+    <!-- GUATEMALA, -6:00 -->
+
     <timezone code="gt">America/Guatemala</timezone>
+
+    <!-- GUAM, 10:00 -->
+
     <timezone code="gu">Pacific/Guam</timezone>
+
+    <!-- GUINEA-BISSAU, 0:00 -->
+
     <timezone code="gw">Africa/Bissau</timezone>
+
+    <!-- GUYANA, -4:00 -->
+
     <timezone code="gy">America/Guyana</timezone>
+
+    <!-- HONG KONG, 8:00 -->
+
     <timezone code="hk">Asia/Hong_Kong</timezone>
+
+    <!-- HONDURAS, -6:00 -->
+
     <timezone code="hn">America/Tegucigalpa</timezone>
+
+    <!-- CROATIA, 1:00 -->
+
     <timezone code="hr">Europe/Zagreb</timezone>
+
+    <!-- HAITI, -5:00 -->
+
     <timezone code="ht">America/Port-au-Prince</timezone>
+
+    <!-- HUNGARY, 1:00 -->
+
     <timezone code="hu">Europe/Budapest</timezone>
+
+    <!-- INDONESIA, 9:00 -->
+
+    <timezone code="id">Asia/Jayapura</timezone>
+
+    <!-- INDONESIA, 8:00 -->
+
+    <timezone code="id">Asia/Makassar</timezone>
+
+    <!-- INDONESIA, 7:00 -->
+
     <timezone code="id">Asia/Jakarta</timezone>
     <timezone code="id">Asia/Pontianak</timezone>
-    <timezone code="id">Asia/Makassar</timezone>
-    <timezone code="id">Asia/Jayapura</timezone>
+
+    <!-- IRELAND, 0:00 -->
+
     <timezone code="ie">Europe/Dublin</timezone>
+
+    <!-- ISRAEL, 2:00 -->
+
     <timezone code="il">Asia/Jerusalem</timezone>
+
+    <!-- ISLE OF MAN, 0:00 -->
+
     <timezone code="im">Europe/Isle_of_Man</timezone>
+
+    <!-- INDIA, 5:30 -->
+
     <timezone code="in">Asia/Calcutta</timezone>
+
+    <!-- BRITISH INDIAN OCEAN TERRITORY, 6:00 -->
+
     <timezone code="io">Indian/Chagos</timezone>
+
+    <!-- IRAQ, 3:00 -->
+
     <timezone code="iq">Asia/Baghdad</timezone>
+
+    <!-- IRAN, ISLAMIC REPUBLIC OF, 3:30 -->
+
     <timezone code="ir">Asia/Tehran</timezone>
+
+    <!-- ICELAND, 0:00 -->
+
     <timezone code="is">Atlantic/Reykjavik</timezone>
+
+    <!-- ITALY, 1:00 -->
+
     <timezone code="it">Europe/Rome</timezone>
+
+    <!-- JERSEY, 0:00 -->
+
     <timezone code="je">Europe/Jersey</timezone>
+
+    <!-- JAMAICA, -5:00 -->
+
     <timezone code="jm">America/Jamaica</timezone>
+
+    <!-- JORDAN, 2:00 -->
+
     <timezone code="jo">Asia/Amman</timezone>
+
+    <!-- JAPAN, 9:00 -->
+
     <timezone code="jp">Asia/Tokyo</timezone>
+
+    <!-- KENYA, 3:00 -->
+
     <timezone code="ke">Africa/Nairobi</timezone>
+
+    <!-- KYRGYZSTAN, 6:00 -->
+
     <timezone code="kg">Asia/Bishkek</timezone>
+
+    <!-- CAMBODIA, 7:00 -->
+
     <timezone code="kh">Asia/Phnom_Penh</timezone>
-    <timezone code="ki">Pacific/Tarawa</timezone>
-    <timezone code="ki">Pacific/Enderbury</timezone>
+
+    <!-- KIRIBATI, 14:00 -->
+
     <timezone code="ki">Pacific/Kiritimati</timezone>
+
+    <!-- KIRIBATI, 13:00 -->
+
+    <timezone code="ki">Pacific/Enderbury</timezone>
+
+    <!-- KIRIBATI, 12:00 -->
+
+    <timezone code="ki">Pacific/Tarawa</timezone>
+
+    <!-- COMOROS, 3:00 -->
+
     <timezone code="km">Indian/Comoro</timezone>
+
+    <!-- SAINT KITTS AND NEVIS, -4:00 -->
+
     <timezone code="kn">America/St_Kitts</timezone>
+
+    <!-- KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF, 9:00 -->
+
     <timezone code="kp">Asia/Pyongyang</timezone>
+
+    <!-- KOREA, REPUBLIC OF, 9:00 -->
+
     <timezone code="kr">Asia/Seoul</timezone>
+
+    <!-- KUWAIT, 3:00 -->
+
     <timezone code="kw">Asia/Kuwait</timezone>
+
+    <!-- CAYMAN ISLANDS, -5:00 -->
+
     <timezone code="ky">America/Cayman</timezone>
+
+    <!-- KAZAKHSTAN, 6:00 -->
+
     <timezone code="kz">Asia/Almaty</timezone>
     <timezone code="kz">Asia/Qyzylorda</timezone>
-    <timezone code="kz">Asia/Aqtobe</timezone>
+
+    <!-- KAZAKHSTAN, 5:00 -->
+
     <timezone code="kz">Asia/Aqtau</timezone>
     <timezone code="kz">Asia/Oral</timezone>
+    <timezone code="kz">Asia/Aqtobe</timezone>
+
+    <!-- LAO PEOPLE'S DEMOCRATIC REPUBLIC, 7:00 -->
+
     <timezone code="la">Asia/Vientiane</timezone>
+
+    <!-- LEBANON, 2:00 -->
+
     <timezone code="lb">Asia/Beirut</timezone>
+
+    <!-- SAINT LUCIA, -4:00 -->
+
     <timezone code="lc">America/St_Lucia</timezone>
+
+    <!-- LIECHTENSTEIN, 1:00 -->
+
     <timezone code="li">Europe/Vaduz</timezone>
+
+    <!-- SRI LANKA, 5:30 -->
+
     <timezone code="lk">Asia/Colombo</timezone>
+
+    <!-- LIBERIA, 0:00 -->
+
     <timezone code="lr">Africa/Monrovia</timezone>
+
+    <!-- LESOTHO, 2:00 -->
+
     <timezone code="ls">Africa/Maseru</timezone>
+
+    <!-- LITHUANIA, 2:00 -->
+
     <timezone code="lt">Europe/Vilnius</timezone>
+
+    <!-- LUXEMBOURG, 1:00 -->
+
     <timezone code="lu">Europe/Luxembourg</timezone>
+
+    <!-- LATVIA, 2:00 -->
+
     <timezone code="lv">Europe/Riga</timezone>
+
+    <!-- LIBYAN ARAB JAMAHIRIYA, 2:00 -->
+
     <timezone code="ly">Africa/Tripoli</timezone>
+
+    <!-- MOROCCO, 0:00 -->
+
     <timezone code="ma">Africa/Casablanca</timezone>
+
+    <!-- MONACO, 1:00 -->
+
     <timezone code="mc">Europe/Monaco</timezone>
+
+    <!-- MOLDOVA, 2:00 -->
+
     <timezone code="md">Europe/Chisinau</timezone>
+
+    <!-- MONTENEGRO, 1:00 -->
+
     <timezone code="me">Europe/Podgorica</timezone>
+
+    <!-- MADAGASCAR, 3:00 -->
+
     <timezone code="mg">Indian/Antananarivo</timezone>
+
+    <!-- MARSHALL ISLANDS, 12:00 -->
+
     <timezone code="mh">Pacific/Majuro</timezone>
     <timezone code="mh">Pacific/Kwajalein</timezone>
+
+    <!-- MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF, 1:00 -->
+
     <timezone code="mk">Europe/Skopje</timezone>
+
+    <!-- MALI, 0:00 -->
+
     <timezone code="ml">Africa/Bamako</timezone>
+
+    <!-- MYANMAR, 6:30 -->
+
     <timezone code="mm">Asia/Rangoon</timezone>
-    <timezone code="mn">Asia/Ulaanbaatar</timezone>
-    <timezone code="mn">Asia/Hovd</timezone>
+
+    <!-- MONGOLIA, 8:00 -->
+
     <timezone code="mn">Asia/Choibalsan</timezone>
+    <timezone code="mn">Asia/Ulaanbaatar</timezone>
+
+    <!-- MONGOLIA, 7:00 -->
+
+    <timezone code="mn">Asia/Hovd</timezone>
+
+    <!-- MACAO, 8:00 -->
+
     <timezone code="mo">Asia/Macau</timezone>
+
+    <!-- NORTHERN MARIANA ISLANDS, 10:00 -->
+
     <timezone code="mp">Pacific/Saipan</timezone>
+
+    <!-- MARTINIQUE, -4:00 -->
+
     <timezone code="mq">America/Martinique</timezone>
+
+    <!-- MAURITANIA, 0:00 -->
+
     <timezone code="mr">Africa/Nouakchott</timezone>
+
+    <!-- MONTSERRAT, -4:00 -->
+
     <timezone code="ms">America/Montserrat</timezone>
+
+    <!-- MALTA, 1:00 -->
+
     <timezone code="mt">Europe/Malta</timezone>
+
+    <!-- MAURITIUS, 4:00 -->
+
     <timezone code="mu">Indian/Mauritius</timezone>
+
+    <!-- MALDIVES, 5:00 -->
+
     <timezone code="mv">Indian/Maldives</timezone>
+
+    <!-- MALAWI, 2:00 -->
+
     <timezone code="mw">Africa/Blantyre</timezone>
+
+    <!-- MEXICO, -6:00 -->
+
     <timezone code="mx">America/Mexico_City</timezone>
     <timezone code="mx">America/Cancun</timezone>
     <timezone code="mx">America/Merida</timezone>
     <timezone code="mx">America/Monterrey</timezone>
-    <timezone code="mx">America/Mazatlan</timezone>
+
+    <!-- MEXICO, -7:00 -->
+
     <timezone code="mx">America/Chihuahua</timezone>
     <timezone code="mx">America/Hermosillo</timezone>
+    <timezone code="mx">America/Mazatlan</timezone>
+
+    <!-- MEXICO, -8:00 -->
+
     <timezone code="mx">America/Tijuana</timezone>
+
+    <!-- MALAYSIA, 8:00 -->
+
     <timezone code="my">Asia/Kuala_Lumpur</timezone>
     <timezone code="my">Asia/Kuching</timezone>
+
+    <!-- MOZAMBIQUE, 2:00 -->
+
     <timezone code="mz">Africa/Maputo</timezone>
+
+    <!-- NAMIBIA, 1:00 -->
+
     <timezone code="na">Africa/Windhoek</timezone>
+
+    <!-- NEW CALEDONIA, 11:00 -->
+
     <timezone code="nc">Pacific/Noumea</timezone>
+
+    <!-- NIGER, 1:00 -->
+
     <timezone code="ne">Africa/Niamey</timezone>
+
+    <!-- NORFOLK ISLAND, 11:30 -->
+
     <timezone code="nf">Pacific/Norfolk</timezone>
+
+    <!-- NIGERIA, 1:00 -->
+
     <timezone code="ng">Africa/Lagos</timezone>
+
+    <!-- NICARAGUA, -6:00 -->
+
     <timezone code="ni">America/Managua</timezone>
+
+    <!-- NETHERLANDS, 1:00 -->
+
     <timezone code="nl">Europe/Amsterdam</timezone>
+
+    <!-- NORWAY, 1:00 -->
+
     <timezone code="no">Europe/Oslo</timezone>
+
+    <!-- NEPAL, 5:45 -->
+
     <timezone code="np">Asia/Katmandu</timezone>
+
+    <!-- NAURU, 12:00 -->
+
     <timezone code="nr">Pacific/Nauru</timezone>
+
+    <!-- NIUE, -11:00 -->
+
     <timezone code="nu">Pacific/Niue</timezone>
+
+    <!-- NEW ZEALAND, 12:00 -->
+
     <timezone code="nz">Pacific/Auckland</timezone>
+
+    <!-- NEW ZEALAND, 12:45 -->
+
     <timezone code="nz">Pacific/Chatham</timezone>
+
+    <!-- OMAN, 4:00 -->
+
     <timezone code="om">Asia/Muscat</timezone>
+
+    <!-- PANAMA, -5:00 -->
+
     <timezone code="pa">America/Panama</timezone>
+
+    <!-- PERU, -5:00 -->
+
     <timezone code="pe">America/Lima</timezone>
-    <timezone code="pf">Pacific/Tahiti</timezone>
-    <timezone code="pf">Pacific/Marquesas</timezone>
+
+    <!-- FRENCH POLYNESIA, -9:00 -->
+
     <timezone code="pf">Pacific/Gambier</timezone>
+
+    <!-- FRENCH POLYNESIA, -9:30 -->
+
+    <timezone code="pf">Pacific/Marquesas</timezone>
+
+    <!-- FRENCH POLYNESIA, -10:00 -->
+
+    <timezone code="pf">Pacific/Tahiti</timezone>
+
+    <!-- PAPUA NEW GUINEA, 10:00 -->
+
     <timezone code="pg">Pacific/Port_Moresby</timezone>
+
+    <!-- PHILIPPINES, 8:00 -->
+
     <timezone code="ph">Asia/Manila</timezone>
+
+    <!-- PAKISTAN, 5:00 -->
+
     <timezone code="pk">Asia/Karachi</timezone>
+
+    <!-- POLAND, 1:00 -->
+
     <timezone code="pl">Europe/Warsaw</timezone>
+
+    <!-- SAINT PIERRE AND MIQUELON, -3:00 -->
+
     <timezone code="pm">America/Miquelon</timezone>
+
+    <!-- PITCAIRN, -8:00 -->
+
     <timezone code="pn">Pacific/Pitcairn</timezone>
+
+    <!-- PUERTO RICO, -4:00 -->
+
     <timezone code="pr">America/Puerto_Rico</timezone>
+
+    <!-- PALESTINIAN TERRITORY, OCCUPIED, 2:00 -->
+
     <timezone code="ps">Asia/Gaza</timezone>
+
+    <!-- PORTUGAL, 0:00 -->
+
     <timezone code="pt">Europe/Lisbon</timezone>
     <timezone code="pt">Atlantic/Madeira</timezone>
+
+    <!-- PORTUGAL, -1:00 -->
+
     <timezone code="pt">Atlantic/Azores</timezone>
+
+    <!-- PALAU, 9:00 -->
+
     <timezone code="pw">Pacific/Palau</timezone>
+
+    <!-- PARAGUAY, -4:00 -->
+
     <timezone code="py">America/Asuncion</timezone>
+
+    <!-- QATAR, 3:00 -->
+
     <timezone code="qa">Asia/Qatar</timezone>
+
+    <!-- REUNION, 4:00 -->
+
     <timezone code="re">Indian/Reunion</timezone>
+
+    <!-- ROMANIA, 2:00 -->
+
     <timezone code="ro">Europe/Bucharest</timezone>
+
+    <!-- SERBIA, 1:00 -->
+
     <timezone code="rs">Europe/Belgrade</timezone>
-    <timezone code="ru">Europe/Kaliningrad</timezone>
-    <timezone code="ru">Europe/Moscow</timezone>
-    <timezone code="ru">Europe/Volgograd</timezone>
-    <timezone code="ru">Europe/Samara</timezone>
-    <timezone code="ru">Asia/Yekaterinburg</timezone>
-    <timezone code="ru">Asia/Omsk</timezone>
-    <timezone code="ru">Asia/Novosibirsk</timezone>
-    <timezone code="ru">Asia/Krasnoyarsk</timezone>
-    <timezone code="ru">Asia/Irkutsk</timezone>
-    <timezone code="ru">Asia/Yakutsk</timezone>
-    <timezone code="ru">Asia/Vladivostok</timezone>
-    <timezone code="ru">Asia/Sakhalin</timezone>
-    <timezone code="ru">Asia/Magadan</timezone>
+
+    <!-- RUSSIAN FEDERATION, 12:00 -->
+
     <timezone code="ru">Asia/Kamchatka</timezone>
     <timezone code="ru">Asia/Anadyr</timezone>
+
+    <!-- RUSSIAN FEDERATION, 11:00 -->
+
+    <timezone code="ru">Asia/Magadan</timezone>
+
+    <!-- RUSSIAN FEDERATION, 10:00 -->
+
+    <timezone code="ru">Asia/Vladivostok</timezone>
+    <timezone code="ru">Asia/Sakhalin</timezone>
+
+    <!-- RUSSIAN FEDERATION, 9:00 -->
+
+    <timezone code="ru">Asia/Yakutsk</timezone>
+
+    <!-- RUSSIAN FEDERATION, 8:00 -->
+
+    <timezone code="ru">Asia/Irkutsk</timezone>
+
+    <!-- RUSSIAN FEDERATION, 7:00 -->
+
+    <timezone code="ru">Asia/Krasnoyarsk</timezone>
+
+    <!-- RUSSIAN FEDERATION, 6:00 -->
+
+    <timezone code="ru">Asia/Novosibirsk</timezone>
+    <timezone code="ru">Asia/Omsk</timezone>
+
+    <!-- RUSSIAN FEDERATION, 5:00 -->
+
+    <timezone code="ru">Asia/Yekaterinburg</timezone>
+
+    <!-- RUSSIAN FEDERATION, 4:00 -->
+
+    <timezone code="ru">Europe/Samara</timezone>
+
+    <!-- RUSSIAN FEDERATION, 3:00 -->
+
+    <timezone code="ru">Europe/Moscow</timezone>
+    <timezone code="ru">Europe/Volgograd</timezone>
+
+    <!-- RUSSIAN FEDERATION, 2:00 -->
+
+    <timezone code="ru">Europe/Kaliningrad</timezone>
+
+    <!-- RWANDA, 2:00 -->
+
     <timezone code="rw">Africa/Kigali</timezone>
+
+    <!-- SAUDI ARABIA, 3:00 -->
+
     <timezone code="sa">Asia/Riyadh</timezone>
+
+    <!-- SOLOMON ISLANDS, 11:00 -->
+
     <timezone code="sb">Pacific/Guadalcanal</timezone>
+
+    <!-- SEYCHELLES, 4:00 -->
+
     <timezone code="sc">Indian/Mahe</timezone>
+
+    <!-- SUDAN, 3:00 -->
+
     <timezone code="sd">Africa/Khartoum</timezone>
+
+    <!-- SWEDEN, 1:00 -->
+
     <timezone code="se">Europe/Stockholm</timezone>
+
+    <!-- SINGAPORE, 8:00 -->
+
     <timezone code="sg">Asia/Singapore</timezone>
+
+    <!-- SAINT HELENA, 0:00 -->
+
     <timezone code="sh">Atlantic/St_Helena</timezone>
+
+    <!-- SLOVENIA, 1:00 -->
+
     <timezone code="si">Europe/Ljubljana</timezone>
+
+    <!-- SVALBARD AND JAN MAYEN, 1:00 -->
+
     <timezone code="sj">Arctic/Longyearbyen</timezone>
-    <timezone code="sj">Atlantic/Jan_Mayen</timezone>
+
+    <!-- SLOVAKIA, 1:00 -->
+
     <timezone code="sk">Europe/Bratislava</timezone>
+
+    <!-- SIERRA LEONE, 0:00 -->
+
     <timezone code="sl">Africa/Freetown</timezone>
+
+    <!-- SAN MARINO, 1:00 -->
+
     <timezone code="sm">Europe/San_Marino</timezone>
+
+    <!-- SENEGAL, 0:00 -->
+
     <timezone code="sn">Africa/Dakar</timezone>
+
+    <!-- SOMALIA, 3:00 -->
+
     <timezone code="so">Africa/Mogadishu</timezone>
+
+    <!-- SURINAME, -3:00 -->
+
     <timezone code="sr">America/Paramaribo</timezone>
+
+    <!-- SAO TOME AND PRINCIPE, 0:00 -->
+
     <timezone code="st">Africa/Sao_Tome</timezone>
+
+    <!-- EL SALVADOR, -6:00 -->
+
     <timezone code="sv">America/El_Salvador</timezone>
+
+    <!-- SYRIAN ARAB REPUBLIC, 2:00 -->
+
     <timezone code="sy">Asia/Damascus</timezone>
+
+    <!-- SWAZILAND, 2:00 -->
+
     <timezone code="sz">Africa/Mbabane</timezone>
+
+    <!-- TURKS AND CAICOS ISLANDS, -5:00 -->
+
     <timezone code="tc">America/Grand_Turk</timezone>
+
+    <!-- CHAD, 1:00 -->
+
     <timezone code="td">Africa/Ndjamena</timezone>
+
+    <!-- FRENCH SOUTHERN TERRITORIES, 5:00 -->
+
     <timezone code="tf">Indian/Kerguelen</timezone>
+
+    <!-- TOGO, 0:00 -->
+
     <timezone code="tg">Africa/Lome</timezone>
+
+    <!-- THAILAND, 7:00 -->
+
     <timezone code="th">Asia/Bangkok</timezone>
+
+    <!-- TAJIKISTAN, 5:00 -->
+
     <timezone code="tj">Asia/Dushanbe</timezone>
+
+    <!-- TOKELAU, -10:00 -->
+
     <timezone code="tk">Pacific/Fakaofo</timezone>
+
+    <!-- TIMOR-LESTE, 9:00 -->
+
     <timezone code="tl">Asia/Dili</timezone>
+
+    <!-- TURKMENISTAN, 5:00 -->
+
     <timezone code="tm">Asia/Ashgabat</timezone>
+
+    <!-- TUNISIA, 1:00 -->
+
     <timezone code="tn">Africa/Tunis</timezone>
+
+    <!-- TONGA, 13:00 -->
+
     <timezone code="to">Pacific/Tongatapu</timezone>
+
+    <!-- TURKEY, 2:00 -->
+
     <timezone code="tr">Europe/Istanbul</timezone>
+
+    <!-- TRINIDAD AND TOBAGO, -4:00 -->
+
     <timezone code="tt">America/Port_of_Spain</timezone>
+
+    <!-- TUVALU, 12:00 -->
+
     <timezone code="tv">Pacific/Funafuti</timezone>
+
+    <!-- TAIWAN, PROVINCE OF CHINA, 8:00 -->
+
     <timezone code="tw">Asia/Taipei</timezone>
+
+    <!-- TANZANIA, UNITED REPUBLIC OF, 3:00 -->
+
     <timezone code="tz">Africa/Dar_es_Salaam</timezone>
+
+    <!-- UKRAINE, 2:00 -->
+
     <timezone code="ua">Europe/Kiev</timezone>
     <timezone code="ua">Europe/Uzhgorod</timezone>
     <timezone code="ua">Europe/Zaporozhye</timezone>
     <timezone code="ua">Europe/Simferopol</timezone>
+
+    <!-- UGANDA, 3:00 -->
+
     <timezone code="ug">Africa/Kampala</timezone>
-    <timezone code="um">Pacific/Johnston</timezone>
-    <timezone code="um">Pacific/Midway</timezone>
+
+    <!-- UNITED STATES MINOR OUTLYING ISLANDS, 12:00 -->
+
     <timezone code="um">Pacific/Wake</timezone>
+
+    <!-- UNITED STATES MINOR OUTLYING ISLANDS, -10:00 -->
+
+    <timezone code="um">Pacific/Johnston</timezone>
+
+    <!-- UNITED STATES MINOR OUTLYING ISLANDS, -11:00 -->
+
+    <timezone code="um">Pacific/Midway</timezone>
+
+    <!-- UNITED STATES, -5:00 -->
+
     <timezone code="us">America/New_York</timezone>
     <timezone code="us">America/Detroit</timezone>
     <timezone code="us">America/Kentucky/Louisville</timezone>
     <timezone code="us">America/Kentucky/Monticello</timezone>
     <timezone code="us">America/Indiana/Indianapolis</timezone>
-    <timezone code="us">America/Indiana/Knox</timezone>
+    <timezone code="us">America/Indiana/Vincennes</timezone>
     <timezone code="us">America/Indiana/Winamac</timezone>
     <timezone code="us">America/Indiana/Marengo</timezone>
-    <timezone code="us">America/Indiana/Vevay</timezone>
-    <timezone code="us">America/Chicago</timezone>
-    <timezone code="us">America/Indiana/Vincennes</timezone>
     <timezone code="us">America/Indiana/Petersburg</timezone>
+    <timezone code="us">America/Indiana/Vevay</timezone>
+
+    <!-- UNITED STATES, -6:00 -->
+
+    <timezone code="us">America/Chicago</timezone>
+    <timezone code="us">America/Indiana/Knox</timezone>
     <timezone code="us">America/Menominee</timezone>
     <timezone code="us">America/North_Dakota/Center</timezone>
     <timezone code="us">America/North_Dakota/New_Salem</timezone>
+
+    <!-- UNITED STATES, -7:00 -->
+
     <timezone code="us">America/Denver</timezone>
     <timezone code="us">America/Boise</timezone>
     <timezone code="us">America/Shiprock</timezone>
     <timezone code="us">America/Phoenix</timezone>
+
+    <!-- UNITED STATES, -8:00 -->
+
     <timezone code="us">America/Los_Angeles</timezone>
+
+    <!-- UNITED STATES, -9:00 -->
+
     <timezone code="us">America/Anchorage</timezone>
     <timezone code="us">America/Juneau</timezone>
     <timezone code="us">America/Yakutat</timezone>
     <timezone code="us">America/Nome</timezone>
-    <timezone code="us">America/Adak</timezone>
+
+    <!-- UNITED STATES, -10:00 -->
+
     <timezone code="us">Pacific/Honolulu</timezone>
+    <timezone code="us">America/Adak</timezone>
+
+    <!-- URUGUAY, -3:00 -->
+
     <timezone code="uy">America/Montevideo</timezone>
-    <timezone code="uz">Asia/Samarkand</timezone>
+
+    <!-- UZBEKISTAN, 5:00 -->
+
     <timezone code="uz">Asia/Tashkent</timezone>
+    <timezone code="uz">Asia/Samarkand</timezone>
+
+    <!-- HOLY SEE (VATICAN CITY STATE), 1:00 -->
+
     <timezone code="va">Europe/Vatican</timezone>
+
+    <!-- SAINT VINCENT AND THE GRENADINES, -4:00 -->
+
     <timezone code="vc">America/St_Vincent</timezone>
+
+    <!-- VENEZUELA, -4:30 -->
+
     <timezone code="ve">America/Caracas</timezone>
+
+    <!-- VIRGIN ISLANDS, BRITISH, -4:00 -->
+
     <timezone code="vg">America/Tortola</timezone>
+
+    <!-- VIRGIN ISLANDS, U.S., -4:00 -->
+
     <timezone code="vi">America/St_Thomas</timezone>
+
+    <!-- VIET NAM, 7:00 -->
+
     <timezone code="vn">Asia/Saigon</timezone>
+
+    <!-- VANUATU, 11:00 -->
+
     <timezone code="vu">Pacific/Efate</timezone>
+
+    <!-- WALLIS AND FUTUNA, 12:00 -->
+
     <timezone code="wf">Pacific/Wallis</timezone>
+
+    <!-- SAMOA, -11:00 -->
+
     <timezone code="ws">Pacific/Apia</timezone>
+
+    <!-- YEMEN, 3:00 -->
+
     <timezone code="ye">Asia/Aden</timezone>
+
+    <!-- MAYOTTE, 3:00 -->
+
     <timezone code="yt">Indian/Mayotte</timezone>
+
+    <!-- SOUTH AFRICA, 2:00 -->
+
     <timezone code="za">Africa/Johannesburg</timezone>
+
+    <!-- ZAMBIA, 2:00 -->
+
     <timezone code="zm">Africa/Lusaka</timezone>
+
+    <!-- ZIMBABWE, 2:00 -->
+
     <timezone code="zw">Africa/Harare</timezone>
 </timezones>