Merge change 6356

* changes:
  Add fullscreen support back in.
diff --git a/api/current.xml b/api/current.xml
index ecde4c6..3b9fa76 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -2341,6 +2341,17 @@
  visibility="public"
 >
 </field>
+<field name="autoUrlDetect"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843404"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="background"
  type="int"
  transient="false"
@@ -3463,28 +3474,6 @@
  visibility="public"
 >
 </field>
-<field name="donut_resource_pad20"
- type="int"
- transient="false"
- volatile="false"
- value="16843404"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="donut_resource_pad21"
- type="int"
- transient="false"
- volatile="false"
- value="16843403"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="donut_resource_pad3"
  type="int"
  transient="false"
@@ -8490,6 +8479,17 @@
  visibility="public"
 >
 </field>
+<field name="textColorPrimaryInverseDisableOnly"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843403"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="textColorPrimaryInverseNoDisable"
  type="int"
  transient="false"
@@ -73919,6 +73919,17 @@
  visibility="public"
 >
 </field>
+<field name="MEDIA_INFO_METADATA_UPDATE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="802"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="MEDIA_INFO_NOT_SEEKABLE"
  type="int"
  transient="false"
diff --git a/awt/Android.mk b/awt/Android.mk
index c7480f53a..213c6ce 100644
--- a/awt/Android.mk
+++ b/awt/Android.mk
@@ -28,4 +28,4 @@
 
 LOCAL_DX_FLAGS := --core-library
 
-include $(BUILD_JAVA_LIBRARY)
+#include $(BUILD_JAVA_LIBRARY)
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 030d887..96389dd 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -504,8 +504,7 @@
     }
 
     // start recording mode
-    ret = mHardware->startRecording(recordingCallback,
-                                    mCameraService.get());
+    ret = mHardware->startRecording(recordingCallback, mCameraService.get());
     if (ret != NO_ERROR) {
         LOGE("mHardware->startRecording() failed with status %d", ret);
     }
@@ -798,7 +797,7 @@
 }
 
 // recording callback
-void CameraService::Client::recordingCallback(const sp<IMemory>& mem, void* user)
+void CameraService::Client::recordingCallback(nsecs_t timestamp, const sp<IMemory>& mem, void* user)
 {
     LOGV("recordingCallback");
     sp<Client> client = getClientFromCookie(user);
@@ -806,7 +805,7 @@
         return;
     }
     // The strong pointer guarantees the client will exist, but no lock is held.
-    client->postRecordingFrame(mem);
+    client->postRecordingFrame(timestamp, mem);
 }
 
 // take a picture - image is returned in callback
@@ -1072,14 +1071,14 @@
     mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
 }
 
-void CameraService::Client::postRecordingFrame(const sp<IMemory>& frame)
+void CameraService::Client::postRecordingFrame(nsecs_t timestamp, const sp<IMemory>& frame)
 {
     LOGV("postRecordingFrame");
     if (frame == 0) {
         LOGW("frame is a null pointer");
         return;
     }
-    mCameraClient->dataCallback(CAMERA_MSG_VIDEO_FRAME, frame);
+    mCameraClient->dataCallbackTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, frame);
 }
 
 void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem)
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index 0f07673..ea93789 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -132,7 +132,7 @@
 
                     status_t    checkPid();
 
-        static      void        recordingCallback(const sp<IMemory>& mem, void* user);
+        static      void        recordingCallback(nsecs_t timestamp, const sp<IMemory>& mem, void* user);
         static      void        previewCallback(const sp<IMemory>& mem, void* user);
         static      void        shutterCallback(void *user);
         static      void        yuvPictureCallback(const sp<IMemory>& mem, void* user);
@@ -144,7 +144,7 @@
                     void        postRaw(const sp<IMemory>& mem);
                     void        postJpeg(const sp<IMemory>& mem);
                     void        postPreviewFrame(const sp<IMemory>& mem);
-                    void        postRecordingFrame(const sp<IMemory>& frame);
+                    void        postRecordingFrame(nsecs_t timestamp, const sp<IMemory>& frame);
                     void        copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size);
                     void        postError(status_t error);
                     void        postAutoFocus(bool focused);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ca9632a..6c2560d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -606,7 +606,6 @@
     private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
     private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
     private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
-    private static final String SAVED_SEARCH_DIALOG_KEY = "android:search_dialog";
 
     private SparseArray<Dialog> mManagedDialogs;
 
@@ -630,7 +629,6 @@
     /*package*/ int mConfigChangeFlags;
     /*package*/ Configuration mCurrentConfig;
     private SearchManager mSearchManager;
-    private Bundle mSearchDialogState = null;
 
     private Window mWindow;
 
@@ -808,13 +806,6 @@
     final void performRestoreInstanceState(Bundle savedInstanceState) {
         onRestoreInstanceState(savedInstanceState);
         restoreManagedDialogs(savedInstanceState);
-        
-        // Also restore the state of a search dialog (if any)
-        // TODO more generic than just this manager
-        Bundle searchState = savedInstanceState.getBundle(SAVED_SEARCH_DIALOG_KEY);
-        if (searchState != null) {
-            mSearchManager.restoreSearchDialog(searchState);
-        }
     }
 
     /**
@@ -866,7 +857,7 @@
             if (dialogState != null) {
                 // Calling onRestoreInstanceState() below will invoke dispatchOnCreate
                 // so tell createDialog() not to do it, otherwise we get an exception
-                final Dialog dialog = createDialog(dialogId, false);
+                final Dialog dialog = createDialog(dialogId, dialogState);
                 mManagedDialogs.put(dialogId, dialog);
                 onPrepareDialog(dialogId, dialog);
                 dialog.onRestoreInstanceState(dialogState);
@@ -874,13 +865,13 @@
         }
     }
 
-    private Dialog createDialog(Integer dialogId, boolean dispatchOnCreate) {
+    private Dialog createDialog(Integer dialogId, Bundle state) {
         final Dialog dialog = onCreateDialog(dialogId);
         if (dialog == null) {
             throw new IllegalArgumentException("Activity#onCreateDialog did "
                     + "not create a dialog for id " + dialogId);
         }
-        if (dispatchOnCreate) dialog.dispatchOnCreate(null);
+        dialog.dispatchOnCreate(state);
         return dialog;
     }
 
@@ -1030,14 +1021,6 @@
     final void performSaveInstanceState(Bundle outState) {
         onSaveInstanceState(outState);
         saveManagedDialogs(outState);
-
-        // Also save the state of a search dialog (if any)
-        // TODO more generic than just this manager
-        // onPause() should always be called before this method, so mSearchManagerState
-        // should be up to date.
-        if (mSearchDialogState != null) {
-            outState.putBundle(SAVED_SEARCH_DIALOG_KEY, mSearchDialogState);
-        }
     }
 
     /**
@@ -1317,10 +1300,6 @@
                 c.mCursor.close();
             }
         }
-
-        // Clear any search state saved in performPause(). If the state may be needed in the
-        // future, it will have been saved by performSaveInstanceState()
-        mSearchDialogState = null;
     }
 
     /**
@@ -1341,11 +1320,7 @@
      */
     public void onConfigurationChanged(Configuration newConfig) {
         mCalled = true;
-        
-        // also update search dialog if showing
-        // TODO more generic than just this manager
-        mSearchManager.onConfigurationChanged(newConfig);
-        
+
         if (mWindow != null) {
             // Pass the configuration changed event to the window
             mWindow.onConfigurationChanged(newConfig);
@@ -2432,7 +2407,7 @@
         }
         Dialog dialog = mManagedDialogs.get(id);
         if (dialog == null) {
-            dialog = createDialog(id, true);
+            dialog = createDialog(id, null);
             mManagedDialogs.put(id, dialog);
         }
         
@@ -3575,20 +3550,12 @@
                 "Activity " + mComponent.toShortString() +
                 " did not call through to super.onPostResume()");
         }
-
-        // restore search dialog, if any
-        if (mSearchDialogState != null) {
-            mSearchManager.restoreSearchDialog(mSearchDialogState);
-        }
-        mSearchDialogState = null;
     }
 
     final void performPause() {
         onPause();
 
-        // save search dialog state if the search dialog is open,
-        // and then dismiss the search dialog
-        mSearchDialogState = mSearchManager.saveSearchDialog();
+        // dismiss the search dialog if it is open
         mSearchManager.stopSearch();
     }
     
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 222fe75..2b165fc 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -292,8 +292,10 @@
     // internal method to make sure mcreated is set properly without requiring
     // users to call through to super in onCreate
     void dispatchOnCreate(Bundle savedInstanceState) {
-        onCreate(savedInstanceState);
-        mCreated = true;
+        if (!mCreated) {
+            onCreate(savedInstanceState);
+            mCreated = true;
+        }
     }
 
     /**
diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl
index e8bd60a..5b62192 100644
--- a/core/java/android/app/ISearchManager.aidl
+++ b/core/java/android/app/ISearchManager.aidl
@@ -36,8 +36,4 @@
             boolean globalSearch,
             ISearchManagerCallback searchManagerCallback);
     void stopSearch();
-    boolean isVisible();
-    Bundle onSaveInstanceState();
-    void onRestoreInstanceState(in Bundle savedInstanceState);
-    void onConfigurationChanged(in Configuration newConfig);
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9834c75..a67e60b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -458,7 +458,9 @@
                 sb.append(this.vibrate[i]);
                 sb.append(',');
             }
-            sb.append(this.vibrate[N]);
+            if (N != -1) {
+                sb.append(this.vibrate[N]);
+            }
             sb.append("]");
         } else if ((this.defaults & DEFAULT_VIBRATE) != 0) {
             sb.append("default");
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index fdb619a..022a9d9 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -19,13 +19,11 @@
 import static android.app.SuggestionsAdapter.getColumnString;
 
 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.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -33,8 +31,8 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.Cursor;
-import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
@@ -95,11 +93,7 @@
 
     private static final int SEARCH_PLATE_LEFT_PADDING_GLOBAL = 12;
     private static final int SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL = 7;
-    
-    // interaction with runtime
-    private IntentFilter mCloseDialogsFilter;
-    private IntentFilter mPackageFilter;
-    
+
     // views & widgets
     private TextView mBadgeLabel;
     private ImageView mAppIcon;
@@ -210,15 +204,7 @@
 
         // Touching outside of the search dialog will dismiss it 
         setCanceledOnTouchOutside(true);
-        
-        // Set up broadcast filters
-        mCloseDialogsFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        mPackageFilter = new IntentFilter();
-        mPackageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        mPackageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        mPackageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        mPackageFilter.addDataScheme("package");
-        
+
         // Save voice intent for later queries/launching
         mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
         mVoiceWebSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -382,15 +368,6 @@
         
         return true;
     }
-    
-    @Override
-    protected void onStart() {
-        super.onStart();
-        
-        // receive broadcasts
-        getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter);
-        getContext().registerReceiver(mBroadcastReceiver, mPackageFilter);
-    }
 
     /**
      * The search dialog is being dismissed, so handle all of the local shutdown operations.
@@ -401,14 +378,7 @@
     @Override
     public void onStop() {
         super.onStop();
-        
-        // stop receiving broadcasts (throws exception if none registered)
-        try {
-            getContext().unregisterReceiver(mBroadcastReceiver);
-        } catch (RuntimeException e) {
-            // This is OK - it just means we didn't have any registered
-        }
-        
+
         closeSuggestionsAdapter();
         
         // dump extra memory we're hanging on to
@@ -455,12 +425,15 @@
     /**
      * Save the minimal set of data necessary to recreate the search
      * 
-     * @return A bundle with the state of the dialog.
+     * @return A bundle with the state of the dialog, or {@code null} if the search
+     *         dialog is not showing.
      */
     @Override
     public Bundle onSaveInstanceState() {
+        if (!isShowing()) return null;
+
         Bundle bundle = new Bundle();
-        
+
         // setup info so I can recreate this particular search       
         bundle.putParcelable(INSTANCE_KEY_COMPONENT, mLaunchComponent);
         bundle.putBundle(INSTANCE_KEY_APPDATA, mAppSearchData);
@@ -483,6 +456,8 @@
      */
     @Override
     public void onRestoreInstanceState(Bundle savedInstanceState) {
+        if (savedInstanceState == null) return;
+
         ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT);
         Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA);
         boolean globalSearch = savedInstanceState.getBoolean(INSTANCE_KEY_GLOBALSEARCH);
@@ -509,7 +484,7 @@
     /**
      * Called after resources have changed, e.g. after screen rotation or locale change.
      */
-    public void onConfigurationChanged(Configuration newConfig) {
+    public void onConfigurationChanged() {
         if (isShowing()) {
             // Redraw (resources may have changed)
             updateSearchButton();
@@ -777,7 +752,7 @@
         }
 
         public void afterTextChanged(Editable s) {
-            if (!mSearchAutoComplete.isPerformingCompletion()) {
+            if (mSearchable.autoUrlDetect() && !mSearchAutoComplete.isPerformingCompletion()) {
                 // The user changed the query, check if it is a URL and if so change the search
                 // button in the soft keyboard to the 'Go' button.
                 int options = (mSearchAutoComplete.getImeOptions() & (~EditorInfo.IME_MASK_ACTION));
@@ -987,17 +962,19 @@
                         && event.getAction() == KeyEvent.ACTION_UP) {
                     v.cancelLongPress();
 
-                    // If this is a url entered by the user and we displayed the 'Go' button which
-                    // the user clicked, launch the url instead of using it as a search query.
-                    if ((mSearchAutoCompleteImeOptions & EditorInfo.IME_MASK_ACTION)
-                            == EditorInfo.IME_ACTION_GO) {
-                        Uri uri = Uri.parse(fixUrl(mSearchAutoComplete.getText().toString()));
-                        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                        launchIntent(intent);
-                    } else {
-                        // Launch as a regular search.
-                        launchQuerySearch();
+                    if (mSearchable.autoUrlDetect()) {
+                        // If this is a url entered by the user & we displayed the 'Go' button which
+                        // the user clicked, launch the url instead of using it as a search query.
+                        if ((mSearchAutoCompleteImeOptions & EditorInfo.IME_MASK_ACTION)
+                                == EditorInfo.IME_ACTION_GO) {
+                            Uri uri = Uri.parse(fixUrl(mSearchAutoComplete.getText().toString()));
+                            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+                            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                            launchIntent(intent);
+                        } else {
+                            // Launch as a regular search.
+                            launchQuerySearch();
+                        }
                     }
                     return true;
                 }
@@ -1012,35 +989,11 @@
             return false;
         }
     };
-        
-    /**
-     * When the ACTION_CLOSE_SYSTEM_DIALOGS intent is received, we should close ourselves 
-     * immediately, in order to allow a higher-priority UI to take over
-     * (e.g. phone call received).
-     * 
-     * When a package is added, removed or changed, our current context
-     * may no longer be valid.  This would only happen if a package is installed/removed exactly
-     * when the search bar is open.  So for now we're just going to close the search
-     * bar.  
-     * Anything fancier would require some checks to see if the user's context was still valid.
-     * Which would be messier.
-     */
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
-                cancel();
-            } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)
-                    || Intent.ACTION_PACKAGE_REMOVED.equals(action)
-                    || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
-                cancel();
-            }
-        }
-    };
 
     @Override
     public void cancel() {
+        if (!isShowing()) return;
+
         // We made sure the IME was displayed, so also make sure it is closed
         // when we go away.
         InputMethodManager imm = (InputMethodManager)getContext()
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index e5ba6a4..5d25f10 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -20,7 +20,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.res.Configuration;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
@@ -1730,59 +1729,6 @@
     }
 
     /**
-     * Saves the state of the search UI.
-     *
-     * @return A Bundle containing the state of the search dialog, or {@code null}
-     *         if the search UI is not visible.
-     *
-     * @hide
-     */
-    public Bundle saveSearchDialog() {
-        if (DBG) debug("saveSearchDialog(), mIsShowing=" + mIsShowing);
-        if (!mIsShowing) return null;
-        try {
-            return mService.onSaveInstanceState();
-        } catch (RemoteException ex) {
-            Log.e(TAG, "onSaveInstanceState() failed: " + ex);
-            return null;
-        }
-    }
-
-    /**
-     * Restores the state of the search dialog.
-     *
-     * @param searchDialogState Bundle to read the state from.
-     *
-     * @hide
-     */
-    public void restoreSearchDialog(Bundle searchDialogState) {
-        if (DBG) debug("restoreSearchDialog(" + searchDialogState + ")");
-        if (searchDialogState == null) return;
-        try {
-            mService.onRestoreInstanceState(searchDialogState);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "onRestoreInstanceState() failed: " + ex);
-        }
-    }
-
-    /**
-     * Update the search dialog after a configuration change.
-     *
-     * @param newConfig The new configuration.
-     *
-     * @hide
-     */
-    public void onConfigurationChanged(Configuration newConfig) {
-        if (DBG) debug("onConfigurationChanged(" + newConfig + "), mIsShowing=" + mIsShowing);
-        if (!mIsShowing) return;
-        try {
-            mService.onConfigurationChanged(newConfig);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "onConfigurationChanged() failed:" + ex);
-        }
-    }
-
-    /**
      * Gets information about a searchable activity. This method is static so that it can
      * be used from non-Activity contexts.
      *
diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java
index 5b4ac0d..34a1a0c 100644
--- a/core/java/android/backup/BackupManager.java
+++ b/core/java/android/backup/BackupManager.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.util.Log;
 
 /**
  * BackupManager is the interface to the system's backup service.
@@ -39,14 +40,17 @@
  * @hide pending API solidification
  */
 public class BackupManager {
-    private Context mContext;
-    private IBackupManager mService;
+    private static final String TAG = "BackupManager";
 
-    /**
-     * Defined backup transports understood by {@link IBackupManager.selectBackupTransport}.
-     */
-    public static final int TRANSPORT_LOCAL = 1;
-    public static final int TRANSPORT_GOOGLE = 2;
+    private Context mContext;
+    private static IBackupManager sService;
+
+    private static void checkServiceBinder() {
+        if (sService == null) {
+            sService = IBackupManager.Stub.asInterface(
+                    ServiceManager.getService(Context.BACKUP_SERVICE));
+        }
+    }
 
     /**
      * Constructs a BackupManager object through which the application can
@@ -58,8 +62,6 @@
      */
     public BackupManager(Context context) {
         mContext = context;
-        mService = IBackupManager.Stub.asInterface(
-                ServiceManager.getService(Context.BACKUP_SERVICE));
     }
 
     /**
@@ -68,10 +70,31 @@
      * {@link android.app.BackupAgent} subclass will be scheduled when you call this method.
      */
     public void dataChanged() {
-        if (mService != null) {
+        checkServiceBinder();
+        if (sService != null) {
             try {
-                mService.dataChanged(mContext.getPackageName());
+                sService.dataChanged(mContext.getPackageName());
             } catch (RemoteException e) {
+                Log.d(TAG, "dataChanged() couldn't connect");
+            }
+        }
+    }
+
+    /**
+     * Convenience method for callers who need to indicate that some other package
+     * needs a backup pass.  This can be relevant in the case of groups of packages
+     * that share a uid, for example.
+     *
+     * This method requires that the application hold the "android.permission.BACKUP"
+     * permission if the package named in the argument is not the caller's own.
+     */
+    public static void dataChanged(String packageName) {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                sService.dataChanged(packageName);
+            } catch (RemoteException e) {
+                Log.d(TAG, "dataChanged(pkg) couldn't connect");
             }
         }
     }
@@ -85,10 +108,12 @@
      */
     public IRestoreSession beginRestoreSession(String transport) {
         IRestoreSession binder = null;
-        if (mService != null) {
+        checkServiceBinder();
+        if (sService != null) {
             try {
-                binder = mService.beginRestoreSession(transport);
+                binder = sService.beginRestoreSession(transport);
             } catch (RemoteException e) {
+                Log.d(TAG, "beginRestoreSession() couldn't connect");
             }
         }
         return binder;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 4e631c4..4c7a9d3 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -314,9 +314,10 @@
      * Example client call:<p>
      * <pre>// Request a specific record.
      * Cursor managedCursor = managedQuery(
-                Contacts.People.CONTENT_URI.addId(2),
+                ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
                 projection,    // Which columns to return.
                 null,          // WHERE clause.
+                null,          // WHERE clause value substitution
                 People.NAME + " ASC");   // Sort order.</pre>
      * Example implementation:<p>
      * <pre>// SQLiteQueryBuilder is a helper class that creates the
@@ -345,15 +346,18 @@
         return c;</pre>
      *
      * @param uri The URI to query. This will be the full URI sent by the client;
-     * if the client is requesting a specific record, the URI will end in a record number
-     * that the implementation should parse and add to a WHERE or HAVING clause, specifying
-     * that _id value.
+     *      if the client is requesting a specific record, the URI will end in a record number
+     *      that the implementation should parse and add to a WHERE or HAVING clause, specifying
+     *      that _id value.
      * @param projection The list of columns to put into the cursor. If
      *      null all columns are included.
      * @param selection A selection criteria to apply when filtering rows.
      *      If null then all rows are included.
+     * @param selectionArgs You may include ?s in selection, which will be replaced by
+     *      the values from selectionArgs, in order that they appear in the selection.
+     *      The values will be bound as Strings.
      * @param sortOrder How the rows in the cursor should be sorted.
-     *        If null then the provider is free to define the sort order.
+     *      If null then the provider is free to define the sort order.
      * @return a Cursor or null.
      */
     public abstract Cursor query(Uri uri, String[] projection,
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index bcf95b6..0d00f21 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -173,7 +173,7 @@
      * {@hide}
      */
     public static final int ANY_DENSITY = -1;
-    private static final int[] ANY_DENSITIES_ARRAY = { ANY_DENSITY };
+    static final int[] ANY_DENSITIES_ARRAY = { ANY_DENSITY };
 
     /**
      * Flags associated with the application.  Any combination of
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 558b0c3..b293636 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -945,15 +945,25 @@
                         >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) {
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
         }
-        
+        int densities[] = null;
         int size = pkg.supportsDensityList.size();
         if (size > 0) {
-            int densities[] = pkg.supportsDensities = new int[size];
+            densities = pkg.supportsDensities = new int[size];
             List<Integer> densityList = pkg.supportsDensityList;
             for (int i = 0; i < size; i++) {
                 densities[i] = densityList.get(i);
             }
         }
+        /**
+         * TODO: enable this before code freeze. b/1967935
+         * *
+        if ((densities == null || densities.length == 0)
+                && (pkg.applicationInfo.targetSdkVersion
+                        >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) {
+            pkg.supportsDensities = ApplicationInfo.ANY_DENSITIES_ARRAY;
+        }
+         */
+
         return pkg;
     }
 
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index dfe304d..ebe556e 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -51,18 +51,6 @@
     public static final int DEFAULT_PORTRAIT_HEIGHT = 480;
 
     /**
-     * The x-shift mode that controls the position of the content or the window under
-     * compatibility mode.
-     * {@see getTranslator}
-     * {@see Translator#mShiftMode}
-     */
-    private static final int X_SHIFT_NONE = 0;
-    private static final int X_SHIFT_CONTENT = 1;
-    private static final int X_SHIFT_AND_CLIP_CONTENT = 2;
-    private static final int X_SHIFT_WINDOW = 3;
-
-
-    /**
      *  A compatibility flags
      */
     private int mCompatibilityFlags;
@@ -106,20 +94,6 @@
      */
     public final int appFlags;
     
-    /**
-     * Window size in Compatibility Mode, in real pixels. This is updated by
-     * {@link DisplayMetrics#updateMetrics}.
-     */
-    private int mWidth;
-    private int mHeight;
-    
-    /**
-     * The x offset to center the window content. In X_SHIFT_WINDOW mode, the offset is added
-     * to the window's layout. In X_SHIFT_CONTENT/X_SHIFT_AND_CLIP_CONTENT mode, the offset
-     * is used to translate the Canvas.
-     */
-    private int mXOffset;
-
     public CompatibilityInfo(ApplicationInfo appInfo) {
         appFlags = appInfo.flags;
         
@@ -153,6 +127,7 @@
             applicationScale =
                     DisplayMetrics.DEVICE_DENSITY / (float) DisplayMetrics.DEFAULT_DENSITY;
         }
+
         applicationInvertedScale = 1.0f / applicationScale;
         if (applicationScale != 1.0f) {
             mCompatibilityFlags |= SCALING_REQUIRED;
@@ -181,23 +156,10 @@
     public CompatibilityInfo copy() {
         CompatibilityInfo info = new CompatibilityInfo(appFlags, mCompatibilityFlags,
                 applicationScale, applicationInvertedScale);
-        info.setVisibleRect(mXOffset, mWidth, mHeight);
         return info;
     }
  
     /**
-     * Sets the application's visible rect in compatibility mode.
-     * @param xOffset the application's x offset that is added to center the content.
-     * @param widthPixels the application's width in real pixels on the screen.
-     * @param heightPixels the application's height in real pixels on the screen.
-     */
-    public void setVisibleRect(int xOffset, int widthPixels, int heightPixels) {
-        this.mXOffset = xOffset; 
-        mWidth = widthPixels;
-        mHeight = heightPixels;
-    }
-    
-    /**
      * Sets expandable bit in the compatibility flag.
      */
     public void setExpandable(boolean expandable) {
@@ -222,6 +184,10 @@
         return (mCompatibilityFlags & SCALING_REQUIRED) != 0;
     }
     
+    public boolean supportsScreen() {
+        return (mCompatibilityFlags & CompatibilityInfo.EXPANDABLE) != 0;
+    }
+    
     @Override
     public String toString() {
         return "CompatibilityInfo{scale=" + applicationScale +
@@ -231,21 +197,6 @@
     /**
      * Returns the translator which can translate the coordinates of the window.
      * There are five different types of Translator.
-     * 
-     * 1) {@link CompatibilityInfo#X_SHIFT_AND_CLIP_CONTENT}
-     *   Shift and clip the content of the window at drawing time. Used for activities'
-     *   main window (with no gravity).
-     * 2) {@link CompatibilityInfo#X_SHIFT_CONTENT}
-     *   Shift the content of the window at drawing time. Used for windows that is created by
-     *   an application and expected to be aligned with the application window.
-     * 3) {@link CompatibilityInfo#X_SHIFT_WINDOW}
-     *   Create the window with adjusted x- coordinates. This is typically used 
-     *   in popup window, where it has to be placed relative to main window.
-     * 4) {@link CompatibilityInfo#X_SHIFT_NONE}
-     *   No adjustment required, such as dialog.
-     * 5) Same as X_SHIFT_WINDOW, but no scaling. This is used by {@link SurfaceView}, which
-     *  does not require scaling, but its window's location has to be adjusted.
-     * 
      * @param params the window's parameter
      */
     public Translator getTranslator(WindowManager.LayoutParams params) {
@@ -254,35 +205,11 @@
             if (DBG) Log.d(TAG, "no translation required");
             return null;
         }
-        
-        if ((mCompatibilityFlags & CompatibilityInfo.EXPANDABLE) == 0) {
-            if ((params.flags & WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING) != 0) {
-                if (DBG) Log.d(TAG, "translation for surface view selected");
-                return new Translator(X_SHIFT_WINDOW, false, 1.0f, 1.0f);
-            } else {
-                int shiftMode;
-                if (params.gravity == Gravity.NO_GRAVITY) {
-                    // For Regular Application window
-                    shiftMode = X_SHIFT_AND_CLIP_CONTENT;
-                    if (DBG) Log.d(TAG, "shift and clip translator");
-                } else if (params.width == WindowManager.LayoutParams.FILL_PARENT) {
-                    // For Regular Application window
-                    shiftMode = X_SHIFT_CONTENT;
-                    if (DBG) Log.d(TAG, "shift content translator");
-                } else if ((params.gravity & Gravity.LEFT) != 0 && params.x > 0) {
-                    shiftMode = X_SHIFT_WINDOW;
-                    if (DBG) Log.d(TAG, "shift window translator");
-                } else {
-                    shiftMode = X_SHIFT_NONE;
-                    if (DBG) Log.d(TAG, "no content/window translator");
-                }
-                return new Translator(shiftMode);
-            }
-        } else if (isScalingRequired()) {
-            return new Translator();
-        } else {
+        if (!isScalingRequired() ||
+            (params.flags & WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING) != 0) {
             return null;
         }
+        return new Translator();
     }
 
     /**
@@ -290,97 +217,48 @@
      * @hide
      */
     public class Translator {
-        final private int mShiftMode;
-        final public boolean scalingRequired;
         final public float applicationScale;
         final public float applicationInvertedScale;
         
         private Rect mContentInsetsBuffer = null;
-        private Rect mVisibleInsets = null;
+        private Rect mVisibleInsetsBuffer = null;
         
-        Translator(int shiftMode, boolean scalingRequired, float applicationScale,
-                float applicationInvertedScale) {
-            mShiftMode = shiftMode;
-            this.scalingRequired = scalingRequired;
+        Translator(float applicationScale, float applicationInvertedScale) {
             this.applicationScale = applicationScale;
             this.applicationInvertedScale = applicationInvertedScale;
         }
 
-        Translator(int shiftMode) {
-            this(shiftMode,
-                    isScalingRequired(),
-                    CompatibilityInfo.this.applicationScale,
-                    CompatibilityInfo.this.applicationInvertedScale);
-        }
-        
         Translator() {
-            this(X_SHIFT_NONE);
+            this(CompatibilityInfo.this.applicationScale,
+                    CompatibilityInfo.this.applicationInvertedScale);
         }
 
         /**
          * Translate the screen rect to the application frame.
          */
         public void translateRectInScreenToAppWinFrame(Rect rect) {
-            if (rect.isEmpty()) return; // skip if the window size is empty.
-            switch (mShiftMode) {
-                case X_SHIFT_AND_CLIP_CONTENT:
-                    rect.intersect(0, 0, mWidth, mHeight);
-                    break;
-                case X_SHIFT_CONTENT:
-                    rect.intersect(0, 0, mWidth + mXOffset, mHeight);
-                    break;
-                case X_SHIFT_WINDOW:
-                case X_SHIFT_NONE:
-                    break;
-            }
-            if (scalingRequired) {
-                rect.scale(applicationInvertedScale);
-            }
+            rect.scale(applicationInvertedScale);
         }
 
         /**
          * Translate the region in window to screen. 
          */
         public void translateRegionInWindowToScreen(Region transparentRegion) {
-            switch (mShiftMode) {
-                case X_SHIFT_AND_CLIP_CONTENT:
-                case X_SHIFT_CONTENT:
-                    transparentRegion.scale(applicationScale);
-                    transparentRegion.translate(mXOffset, 0);
-                    break;
-                case X_SHIFT_WINDOW:
-                case X_SHIFT_NONE:
-                    transparentRegion.scale(applicationScale);
-            }
+            transparentRegion.scale(applicationScale);
         }
 
         /**
          * Apply translation to the canvas that is necessary to draw the content.
          */
         public void translateCanvas(Canvas canvas) {
-            if (mShiftMode == X_SHIFT_CONTENT ||
-                    mShiftMode == X_SHIFT_AND_CLIP_CONTENT) {
-                // TODO: clear outside when rotation is changed.
-
-                // Translate x-offset only when the content is shifted.
-                canvas.translate(mXOffset, 0);
-            }
-            if (scalingRequired) {
-                canvas.scale(applicationScale, applicationScale);
-            }
+            canvas.scale(applicationScale, applicationScale);
         }
 
         /**
          * Translate the motion event captured on screen to the application's window.
          */
         public void translateEventInScreenToAppWindow(MotionEvent event) {
-            if (mShiftMode == X_SHIFT_CONTENT ||
-                    mShiftMode == X_SHIFT_AND_CLIP_CONTENT) {
-                event.translate(-mXOffset, 0);
-            }
-            if (scalingRequired) {
-                event.scale(applicationInvertedScale);
-            }
+            event.scale(applicationInvertedScale);
         }
 
         /**
@@ -388,62 +266,21 @@
          * Screen's view.
          */
         public void translateWindowLayout(WindowManager.LayoutParams params) {
-            switch (mShiftMode) {
-                case X_SHIFT_NONE:
-                case X_SHIFT_AND_CLIP_CONTENT:
-                case X_SHIFT_CONTENT:
-                    params.scale(applicationScale);
-                    break;
-                case X_SHIFT_WINDOW:
-                    params.scale(applicationScale);
-                    params.x += mXOffset;
-                    break;
-            }
+            params.scale(applicationScale);
         }
         
         /**
          * Translate a Rect in application's window to screen.
          */
         public void translateRectInAppWindowToScreen(Rect rect) {
-            // TODO Auto-generated method stub
-            if (scalingRequired) {
-                rect.scale(applicationScale);
-            }
-            switch(mShiftMode) {
-                case X_SHIFT_NONE:
-                case X_SHIFT_WINDOW:
-                    break;
-                case X_SHIFT_CONTENT:
-                case X_SHIFT_AND_CLIP_CONTENT:
-                    rect.offset(mXOffset, 0);
-                    break;
-            }
+            rect.scale(applicationScale);
         }
  
         /**
          * Translate a Rect in screen coordinates into the app window's coordinates.
          */
         public void translateRectInScreenToAppWindow(Rect rect) {
-            switch (mShiftMode) {
-                case X_SHIFT_NONE:
-                case X_SHIFT_WINDOW:
-                    break;
-                case X_SHIFT_CONTENT: {
-                    rect.intersects(mXOffset, 0, rect.right, rect.bottom);
-                    int dx = Math.min(mXOffset, rect.left);
-                    rect.offset(-dx, 0);
-                    break;
-                }
-                case X_SHIFT_AND_CLIP_CONTENT: {
-                    rect.intersects(mXOffset, 0, mWidth + mXOffset, mHeight);
-                    int dx = Math.min(mXOffset, rect.left);
-                    rect.offset(-dx, 0);
-                    break;
-                }
-            }
-            if (scalingRequired) {
-                rect.scale(applicationInvertedScale);
-            }
+            rect.scale(applicationInvertedScale);
         }
 
         /**
@@ -451,19 +288,7 @@
          * @param params
          */
         public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) {
-            if (scalingRequired) {
-                params.scale(applicationScale);
-            }
-            switch (mShiftMode) {
-                // the window location on these mode does not require adjustmenet.
-                case X_SHIFT_NONE:
-                case X_SHIFT_WINDOW:
-                    break;
-                case X_SHIFT_CONTENT:
-                case X_SHIFT_AND_CLIP_CONTENT:
-                    params.x += mXOffset;
-                    break;
-            }
+            params.scale(applicationScale);
         }
 
         /**
@@ -482,10 +307,31 @@
          * the internal buffer for content insets to avoid extra object allocation.
          */
         public Rect getTranslatedVisbileInsets(Rect visibleInsets) {
-            if (mVisibleInsets == null) mVisibleInsets = new Rect();
-            mVisibleInsets.set(visibleInsets);
-            translateRectInAppWindowToScreen(mVisibleInsets);
-            return mVisibleInsets;
+            if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect();
+            mVisibleInsetsBuffer.set(visibleInsets);
+            translateRectInAppWindowToScreen(mVisibleInsetsBuffer);
+            return mVisibleInsetsBuffer;
+        }
+    }
+
+    /**
+     * Returns the frame Rect for applications runs under compatibility mode.
+     *
+     * @param dm the display metrics used to compute the frame size.
+     * @param orientation the orientation of the screen.
+     * @param outRect the output parameter which will contain the result.
+     */
+    public static void updateCompatibleScreenFrame(DisplayMetrics dm, int orientation,
+            Rect outRect) {
+        int width = dm.widthPixels;
+        int portraitHeight = (int) (DEFAULT_PORTRAIT_HEIGHT * dm.density);
+        int portraitWidth = (int) (DEFAULT_PORTRAIT_WIDTH * dm.density);
+        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            int xOffset = (width - portraitHeight) / 2 ;
+            outRect.set(xOffset, 0, xOffset + portraitHeight, portraitWidth);
+        } else {
+            int xOffset = (width - portraitWidth) / 2 ;
+            outRect.set(xOffset, 0, xOffset + portraitWidth, portraitHeight);
         }
     }
 }
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 577aa60..4928e93 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -60,7 +60,8 @@
     
     /**
      * The kind of keyboard attached to the device.
-     * One of: {@link #KEYBOARD_QWERTY}, {@link #KEYBOARD_12KEY}.
+     * One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY},
+     * {@link #KEYBOARD_12KEY}.
      */
     public int keyboard;
     
@@ -99,8 +100,8 @@
     
     /**
      * The kind of navigation method available on the device.
-     * One of: {@link #NAVIGATION_DPAD}, {@link #NAVIGATION_TRACKBALL}, 
-     * {@link #NAVIGATION_WHEEL}. 
+     * One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD},
+     * {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}.
      */
     public int navigation;
     
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index c23df21..08bd67e 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -371,7 +371,7 @@
     /**
      * Creates a Uri which parses the given encoded URI string.
      *
-     * @param uriString an RFC 3296-compliant, encoded URI
+     * @param uriString an RFC 2396-compliant, encoded URI
      * @throws NullPointerException if uriString is null
      * @return Uri for this given uri string
      */
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 3145166..64786ec 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -693,6 +693,8 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI = Uri.parse("content://calendar/instances/when");
+        public static final Uri CONTENT_BY_DAY_URI =
+            Uri.parse("content://calendar/instances/whenbyday");
 
         /**
          * The default sort order for this table.
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 7d03801..3d14af7 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -73,7 +73,7 @@
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
 
         /**
-         * The type of the the phone number.
+         * The type of the call (incoming, outgoing or missed).
          * <P>Type: INTEGER (int)</P>
          */
         public static final String TYPE = "type";
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 5cc3315..27c1288 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
 
 /**
  * The contract between the contacts provider and applications. Contains definitions
@@ -159,6 +160,12 @@
          * <P>Type: INTEGER REFERENCES data(_id)</P>
          */
         public static final String PHOTO_ID = "photo_id";
+
+        /**
+         * Lookup value that reflects the {@link Groups#MEMBERS_VISIBLE} state
+         * of any {@link GroupMembership} for this aggregate.
+         */
+        public static final String IN_VISIBLE_GROUP = "in_visible_group";
     }
 
     /**
@@ -260,7 +267,6 @@
         }
     }
 
-
     /**
      * Constants for the contacts table, which contains the base contact information.
      */
@@ -965,6 +971,103 @@
         }
     }
 
+    public interface GroupsColumns {
+        /**
+         * The package name that owns this group.
+         */
+        public static final String PACKAGE = "package";
+
+        /**
+         * A unique identifier for the package that owns this group.
+         */
+        public static final String PACKAGE_ID = "package_id";
+
+        /**
+         * The display title of this group.
+         * <p>
+         * Type: TEXT
+         */
+        public static final String TITLE = "title";
+
+        /**
+         * The display title of this group to load as a resource from
+         * {@link #PACKAGE}, which may be localized.
+         * <p>
+         * Type: TEXT
+         */
+        public static final String TITLE_RESOURCE = "title_res";
+
+        /**
+         * The total number of {@link Aggregates} that have
+         * {@link GroupMembership} in this group. Read-only value that is only
+         * present when querying {@link Groups#CONTENT_SUMMARY_URI}.
+         * <p>
+         * Type: INTEGER
+         */
+        public static final String SUMMARY_COUNT = "summ_count";
+
+        /**
+         * The total number of {@link Aggregates} that have both
+         * {@link GroupMembership} in this group, and also have phone numbers.
+         * Read-only value that is only present when querying
+         * {@link Groups#CONTENT_SUMMARY_URI}.
+         * <p>
+         * Type: INTEGER
+         */
+        public static final String SUMMARY_WITH_PHONES = "summ_phones";
+
+        /**
+         * A reference to the {@link Accounts#_ID} that this data belongs to.
+         */
+        public static final String ACCOUNTS_ID = "accounts_id";
+
+        /**
+         * A string that uniquely identifies this contact to its source, which is referred to
+         * by the {@link #ACCOUNTS_ID}
+         */
+        public static final String SOURCE_ID = "sourceid";
+
+        /**
+         * Flag indicating if the contacts belonging to this group should be
+         * visible in any user interface.
+         * <p>
+         * Type: INTEGER
+         */
+        public static final String GROUP_VISIBLE = "group_visible";
+    }
+
+    /**
+     * Constants for the groups table.
+     */
+    public static final class Groups implements BaseColumns, GroupsColumns {
+        /**
+         * This utility class cannot be instantiated
+         */
+        private Groups()  {}
+
+        /**
+         * The content:// style URI for this table
+         */
+        public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "groups");
+
+        /**
+         * The content:// style URI for this table joined with details data from
+         * {@link Data} and {@link Presence}.
+         */
+        public static final Uri CONTENT_SUMMARY_URI = Uri.withAppendedPath(AUTHORITY_URI,
+                "groups_summary");
+
+        /**
+         * The MIME type of a directory of groups.
+         */
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/group";
+
+        /**
+         * The MIME type of a single group.
+         */
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group";
+    }
+
     /**
      * Constants for the contact aggregation exceptions table, which contains
      * aggregation rules overriding those used by automatic aggregation.  This type only
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fca318e..3fe7bfa 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1375,8 +1375,21 @@
             SCREEN_BRIGHTNESS,
             VIBRATE_ON,
             NOTIFICATIONS_USE_RING_VOLUME,
-            RINGTONE,
-            NOTIFICATION_SOUND,
+            MODE_RINGER,
+            MODE_RINGER_STREAMS_AFFECTED,
+            MUTE_STREAMS_AFFECTED,
+            VOLUME_VOICE,
+            VOLUME_SYSTEM,
+            VOLUME_RING,
+            VOLUME_MUSIC,
+            VOLUME_ALARM,
+            VOLUME_NOTIFICATION,
+            VOLUME_VOICE + APPEND_FOR_LAST_AUDIBLE,
+            VOLUME_SYSTEM + APPEND_FOR_LAST_AUDIBLE,
+            VOLUME_RING + APPEND_FOR_LAST_AUDIBLE,
+            VOLUME_MUSIC + APPEND_FOR_LAST_AUDIBLE,
+            VOLUME_ALARM + APPEND_FOR_LAST_AUDIBLE,
+            VOLUME_NOTIFICATION + APPEND_FOR_LAST_AUDIBLE,
             TEXT_AUTO_REPLACE,
             TEXT_AUTO_CAPS,
             TEXT_AUTO_PUNCTUATE,
@@ -2321,6 +2334,8 @@
          * @hide
          */
         public static final String[] SETTINGS_TO_BACKUP = {
+            ADB_ENABLED,
+            ALLOW_MOCK_LOCATION,
             INSTALL_NON_MARKET_APPS,
             PARENTAL_CONTROL_ENABLED,
             PARENTAL_CONTROL_REDIRECT_URL,
@@ -2693,6 +2708,12 @@
         public static final String GMAIL_DISCARD_ERROR_UPHILL_OP = "gmail_discard_error_uphill_op";
 
         /**
+         * Controls how many attempts Gmail will try to upload an uphill operations before it
+         * abandons the operation. Defaults to 20.
+         */
+        public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_discard_error_uphill_op";
+
+        /**
          * the transcoder URL for mobile devices.
          */
         public static final String TRANSCODER_URL = "mobile_transcoder_url";
diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java
new file mode 100644
index 0000000..dbc1e7f
--- /dev/null
+++ b/core/java/android/server/search/SearchDialogWrapper.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.search;
+
+import android.app.ISearchManagerCallback;
+import android.app.SearchDialog;
+import android.app.SearchManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Runs an instance of {@link SearchDialog} on its own thread.
+ */
+class SearchDialogWrapper
+implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
+
+    private static final String TAG = "SearchManagerService";
+    private static final boolean DBG = false;
+
+    private static final String DISABLE_SEARCH_PROPERTY = "dev.disablesearchdialog";
+
+    private static final String SEARCH_UI_THREAD_NAME = "SearchDialog";
+    private static final int SEARCH_UI_THREAD_PRIORITY =
+        android.os.Process.THREAD_PRIORITY_FOREGROUND;
+
+    // Takes no arguments
+    private static final int MSG_INIT = 0;
+    // Takes these arguments:
+    // arg1: selectInitialQuery, 0 = false, 1 = true
+    // arg2: globalSearch, 0 = false, 1 = true
+    // obj: searchManagerCallback
+    // data[KEY_INITIAL_QUERY]: initial query
+    // data[KEY_LAUNCH_ACTIVITY]: launch activity
+    // data[KEY_APP_SEARCH_DATA]: app search data
+    private static final int MSG_START_SEARCH = 1;
+    // Takes no arguments
+    private static final int MSG_STOP_SEARCH = 2;
+    // Takes no arguments
+    private static final int MSG_ON_CONFIGURATION_CHANGED = 3;
+
+    private static final String KEY_INITIAL_QUERY = "q";
+    private static final String KEY_LAUNCH_ACTIVITY = "a";
+    private static final String KEY_APP_SEARCH_DATA = "d";
+
+    // Context used for getting search UI resources
+    private final Context mContext;
+
+    // Handles messages on the search UI thread.
+    private final SearchDialogHandler mSearchUiThread;
+
+    // The search UI
+    SearchDialog mSearchDialog;
+
+    // If the search UI is visible, this is the callback for the client that showed it.
+    ISearchManagerCallback mCallback = null;
+
+    // Allows disabling of search dialog for stress testing runs
+    private final boolean mDisabledOnBoot;
+
+    /**
+     * Creates a new search dialog wrapper and a search UI thread. The search dialog itself will
+     * be created some asynchronously on the search UI thread.
+     *
+     * @param context Context used for getting search UI resources.
+     */
+    public SearchDialogWrapper(Context context) {
+        mContext = context;
+
+        mDisabledOnBoot = !TextUtils.isEmpty(SystemProperties.get(DISABLE_SEARCH_PROPERTY));
+
+        // Create the search UI thread
+        HandlerThread t = new HandlerThread(SEARCH_UI_THREAD_NAME, SEARCH_UI_THREAD_PRIORITY);
+        t.start();
+        mSearchUiThread = new SearchDialogHandler(t.getLooper());
+
+        // Create search UI on the search UI thread
+        mSearchUiThread.sendEmptyMessage(MSG_INIT);
+    }
+
+    /**
+     * Initializes the search UI.
+     * Must be called from the search UI thread.
+     */
+    private void init() {
+        mSearchDialog = new SearchDialog(mContext);
+        mSearchDialog.setOnCancelListener(this);
+        mSearchDialog.setOnDismissListener(this);
+    }
+
+    private void registerBroadcastReceiver() {
+        IntentFilter closeDialogsFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        mContext.registerReceiver(mBroadcastReceiver, closeDialogsFilter);
+        IntentFilter configurationChangedFilter =
+                new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
+        mContext.registerReceiver(mBroadcastReceiver, configurationChangedFilter);
+    }
+
+    private void unregisterBroadcastReceiver() {
+        mContext.unregisterReceiver(mBroadcastReceiver);
+    }
+
+    /**
+     * Closes the search dialog when requested by the system (e.g. when a phone call comes in).
+     */
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
+                if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+                stopSearch();
+            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                if (DBG) debug(Intent.ACTION_CONFIGURATION_CHANGED);
+                onConfigurationChanged();
+            }
+        }
+    };
+
+    //
+    // External API
+    //
+
+    /**
+     * Launches the search UI.
+     * Can be called from any thread.
+     *
+     * @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean)
+     */
+    public void startSearch(final String initialQuery,
+            final boolean selectInitialQuery,
+            final ComponentName launchActivity,
+            final Bundle appSearchData,
+            final boolean globalSearch,
+            final ISearchManagerCallback searchManagerCallback) {
+        if (DBG) debug("startSearch()");
+        Message msg = Message.obtain();
+        msg.what = MSG_START_SEARCH;
+        msg.arg1 = selectInitialQuery ? 1 : 0;
+        msg.arg2 = globalSearch ? 1 : 0;
+        msg.obj = searchManagerCallback;
+        Bundle msgData = msg.getData();
+        msgData.putString(KEY_INITIAL_QUERY, initialQuery);
+        msgData.putParcelable(KEY_LAUNCH_ACTIVITY, launchActivity);
+        msgData.putBundle(KEY_APP_SEARCH_DATA, appSearchData);
+        mSearchUiThread.sendMessage(msg);
+    }
+
+    /**
+     * Cancels the search dialog.
+     * Can be called from any thread.
+     */
+    public void stopSearch() {
+        if (DBG) debug("stopSearch()");
+        mSearchUiThread.sendEmptyMessage(MSG_STOP_SEARCH);
+    }
+
+    /**
+     * Updates the search UI in response to a configuration change.
+     * Can be called from any thread.
+     */
+    void onConfigurationChanged() {
+        if (DBG) debug("onConfigurationChanged()");
+        mSearchUiThread.sendEmptyMessage(MSG_ON_CONFIGURATION_CHANGED);
+    }
+
+    //
+    // Implementation methods that run on the search UI thread
+    //
+
+    private class SearchDialogHandler extends Handler {
+
+        public SearchDialogHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_INIT:
+                    init();
+                    break;
+                case MSG_START_SEARCH:
+                    handleStartSearchMessage(msg);
+                    break;
+                case MSG_STOP_SEARCH:
+                    performStopSearch();
+                    break;
+                case MSG_ON_CONFIGURATION_CHANGED:
+                    performOnConfigurationChanged();
+                    break;
+            }
+        }
+
+        private void handleStartSearchMessage(Message msg) {
+            Bundle msgData = msg.getData();
+            String initialQuery = msgData.getString(KEY_INITIAL_QUERY);
+            boolean selectInitialQuery = msg.arg1 != 0;
+            ComponentName launchActivity =
+                    (ComponentName) msgData.getParcelable(KEY_LAUNCH_ACTIVITY);
+            Bundle appSearchData = msgData.getBundle(KEY_APP_SEARCH_DATA);
+            boolean globalSearch = msg.arg2 != 0;
+            ISearchManagerCallback searchManagerCallback = (ISearchManagerCallback) msg.obj;
+            performStartSearch(initialQuery, selectInitialQuery, launchActivity,
+                    appSearchData, globalSearch, searchManagerCallback);
+        }
+
+    }
+
+    /**
+     * Actually launches the search UI.
+     * This must be called on the search UI thread.
+     */
+    void performStartSearch(String initialQuery,
+            boolean selectInitialQuery,
+            ComponentName launchActivity,
+            Bundle appSearchData,
+            boolean globalSearch,
+            ISearchManagerCallback searchManagerCallback) {
+        if (DBG) debug("performStartSearch()");
+
+        if (mDisabledOnBoot) {
+            Log.d(TAG, "ignoring start search request because " + DISABLE_SEARCH_PROPERTY
+                    + " system property is set.");
+            return;
+        }
+
+        registerBroadcastReceiver();
+        mCallback = searchManagerCallback;
+        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
+                globalSearch);
+    }
+
+    /**
+     * Actually cancels the search UI.
+     * This must be called on the search UI thread.
+     */
+    void performStopSearch() {
+        if (DBG) debug("performStopSearch()");
+        mSearchDialog.cancel();
+    }
+
+    /**
+     * Must be called from the search UI thread.
+     */
+    void performOnConfigurationChanged() {
+        if (DBG) debug("performOnConfigurationChanged()");
+        mSearchDialog.onConfigurationChanged();
+    }
+
+    /**
+     * Called by {@link SearchDialog} when it goes away.
+     */
+    public void onDismiss(DialogInterface dialog) {
+        if (DBG) debug("onDismiss()");
+        if (mCallback != null) {
+            try {
+                // should be safe to do on the search UI thread, since it's a oneway interface
+                mCallback.onDismiss();
+            } catch (DeadObjectException ex) {
+                // The process that hosted the callback has died, do nothing
+            } catch (RemoteException ex) {
+                Log.e(TAG, "onDismiss() failed: " + ex);
+            }
+            // we don't need the callback anymore, release it
+            mCallback = null;
+        }
+        unregisterBroadcastReceiver();
+    }
+
+    /**
+     * Called by {@link SearchDialog} when the user or activity cancels search.
+     * Whenever this method is called, {@link #onDismiss} is always called afterwards.
+     */
+    public void onCancel(DialogInterface dialog) {
+        if (DBG) debug("onCancel()");
+        if (mCallback != null) {
+            try {
+                // should be safe to do on the search UI thread, since it's a oneway interface
+                mCallback.onCancel();
+            } catch (DeadObjectException ex) {
+                // The process that hosted the callback has died, do nothing
+            } catch (RemoteException ex) {
+                Log.e(TAG, "onCancel() failed: " + ex);
+            }
+        }
+    }
+
+    private static void debug(String msg) {
+        Thread thread = Thread.currentThread();
+        Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
+    }
+}
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index 373e61f..87adfb3 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -18,52 +18,38 @@
 
 import android.app.ISearchManager;
 import android.app.ISearchManagerCallback;
-import android.app.SearchDialog;
 import android.app.SearchManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.text.TextUtils;
 import android.util.Log;
 
 import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
 
 /**
- * This is a simplified version of the Search Manager service.  It no longer handles
- * presentation (UI).  Its function is to maintain the map & list of "searchable"
- * items, which provides a mapping from individual activities (where a user might have
- * invoked search) to specific searchable activities (where the search will be dispatched).
+ * The search manager service handles the search UI, and maintains a registry of searchable
+ * activities.
  */
-public class SearchManagerService extends ISearchManager.Stub
-        implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener
-{
-        // general debugging support
+public class SearchManagerService extends ISearchManager.Stub {
+
+    // general debugging support
     private static final String TAG = "SearchManagerService";
     private static final boolean DBG = false;
 
-        // class maintenance and general shared data
+    // Context that the service is running in.
     private final Context mContext;
-    private final Handler mHandler;
-    private boolean mSearchablesDirty;
-    private final Searchables mSearchables;
 
-    final SearchDialog mSearchDialog;
-    ISearchManagerCallback mCallback = null;
+    // This field is initialized in initialize(), and then never modified.
+    // It is volatile since it can be accessed by multiple threads.
+    private volatile Searchables mSearchables;
 
-    private final boolean mDisabledOnBoot;
-
-    private static final String DISABLE_SEARCH_PROPERTY = "dev.disablesearchdialog";
+    // This field is initialized in initialize(), and then never modified.
+    // It is volatile since it can be accessed by multiple threads.
+    private volatile SearchDialogWrapper mSearchDialog;
 
     /**
      * Initializes the Search Manager service in the provided system context.
@@ -73,82 +59,71 @@
      */
     public SearchManagerService(Context context)  {
         mContext = context;
-        mHandler = new Handler();
-        mSearchablesDirty = true;
-        mSearchables = new Searchables(context);
-        mSearchDialog = new SearchDialog(context);
-        mSearchDialog.setOnCancelListener(this);
-        mSearchDialog.setOnDismissListener(this);
-
-        // Setup the infrastructure for updating and maintaining the list
-        // of searchable activities.
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        filter.addDataScheme("package");
-        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
-
-        // After startup settles down, preload the searchables list,
-        // which will reduce the delay when the search UI is invoked.
-        mHandler.post(mRunUpdateSearchable);
-
-        // allows disabling of search dialog for stress testing runs
-        mDisabledOnBoot = !TextUtils.isEmpty(SystemProperties.get(DISABLE_SEARCH_PROPERTY));
+        // call initialize() after all pending actions on the main system thread have finished
+        new Handler().post(new Runnable() {
+            public void run() {
+                initialize();
+            }
+        });
     }
 
     /**
-     * Listens for intent broadcasts.
-     *
-     * The primary purpose here is to refresh the "searchables" list
-     * if packages are added/removed.
+     * Initializes the search UI and the list of searchable activities.
      */
-    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+    void initialize() {
+        mSearchables = createSearchables();
+        mSearchDialog = new SearchDialogWrapper(mContext);
+    }
+
+    private Searchables createSearchables() {
+        Searchables searchables = new Searchables(mContext);
+        searchables.buildSearchableList();
+
+        IntentFilter packageFilter = new IntentFilter();
+        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        packageFilter.addDataScheme("package");
+        mContext.registerReceiver(mPackageChangedReceiver, packageFilter);
+
+        return searchables;
+    }
+
+    /**
+     * Refreshes the "searchables" list when packages are added/removed.
+     */
+    private BroadcastReceiver mPackageChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
 
-            // First, test for intents that matter at any time
-            if (action.equals(Intent.ACTION_PACKAGE_ADDED) ||
-                action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
-                action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
-                mSearchablesDirty = true;
-                mHandler.post(mRunUpdateSearchable);
-                return;
+            if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
+                    Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
+                    Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+                if (DBG) Log.d(TAG, "Got " + action);
+                // Dismiss search dialog, since the search context may no longer be valid
+                mSearchDialog.stopSearch();
+                // Update list of searchable activities
+                mSearchables.buildSearchableList();
+                broadcastSearchablesChanged();
             }
         }
     };
 
     /**
-     * This runnable (for the main handler / UI thread) will update the searchables list.
+     * Informs all listeners that the list of searchables has been updated.
      */
-    private Runnable mRunUpdateSearchable = new Runnable() {
-        public void run() {
-            updateSearchablesIfDirty();
-        }
-    };
-
-    /**
-     * Updates the list of searchables, either at startup or in response to
-     * a package add/remove broadcast message.
-     */
-    private void updateSearchables() {
-        if (DBG) debug("updateSearchables()");
-        mSearchables.buildSearchableList();
-        mSearchablesDirty = false;
+    void broadcastSearchablesChanged() {
+        mContext.sendBroadcast(
+                new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED));
     }
 
-    /**
-     * Updates the list of searchables if needed.
-     */
-    private void updateSearchablesIfDirty() {
-        if (mSearchablesDirty) {
-            updateSearchables();
-        }
-    }
+    //
+    // Searchable activities API
+    //
 
     /**
-     * Returns the SearchableInfo for a given activity
+     * Returns the SearchableInfo for a given activity.
      *
      * @param launchActivity The activity from which we're launching this search.
      * @param globalSearch If false, this will only launch the search that has been specifically
@@ -158,226 +133,84 @@
      * @return Returns a SearchableInfo record describing the parameters of the search,
      * or null if no searchable metadata was available.
      */
-    public SearchableInfo getSearchableInfo(ComponentName launchActivity, boolean globalSearch) {
-        updateSearchablesIfDirty();
-        SearchableInfo si = null;
+    public SearchableInfo getSearchableInfo(final ComponentName launchActivity,
+            final boolean globalSearch) {
+        if (mSearchables == null) return null;
         if (globalSearch) {
-            si = mSearchables.getDefaultSearchable();
+            return mSearchables.getDefaultSearchable();
         } else {
             if (launchActivity == null) {
                 Log.e(TAG, "getSearchableInfo(), activity == null");
                 return null;
             }
-            si = mSearchables.getSearchableInfo(launchActivity);
+            return mSearchables.getSearchableInfo(launchActivity);
         }
-
-        return si;
     }
 
     /**
      * Returns a list of the searchable activities that can be included in global search.
      */
     public List<SearchableInfo> getSearchablesInGlobalSearch() {
-        updateSearchablesIfDirty();
+        if (mSearchables == null) return null;
         return mSearchables.getSearchablesInGlobalSearchList();
     }
-    /**
-     * Launches the search UI on the main thread of the service.
-     *
-     * @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean)
-     */
-    public void startSearch(final String initialQuery,
-            final boolean selectInitialQuery,
-            final ComponentName launchActivity,
-            final Bundle appSearchData,
-            final boolean globalSearch,
-            final ISearchManagerCallback searchManagerCallback) {
-        if (DBG) debug("startSearch()");
-        Runnable task = new Runnable() {
-            public void run() {
-                performStartSearch(initialQuery,
-                        selectInitialQuery,
-                        launchActivity,
-                        appSearchData,
-                        globalSearch,
-                        searchManagerCallback);
-            }
-        };
-        mHandler.post(task);
-    }
 
     /**
-     * Actually launches the search. This must be called on the service UI thread.
+     * Returns a list of the searchable activities that handle web searches.
+     * Can be called from any thread.
      */
-    /*package*/ void performStartSearch(String initialQuery,
+    public List<SearchableInfo> getSearchablesForWebSearch() {
+        if (mSearchables == null) return null;
+        return mSearchables.getSearchablesForWebSearchList();
+    }
+
+    /**
+     * Returns the default searchable activity for web searches.
+     * Can be called from any thread.
+     */
+    public SearchableInfo getDefaultSearchableForWebSearch() {
+        if (mSearchables == null) return null;
+        return mSearchables.getDefaultSearchableForWebSearch();
+    }
+
+    /**
+     * Sets the default searchable activity for web searches.
+     * Can be called from any thread.
+     */
+    public void setDefaultWebSearch(final ComponentName component) {
+        if (mSearchables == null) return;
+        mSearchables.setDefaultWebSearch(component);
+        broadcastSearchablesChanged();
+    }
+
+    // Search UI API
+
+    /**
+     * Launches the search UI. Can be called from any thread.
+     *
+     * @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean)
+     */
+    public void startSearch(String initialQuery,
             boolean selectInitialQuery,
             ComponentName launchActivity,
             Bundle appSearchData,
             boolean globalSearch,
             ISearchManagerCallback searchManagerCallback) {
-        if (DBG) debug("performStartSearch()");
-
-        if (mDisabledOnBoot) {
-            Log.d(TAG, "ignoring start search request because " + DISABLE_SEARCH_PROPERTY
-                    + " system property is set.");
-            return;
-        }
-
-        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
-                globalSearch);
-        if (searchManagerCallback != null) {
-            mCallback = searchManagerCallback;
-        }
+        if (mSearchDialog == null) return;
+        mSearchDialog.startSearch(initialQuery,
+                selectInitialQuery,
+                launchActivity,
+                appSearchData,
+                globalSearch,
+                searchManagerCallback);
     }
 
     /**
      * Cancels the search dialog. Can be called from any thread.
      */
     public void stopSearch() {
-        if (DBG) debug("stopSearch()");
-        mHandler.post(new Runnable() {
-            public void run() {
-                performStopSearch();
-            }
-        });
-    }
-
-    /**
-     * Cancels the search dialog. Must be called from the service UI thread.
-     */
-    /*package*/ void performStopSearch() {
-        if (DBG) debug("performStopSearch()");
-        mSearchDialog.cancel();
-    }
-
-    /**
-     * Determines if the Search UI is currently displayed.
-     *
-     * @see SearchManager#isVisible()
-     */
-    public boolean isVisible() {
-        return postAndWait(mIsShowing, false, "isShowing()");
-    }
-
-    private final Callable<Boolean> mIsShowing = new Callable<Boolean>() {
-        public Boolean call() {
-            return mSearchDialog.isShowing();
-        }
-    };
-
-    public Bundle onSaveInstanceState() {
-        return postAndWait(mOnSaveInstanceState, null, "onSaveInstanceState()");
-    }
-
-    private final Callable<Bundle> mOnSaveInstanceState = new Callable<Bundle>() {
-        public Bundle call() {
-            if (mSearchDialog.isShowing()) {
-                return mSearchDialog.onSaveInstanceState();
-            } else {
-                return null;
-            }
-        }
-    };
-
-    public void onRestoreInstanceState(final Bundle searchDialogState) {
-        if (searchDialogState != null) {
-            mHandler.post(new Runnable() {
-                public void run() {
-                    mSearchDialog.onRestoreInstanceState(searchDialogState);
-                }
-            });
-        }
-    }
-
-    public void onConfigurationChanged(final Configuration newConfig) {
-        mHandler.post(new Runnable() {
-            public void run() {
-                if (mSearchDialog.isShowing()) {
-                    mSearchDialog.onConfigurationChanged(newConfig);
-                }
-            }
-        });
-    }
-
-    /**
-     * Called by {@link SearchDialog} when it goes away.
-     */
-    public void onDismiss(DialogInterface dialog) {
-        if (DBG) debug("onDismiss()");
-        if (mCallback != null) {
-            try {
-                mCallback.onDismiss();
-            } catch (RemoteException ex) {
-                Log.e(TAG, "onDismiss() failed: " + ex);
-            }
-        }
-    }
-
-    /**
-     * Called by {@link SearchDialog} when the user or activity cancels search.
-     * When this is called, {@link #onDismiss} is called too.
-     */
-    public void onCancel(DialogInterface dialog) {
-        if (DBG) debug("onCancel()");
-        if (mCallback != null) {
-            try {
-                mCallback.onCancel();
-            } catch (RemoteException ex) {
-                Log.e(TAG, "onCancel() failed: " + ex);
-            }
-        }
-    }
-
-    /**
-     * Returns a list of the searchable activities that handle web searches.
-     */
-    public List<SearchableInfo> getSearchablesForWebSearch() {
-        updateSearchablesIfDirty();
-        return mSearchables.getSearchablesForWebSearchList();
-    }
-
-    /**
-     * Returns the default searchable activity for web searches.
-     */
-    public SearchableInfo getDefaultSearchableForWebSearch() {
-        updateSearchablesIfDirty();
-        return mSearchables.getDefaultSearchableForWebSearch();
-    }
-
-    /**
-     * Sets the default searchable activity for web searches.
-     */
-    public void setDefaultWebSearch(ComponentName component) {
-        mSearchables.setDefaultWebSearch(component);
-    }
-
-    /**
-     * Runs an operation on the handler for the service, blocks until it returns,
-     * and returns the value returned by the operation.
-     *
-     * @param <V> Return value type.
-     * @param callable Operation to run.
-     * @param errorResult Value to return if the operations throws an exception.
-     * @param name Operation name to include in error log messages.
-     * @return The value returned by the operation.
-     */
-    private <V> V postAndWait(Callable<V> callable, V errorResult, String name) {
-        FutureTask<V> task = new FutureTask<V>(callable);
-        mHandler.post(task);
-        try {
-            return task.get();
-        } catch (InterruptedException ex) {
-            Log.e(TAG, "Error calling " + name + ": " + ex);
-            return errorResult;
-        } catch (ExecutionException ex) {
-            Log.e(TAG, "Error calling " + name + ": " + ex);
-            return errorResult;
-        }
-    }
-
-    private static void debug(String msg) {
-        Thread thread = Thread.currentThread();
-        Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
+        if (mSearchDialog == null) return;
+        mSearchDialog.stopSearch();
     }
 
 }
diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java
index 8ef1f15..283555a 100644
--- a/core/java/android/server/search/SearchableInfo.java
+++ b/core/java/android/server/search/SearchableInfo.java
@@ -67,6 +67,7 @@
     private final int mSearchImeOptions;
     private final boolean mIncludeInGlobalSearch;
     private final boolean mQueryAfterZeroResults;
+    private final boolean mAutoUrlDetect;
     private final String mSettingsDescription;
     private final String mSuggestAuthority;
     private final String mSuggestPath;
@@ -288,6 +289,8 @@
                 com.android.internal.R.styleable.Searchable_includeInGlobalSearch, false);
         mQueryAfterZeroResults = a.getBoolean(
                 com.android.internal.R.styleable.Searchable_queryAfterZeroResults, false);
+        mAutoUrlDetect = a.getBoolean(
+                com.android.internal.R.styleable.Searchable_autoUrlDetect, false);
 
         mSettingsDescription = a.getString(
                 com.android.internal.R.styleable.Searchable_searchSettingsDescription);
@@ -667,6 +670,16 @@
     }
 
     /**
+     * Checks whether this searchable activity has auto URL detect turned on.
+     *
+     * @return The value of the <code>autoUrlDetect</code> attribute,
+     *         or <code>false</code> if the attribute is not set.
+     */
+    public boolean autoUrlDetect() {
+        return mAutoUrlDetect;
+    }
+
+    /**
      * Support for parcelable and aidl operations.
      */
     public static final Parcelable.Creator<SearchableInfo> CREATOR
@@ -698,6 +711,7 @@
         mSearchImeOptions = in.readInt();
         mIncludeInGlobalSearch = in.readInt() != 0;
         mQueryAfterZeroResults = in.readInt() != 0;
+        mAutoUrlDetect = in.readInt() != 0;
         
         mSettingsDescription = in.readString();
         mSuggestAuthority = in.readString();
@@ -735,6 +749,7 @@
         dest.writeInt(mSearchImeOptions);
         dest.writeInt(mIncludeInGlobalSearch ? 1 : 0);
         dest.writeInt(mQueryAfterZeroResults ? 1 : 0);
+        dest.writeInt(mAutoUrlDetect ? 1 : 0);
         
         dest.writeString(mSettingsDescription);
         dest.writeString(mSuggestAuthority);
diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java
index c7cc8ed..b959907 100644
--- a/core/java/android/server/search/Searchables.java
+++ b/core/java/android/server/search/Searchables.java
@@ -17,7 +17,6 @@
 package android.server.search;
 
 import com.android.internal.app.ResolverActivity;
-import com.android.internal.R;
 
 import android.app.SearchManager;
 import android.content.ComponentName;
@@ -27,7 +26,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
 import android.os.Bundle;
 import android.util.Log;
 
@@ -264,7 +262,7 @@
         }
 
         // Find the default web search provider.
-        ComponentName webSearchActivity = getPreferredWebSearchActivity();
+        ComponentName webSearchActivity = getPreferredWebSearchActivity(mContext);
         SearchableInfo newDefaultSearchableForWebSearch = null;
         if (webSearchActivity != null) {
             newDefaultSearchableForWebSearch = newSearchablesMap.get(webSearchActivity);
@@ -283,9 +281,6 @@
             mDefaultSearchable = newDefaultSearchable;
             mDefaultSearchableForWebSearch = newDefaultSearchableForWebSearch;
         }
-
-        // Inform all listeners that the list of searchables has been updated.
-        mContext.sendBroadcast(new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED));
     }
 
     /**
@@ -295,9 +290,10 @@
      * @param action Intent action for which this activity is to be set as preferred.
      * @return true if component was detected and set as preferred activity, false if not.
      */
-    private boolean setPreferredActivity(ComponentName component, String action) {
+    private static boolean setPreferredActivity(Context context,
+            ComponentName component, String action) {
         Log.d(LOG_TAG, "Checking component " + component);
-        PackageManager pm = mContext.getPackageManager();
+        PackageManager pm = context.getPackageManager();
         ActivityInfo ai;
         try {
             ai = pm.getActivityInfo(component, 0);
@@ -326,10 +322,10 @@
         return true;
     }
 
-    public ComponentName getPreferredWebSearchActivity() {
+    private static ComponentName getPreferredWebSearchActivity(Context context) {
         // Check if we have a preferred web search activity.
         Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
-        PackageManager pm = mContext.getPackageManager();
+        PackageManager pm = context.getPackageManager();
         ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
 
         if (ri == null || ri.activityInfo.name.equals(ResolverActivity.class.getName())) {
@@ -338,11 +334,11 @@
             // The components in the providers array are checked in the order of declaration so the
             // first one has the highest priority. If the component exists in the system it is set
             // as the preferred activity to handle intent action web search.
-            String[] preferredActivities = mContext.getResources().getStringArray(
+            String[] preferredActivities = context.getResources().getStringArray(
                     com.android.internal.R.array.default_web_search_providers);
             for (String componentName : preferredActivities) {
                 ComponentName component = ComponentName.unflattenFromString(componentName);
-                if (setPreferredActivity(component, Intent.ACTION_WEB_SEARCH)) {
+                if (setPreferredActivity(context, component, Intent.ACTION_WEB_SEARCH)) {
                     return component;
                 }
             }
@@ -354,7 +350,8 @@
             if (cn.flattenToShortString().equals(GOOGLE_SEARCH_COMPONENT_NAME)) {
                 ComponentName enhancedGoogleSearch = ComponentName.unflattenFromString(
                         ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME);
-                if (setPreferredActivity(enhancedGoogleSearch, Intent.ACTION_WEB_SEARCH)) {
+                if (setPreferredActivity(context, enhancedGoogleSearch,
+                        Intent.ACTION_WEB_SEARCH)) {
                     return enhancedGoogleSearch;
                 }
             }
@@ -397,7 +394,7 @@
      * Sets the default searchable activity for web searches.
      */
     public synchronized void setDefaultWebSearch(ComponentName component) {
-        setPreferredActivity(component, Intent.ACTION_WEB_SEARCH);
+        setPreferredActivity(mContext, component, Intent.ACTION_WEB_SEARCH);
         buildSearchableList();
     }
 }
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
old mode 100755
new mode 100644
index 61e182a..ed1e4ff6
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -107,9 +107,7 @@
         public static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x
         public static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x
         public static final int FALLBACK_TTS_USE_DEFAULTS = 0; // false
-        public static final String FALLBACK_TTS_DEFAULT_LANG = "eng";
-        public static final String FALLBACK_TTS_DEFAULT_COUNTRY = "";
-        public static final String FALLBACK_TTS_DEFAULT_VARIANT = "";
+        public static final String FALLBACK_TTS_DEFAULT_SYNTH = "com.svox.pico";
 
         // return codes for a TTS engine's check data activity
         public static final int CHECK_VOICE_DATA_PASS = 1;
@@ -144,10 +142,10 @@
     private OnInitListener mInitListener = null;
     private boolean mStarted = false;
     private final Object mStartLock = new Object();
-    private int mCachedRate = Engine.FALLBACK_TTS_DEFAULT_RATE;
-    private String mCachedLang = Engine.FALLBACK_TTS_DEFAULT_LANG;
-    private String mCachedCountry = Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
-    private String mCachedVariant = Engine.FALLBACK_TTS_DEFAULT_VARIANT;
+    /**
+     * Used to store the cached parameters sent along with each synthesis request to the
+     * TTS service.
+     */
     private String[] mCachedParams;
 
     /**
@@ -163,25 +161,24 @@
         mContext = context;
         mInitListener = listener;
 
-        mCachedParams = new String[2*4]; //4 parameters, store key and value
+        mCachedParams = new String[2*4]; // 4 parameters, store key and value
         mCachedParams[Engine.TTS_PARAM_POSITION_RATE] = Engine.TTS_KEY_PARAM_RATE;
         mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE] = Engine.TTS_KEY_PARAM_LANGUAGE;
         mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY] = Engine.TTS_KEY_PARAM_COUNTRY;
         mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT] = Engine.TTS_KEY_PARAM_VARIANT;
-        updateCachedParamArray();
+
+        mCachedParams[Engine.TTS_PARAM_POSITION_RATE + 1] =
+                String.valueOf(Engine.FALLBACK_TTS_DEFAULT_RATE);
+        // initialize the language cached parameters with the current Locale
+        Locale defaultLoc = Locale.getDefault();
+        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1] = defaultLoc.getISO3Language();
+        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1] = defaultLoc.getISO3Country();
+        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] = defaultLoc.getVariant();
 
         initTts();
     }
 
 
-    private void updateCachedParamArray() {
-        mCachedParams[Engine.TTS_PARAM_POSITION_RATE+1] = String.valueOf(mCachedRate);
-        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE+1] = mCachedLang;
-        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY+1] = mCachedCountry;
-        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT+1] = mCachedVariant;
-    }
-
-
     private void initTts() {
         mStarted = false;
 
@@ -342,14 +339,14 @@
     public int speak(String text, int queueMode, HashMap<String,String> params)
     {
         synchronized (mStartLock) {
+            int result = TTS_ERROR;
             Log.i("TTS received: ", text);
             if (!mStarted) {
-                return TTS_ERROR;
+                return result;
             }
             try {
                 // TODO support extra parameters, passing cache of current parameters for the moment
-                mITts.speak(text, queueMode, mCachedParams);
-                return TTS_SUCCESS;
+                result = mITts.speak(text, queueMode, mCachedParams);
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
@@ -362,8 +359,9 @@
                 // TTS died; restart it.
                 mStarted = false;
                 initTts();
+            } finally {
+              return result;
             }
-            return TTS_ERROR;
         }
     }
 
@@ -383,13 +381,13 @@
     public int playEarcon(String earcon, int queueMode,
             HashMap<String,String> params) {
         synchronized (mStartLock) {
+            int result = TTS_ERROR;
             if (!mStarted) {
-                return TTS_ERROR;
+                return result;
             }
             try {
                 // TODO support extra parameters, passing null for the moment
-                mITts.playEarcon(earcon, queueMode, null);
-                return TTS_SUCCESS;
+                result = mITts.playEarcon(earcon, queueMode, null);
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
@@ -402,8 +400,9 @@
                 // TTS died; restart it.
                 mStarted = false;
                 initTts();
+            } finally {
+              return result;
             }
-            return TTS_ERROR;
         }
     }
 
@@ -420,13 +419,13 @@
      */
     public int playSilence(long durationInMs, int queueMode) {
         synchronized (mStartLock) {
+            int result = TTS_ERROR;
             if (!mStarted) {
-                return TTS_ERROR;
+                return result;
             }
             try {
                 // TODO support extra parameters, passing cache of current parameters for the moment
-                mITts.playSilence(durationInMs, queueMode, mCachedParams);
-                return TTS_SUCCESS;
+                result = mITts.playSilence(durationInMs, queueMode, mCachedParams);
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
@@ -439,8 +438,9 @@
                 // TTS died; restart it.
                 mStarted = false;
                 initTts();
+            } finally {
+              return result;
             }
-            return TTS_ERROR;
         }
     }
 
@@ -482,12 +482,12 @@
      */
     public int stop() {
         synchronized (mStartLock) {
+            int result = TTS_ERROR;
             if (!mStarted) {
-                return TTS_ERROR;
+                return result;
             }
             try {
-                mITts.stop();
-                return TTS_SUCCESS;
+                result = mITts.stop();
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
@@ -500,8 +500,9 @@
                 // TTS died; restart it.
                 mStarted = false;
                 initTts();
+            } finally {
+              return result;
             }
-            return TTS_ERROR;
         }
     }
 
@@ -523,22 +524,23 @@
      */
     public int setSpeechRate(float speechRate) {
         synchronized (mStartLock) {
+            int result = TTS_ERROR;
             if (!mStarted) {
-                return TTS_SUCCESS;
+                return result;
             }
             try {
                 if (speechRate > 0) {
-                    mCachedRate = (int)(speechRate*100);
-                    updateCachedParamArray();
-                    mITts.setSpeechRate(mCachedRate);
-                    return TTS_SUCCESS;
+                    int rate = (int)(speechRate*100);
+                    mCachedParams[Engine.TTS_PARAM_POSITION_RATE + 1] = String.valueOf(rate);
+                    result = mITts.setSpeechRate(rate);
                 }
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
                 initTts();
+            } finally {
+              return result;
             }
-            return TTS_ERROR;
         }
     }
 
@@ -560,20 +562,21 @@
      */
     public int setPitch(float pitch) {
         synchronized (mStartLock) {
+            int result = TTS_ERROR;
             if (!mStarted) {
-                return TTS_ERROR;
+                return result;
             }
             try {
                 if (pitch > 0) {
-                    mITts.setPitch((int)(pitch*100));
-                    return TTS_SUCCESS;
+                    result = mITts.setPitch((int)(pitch*100));
                 }
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
                 initTts();
+            } finally {
+              return result;
             }
-            return TTS_ERROR;
         }
     }
 
@@ -588,26 +591,28 @@
      * @param loc
      *            The locale describing the language to be used.
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating the support status for the locale. See the TTS_LANG_ codes.
      */
     public int setLanguage(Locale loc) {
         synchronized (mStartLock) {
+            int result = TTS_LANG_NOT_SUPPORTED;
             if (!mStarted) {
-                return TTS_ERROR;
+                return result;
             }
             try {
-                mCachedLang = loc.getISO3Language();
-                mCachedCountry = loc.getISO3Country();
-                mCachedVariant = loc.getVariant();
-                updateCachedParamArray();
-                mITts.setLanguage(mCachedLang, mCachedCountry, mCachedVariant);
-                return TTS_SUCCESS;
+                mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1] = loc.getISO3Language();
+                mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1] = loc.getISO3Country();
+                mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] = loc.getVariant();
+                result = mITts.setLanguage(mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1],
+                        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1],
+                        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] );
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
                 initTts();
+            } finally {
+              return result;
             }
-            return TTS_ERROR;
         }
     }
 
@@ -649,18 +654,20 @@
      */
     public int isLanguageAvailable(Locale loc) {
         synchronized (mStartLock) {
+            int result = TTS_LANG_NOT_SUPPORTED;
             if (!mStarted) {
-                return TTS_LANG_NOT_SUPPORTED;
+                return result;
             }
             try {
-                return mITts.isLanguageAvailable(loc.getISO3Language(), loc.getISO3Country(),
-                        loc.getVariant());
+                result = mITts.isLanguageAvailable(loc.getISO3Language(),
+                        loc.getISO3Country(), loc.getVariant());
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
                 initTts();
+            } finally {
+              return result;
             }
-            return TTS_LANG_NOT_SUPPORTED;
         }
     }
 
@@ -681,13 +688,14 @@
     public int synthesizeToFile(String text, HashMap<String,String> params,
             String filename) {
         synchronized (mStartLock) {
+            int result = TTS_ERROR;
             if (!mStarted) {
-                return TTS_ERROR;
+                return result;
             }
             try {
                 // TODO support extra parameters, passing null for the moment
                 if (mITts.synthesizeToFile(text, null, filename)){
-                    return TTS_SUCCESS;
+                    result = TTS_SUCCESS;
                 }
             } catch (RemoteException e) {
                 // TTS died; restart it.
@@ -701,8 +709,9 @@
                 // TTS died; restart it.
                 mStarted = false;
                 initTts();
+            } finally {
+              return result;
             }
-            return TTS_ERROR;
         }
     }
 
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 4179edb..9071bf0 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -109,7 +109,6 @@
      */
     public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation,
             int screenLayout) {
-        int xOffset = 0;
         if (!compatibilityInfo.isConfiguredExpandable()) {
             // Note: this assume that configuration is updated before calling
             // updateMetrics method.
@@ -142,7 +141,6 @@
                 
                 if (defaultWidth < widthPixels) {
                     // content/window's x offset in original pixels
-                    xOffset = ((widthPixels - defaultWidth) / 2);
                     widthPixels = defaultWidth;
                 }
                 if (defaultHeight < heightPixels) {
@@ -154,7 +152,6 @@
                 compatibilityInfo.setExpandable(true);
             }
         }
-        compatibilityInfo.setVisibleRect(xOffset, widthPixels, heightPixels);
         if (compatibilityInfo.isScalingRequired()) {
             float invertedRatio = compatibilityInfo.applicationInvertedScale;
             density *= invertedRatio;
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 7c87248..0f0be79 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -73,7 +73,7 @@
  *   </ul>
  * </li>
  * <li> '\n': 1 byte - an automatically generated newline, used to help detect and recover from log
- *                     corruption and enable stansard unix tools like grep, tail and wc to operate
+ *                     corruption and enable standard unix tools like grep, tail and wc to operate
  *                     on event logs. </li>
  * </ul>
  *
@@ -289,4 +289,13 @@
      */
     public static native void readEvents(int[] tags, Collection<Event> output)
             throws IOException;
+
+    /**
+     * Read events from a file.
+     * @param path to read from
+     * @param output container to add events into
+     * @throws IOException if something goes wrong reading events
+     */
+    public static native void readEvents(String path, Collection<Event> output)
+            throws IOException;
 }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 1e2bc1f..13a6e7a 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -307,7 +307,7 @@
 
         // Use original size if the app specified the size of the view,
         // and let the flinger to scale up.
-        if (mRequestedWidth <= 0 && mTranslator != null && mTranslator.scalingRequired) {
+        if (mRequestedWidth <= 0 && mTranslator != null) {
             myWidth *= appScale;
             myHeight *= appScale;
         }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index a12b14a..ce25913 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -392,6 +392,7 @@
             if (mView == null) {
                 mView = view;
                 mWindowAttributes.copyFrom(attrs);
+                attrs = mWindowAttributes;
 
                 CompatibilityInfo compatibilityInfo =
                         mView.getContext().getResources().getCompatibilityInfo();
@@ -404,11 +405,14 @@
                 }
                 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
 
+                if (!compatibilityInfo.supportsScreen()) {
+                    attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
+                }
+
                 mSoftInputMode = attrs.softInputMode;
                 mWindowAttributesChanged = true;
                 mAttachInfo.mRootView = view;
-                mAttachInfo.mScalingRequired =
-                        mTranslator == null ? false : mTranslator.scalingRequired;
+                mAttachInfo.mScalingRequired = mTranslator == null ? false : true;
                 mAttachInfo.mApplicationScale =
                         mTranslator == null ? 1.0f : mTranslator.applicationScale;
                 if (panelParentView != null) {
@@ -553,13 +557,16 @@
         if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
         if (mCurScrollY != 0 || mTranslator != null) {
             mTempRect.set(dirty);
+            dirty = mTempRect;
             if (mCurScrollY != 0) {
-               mTempRect.offset(0, -mCurScrollY);
+               dirty.offset(0, -mCurScrollY);
             }
             if (mTranslator != null) {
-                mTranslator.translateRectInAppWindowToScreen(mTempRect);
+                mTranslator.translateRectInAppWindowToScreen(dirty);
             }
-            dirty = mTempRect;
+            if (mAttachInfo.mScalingRequired) {
+                dirty.inset(-1, -1);
+            }
         }
         mDirty.union(dirty);
         if (!mWillDrawSoon) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index bdb86d7..e96a15b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -484,11 +484,19 @@
         public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
 
         /** Window flag: special flag to let a window ignore the compatibility scaling.
-         * This is used by SurfaceView to create a window that does not scale the content.
+         * This is used by SurfaceView to pass this info into ViewRoot, and not used
+         * by WindowManager.
          *
          * {@hide} */
         public static final int FLAG_NO_COMPATIBILITY_SCALING = 0x00100000;
 
+        /** Window flag: special flag to limit the size of the window to be
+         * original size ([320x480] x density). Used to create window for applications
+         * running under compatibility mode.
+         *
+         * {@hide} */
+        public static final int FLAG_COMPATIBLE_WINDOW = 0x00200000;
+
         /** Window flag: a special option intended for system dialogs.  When
          * this flag is set, the window will demand focus unconditionally when
          * it is created.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index b2f2e51..899d636 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3024,7 +3024,12 @@
      */
     /* package */ void deleteSelection(int start, int end) {
         mTextGeneration++;
-        mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end);
+        WebViewCore.DeleteSelectionData data
+                = new WebViewCore.DeleteSelectionData();
+        data.mStart = start;
+        data.mEnd = end;
+        data.mTextGeneration = mTextGeneration;
+        mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, data);
     }
 
     /**
@@ -4672,6 +4677,7 @@
         arg.mNewStart = newStart;
         arg.mNewEnd = newEnd;
         mTextGeneration++;
+        arg.mTextGeneration = mTextGeneration;
         mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
     }
 
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 44d8b7e..20f7239 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -370,7 +370,8 @@
 
     // Start: functions that deal with text editing
     private native void nativeReplaceTextfieldText(
-            int oldStart, int oldEnd, String replace, int newStart, int newEnd);
+            int oldStart, int oldEnd, String replace, int newStart, int newEnd,
+            int textGeneration);
 
     private native void passToJs(int gen,
             String currentText, int keyCode, int keyValue, boolean down,
@@ -415,8 +416,10 @@
      *  order, swap them.
      *  @param  start   Beginning of selection to delete.
      *  @param  end     End of selection to delete.
+     *  @param  textGeneration Text generation number when delete was pressed.
      */
-    private native void nativeDeleteSelection(int start, int end);
+    private native void nativeDeleteSelection(int start, int end,
+            int textGeneration);
 
     /**
      *  Set the selection to (start, end) in the focused textfield. If start and
@@ -551,10 +554,17 @@
         byte[] mPostData;
     }
 
+    static class DeleteSelectionData {
+        int mStart;
+        int mEnd;
+        int mTextGeneration;
+    }
+
     static class ReplaceTextData {
         String mReplace;
         int mNewStart;
         int mNewEnd;
+        int mTextGeneration;
     }
 
     static class TouchUpData {
@@ -920,7 +930,8 @@
                         case REPLACE_TEXT:
                             ReplaceTextData rep = (ReplaceTextData) msg.obj;
                             nativeReplaceTextfieldText(msg.arg1, msg.arg2,
-                                    rep.mReplace, rep.mNewStart, rep.mNewEnd);
+                                    rep.mReplace, rep.mNewStart, rep.mNewEnd,
+                                    rep.mTextGeneration);
                             break;
 
                         case PASS_TO_JS: {
@@ -1029,7 +1040,11 @@
                             break;
 
                         case DELETE_SELECTION:
-                            nativeDeleteSelection(msg.arg1, msg.arg2);
+                            DeleteSelectionData deleteSelectionData
+                                    = (DeleteSelectionData) msg.obj;
+                            nativeDeleteSelection(deleteSelectionData.mStart,
+                                    deleteSelectionData.mEnd,
+                                    deleteSelectionData.mTextGeneration);
                             break;
 
                         case SET_SELECTION:
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index c28210d..32e5504 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -348,7 +348,12 @@
                     "ArrayAdapter requires the resource ID to be a TextView", e);
         }
 
-        text.setText(getItem(position).toString());
+        T item = getItem(position);
+        if (item instanceof CharSequence) {
+            text.setText((CharSequence)item);
+        } else {
+            text.setText(item.toString());
+        }
 
         return view;
     }
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 374b0ae..be3dd19 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -823,6 +823,7 @@
      */
     public void setListSelection(int position) {
         if (mPopup.isShowing() && (mDropDownList != null)) {
+            mDropDownList.mListSelectionHidden = false;
             mDropDownList.setSelection(position);
             // ListView.setSelection() will call requestLayout()
         }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index f8a6f89..515b581 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3285,11 +3285,12 @@
 
     /**
      * Returns the checked state of the specified position. The result is only
-     * valid if the choice mode has not been set to {@link #CHOICE_MODE_SINGLE}
+     * valid if the choice mode has been set to {@link #CHOICE_MODE_SINGLE}
      * or {@link #CHOICE_MODE_MULTIPLE}.
      *
      * @param position The item whose checked state to return
-     * @return The item's checked state
+     * @return The item's checked state or <code>false</code> if choice mode
+     *         is invalid
      *
      * @see #setChoiceMode(int)
      */
@@ -3303,7 +3304,7 @@
 
     /**
      * Returns the currently checked item. The result is only valid if the choice
-     * mode has not been set to {@link #CHOICE_MODE_SINGLE}.
+     * mode has been set to {@link #CHOICE_MODE_SINGLE}.
      *
      * @return The position of the currently checked item or
      *         {@link #INVALID_POSITION} if nothing is selected
@@ -3320,10 +3321,12 @@
 
     /**
      * Returns the set of checked items in the list. The result is only valid if
-     * the choice mode has not been set to {@link #CHOICE_MODE_SINGLE}.
+     * the choice mode has not been set to {@link #CHOICE_MODE_NONE}.
      *
      * @return  A SparseBooleanArray which will return true for each call to
-     *          get(int position) where position is a position in the list.
+     *          get(int position) where position is a position in the list,
+     *          or <code>null</code> if the choice mode is set to
+     *          {@link #CHOICE_MODE_NONE}.
      */
     public SparseBooleanArray getCheckedItemPositions() {
         if (mChoiceMode != CHOICE_MODE_NONE) {
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index c9ace0a..381641f 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.content.Context;
+import android.hardware.SensorManager;
 import android.view.ViewConfiguration;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -79,9 +80,9 @@
         mFinished = true;
         mInterpolator = interpolator;
         float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
-        mDeceleration = 9.8f   // g (m/s^2)
-                      * 39.37f // inch/meter
-                      * ppi    // pixels per inch
+        mDeceleration = SensorManager.GRAVITY_EARTH   // g (m/s^2)
+                      * 39.37f                        // inch/meter
+                      * ppi                           // pixels per inch
                       * ViewConfiguration.getScrollFriction();
     }
     
@@ -347,7 +348,11 @@
     }
     
     /**
-     * 
+     * Stops the animation. Contrary to {@link #forceFinished(boolean)},
+     * aborting the animating cause the scroller to move to the final x and y
+     * position
+     *
+     * @see #forceFinished(boolean)
      */
     public void abortAnimation() {
         mCurrX = mFinalX;
@@ -356,10 +361,12 @@
     }
     
     /**
-     * Extend the scroll animation. This allows a running animation to 
-     * scroll further and longer, when used with setFinalX() or setFinalY().
+     * Extend the scroll animation. This allows a running animation to scroll
+     * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
      *
      * @param extend Additional time to scroll in milliseconds.
+     * @see #setFinalX(int)
+     * @see #setFinalY(int)
      */
     public void extendDuration(int extend) {
         int passed = timePassed();
@@ -367,18 +374,37 @@
         mDurationReciprocal = 1.0f / (float)mDuration;
         mFinished = false;
     }
-    
+
+    /**
+     * Returns the time elapsed since the beginning of the scrolling.
+     *
+     * @return The elapsed time in milliseconds.
+     */
     public int timePassed() {
         return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
     }
-    
+
+    /**
+     * Sets the final position (X) for this scroller.
+     *
+     * @param newX The new X offset as an absolute distance from the origin.
+     * @see #extendDuration(int)
+     * @see #setFinalY(int)
+     */
     public void setFinalX(int newX) {
         mFinalX = newX;
         mDeltaX = mFinalX - mStartX;
         mFinished = false;
     }
 
-   public void setFinalY(int newY) {
+    /**
+     * Sets the final position (Y) for this scroller.
+     *
+     * @param newY The new Y offset as an absolute distance from the origin.
+     * @see #extendDuration(int)
+     * @see #setFinalX(int)
+     */
+    public void setFinalY(int newY) {
         mFinalY = newY;
         mDeltaY = mFinalY - mStartY;
         mFinished = false;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d8ed4f0..7eeb1ca 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5760,7 +5760,7 @@
      * Causes words in the text that are longer than the view is wide
      * to be ellipsized instead of broken in the middle.  You may also
      * want to {@link #setSingleLine} or {@link #setHorizontallyScrolling}
-     * to constrain the text toa single line.  Use <code>null</code>
+     * to constrain the text to a single line.  Use <code>null</code>
      * to turn off ellipsizing.
      *
      * @attr ref android.R.styleable#TextView_ellipsize
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 670692f..df957ac 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -65,6 +65,7 @@
      */
     public static final int LENGTH_LONG = 1;
 
+    final Handler mHandler = new Handler();    
     final Context mContext;
     final TN mTN;
     int mDuration;
@@ -84,7 +85,7 @@
      */
     public Toast(Context context) {
         mContext = context;
-        mTN = new TN(context);
+        mTN = new TN();
         mY = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.toast_y_offset);
     }
@@ -229,7 +230,8 @@
     public static Toast makeText(Context context, CharSequence text, int duration) {
         Toast result = new Toast(context);
 
-        LayoutInflater inflate = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        LayoutInflater inflate = (LayoutInflater)
+                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
         TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
         tv.setText(text);
@@ -286,8 +288,7 @@
 
     private static INotificationManager sService;
 
-    static private INotificationManager getService()
-    {
+    static private INotificationManager getService() {
         if (sService != null) {
             return sService;
         }
@@ -295,28 +296,42 @@
         return sService;
     }
 
-    private class TN extends ITransientNotification.Stub
-    {
-        TN(Context context)
-        {
+    private class TN extends ITransientNotification.Stub {
+        final Runnable mShow = new Runnable() {
+            public void run() {
+                handleShow();
+            }
+        };
+
+        final Runnable mHide = new Runnable() {
+            public void run() {
+                handleHide();
+            }
+        };
+
+        private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
+        
+        WindowManagerImpl mWM;
+
+        TN() {
             // XXX This should be changed to use a Dialog, with a Theme.Toast
             // defined that sets up the layout params appropriately.
-            mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
-            mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
-            mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+            final WindowManager.LayoutParams params = mParams;
+            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+            params.width = WindowManager.LayoutParams.WRAP_CONTENT;
+            params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                     | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                     | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
-            mParams.format = PixelFormat.TRANSLUCENT;
-            mParams.windowAnimations = com.android.internal.R.style.Animation_Toast;
-            mParams.type = WindowManager.LayoutParams.TYPE_TOAST;
-            mParams.setTitle("Toast");
+            params.format = PixelFormat.TRANSLUCENT;
+            params.windowAnimations = com.android.internal.R.style.Animation_Toast;
+            params.type = WindowManager.LayoutParams.TYPE_TOAST;
+            params.setTitle("Toast");
         }
 
         /**
          * schedule handleShow into the right thread
          */
-        public void show()
-        {
+        public void show() {
             if (localLOGV) Log.v(TAG, "SHOW: " + this);
             mHandler.post(mShow);
         }
@@ -324,14 +339,12 @@
         /**
          * schedule handleHide into the right thread
          */
-        public void hide()
-        {
+        public void hide() {
             if (localLOGV) Log.v(TAG, "HIDE: " + this);
             mHandler.post(mHide);
         }
 
-        public void handleShow()
-        {
+        public void handleShow() {
             if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
                     + " mNextView=" + mNextView);
             if (mView != mNextView) {
@@ -361,8 +374,7 @@
             }
         }
 
-        public void handleHide()
-        {
+        public void handleHide() {
             if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
             if (mView != null) {
                 // note: checking parent() just to make sure the view has
@@ -377,24 +389,5 @@
                 mView = null;
             }
         }
-
-        Runnable mShow = new Runnable() {
-            public void run() {
-                handleShow();
-            }
-        };
-
-        Runnable mHide = new Runnable() {
-            public void run() {
-                handleHide();
-            }
-        };
-
-        private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
-        
-        WindowManagerImpl mWM;
     }
-
-    final Handler mHandler = new Handler();
 }
-
diff --git a/core/java/com/google/android/gdata2/client/AndroidGDataClient.java b/core/java/com/google/android/gdata2/client/AndroidGDataClient.java
new file mode 100644
index 0000000..7ac44c9
--- /dev/null
+++ b/core/java/com/google/android/gdata2/client/AndroidGDataClient.java
@@ -0,0 +1,584 @@
+// Copyright 2007 The Android Open Source Project
+
+package com.google.android.gdata2.client;
+
+import com.google.android.net.GoogleHttpClient;
+import com.google.wireless.gdata2.client.GDataClient;
+import com.google.wireless.gdata2.client.HttpException;
+import com.google.wireless.gdata2.client.QueryParams;
+import com.google.wireless.gdata2.data.StringUtils;
+import com.google.wireless.gdata2.parser.ParseException;
+import com.google.wireless.gdata2.serializer.GDataSerializer;
+import com.google.android.gdata2.client.QueryParamsImpl;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.entity.AbstractHttpEntity;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.http.AndroidHttpClient;
+import android.text.TextUtils;
+import android.util.Config;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.BufferedInputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+
+/**
+ * Implementation of a GDataClient using GoogleHttpClient to make HTTP
+ * requests.  Always issues GETs and POSTs, using the X-HTTP-Method-Override
+ * header when a PUT or DELETE is desired, to avoid issues with firewalls, etc.,
+ * that do not allow methods other than GET or POST.
+ */
+public class AndroidGDataClient implements GDataClient {
+
+    private static final String TAG = "GDataClient";
+    private static final boolean DEBUG = false;
+    private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
+
+    private static final String X_HTTP_METHOD_OVERRIDE =
+        "X-HTTP-Method-Override";
+
+    private static final String DEFAULT_USER_AGENT_APP_VERSION = "Android-GData/1.2";
+
+    private static final int MAX_REDIRECTS = 10;
+    private static String DEFAULT_GDATA_VERSION = "2.0";
+
+
+    private String mGDataVersion; 
+    private final GoogleHttpClient mHttpClient;
+    private ContentResolver mResolver;
+
+    /**
+     * Interface for creating HTTP requests.  Used by
+     * {@link AndroidGDataClient#createAndExecuteMethod}, since HttpUriRequest does not allow for
+     * changing the URI after creation, e.g., when you want to follow a redirect.
+     */
+    private interface HttpRequestCreator {
+        HttpUriRequest createRequest(URI uri);
+    }
+
+    private static class GetRequestCreator implements HttpRequestCreator {
+        public GetRequestCreator() {
+        }
+
+        public HttpUriRequest createRequest(URI uri) {
+            HttpGet get = new HttpGet(uri);
+            return get;
+        }
+    }
+
+    private static class PostRequestCreator implements HttpRequestCreator {
+        private final String mMethodOverride;
+        private final HttpEntity mEntity;
+        public PostRequestCreator(String methodOverride, HttpEntity entity) {
+            mMethodOverride = methodOverride;
+            mEntity = entity;
+        }
+
+        public HttpUriRequest createRequest(URI uri) {
+            HttpPost post = new HttpPost(uri);
+            if (mMethodOverride != null) {
+                post.addHeader(X_HTTP_METHOD_OVERRIDE, mMethodOverride);
+            }
+            post.setEntity(mEntity);
+            return post;
+        }
+    }
+
+    // MAJOR TODO: make this work across redirects (if we can reset the InputStream).
+    // OR, read the bits into a local buffer (yuck, the media could be large).
+    private static class MediaPutRequestCreator implements HttpRequestCreator {
+        private final InputStream mMediaInputStream;
+        private final String mContentType;
+        public MediaPutRequestCreator(InputStream mediaInputStream, String contentType) {
+            mMediaInputStream = mediaInputStream;
+            mContentType = contentType;
+        }
+
+        public HttpUriRequest createRequest(URI uri) {
+            HttpPost post = new HttpPost(uri);
+            post.addHeader(X_HTTP_METHOD_OVERRIDE, "PUT");
+            // mMediaInputStream.reset();
+            InputStreamEntity entity = new InputStreamEntity(mMediaInputStream,
+                    -1 /* read until EOF */);
+            entity.setContentType(mContentType);
+            post.setEntity(entity);
+            return post;
+        }
+    }
+
+   
+    /**
+     * Creates a new AndroidGDataClient.
+     * 
+     * @param context The ContentResolver to get URL rewriting rules from
+     * through the Android proxy server, using null to indicate not using proxy.
+     * The context will also be used by GoogleHttpClient for configuration of 
+     * SSL session persistence.
+     */
+    public AndroidGDataClient(Context context) {
+       this(context, DEFAULT_USER_AGENT_APP_VERSION);
+    }
+
+    /**
+     * Creates a new AndroidGDataClient.
+     *
+     * @param context The ContentResolver to get URL rewriting rules from
+     * through the Android proxy server, using null to indicate not using proxy.
+     * The context will also be used by GoogleHttpClient for configuration of
+     * SSL session persistence.
+     * @param appAndVersion The application name and version to be used as the basis of the
+     * User-Agent.  e.g., Android-GData/1.5.0.
+     */
+    public AndroidGDataClient(Context context, String appAndVersion) {
+        this(context, appAndVersion, DEFAULT_GDATA_VERSION);
+    }
+
+    /**
+     * Creates a new AndroidGDataClient.
+     *
+     * @param context The ContentResolver to get URL rewriting rules from
+     * through the Android proxy server, using null to indicate not using proxy.
+     * The context will also be used by GoogleHttpClient for configuration of
+     * SSL session persistence.
+     * @param appAndVersion The application name and version to be used as the basis of the
+     * User-Agent.  e.g., Android-GData/1.5.0. 
+     * @param gdataVersion The gdata service version that should be 
+     * used, e.g. "2.0" 
+     *  
+     */
+    public AndroidGDataClient(Context context, String appAndVersion, String gdataVersion) {
+        mHttpClient = new GoogleHttpClient(context, appAndVersion,
+                true /* gzip capable */);
+        mHttpClient.enableCurlLogging(TAG, Log.VERBOSE);
+        mResolver = context.getContentResolver();
+        mGDataVersion = gdataVersion;
+    }
+
+
+    public void close() {
+        mHttpClient.close();
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see GDataClient#encodeUri(java.lang.String)
+     */
+    public String encodeUri(String uri) {
+        String encodedUri;
+        try {
+            encodedUri = URLEncoder.encode(uri, "UTF-8");
+        } catch (UnsupportedEncodingException uee) {
+            // should not happen.
+            Log.e("JakartaGDataClient",
+                  "UTF-8 not supported -- should not happen.  "
+                  + "Using default encoding.", uee);
+            encodedUri = URLEncoder.encode(uri);
+        }
+        return encodedUri;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see com.google.wireless.gdata.client.GDataClient#createQueryParams()
+     */
+    public QueryParams createQueryParams() {
+        return new QueryParamsImpl();
+    }
+
+    // follows redirects
+    private InputStream createAndExecuteMethod(HttpRequestCreator creator,
+                                               String uriString,
+                                               String authToken,
+                                               String eTag,
+                                               String protocolVersion)
+        throws HttpException, IOException {
+
+        HttpResponse response = null;
+        int status = 500;
+        int redirectsLeft = MAX_REDIRECTS;
+
+        URI uri;
+        try {
+            uri = new URI(uriString);
+        } catch (URISyntaxException use) {
+            Log.w(TAG, "Unable to parse " + uriString + " as URI.", use);
+            throw new IOException("Unable to parse " + uriString + " as URI: "
+                    + use.getMessage());
+        }
+
+        // we follow redirects ourselves, since we want to follow redirects even on POSTs, which
+        // the HTTP library does not do.  following redirects ourselves also allows us to log
+        // the redirects using our own logging.
+        while (redirectsLeft > 0) {
+
+            HttpUriRequest request = creator.createRequest(uri);
+
+            AndroidHttpClient.modifyRequestToAcceptGzipResponse(request);
+            // only add the auth token if not null (to allow for GData feeds that do not require
+            // authentication.)
+            if (!TextUtils.isEmpty(authToken)) {
+                request.addHeader("Authorization", "GoogleLogin auth=" + authToken);
+            }
+
+            // while by default we have a 2.0 in this variable, it is possible to construct
+            // a client that has an empty version field, to work with 1.0 services. 
+            if (!TextUtils.isEmpty(mGDataVersion)) {
+                request.addHeader("GData-Version", mGDataVersion);
+            }
+
+            // if we have a passed down eTag value, we need to add several headers
+            if (!TextUtils.isEmpty(eTag)) { 
+                String method = request.getMethod();
+                if ("GET".equals(method)) {
+                    // add the none match header, if the resource is not changed
+                    // this request will result in a 304 now.
+                    request.addHeader("If-None-Match", eTag);
+                } else if ("DELETE".equals(method) 
+                           || "PUT".equals(method)) {
+                    // now we send an if-match, but only if the passed in eTag is a strong eTag
+                    // as this only makes sense for a strong eTag
+                     if (eTag.startsWith("W/") == false) {
+                         request.addHeader("If-Match", eTag);
+                     }
+                }
+            }
+
+
+            if (LOCAL_LOGV) {
+                for (Header h : request.getAllHeaders()) {
+                    Log.v(TAG, h.getName() + ": " + h.getValue());
+                }
+            }
+
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Executing " + request.getRequestLine().toString());
+            }
+
+            response = null;
+
+            try {
+                response = mHttpClient.execute(request);
+            } catch (IOException ioe) {
+                Log.w(TAG, "Unable to execute HTTP request." + ioe);
+                throw ioe;
+            }
+
+            StatusLine statusLine = response.getStatusLine();
+            if (statusLine == null) {
+                Log.w(TAG, "StatusLine is null.");
+                throw new NullPointerException("StatusLine is null -- should not happen.");
+            }
+
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, response.getStatusLine().toString());
+                for (Header h : response.getAllHeaders()) {
+                    Log.d(TAG, h.getName() + ": " + h.getValue());
+                }
+            }
+            status = statusLine.getStatusCode();
+
+            HttpEntity entity = response.getEntity();
+
+            if ((status >= 200) && (status < 300) && entity != null) {
+                InputStream in = AndroidHttpClient.getUngzippedContent(entity);
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    in = logInputStreamContents(in);
+                }
+                return in;
+            }
+
+            // TODO: handle 301, 307?
+            // TODO: let the http client handle the redirects, if we can be sure we'll never get a
+            // redirect on POST.
+            if (status == 302) {
+                // consume the content, so the connection can be closed.
+                entity.consumeContent();
+                Header location = response.getFirstHeader("Location");
+                if (location == null) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Redirect requested but no Location "
+                                + "specified.");
+                    }
+                    break;
+                }
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Following redirect to " + location.getValue());
+                }
+                try {
+                    uri = new URI(location.getValue());
+                } catch (URISyntaxException use) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Unable to parse " + location.getValue() + " as URI.", use);
+                        throw new IOException("Unable to parse " + location.getValue()
+                                + " as URI.");
+                    }
+                    break;
+                }
+                --redirectsLeft;
+            } else {
+                break;
+            }
+        }
+
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "Received " + status + " status code.");
+        }
+        String errorMessage = null;
+        HttpEntity entity = response.getEntity();
+        try {
+            if (response != null && entity != null) {
+                InputStream in = AndroidHttpClient.getUngzippedContent(entity);
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                byte[] buf = new byte[8192];
+                int bytesRead = -1;
+                while ((bytesRead = in.read(buf)) != -1) {
+                    baos.write(buf, 0, bytesRead);
+                }
+                // TODO: use appropriate encoding, picked up from Content-Type.
+                errorMessage = new String(baos.toByteArray());
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, errorMessage);
+                }
+            }
+        } finally {
+            if (entity != null) {
+                entity.consumeContent();
+            }
+        }
+        String exceptionMessage = "Received " + status + " status code";
+        if (errorMessage != null) {
+            exceptionMessage += (": " + errorMessage);
+        }
+        throw new HttpException(exceptionMessage, status, null /* InputStream */);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see GDataClient#getFeedAsStream(java.lang.String, java.lang.String)
+     */
+    public InputStream getFeedAsStream(String feedUrl,
+                                       String authToken,
+                                       String eTag,
+                                       String protocolVersion)
+        throws HttpException, IOException {
+
+        InputStream in = createAndExecuteMethod(new GetRequestCreator(), feedUrl, authToken, eTag, protocolVersion);
+        if (in != null) {
+            return in;
+        }
+        throw new IOException("Unable to access feed.");
+    }
+
+    /**
+     * Log the contents of the input stream.
+     * The original input stream is consumed, so the caller must use the
+     * BufferedInputStream that is returned.
+     * @param in InputStream
+     * @return replacement input stream for caller to use
+     * @throws IOException
+     */
+    private InputStream logInputStreamContents(InputStream in) throws IOException {
+        if (in == null) {
+            return in;
+        }
+        // bufferSize is the (arbitrary) maximum amount to log.
+        // The original InputStream is wrapped in a
+        // BufferedInputStream with a 16K buffer.  This lets
+        // us read up to 16K, write it to the log, and then
+        // reset the stream so the the original client can
+        // then read the data.  The BufferedInputStream
+        // provides the mark and reset support, even when
+        // the original InputStream does not.
+        final int bufferSize = 16384;
+        BufferedInputStream bin = new BufferedInputStream(in, bufferSize);
+        bin.mark(bufferSize);
+        int wanted = bufferSize;
+        int totalReceived = 0;
+        byte buf[] = new byte[wanted];
+        while (wanted > 0) {
+            int got = bin.read(buf, totalReceived, wanted);
+            if (got <= 0) break; // EOF
+            wanted -= got;
+            totalReceived += got;
+        }
+        Log.d(TAG, new String(buf, 0, totalReceived, "UTF-8"));
+        bin.reset();
+        return bin;
+    }
+
+    public InputStream getMediaEntryAsStream(String mediaEntryUrl, String authToken, String eTag, String protocolVersion)
+            throws HttpException, IOException {
+
+        InputStream in = createAndExecuteMethod(new GetRequestCreator(), mediaEntryUrl, authToken, eTag, protocolVersion);
+
+        if (in != null) {
+            return in;
+        }
+        throw new IOException("Unable to access media entry.");
+    }
+
+    /* (non-Javadoc)
+    * @see GDataClient#createEntry
+    */
+    public InputStream createEntry(String feedUrl,
+                                   String authToken,
+                                   String protocolVersion, 
+                                   GDataSerializer entry)
+        throws HttpException, IOException {
+
+        HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_CREATE);
+        InputStream in = createAndExecuteMethod(
+                new PostRequestCreator(null /* override */, entity),
+                feedUrl,
+                authToken,
+                null,
+                protocolVersion);
+        if (in != null) {
+            return in;
+        }
+        throw new IOException("Unable to create entry.");
+    }
+
+    /* (non-Javadoc)
+     * @see GDataClient#updateEntry
+     */
+    public InputStream updateEntry(String editUri,
+                                   String authToken,
+                                   String eTag,
+                                   String protocolVersion, 
+                                   GDataSerializer entry)
+        throws HttpException, IOException {
+        HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_UPDATE);
+        InputStream in = createAndExecuteMethod(
+                new PostRequestCreator("PUT", entity),
+                editUri,
+                authToken,
+                eTag,
+                protocolVersion);
+        if (in != null) {
+            return in;
+        }
+        throw new IOException("Unable to update entry.");
+    }
+
+    /* (non-Javadoc)
+     * @see GDataClient#deleteEntry
+     */
+    public void deleteEntry(String editUri, String authToken, String eTag)
+        throws HttpException, IOException {
+        if (StringUtils.isEmpty(editUri)) {
+            throw new IllegalArgumentException(
+                    "you must specify an non-empty edit url");
+        }
+        InputStream in =
+            createAndExecuteMethod(
+                    new PostRequestCreator("DELETE", null /* entity */),
+                    editUri,
+                    authToken,
+                    eTag,
+                    null /* protocolVersion, not required for a delete */);
+        if (in == null) {
+            throw new IOException("Unable to delete entry.");
+        }
+        try {
+            in.close();
+        } catch (IOException ioe) {
+            // ignore
+        }
+    }
+
+    public InputStream updateMediaEntry(String editUri, String authToken, String eTag,
+            String protocolVersion, InputStream mediaEntryInputStream, String contentType)
+        throws HttpException, IOException {
+        InputStream in = createAndExecuteMethod(
+                new MediaPutRequestCreator(mediaEntryInputStream, contentType),
+                editUri,
+                authToken,
+                eTag,
+                protocolVersion);
+        if (in != null) {
+            return in;
+        }
+        throw new IOException("Unable to write media entry.");
+    }
+
+    private HttpEntity createEntityForEntry(GDataSerializer entry, int format) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            entry.serialize(baos, format);
+        } catch (IOException ioe) {
+            Log.e(TAG, "Unable to serialize entry.", ioe);
+            throw ioe;
+        } catch (ParseException pe) {
+            Log.e(TAG, "Unable to serialize entry.", pe);
+            throw new IOException("Unable to serialize entry: " + pe.getMessage());
+        }
+
+        byte[] entryBytes = baos.toByteArray();
+
+        if (entryBytes != null && Log.isLoggable(TAG, Log.DEBUG)) {
+            try {
+                Log.d(TAG, "Serialized entry: " + new String(entryBytes, "UTF-8"));
+            } catch (UnsupportedEncodingException uee) {
+                // should not happen
+                throw new IllegalStateException("UTF-8 should be supported!",
+                        uee);
+            }
+        }
+
+        AbstractHttpEntity entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver);
+        entity.setContentType(entry.getContentType());
+        return entity;
+    }
+
+    /**
+     * Connects to a GData server (specified by the batchUrl) and submits a
+     * batch for processing.  The response from the server is returned as an
+     * {@link InputStream}.  The caller is responsible for calling
+     * {@link InputStream#close()} on the returned {@link InputStream}.
+     *
+     * @param batchUrl The batch url to which the batch is submitted.
+     * @param authToken the authentication token that should be used when
+     * submitting the batch.
+     * @param protocolVersion The version of the protocol that 
+     *                 should be used for this request.
+     * @param batch The batch of entries to submit.
+     * @throws IOException Thrown if an io error occurs while communicating with
+     * the service.
+     * @throws HttpException if the service returns an error response.
+     */
+    public InputStream submitBatch(String batchUrl,
+       String authToken,
+       String protocolVersion,
+       GDataSerializer batch)
+       throws HttpException, IOException
+    {
+        HttpEntity entity = createEntityForEntry(batch, GDataSerializer.FORMAT_BATCH);
+        InputStream in = createAndExecuteMethod(
+                new PostRequestCreator("POST", entity),
+                batchUrl,
+                authToken,
+                null,
+                protocolVersion);
+        if (in != null) {
+            return in;
+        }
+        throw new IOException("Unable to process batch request.");
+    }
+}   
+
diff --git a/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java b/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java
new file mode 100644
index 0000000..f097706
--- /dev/null
+++ b/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java
@@ -0,0 +1,31 @@
+package com.google.android.gdata2.client;
+
+import com.google.wireless.gdata2.parser.xml.XmlParserFactory;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.util.Xml;
+
+/**
+ * XmlParserFactory for the Android platform.
+ */
+public class AndroidXmlParserFactory implements XmlParserFactory {
+
+    /*
+     * (non-javadoc)
+     * @see XmlParserFactory#createParser
+     */
+    public XmlPullParser createParser() throws XmlPullParserException {
+        return Xml.newPullParser();
+    }
+
+    /*
+     * (non-javadoc)
+     * @see XmlParserFactory#createSerializer
+     */
+    public XmlSerializer createSerializer() throws XmlPullParserException {
+        return Xml.newSerializer();
+    }
+}
diff --git a/core/java/com/google/android/gdata2/client/QueryParamsImpl.java b/core/java/com/google/android/gdata2/client/QueryParamsImpl.java
new file mode 100644
index 0000000..a26f4ce
--- /dev/null
+++ b/core/java/com/google/android/gdata2/client/QueryParamsImpl.java
@@ -0,0 +1,99 @@
+package com.google.android.gdata2.client;
+import com.google.wireless.gdata2.client.QueryParams;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Simple implementation of the QueryParams interface.
+ */
+// TODO: deal with categories
+public class QueryParamsImpl extends QueryParams {
+
+    private final Map<String,String> mParams = new HashMap<String,String>();
+
+    /**
+     * Creates a new empty QueryParamsImpl.
+     */
+    public QueryParamsImpl() {
+    }
+
+    @Override
+    public void clear() {
+        setEntryId(null);
+        mParams.clear();
+    }
+
+    @Override
+    public String generateQueryUrl(String feedUrl) {
+
+        if (TextUtils.isEmpty(getEntryId()) &&
+            mParams.isEmpty()) {
+            // nothing to do
+            return feedUrl;
+        }
+
+        // handle entry IDs
+        if (!TextUtils.isEmpty(getEntryId())) {
+            if (!mParams.isEmpty()) {
+                throw new IllegalStateException("Cannot set both an entry ID "
+                        + "and other query paramters.");
+            }
+            return feedUrl + '/' + getEntryId();
+        }
+
+        // otherwise, append the querystring params.
+        StringBuilder sb = new StringBuilder();
+        sb.append(feedUrl);
+        Set<String> params = mParams.keySet();
+        boolean first = true;
+        if (feedUrl.contains("?")) {
+            first = false;
+        } else {
+            sb.append('?');
+        }
+        for (String param : params) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append('&');
+            }
+            sb.append(param);
+            sb.append('=');
+            String value = mParams.get(param);
+            String encodedValue = null;
+
+            try {
+                encodedValue = URLEncoder.encode(value, "UTF-8");
+            } catch (UnsupportedEncodingException uee) {
+                // should not happen.
+                Log.w("QueryParamsImpl",
+                      "UTF-8 not supported -- should not happen.  "
+                      + "Using default encoding.", uee);
+                encodedValue = URLEncoder.encode(value);
+            }
+            sb.append(encodedValue);
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String getParamValue(String param) {
+        if (!(mParams.containsKey(param))) {
+            return null;
+        }
+        return mParams.get(param);
+    }
+
+    @Override
+    public void setParamValue(String param, String value) {
+        mParams.put(param, value);
+    }
+
+}
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 83d2502..676ca3a 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -55,6 +55,7 @@
     ~JNICameraContext() { release(); }
     virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
     virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr);
+    virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
     sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; }
     void release();
 
@@ -188,6 +189,12 @@
     }
 }
 
+void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr)
+{
+    // TODO: plumb up to Java. For now, just drop the timestamp
+    postData(msgType, dataPtr);
+}
+
 // connect to camera service
 static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
 {
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 0cce3a6..cf3ba7f 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -539,16 +539,17 @@
 
 
 // ----------------------------------------------------------------------------
-static void android_media_AudioTrack_set_playback_rate(JNIEnv *env,  jobject thiz,
+static jint 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);   
+        return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
     } else {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setSampleRate()");
+        return AUDIOTRACK_ERROR;
     }
 }
 
@@ -788,7 +789,7 @@
     {"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},
+                             "(I)I",     (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},
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 5e5103a..34b7c89 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -51,17 +51,17 @@
     size_t len;
     size_t capacity;
     uint8_t* buf;
-    
+
     ByteBuf(size_t initSize) {
         buf = (uint8_t*)malloc(initSize);
         len = 0;
-        capacity = initSize;        
+        capacity = initSize;
     }
-    
+
     ~ByteBuf() {
         free(buf);
     }
-    
+
     bool ensureExtraCapacity(size_t extra) {
         size_t spaceNeeded = len + extra;
         if (spaceNeeded > capacity) {
@@ -77,7 +77,7 @@
             return true;
         }
     }
- 
+
     void putIntEvent(jint value) {
         bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE);
         buf[len++] = EVENT_TYPE_INT;
@@ -162,7 +162,7 @@
  * In class android.util.EventLog:
  *  static native int writeEvent(long tag, long value)
  */
-static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz, 
+static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
                                                   jint tag, jlong value)
 {
     return android_btWriteLog(tag, EVENT_TYPE_LONG, &value, sizeof(value));
@@ -210,6 +210,8 @@
 /*
  * In class android.util.EventLog:
  *  static native void readEvents(int[] tags, Collection<Event> output)
+ *
+ *  Reads events from the event log, typically /dev/log/events
  */
 static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
                                              jintArray tags,
@@ -273,6 +275,80 @@
     env->ReleaseIntArrayElements(tags, tagValues, 0);
 }
 
+/*
+ * In class android.util.EventLog:
+ *  static native void readEvents(String path, Collection<Event> output)
+ *
+ *  Reads events from a file (See Checkin.Aggregation). Events are stored in
+ *  native raw format (logger_entry + payload).
+ */
+static void android_util_EventLog_readEventsFile(JNIEnv* env, jobject clazz, jstring path,
+            jobject out) {
+    if (path == NULL || out == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
+        return;
+    }
+
+    const char *pathString = env->GetStringUTFChars(path, 0);
+    int fd = open(pathString, O_RDONLY | O_NONBLOCK);
+    env->ReleaseStringUTFChars(path, pathString);
+
+    if (fd < 0) {
+        jniThrowIOException(env, errno);
+        return;
+    }
+
+    uint8_t buf[LOGGER_ENTRY_MAX_LEN];
+    for (;;) {
+        // read log entry structure from file
+        int len = read(fd, buf, sizeof(logger_entry));
+        if (len == 0) {
+            break; // end of file
+        } else if (len < 0) {
+            jniThrowIOException(env, errno);
+        } else if ((size_t) len < sizeof(logger_entry)) {
+            jniThrowException(env, "java/io/IOException", "Event header too short");
+            break;
+        }
+
+        // read event payload
+        logger_entry* entry = (logger_entry*) buf;
+        if (entry->len > LOGGER_ENTRY_MAX_PAYLOAD) {
+            jniThrowException(env,
+                    "java/lang/IllegalArgumentException",
+                    "Too much data for event payload. Corrupt file?");
+            break;
+        }
+
+        len = read(fd, buf + sizeof(logger_entry), entry->len);
+        if (len == 0) {
+            break; // end of file
+        } else if (len < 0) {
+            jniThrowIOException(env, errno);
+        } else if ((size_t) len < entry->len) {
+            jniThrowException(env, "java/io/IOException", "Event payload too short");
+            break;
+        }
+
+        // create EventLog$Event and add it to the collection
+        int buffer_size = sizeof(logger_entry) + entry->len;
+        jbyteArray array = env->NewByteArray(buffer_size);
+        if (array == NULL) break;
+
+        jbyte *bytes = env->GetByteArrayElements(array, NULL);
+        memcpy(bytes, buf, buffer_size);
+        env->ReleaseByteArrayElements(array, bytes, 0);
+
+        jobject event = env->NewObject(gEventClass, gEventInitID, array);
+        if (event == NULL) break;
+
+        env->CallBooleanMethod(out, gCollectionAddID, event);
+        env->DeleteLocalRef(event);
+        env->DeleteLocalRef(array);
+    }
+
+    close(fd);
+}
 
 /*
  * JNI registration.
@@ -292,6 +368,10 @@
     { "readEvents",
       "([ILjava/util/Collection;)V",
       (void*) android_util_EventLog_readEvents
+    },
+    { "readEvents",
+      "(Ljava/lang/String;Ljava/util/Collection;)V",
+      (void*) android_util_EventLog_readEventsFile
     }
 };
 
diff --git a/core/res/res/drawable/rate_star_big_half.png b/core/res/res/drawable/rate_star_big_half.png
index e73ca79..9762292 100644
--- a/core/res/res/drawable/rate_star_big_half.png
+++ b/core/res/res/drawable/rate_star_big_half.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_big_off.png b/core/res/res/drawable/rate_star_big_off.png
index b4dfa9d..6b5039f 100644
--- a/core/res/res/drawable/rate_star_big_off.png
+++ b/core/res/res/drawable/rate_star_big_off.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_big_on.png b/core/res/res/drawable/rate_star_big_on.png
index 7442c93..a972db2 100644
--- a/core/res/res/drawable/rate_star_big_on.png
+++ b/core/res/res/drawable/rate_star_big_on.png
Binary files differ
diff --git a/core/res/res/values-en-rUS/strings.xml b/core/res/res/values-en-rUS/strings.xml
index 05f30fc..e17303cd 100644
--- a/core/res/res/values-en-rUS/strings.xml
+++ b/core/res/res/values-en-rUS/strings.xml
@@ -1249,4 +1249,155 @@
     <skip />
     <!-- no translation found for candidates_style (7738463880139922176) -->
     <skip />
+
+    <string-array name="common_nicknames">
+      <item>Albert, Al, Bert, Bertie</item>
+      <item>Alexander, Al, Alex, Lex, Sasha</item>
+      <item>Alexandra, Al, Alex, Allie, Ally, Lex, Lexie, Sandra, Sandy, Sasha</item>
+      <item>Alice, Allie, Ally</item>
+      <item>Alison, Allie, Ally</item>
+      <item>Allison, Allie, Ally</item>
+      <item>Amanda, Mandi, Mandy</item>
+      <item>Andrea, Andie</item>
+      <item>Andrew, Andy, Drew</item>
+      <item>Anthony, Tony, Toni, Tone</item>
+      <item>Arthur, Art, Arty</item>
+      <item>Barbara, Babs, Barb, Barbie</item>
+      <item>Benjamin, Ben, Benji, Benny</item>
+      <item>Bernard, Bern, Bernie</item>
+      <item>Bertram, Bert, Bertie</item>
+      <item>Bradly, Brad</item>
+      <item>Catherine, Cat, Cate, Cath, Catie, Cathy, Kat, Kate, Katie, Kathy</item>
+      <item>Charles, Chuck, Chaz, Charlie, Buck</item>
+      <item>Christine, Chris, Chrissy, Chrissie</item>
+      <item>Christopher, Chris</item>
+      <item>Cynthia, Cindy, Cynth</item>
+      <item>Daniel, Dan, Danny</item>
+      <item>David, Dave</item>
+      <item>Deborah, Deb, Debbie</item>
+      <item>Dennis, Den, Denny, Dean</item>
+      <item>Dolores, Dolly</item>
+      <item>Donald, Don, Donny</item>
+      <item>Donnatella, Donna</item>
+      <item>Dorothea, Dot, Dotty</item>
+      <item>Dorothy, Dot, Dotty</item>
+      <item>Douglas, Doug</item>
+      <item>Edward, Ed, Eddie, Ned, Neddie, Neddy, Ted, Teddy, Teddie</item>
+      <item>Eleanor, Ella, Ellie, Elle</item>
+      <item>Elisabetta, Betta</item>
+      <item>Elizabeth, Beth, Bess, Bessie, Betsy, Betty, Bette, Eliza, Lisa, Liza, Liz</item>
+      <item>Emily, Em, Ems, Emmy</item>
+      <item>Emma, Em, Ems, Emmy</item>
+      <item>Erica, Rikki, Rikkie, Ricky</item>
+      <item>Eugene, Gene</item>
+      <item>Florence, Flo</item>
+      <item>Frances, Fran, Francie</item>
+      <item>Francis, Fran, Frank</item>
+      <item>Frederick, Fred, Freddy</item>
+      <item>Gabriel, Gabe</item>
+      <item>Geoffrey, Jeff</item>
+      <item>Gerald, Gerry</item>
+      <item>Gerard, Gerry</item>
+      <item>Gregory, Greg</item>
+      <item>Harold, Hal, Hank, Harry</item>
+      <item>Henry, Hal, Hank, Harry</item>
+      <item>Herbert, Bert, Bertie</item>
+      <item>Irving, Irv</item>
+      <item>Isabella, Isa, Izzy</item>
+      <item>Jacob, Jake</item>
+      <item>Jacqueline, Jackie</item>
+      <item>James, Jim, Jimmy, Jamie, Jock</item>
+      <item>Janet, Jan</item>
+      <item>Janice, Jan</item>
+      <item>Jason, Jay</item>
+      <item>Jefferson, Jeff</item>
+      <item>Jeffrey, Jeff</item>
+      <item>Jennifer, Jen, Jenny</item>
+      <item>Jerome, Jerry</item>
+      <item>Jessica, Jessie</item>
+      <item>John, Jack, Jacky, Johnny, Jon</item>
+      <item>Jonathan, Jon, John</item>
+      <item>Joseph, Joe, Joey</item>
+      <item>Joshua, Josh</item>
+      <item>Kaitlyn, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+      <item>Katherine, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+      <item>Kathleen, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+      <item>Katrina, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+      <item>Kenneth, Ken</item>
+      <item>Kevin, Kev</item>
+      <item>Laura, Lauri, Laurie</item>
+      <item>Lauren, Lauri, Laurie</item>
+      <item>Laurence, Larry, Lauri, Laurie</item>
+      <item>Lawrence, Larry, Lauri, Laurie</item>
+      <item>Leonard, Leo, Len, Lenny</item>
+      <item>Leopold, Leo, Len, Lenny</item>
+      <item>Madeline, Maddie, Maddy</item>
+      <item>Margaret, Marge, Marg, Maggie, Mags, Meg, Peggy</item>
+      <item>Matthew, Matt, Mattie</item>
+      <item>Maureen, Mo</item>
+      <item>Maurice, Mo</item>
+      <item>Megan, Meg</item>
+      <item>Michael, Mickey, Mick, Mike, Mikey</item>
+      <item>Morris, Mo</item>
+      <item>Nancy, Nan</item>
+      <item>Nathan, Nat, Nate</item>
+      <item>Nathaniel, Nat, Nate</item>
+      <item>Nicholas, Nick</item>
+      <item>Pamela, Pam</item>
+      <item>Patricia, Pat, Patsy, Patty, Trish, Tricia</item>
+      <item>Patrick, Paddy, Pat, Patty, Patter, Rick, Ricky</item>
+      <item>Peter, Pete</item>
+      <item>Philip, Phil</item>
+      <item>Raymond, Ray</item>
+      <item>Rebecca, Becca</item>
+      <item>Richard, Rick, Rich, Dick</item>
+      <item>Robert, Bob, Rob, Robbie, Bobby, Rab</item>
+      <item>Roberta, Bobbie</item>
+      <item>Rodney. Rod</item>
+      <item>Ronald, Ron, Ronnie</item>
+      <item>Rosemary, Rosie, Rose</item>
+      <item>Russell, Russ, Rusty</item>
+      <item>Ryan, Ry</item>
+      <item>Samantha, Sam</item>
+      <item>Samuel, Sam, Sammy</item>
+      <item>Sophia, Sophie</item>
+      <item>Stephanie, Steph, Stephie</item>
+      <item>Stephen, Steve</item>
+      <item>Steven, Steve</item>
+      <item>Stuart, Stu</item>
+      <item>Susan, Sue, Susie, Suzie</item>
+      <item>Suzanne, Sue, Susie, Suzie</item>
+      <item>Teresa, Terrie, Terry</item>
+      <item>Theodora, Teddie, Thea, Theo</item>
+      <item>Theodore, Ted, Teddy, Theo</item>
+      <item>Thomas, Tom, Thom, Tommy</item>
+      <item>Timothy, Tim, Timmy</item>
+      <item>Valerie, Val</item>
+      <item>Veronica, Ronnie, Roni, Nica, Nikki, Nikka</item>
+      <item>Victor, Vic</item>
+      <item>Victoria, Vicky, Vicki, Vickie, Tori</item>
+      <item>Vincent, Vince, Vin, Vinnie</item>
+      <item>Vivian, Vivi</item>
+      <item>Walter, Walt, Wally</item>
+      <item>Wendy, Wen, Wendel</item>
+      <item>William, Bill, Billy, Will, Willy, Liam</item>
+      <item>Yvonna, Vonna</item>
+      <item>Zachary, Zach, Zack, Zac</item>
+   </string-array>
+   <string name="common_name_prefixes">
+      1LT, 1ST, 2LT, 2ND, 3RD, ADMIRAL, CAPT, CAPTAIN, COL, CPT, DR,
+      GEN, GENERAL, LCDR, LT, LTC, LTG, LTJG, MAJ, MAJOR, MG, MR,
+      MRS, MS, PASTOR, PROF, REP, REVEREND, REV, SEN, ST
+   </string>
+   <string name="common_name_suffixes">
+      B.A., BA, D.D.S., DDS, I, II, III, IV, IX, JR, M.A., M.D, MA,
+      MD, MS, PH.D., PHD, SR, V, VI, VII, VIII, X
+   </string>
+   <string name="common_last_name_prefixes">
+      D', DE, DEL, DI, LA, LE, MC, SAN, ST, TER, VAN, VON
+   </string>
+   <string name="common_name_conjunctions">
+      &amp;, AND, OR
+   </string>
+
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b4d9172..ad6d94f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -68,6 +68,9 @@
         <!-- Bright text color. Only differentiates based on the disabled state. -->
         <attr name="textColorPrimaryDisableOnly" format="reference|color" />
 
+        <!-- Bright inverse text color. Only differentiates based on the disabled state. -->
+        <attr name="textColorPrimaryInverseDisableOnly" format="reference|color" />
+
         <!-- Bright text color. This does not differentiate the disabled state. As an example,
              buttons use this since they display the disabled state via the background and not the
              foreground text color. -->
@@ -595,7 +598,7 @@
         <flag name="time" value="0x00000024" />
     </attr>
 
-    <!-- Additional features you can enable in an IME associated with an editor,
+    <!-- Additional features you can enable in an IME associated with an editor
          to improve the integration with your application.  The constants
          here correspond to those defined by
          {@link android.view.inputmethod.EditorInfo#imeOptions}. -->
@@ -679,7 +682,7 @@
     <attr name="y" format="dimension" />
 
     <!-- Specifies how to place the content of an object, both
-         on the x and y axis, within the object itself. -->
+         on the x- and y-axis, within the object itself. -->
     <attr name="gravity">
         <!-- Push object to the top of its container, not changing its size. -->
         <flag name="top" value="0x30" />
@@ -735,7 +738,7 @@
     <attr name="entries" format="reference" />
 
     <!-- Standard gravity constant that a child can supply to its parent.
-         Defines how to place the view, both its x and y axis, within its parent view group. -->
+         Defines how to place the view, both its x- and y-axis, within its parent view group. -->
     <attr name="layout_gravity">
         <!-- Push object to the top of its container, not changing its size. -->
         <flag name="top" value="0x30" />
@@ -1814,7 +1817,7 @@
         <attr name="minEms" format="integer" min="0" />
         <!-- Makes the TextView be at least this many pixels wide -->
         <attr name="minWidth" />
-        <!-- Specifies how to align the text by the view's x and/or y axis
+        <!-- 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
@@ -2885,6 +2888,14 @@
              attribute.</i> -->
         <attr name="searchSettingsDescription" format="string" />
 
+        <!-- If provided and <code>true</code>, URLs entered in the search dialog while searching
+             within this activity would be detected and treated as URLs (show a 'go' button in the
+             keyboard and invoke the browser directly when user launches the URL instead of passing
+             the URL to the activity). If set to <code>false</code> any URLs entered are treated as
+             normal query text.
+             The default value is <code>false</code>. <i>Optional attribute.</i>. -->
+        <attr name="autoUrlDetect" format="boolean" />
+
     </declare-styleable>
 
     <!-- In order to process special action keys during search, you must define them using
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7af49a6..6906e438 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1124,6 +1124,8 @@
   <public type="attr" name="progressBarStyleSmallInverse" />
   <public type="attr" name="progressBarStyleLargeInverse" /> 
   <public type="attr" name="searchSettingsDescription" />
+  <public type="attr" name="textColorPrimaryInverseDisableOnly" />
+  <public type="attr" name="autoUrlDetect" />
 
   <public-padding type="attr" name="donut_resource_pad" end="0x0101029f" />
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7219694..2ba4cbd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1884,6 +1884,13 @@
     <!-- This string appears (on two lines) when you type a number into contacts search, to let you create a contact whose phone number is the number you typed.  The first line will be in bigger type than the second. -->
     <string name="create_contact_using">Create contact\nusing <xliff:g id="number" example="555">%s</xliff:g></string>
 
+    <!-- various string resources for Contacts -->
+    <string-array name="common_nicknames"></string-array>
+    <string name="common_name_prefixes"></string>
+    <string name="common_name_suffixes"></string>
+    <string name="common_last_name_prefixes"></string>
+    <string name="common_name_conjunctions"></string>
+
     <!-- This string array should be overridden by the manufacture to present a list of carrier-id,locale,wifi-channel sets.  This is used at startup to set system defaults by checking the system property ro.carrier for the carrier-id and searching through this array -->
     <!-- An Array of [[Carrier-ID]                     -->
     <!--              [default-locale]                 -->
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index bd6e1df..be836eb 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -44,6 +44,7 @@
         <item name="textColorSecondaryInverse">@android:color/secondary_text_light</item>
         <item name="textColorTertiaryInverse">@android:color/tertiary_text_light</item>
         <item name="textColorPrimaryDisableOnly">@android:color/primary_text_dark_disable_only</item>
+        <item name="textColorPrimaryInverseDisableOnly">@android:color/primary_text_light_disable_only</item>
         <item name="textColorPrimaryNoDisable">@android:color/primary_text_dark_nodisable</item>
         <item name="textColorSecondaryNoDisable">@android:color/secondary_text_dark_nodisable</item>
         <item name="textColorPrimaryInverseNoDisable">@android:color/primary_text_light_nodisable</item>
@@ -220,6 +221,7 @@
         <item name="textColorSecondaryInverse">@android:color/secondary_text_dark</item>
         <item name="textColorTertiaryInverse">@android:color/tertiary_text_dark</item>
         <item name="textColorPrimaryDisableOnly">@android:color/primary_text_light_disable_only</item>
+        <item name="textColorPrimaryInverseDisableOnly">@android:color/primary_text_dark_disable_only</item>
         <item name="textColorPrimaryNoDisable">@android:color/primary_text_light_nodisable</item>
         <item name="textColorSecondaryNoDisable">@android:color/secondary_text_light_nodisable</item>
         <item name="textColorPrimaryInverseNoDisable">@android:color/primary_text_dark_nodisable</item>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 0bd3276..a3579c7 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -143,8 +143,6 @@
     <!-- This is a list of all the libraries available for application
          code to link against. -->
 
-    <library name="android.awt"
-            file="/system/framework/android.awt.jar" />
     <library name="android.test.runner"
             file="/system/framework/android.test.runner.jar" />
     <library name="com.android.im.plugin"
diff --git a/docs/html/guide/appendix/faq/commontasks.jd b/docs/html/guide/appendix/faq/commontasks.jd
index 0f89e75..259b5d1 100644
--- a/docs/html/guide/appendix/faq/commontasks.jd
+++ b/docs/html/guide/appendix/faq/commontasks.jd
@@ -427,7 +427,7 @@
         <td>Activity</td>
         <td>By setting the theme of an activity to
             {@link android.R.style#Theme_Dialog 
-            android:theme=&quot;android:style/Theme.Dialog&quot;}, 
+            android:theme=&quot;&#064;android:style/Theme.Dialog&quot;}, 
             your activity will take on
             the appearance of a normal dialog, floating on top of whatever was
             underneath it.  You usually set the theme through the
diff --git a/docs/html/guide/developing/tools/adb.jd b/docs/html/guide/developing/tools/adb.jd
index b111047..e8c726f 100644
--- a/docs/html/guide/developing/tools/adb.jd
+++ b/docs/html/guide/developing/tools/adb.jd
@@ -313,7 +313,7 @@
 <li><code>&lt;tty&gt;</code> &mdash; the tty for PPP stream. For example <code>dev:/dev/omap_csmi_ttyl</code>. </li>
 <li><code>[parm]... </code> &mdash zero or more PPP/PPPD options, such as <code>defaultroute</code>, <code>local</code>, <code>notty</code>, etc.</li></ul>
 
-<p>Note that you should not automatically start a PDP connection. </p></td>
+<p>Note that you should not automatically start a PPP connection. </p></td>
 <td></td>
 </tr>
 
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index a9d1090..48e598a 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -44,8 +44,11 @@
 
 <dt><a name="package"></a>{@code package}</dt>
 <dd>A full Java package name for the application.  The name should 
-be unique.  For example, applications published by Google could have 
-names in the form <code>com.google.app.<i>application_name</i></code>.
+be unique.  The name may contain uppercase or lowercase letters ('A'
+through 'Z'), numbers, and underscores ('_').  However, individual
+package name parts may only start with letters.  For example, applications
+published by Google could have names in the form
+<code>com.google.app.<i>application_name</i></code>.
 
 <p>
 The package name serves as a unique identifier for the application.  
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 910e111..4f58a0c 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -101,7 +101,7 @@
     private int[] mStateSet = StateSet.WILD_CARD;
     private int mLevel = 0;
     private int mChangingConfigurations = 0;
-    private Rect mBounds = ZERO_BOUNDS_RECT;
+    private Rect mBounds = ZERO_BOUNDS_RECT;  // lazily becomes a new Rect()
     /*package*/ Callback mCallback = null;
     private boolean mVisible = true;
 
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index d24194f..6677a35 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -278,10 +278,15 @@
         if (name.equals("padding")) {
             TypedArray a = r.obtainAttributes(attrs,
                     com.android.internal.R.styleable.ShapeDrawablePadding);
-            setPadding(a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_left, 0),
-                       a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_top, 0),
-                       a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_right, 0),
-                       a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_bottom, 0));
+            setPadding(
+                    a.getDimensionPixelOffset(
+                            com.android.internal.R.styleable.ShapeDrawablePadding_left, 0),
+                    a.getDimensionPixelOffset(
+                            com.android.internal.R.styleable.ShapeDrawablePadding_top, 0),
+                    a.getDimensionPixelOffset(
+                            com.android.internal.R.styleable.ShapeDrawablePadding_right, 0),
+                    a.getDimensionPixelOffset(
+                            com.android.internal.R.styleable.ShapeDrawablePadding_bottom, 0));
             a.recycle();
             return true;
         }
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 106807e..83ff508 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -197,7 +197,6 @@
 
    /* getters, see constructor */
 
-            uint32_t    sampleRate() const;
             int         format() const;
             int         channelCount() const;
             uint32_t    frameCount() const;
@@ -217,7 +216,7 @@
             status_t    stop();
             bool        stopped() const;
 
-    /* get sample rate for this track
+    /* get sample rate for this record track
      */
             uint32_t    getSampleRate();
 
@@ -323,7 +322,6 @@
     sp<ClientRecordThread>  mClientRecordThread;
     Mutex                   mRecordThreadLock;
 
-    uint32_t                mSampleRate;
     uint32_t                mFrameCount;
 
     audio_track_cblk_t*     mCblk;
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 0955819..2e1fbda 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -201,7 +201,6 @@
     /* getters, see constructor */
 
             int         streamType() const;
-            uint32_t    sampleRate() const;
             int         format() const;
             int         channelCount() const;
             uint32_t    frameCount() const;
@@ -246,7 +245,7 @@
 
     /* set sample rate for this track, mostly used for games' sound effects
      */
-            void        setSampleRate(int sampleRate);
+            status_t    setSampleRate(int sampleRate);
             uint32_t    getSampleRate();
 
     /* Enables looping and sets the start and end points of looping.
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index bda969c..496a739 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -26,7 +26,6 @@
 
 // ----------------------------------------------------------------------------
 
-#define MAX_SAMPLE_RATE     65535
 #define THREAD_PRIORITY_AUDIO_CLIENT (ANDROID_PRIORITY_AUDIO)
 // Maximum cumulated timeout milliseconds before restarting audioflinger thread
 #define MAX_STARTUP_TIMEOUT_MS  3000    // Longer timeout period at startup to cope with A2DP init time
@@ -55,9 +54,9 @@
                     uint16_t    volume[2];
                     uint32_t    volumeLR;
                 };
-                uint16_t    sampleRate;
-                uint16_t    channels;
-                int16_t     flowControlFlag; // underrun (out) or overrrun (in) indication
+                uint32_t    sampleRate;
+                uint8_t     channels;
+                uint8_t     flowControlFlag; // underrun (out) or overrrun (in) indication
                 uint8_t     out;        // out equals 1 for AudioTrack and 0 for AudioRecord
                 uint8_t     forceReady; 
                 uint16_t    bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index 6c847ff..926fddb 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -62,6 +62,8 @@
     class region_rasterizer {
         friend class region_operator;
         virtual void operator()(const RECT& rect) = 0;
+    public:
+        virtual ~region_rasterizer() { };
     };
     
     inline region_operator(int op, const region& lhs, const region& rhs) 
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
index 21cb73b..ed084ca 100644
--- a/include/tts/TtsEngine.h
+++ b/include/tts/TtsEngine.h
@@ -80,6 +80,8 @@
 class TtsEngine
 {
 public:
+    virtual ~TtsEngine() {}
+
     // Initialize the TTS engine and returns whether initialization succeeded.
     // @param synthDoneCBPtr synthesis callback function pointer
     // @return TTS_SUCCESS, or TTS_FAILURE
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index e3544ab..afb07b5 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -18,6 +18,7 @@
 #ifndef ANDROID_HARDWARE_CAMERA_H
 #define ANDROID_HARDWARE_CAMERA_H
 
+#include <utils/Timers.h>
 #include <ui/ICameraClient.h>
 
 namespace android {
@@ -94,6 +95,7 @@
 public:
     virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
     virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0;
+    virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
 };
 
 class Camera : public BnCameraClient, public IBinder::DeathRecipient
@@ -155,6 +157,7 @@
     // ICameraClient interface
     virtual void        notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
     virtual void        dataCallback(int32_t msgType, const sp<IMemory>& dataPtr);
+    virtual void        dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
 
     sp<ICamera>         remote();
 
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
index 2cdcc06..c703f5e 100644
--- a/include/ui/CameraHardwareInterface.h
+++ b/include/ui/CameraHardwareInterface.h
@@ -28,7 +28,7 @@
 typedef void (*preview_callback)(const sp<IMemory>& mem, void* user);
 
 /** Callback for startRecord() */
-typedef void (*recording_callback)(const sp<IMemory>& mem, void* user);
+typedef void (*recording_callback)(nsecs_t timestamp, const sp<IMemory>& mem, void* user);
 
 /** Callback for takePicture() */
 typedef void (*shutter_callback)(void* user);
diff --git a/include/ui/ICameraClient.h b/include/ui/ICameraClient.h
index f38a6aa..236d0f6 100644
--- a/include/ui/ICameraClient.h
+++ b/include/ui/ICameraClient.h
@@ -21,6 +21,7 @@
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
 #include <binder/IMemory.h>
+#include <utils/Timers.h>
 
 namespace android {
 
@@ -31,7 +32,7 @@
 
     virtual void            notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
     virtual void            dataCallback(int32_t msgType, const sp<IMemory>& data) = 0;
-
+    virtual void            dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& data) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/utils/List.h b/include/utils/List.h
index 4041a89..403cd7f 100644
--- a/include/utils/List.h
+++ b/include/utils/List.h
@@ -154,9 +154,9 @@
 
         inline _NodePtr getNode() const { return mpNode; }
 
+        _NodePtr mpNode;    /* should be private, but older gcc fails */
     private:
         friend class List;
-        _NodePtr mpNode;
     };
 
 public:
diff --git a/libs/audioflinger/AudioBufferProvider.h b/libs/audioflinger/AudioBufferProvider.h
index 1a467c7..81c5c39 100644
--- a/libs/audioflinger/AudioBufferProvider.h
+++ b/libs/audioflinger/AudioBufferProvider.h
@@ -36,6 +36,8 @@
         };
         size_t frameCount;
     };
+
+    virtual ~AudioBufferProvider() {}
     
     virtual status_t getNextBuffer(Buffer* buffer) = 0;
     virtual void releaseBuffer(Buffer* buffer) = 0;
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index a5b91f6..82289dd 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -1288,7 +1288,7 @@
     status_t lStatus;
     
     // Resampler implementation limits input sampling rate to 2 x output sampling rate.
-    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+    if (sampleRate > mSampleRate*2) {
         LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
         lStatus = BAD_VALUE;
         goto Exit;
@@ -1603,8 +1603,8 @@
                 new(mCblk) audio_track_cblk_t();
                 // clear all buffers
                 mCblk->frameCount = frameCount;
-                mCblk->sampleRate = (uint16_t)sampleRate;
-                mCblk->channels = (uint16_t)channelCount;
+                mCblk->sampleRate = sampleRate;
+                mCblk->channels = (uint8_t)channelCount;
                 if (sharedBuffer == 0) {
                     mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
                     memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
@@ -1627,8 +1627,8 @@
            new(mCblk) audio_track_cblk_t();
            // clear all buffers
            mCblk->frameCount = frameCount;
-           mCblk->sampleRate = (uint16_t)sampleRate;
-           mCblk->channels = (uint16_t)channelCount;
+           mCblk->sampleRate = sampleRate;
+           mCblk->channels = (uint8_t)channelCount;
            mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
            memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
            // Force underrun condition to avoid false underrun callback until first data is
@@ -1689,7 +1689,7 @@
 }
 
 int AudioFlinger::MixerThread::TrackBase::channelCount() const {
-    return mCblk->channels;
+    return (int)mCblk->channels;
 }
 
 void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
@@ -2274,12 +2274,6 @@
         goto Exit;
     }
 
-    if (sampleRate > MAX_SAMPLE_RATE) {
-        LOGE("Sample rate out of range");
-        lStatus = BAD_VALUE;
-        goto Exit;
-    }
-
     if (mAudioRecordThread == 0) {
         LOGE("Audio record thread not started");
         lStatus = NO_INIT;
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 0aa77ff..12a7725 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -310,6 +310,19 @@
     }
 }
 
+// callback from camera service when timestamped frame is ready
+void Camera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr)
+{
+    sp<CameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        listener->postDataTimestamp(timestamp, msgType, dataPtr);
+    }
+}
+
 void Camera::binderDied(const wp<IBinder>& who) {
     LOGW("ICamera died");
     notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, 0);
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index a88fd48..42b4da4 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -27,6 +27,7 @@
 enum {
     NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
     DATA_CALLBACK,
+    DATA_CALLBACK_TIMESTAMP,
 };
 
 class BpCameraClient: public BpInterface<ICameraClient>
@@ -60,6 +61,17 @@
         remote()->transact(DATA_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
+    // generic data callback from camera service to app with image data
+    void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& imageData)
+    {
+        LOGV("dataCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        data.writeInt64(timestamp);
+        data.writeInt32(msgType);
+        data.writeStrongBinder(imageData->asBinder());
+        remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient");
@@ -80,13 +92,22 @@
             return NO_ERROR;
         } break;
         case DATA_CALLBACK: {
-            LOGV("RAW_CALLBACK");
+            LOGV("DATA_CALLBACK");
             CHECK_INTERFACE(ICameraClient, data, reply);
             int32_t msgType = data.readInt32();
             sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
             dataCallback(msgType, imageData);
             return NO_ERROR;
         } break;
+        case DATA_CALLBACK_TIMESTAMP: {
+            LOGV("DATA_CALLBACK_TIMESTAMP");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            nsecs_t timestamp = data.readInt64();
+            int32_t msgType = data.readInt32();
+            sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
+            dataCallbackTimestamp(timestamp, msgType, imageData);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 86ea66f..ca16f19 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -68,7 +68,7 @@
      * satellites. Depending on conditions, this provider may take a while to return
      * a location fix.
      *
-     * Requires the permission android.permissions.ACCESS_FINE_LOCATION.
+     * Requires the permission android.permission.ACCESS_FINE_LOCATION.
      *
      * <p> The extras Bundle for the GPS location provider can contain the
      * following key/value pairs:
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index cfdf5e3..a65a417 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1063,6 +1063,21 @@
         }
     }
 
+    /**
+     *  @hide
+     *  Reload audio settings. This method is called by Settings backup
+     *  agent when audio settings are restored and causes the AudioService
+     *  to read and apply restored settings.
+     */
+    public void reloadAudioSettings() {
+        IAudioService service = getService();
+        try {
+            service.reloadAudioSettings();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in reloadAudioSettings"+e);
+        }
+    }
+
      /**
       * {@hide}
       */
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 937baad..ee41021 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -508,14 +508,14 @@
     /** @see AudioManager#setRingerMode(int) */
     public void setRingerMode(int ringerMode) {
         if (ringerMode != mRingerMode) {
-            setRingerModeInt(ringerMode);
+            setRingerModeInt(ringerMode, true);
 
             // Send sticky broadcast
             broadcastRingerMode();
         }
     }
 
-    private void setRingerModeInt(int ringerMode) {
+    private void setRingerModeInt(int ringerMode, boolean persist) {
         mRingerMode = ringerMode;
 
         // Adjust volumes via posting message
@@ -543,8 +543,10 @@
         }
         
         // Post a persist ringer mode msg
-        sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG,
-                SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
+        if (persist) {
+            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG,
+                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
+        }
     }
 
     /** @see AudioManager#shouldVibrate(int) */
@@ -914,6 +916,46 @@
         }
     }
 
+    /** @see AudioManager#reloadAudioSettings() */
+    public void reloadAudioSettings() {
+        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
+        readPersistedSettings();
+
+        // restore volume settings
+        int numStreamTypes = AudioSystem.getNumStreamTypes();
+        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+            VolumeStreamState streamState = mStreamStates[streamType];
+
+            // there is no volume setting for STREAM_BLUETOOTH_SCO
+            if (streamType != AudioSystem.STREAM_BLUETOOTH_SCO) {
+                String settingName = System.VOLUME_SETTINGS[streamType];
+                String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
+
+                streamState.mIndex = streamState.getValidIndex(Settings.System.getInt(mContentResolver,
+                        settingName,
+                        AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
+                streamState.mLastAudibleIndex = streamState.getValidIndex(Settings.System.getInt(mContentResolver,
+                        lastAudibleSettingName,
+                        streamState.mIndex > 0 ? streamState.mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
+            }
+            // unmute stream that whas muted but is not affect by mute anymore
+            if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
+                int size = streamState.mDeathHandlers.size();
+                for (int i = 0; i < size; i++) {
+                    streamState.mDeathHandlers.get(i).mMuteCount = 1;
+                    streamState.mDeathHandlers.get(i).mute(false);
+                }
+            }
+            // apply stream volume
+            if (streamState.muteCount() == 0) {
+                AudioSystem.setVolume(streamType, streamState.mVolumes[streamState.mIndex]);
+            }
+        }
+
+        // apply new ringer mode
+        setRingerModeInt(getRingerMode(), false);
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Internal methods
     ///////////////////////////////////////////////////////////////////////////
@@ -1426,7 +1468,7 @@
              * Ensure all stream types that should be affected by ringer mode
              * are in the proper state.
              */
-            setRingerModeInt(getRingerMode());
+            setRingerModeInt(getRingerMode(), false);
         }
         
     }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 3cd841d..5f1be9d 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -425,8 +425,7 @@
     }
     
     /**
-     * Returns the current playback rate in Hz. Note that this rate may differ from the one set
-     * with {@link #setPlaybackRate(int)} as the value effectively used is implementation-dependent.
+     * Returns the current playback rate in Hz.
      */
     public int getPlaybackRate() {
         return native_get_playback_rate();
@@ -651,18 +650,13 @@
      * Sets the playback sample rate for this track. This sets the sampling rate at which
      * the audio data will be consumed and played back, not the original sampling rate of the
      * content. Setting it to half the sample rate of the content will cause the playback to
-     * last twice as long, but will also result result in a negative pitch shift.
-     * The current implementation supports a maximum sample rate of 64kHz.
-     * Use {@link #getSampleRate()} to check the rate actually used in hardware after 
-     * potential clamping.
+     * last twice as long, but will also result in a negative pitch shift.
+     * The valid sample rate range if from 1Hz to twice the value returned by
+     * {@link #getNativeOutputSampleRate(int)}.
      * @param sampleRateInHz the sample rate expressed in Hz
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *    {@link #ERROR_INVALID_OPERATION}
      */
-    // FIXME: the implementation should support twice the hardware output sample rate
-    //   (see {@link #getNativeOutputSampleRate(int)}), but currently
-    //  due to the representation of the sample rate in the native layer, the sample rate
-    //  is limited to 65535Hz
     public int setPlaybackRate(int sampleRateInHz) {
         if (mState != STATE_INITIALIZED) {
             return ERROR_INVALID_OPERATION;
@@ -670,8 +664,7 @@
         if (sampleRateInHz <= 0) {
             return ERROR_BAD_VALUE;
         }
-        native_set_playback_rate(sampleRateInHz);
-        return SUCCESS;
+        return native_set_playback_rate(sampleRateInHz);
     }
 
 
@@ -1031,8 +1024,8 @@
 
     private native final void native_setVolume(float leftVolume, float rightVolume);
 
-    private native final void native_set_playback_rate(int sampleRateInHz);
-    private native final int  native_get_playback_rate();
+    private native final int native_set_playback_rate(int sampleRateInHz);
+    private native final int native_get_playback_rate();
 
     private native final int native_set_marker_pos(int marker);
     private native final int native_get_marker_pos();
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index f5e242d..9a8264f 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -71,4 +71,5 @@
   
     oneway void unloadSoundEffects();
 
+    oneway void reloadAudioSettings();
 }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 298cce9..139fb41 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -34,7 +34,7 @@
 
 import java.io.FileDescriptor;
 import java.io.IOException;
-
+import java.util.Set;
 import java.lang.ref.WeakReference;
 
 /**
@@ -431,6 +431,39 @@
  */
 public class MediaPlayer
 {
+    /**
+       Constant to retrieve only the new metadata since the last
+       call.
+       // FIXME: unhide.
+       // FIXME: add link to getMetadata(boolean, boolean)
+       {@hide}
+     */
+    public static final boolean METADATA_UPDATE_ONLY = true;
+
+    /**
+       Constant to retrieve all the metadata.
+       // FIXME: unhide.
+       // FIXME: add link to getMetadata(boolean, boolean)
+       {@hide}
+     */
+    public static final boolean METADATA_ALL = false;
+
+    /**
+       Constant to enable the metadata filter during retrieval.
+       // FIXME: unhide.
+       // FIXME: add link to getMetadata(boolean, boolean)
+       {@hide}
+     */
+    public static final boolean APPLY_METADATA_FILTER = true;
+
+    /**
+       Constant to disable the metadata filter during retrieval.
+       // FIXME: unhide.
+       // FIXME: add link to getMetadata(boolean, boolean)
+       {@hide}
+     */
+    public static final boolean BYPASS_METADATA_FILTER = false;
+
     static {
         System.loadLibrary("media_jni");
     }
@@ -880,6 +913,52 @@
     public native int getDuration();
 
     /**
+     * Gets the media metadata.
+     *
+     * @param update_only controls whether the full set of available
+     * metadata is returned or just the set that changed since the
+     * last call. See {@see #METADATA_UPDATE_ONLY} and {@see
+     * #METADATA_ALL}.
+     *
+     * @param apply_filter if true only metadata that matches the
+     * filter is returned. See {@see #APPLY_METADATA_FILTER} and {@see
+     * #BYPASS_METADATA_FILTER}.
+     *
+     * @return The metadata, possibly empty. null if an error occured.
+     // FIXME: unhide.
+     * {@hide}
+     */
+    public Metadata getMetadata(final boolean update_only,
+                                final boolean apply_filter) {
+        // FIXME: Implement.
+        return new Metadata();
+    }
+
+    /**
+     * Set a filter for the metadata update notification and update
+     * retrieval. The caller provides 2 set of metadata keys, allowed
+     * and disallowed. The disallow set always takes the precedence
+     * over the allowed one.
+     * Metadata.MATCH_ALL and Metadata.MATCH_NONE are 2 sets available as
+     * shorthands to allow/disallow all or no metadata.
+     *
+     * By default, there is no filter set.
+     *
+     * @param allow Is the set of metadata the client is interested
+     *              receiving new notifications for.
+     * @param disallow Is the set of metadata the client is not interested
+     *                 receiving new notifications for.
+     * @return The call status code.
+     *
+     // FIXME: unhide.
+     * {@hide}
+     */
+    public int setMetadataFilter(Set<Integer> allow, Set<Integer> disallow) {
+        // FIXME: Implement.
+        return 0;
+    }
+
+    /**
      * Releases resources associated with this MediaPlayer object.
      * It is considered good practice to call this method when you're
      * done using the MediaPlayer.
@@ -1306,6 +1385,11 @@
      */
     public static final int MEDIA_INFO_NOT_SEEKABLE = 801;
 
+    /** A new set of metadata is available.
+     * @see android.media.MediaPlayer.OnInfoListener
+     */
+    public static final int MEDIA_INFO_METADATA_UPDATE = 802;
+
     /**
      * Interface definition of a callback to be invoked to communicate some
      * info and/or warning about the media or its playback.
@@ -1322,6 +1406,7 @@
          * <li>{@link #MEDIA_INFO_VIDEO_TRACK_LAGGING}
          * <li>{@link #MEDIA_INFO_BAD_INTERLEAVING}
          * <li>{@link #MEDIA_INFO_NOT_SEEKABLE}
+         * <li>{@link #MEDIA_INFO_METADATA_UPDATE}
          * </ul>
          * @param extra an extra code, specific to the info. Typically
          * implementation dependant.
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
new file mode 100644
index 0000000..80748a9
--- /dev/null
+++ b/media/java/android/media/Metadata.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.graphics.Bitmap;
+import android.util.Log;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+   Class to hold the media's metadata.  Metadata are used
+   for human consumption and can be embedded in the media (e.g
+   shoutcast) or available from an external source. The source can be
+   local (e.g thumbnail stored in the DB) or remote (e.g caption
+   server).
+
+   Metadata is like a Bundle. It is sparse and each key can occur at
+   most once. The key is an integer and the value is the actual metadata.
+
+   The caller is expected to know the type of the metadata and call
+   the right get* method to fetch its value.
+
+   // FIXME: unhide.
+   {@hide}
+ */
+public class Metadata
+{
+    // The metadata are keyed using integers rather than more heavy
+    // weight strings. We considered using Bundle to ship the metadata
+    // between the native layer and the java layer but dropped that
+    // option since keeping in sync a native implementation of Bundle
+    // and the java one would be too burdensome. Besides Bundle uses
+    // String for its keys.
+    // The key range [0 8192) is reserved for the system.
+    //
+    // We manually serialize the data in Parcels. For large memory
+    // blob (bitmaps, raw pictures) we use MemoryFile which allow the
+    // client to make the data purgeable once it is done with it.
+    //
+
+    public static final int ANY = 0;  // Never used for metadata returned, only for filtering.
+
+    // TODO: Should we use numbers compatible with the metadata retriever?
+    public static final int TITLE = 1;           // String
+    public static final int COMMENT = 2;         // String
+    public static final int COPYRIGHT = 3;       // String
+    public static final int ALBUM = 4;           // String
+    public static final int ARTIST = 5;          // String
+    public static final int AUTHOR = 6;          // String
+    public static final int COMPOSER = 7;        // String
+    public static final int GENRE = 8;           // String
+    public static final int DATE = 9;            // Date
+    public static final int DURATION = 10;       // Integer(millisec)
+    public static final int CD_TRACK_NUM = 11;   // Integer 1-based
+    public static final int CD_TRACK_MAX = 12;   // Integer
+    public static final int RATING = 13;         // String
+    public static final int ALBUM_ART = 14;      // byte[]
+    public static final int VIDEO_FRAME = 15;    // Bitmap
+    public static final int CAPTION = 16;        // TimedText
+
+    public static final int BIT_RATE = 17;       // Integer, Aggregate rate of
+                                                 // all the streams in bps.
+
+    public static final int AUDIO_BIT_RATE = 18; // Integer, bps
+    public static final int VIDEO_BIT_RATE = 19; // Integer, bps
+    public static final int AUDIO_SAMPLE_RATE = 20; // Integer, Hz
+    public static final int VIDEO_FRAME_RATE = 21;  // Integer, Hz
+
+    // See RFC2046 and RFC4281.
+    public static final int MIME_TYPE = 22;      // String
+    public static final int AUDIO_CODEC = 23;    // String
+    public static final int VIDEO_CODEC = 24;    // String
+
+    public static final int VIDEO_HEIGHT = 25;   // Integer
+    public static final int VIDEO_WIDTH = 26;    // Integer
+    public static final int NUM_TRACKS = 27;     // Integer
+    public static final int DRM_CRIPPLED = 28;   // Boolean
+    public static final int LAST_SYSTEM = 29;
+    public static final int FIRST_CUSTOM = 8092;
+
+    // Shorthands to set the MediaPlayer's metadata filter.
+    public static final Set<Integer> MATCH_NONE = Collections.EMPTY_SET;
+    public static final Set<Integer> MATCH_ALL = Collections.singleton(ANY);
+
+    /**
+     * Helper class to hold a pair (time, text). Can be used to implement caption.
+     */
+    public class TimedText {
+        private Date mTime;
+        private String mText;
+        public TimedText(final Date time, final String text) {
+            mTime = time;
+            mText = text;
+        }
+        public String toString() {
+            StringBuilder res = new StringBuilder(80);
+            res.append(mTime).append(":").append(mText);
+            return res.toString();
+        }
+    }
+
+    /* package */ Metadata() {}
+
+    /**
+     * @return the number of element in this metadata set.
+     */
+    public int size() {
+        // FIXME: Implement.
+        return 0;
+    }
+
+    /**
+     * @return an iterator over the keys.
+     */
+    public Iterator<Integer> iterator() {
+        // FIXME: Implement.
+        return new java.util.HashSet<Integer>().iterator();
+    }
+
+    /**
+     * @return true if a value is present for the given key.
+     */
+    public boolean has(final int key) {
+        if (key <= ANY) {
+            throw new IllegalArgumentException("Invalid key: " + key);
+        }
+        if (LAST_SYSTEM <= key && key < FIRST_CUSTOM) {
+            throw new IllegalArgumentException("Key in reserved range: " + key);
+        }
+        // FIXME: Implement.
+        return true;
+    }
+
+    // Accessors
+    public String getString(final int key) {
+        // FIXME: Implement.
+        return new String();
+    }
+
+    public int getInt(final int key) {
+        // FIXME: Implement.
+        return 0;
+    }
+
+    public long getLong(final int key) {
+        // FIXME: Implement.
+        return 0;
+    }
+
+    public double getDouble(final int key) {
+        // FIXME: Implement.
+        return 0.0;
+    }
+
+    public byte[] getByteArray(final int key) {
+        return new byte[0];
+    }
+
+    public Bitmap getBitmap(final int key) {
+        // FIXME: Implement.
+        return null;
+    }
+
+    public Date getDate(final int key) {
+        // FIXME: Implement.
+        return new Date();
+    }
+
+    public TimedText getTimedText(final int key) {
+        // FIXME: Implement.
+        return new TimedText(new Date(0), "<missing>");
+    }
+}
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index cf0965e..0a6f4f7 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -185,7 +185,6 @@
     mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
     mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
     mCblk->out = 0;
-    mSampleRate = sampleRate;
     mFormat = format;
     // Update buffer size in case it has been limited by AudioFlinger during track creation
     mFrameCount = mCblk->frameCount;
@@ -196,7 +195,7 @@
     mRemainingFrames = notificationFrames;
     mUserData = user;
     // TODO: add audio hardware input latency here
-    mLatency = (1000*mFrameCount) / mSampleRate;
+    mLatency = (1000*mFrameCount) / sampleRate;
     mMarkerPosition = 0;
     mMarkerReached = false;
     mNewPosition = 0;
@@ -218,11 +217,6 @@
     return mLatency;
 }
 
-uint32_t AudioRecord::sampleRate() const
-{
-    return mSampleRate;
-}
-
 int AudioRecord::format() const
 {
     return mFormat;
@@ -321,6 +315,11 @@
     return !mActive;
 }
 
+uint32_t AudioRecord::getSampleRate()
+{
+    return mCblk->sampleRate;
+}
+
 status_t AudioRecord::setMarkerPosition(uint32_t marker)
 {
     if (mCbf == 0) return INVALID_OPERATION;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 4a1b69e..af7dae5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -243,7 +243,6 @@
     mCblk->volume[0] = mCblk->volume[1] = 0x1000;
     mVolume[LEFT] = 1.0f;
     mVolume[RIGHT] = 1.0f;
-    mSampleRate = sampleRate;
     mStreamType = streamType;
     mFormat = format;
     mChannelCount = channelCount;
@@ -254,7 +253,7 @@
     mNotificationFrames = notificationFrames;
     mRemainingFrames = notificationFrames;
     mUserData = user;
-    mLatency = afLatency + (1000*mFrameCount) / mSampleRate;
+    mLatency = afLatency + (1000*mFrameCount) / sampleRate;
     mLoopCount = 0;
     mMarkerPosition = 0;
     mMarkerReached = false;
@@ -281,11 +280,6 @@
     return mStreamType;
 }
 
-uint32_t AudioTrack::sampleRate() const
-{
-    return mSampleRate;
-}
-
 int AudioTrack::format() const
 {
     return mFormat;
@@ -438,24 +432,23 @@
     *right = mVolume[RIGHT];
 }
 
-void AudioTrack::setSampleRate(int rate)
+status_t AudioTrack::setSampleRate(int rate)
 {
     int afSamplingRate;
 
     if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
-        return;
+        return NO_INIT;
     }
     // Resampler implementation limits input sampling rate to 2 x output sampling rate.
-    if (rate <= 0) rate = 1;
-    if (rate > afSamplingRate*2) rate = afSamplingRate*2;
-    if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
+    if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE;
 
-    mCblk->sampleRate = (uint16_t)rate;
+    mCblk->sampleRate = rate;
+    return NO_ERROR;
 }
 
 uint32_t AudioTrack::getSampleRate()
 {
-    return uint32_t(mCblk->sampleRate);
+    return mCblk->sampleRate;
 }
 
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
@@ -866,7 +859,7 @@
     result.append(buffer);
     snprintf(buffer, 255, "  format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mFrameCount);
     result.append(buffer);
-    snprintf(buffer, 255, "  sample rate(%d), status(%d), muted(%d)\n", mSampleRate, mStatus, mMuted);
+    snprintf(buffer, 255, "  sample rate(%d), status(%d), muted(%d)\n", (mCblk == 0) ? 0 : mCblk->sampleRate, mStatus, mMuted);
     result.append(buffer);
     snprintf(buffer, 255, "  active(%d), latency (%d)\n", mActive, mLatency);
     result.append(buffer);
diff --git a/obex/javax/obex/ApplicationParameter.java b/obex/javax/obex/ApplicationParameter.java
index e808360..a62210f 100644
--- a/obex/javax/obex/ApplicationParameter.java
+++ b/obex/javax/obex/ApplicationParameter.java
@@ -37,9 +37,11 @@
  */
 public final class ApplicationParameter {
 
-    private byte[] b_array;
-    private int length;
-    private int max_length = 1000;
+    private byte[] mArray;
+
+    private int mLength;
+
+    private int mMaxLength = 1000;
 
     public static class TRIPLET_TAGID {
         public static final byte ORDER_TAGID = 0x01;
@@ -91,7 +93,6 @@
     public static class TRIPLET_LENGTH {
         public static final byte ORDER_LENGTH = 1;
 
-        //public final byte SEARCH_VALUE_LENGTH = 0x02;
         public static final byte SEARCH_ATTRIBUTE_LENGTH = 1;
 
         public static final byte MAXLISTCOUNT_LENGTH = 2;
@@ -107,34 +108,27 @@
         public static final byte NEWMISSEDCALLS_LENGTH = 1;
     }
 
-    /*
-    public class TRIPLET_STRUCTURE{
-        TRIPLET_TAGID id;
-        TRIPLET_LENGTH length;
-        byte[] value;
-    }
-    */
     public ApplicationParameter() {
-        b_array = new byte[max_length];
-        length = 0;
+        mArray = new byte[mMaxLength];
+        mLength = 0;
     }
 
     public void addAPPHeader(byte tag, byte len, byte[] value) {
-        if ((length + len + 2) > max_length) {
-            byte[] array_tmp = new byte[length + 4 * len];
-            System.arraycopy(b_array, 0, array_tmp, 0, length);
-            b_array = array_tmp;
-            max_length = length + 4 * len;
+        if ((mLength + len + 2) > mMaxLength) {
+            byte[] array_tmp = new byte[mLength + 4 * len];
+            System.arraycopy(mArray, 0, array_tmp, 0, mLength);
+            mArray = array_tmp;
+            mMaxLength = mLength + 4 * len;
         }
-        b_array[length++] = tag;
-        b_array[length++] = len;
-        System.arraycopy(value, 0, b_array, length, len);
-        length += len;
+        mArray[mLength++] = tag;
+        mArray[mLength++] = len;
+        System.arraycopy(value, 0, mArray, mLength, len);
+        mLength += len;
     }
 
     public byte[] getAPPparam() {
-        byte[] para = new byte[length];
-        System.arraycopy(b_array, 0, para, 0, length);
+        byte[] para = new byte[mLength];
+        System.arraycopy(mArray, 0, para, 0, mLength);
         return para;
     }
 }
diff --git a/obex/javax/obex/Authenticator.java b/obex/javax/obex/Authenticator.java
index 90da7ba..7246e91 100644
--- a/obex/javax/obex/Authenticator.java
+++ b/obex/javax/obex/Authenticator.java
@@ -106,8 +106,8 @@
      * @return a <code>PasswordAuthentication</code> object containing the
      * user name and password used for authentication
      */
-    public PasswordAuthentication onAuthenticationChallenge(String description,
-            boolean isUserIdRequired, boolean isFullAccess);
+    PasswordAuthentication onAuthenticationChallenge(String description, boolean isUserIdRequired,
+            boolean isFullAccess);
 
     /**
      * Called when a client or server receives an authentication response
@@ -120,5 +120,5 @@
      * @return the correct password for the user name provided; if
      * <code>null</code> is returned then the authentication request failed
      */
-    public byte[] onAuthenticationResponse(byte[] userName);
+    byte[] onAuthenticationResponse(byte[] userName);
 }
diff --git a/obex/javax/obex/BaseStream.java b/obex/javax/obex/BaseStream.java
index 67581bf..c32717f 100644
--- a/obex/javax/obex/BaseStream.java
+++ b/obex/javax/obex/BaseStream.java
@@ -47,7 +47,7 @@
      *
      * @throws IOException if the object is closed
      */
-    public void ensureOpen() throws IOException;
+    void ensureOpen() throws IOException;
 
     /**
      * Verifies that additional information may be sent.  In other words, the
@@ -55,7 +55,7 @@
      *
      * @throws IOException if the operation is completed
      */
-    public void ensureNotDone() throws IOException;
+    void ensureNotDone() throws IOException;
 
     /**
      * Continues the operation since there is no data to read.
@@ -69,7 +69,7 @@
      *
      * @throws IOException if an IO error occurs
      */
-    public boolean continueOperation(boolean sendEmpty, boolean inStream) throws IOException;
+    boolean continueOperation(boolean sendEmpty, boolean inStream) throws IOException;
 
     /**
      * Called when the output or input stream is closed.
@@ -79,5 +79,5 @@
      *
      * @throws IOException if an IO error occurs
      */
-    public void streamClosed(boolean inStream) throws IOException;
+    void streamClosed(boolean inStream) throws IOException;
 }
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index 5bc302a..b3807af 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -47,104 +47,82 @@
  */
 public final class ClientOperation implements Operation, BaseStream {
 
-    /**
-     * Defines the basic packet length used by OBEX.  Event OBEX packet has the
-     * same basic format:<BR>
-     * Byte 0: Request or Response Code
-     * Byte 1&2: Length of the packet.
-     */
-    private static final int BASE_PACKET_LENGTH = 3;
+    private ClientSession mParent;
 
-    private ClientSession parent;
+    private boolean mInputOpen;
 
-    private InputStream socketInput;
+    private PrivateInputStream mPrivateInput;
 
-    private PrivateInputStream privateInput;
+    private boolean mPrivateInputOpen;
 
-    private PrivateOutputStream privateOutput;
+    private PrivateOutputStream mPrivateOutput;
 
-    private boolean isClosed;
+    private boolean mPrivateOutputOpen;
 
-    private String exceptionMessage;
+    private String mExceptionMessage;
 
-    private int maxPacketSize;
+    private int mMaxPacketSize;
 
-    private boolean isDone;
+    private boolean mOperationDone;
 
-    private boolean isGet;
+    private boolean mGetOperation;
 
-    private HeaderSet requestHeaders;
+    private HeaderSet mRequestHeader;
 
-    private HeaderSet replyHeaders;
+    private HeaderSet mReplyHeader;
 
-    private boolean isEndOfBodySent;
-
-    private boolean inputStreamOpened;
-
-    private boolean outputStreamOpened;
-
-    private boolean isValidateConnected;
+    private boolean mEndOfBodySent;
 
     /** 
      * Creates new OperationImpl to read and write data to a server
-     *
-     * @param in the input stream to read from
-     *
      * @param maxSize the maximum packet size
-     *
      * @param p the parent to this object
-     *
-     * @param headers the headers to set in the initial request
-     *
      * @param type <code>true</code> if this is a get request;
      * <code>false</code. if this is a put request
+     * @param headers the headers to set in the initial request
      *
      * @throws IOExcpetion if the an IO error occured
      */
-    public ClientOperation(InputStream in, int maxSize, ClientSession p, HeaderSet header,
-            boolean type) throws IOException {
+    public ClientOperation(int maxSize, ClientSession p, HeaderSet header, boolean type)
+            throws IOException {
 
-        parent = p;
-        isEndOfBodySent = false;
-        socketInput = in;
-        isClosed = false;
-        isDone = false;
-        maxPacketSize = maxSize;
-        isGet = type;
+        mParent = p;
+        mEndOfBodySent = false;
+        mInputOpen = true;
+        mOperationDone = false;
+        mMaxPacketSize = maxSize;
+        mGetOperation = type;
 
-        inputStreamOpened = false;
-        outputStreamOpened = false;
-        isValidateConnected = false;
+        mPrivateInputOpen = false;
+        mPrivateOutputOpen = false;
+        mPrivateInput = null;
+        mPrivateOutput = null;
 
-        privateInput = null;
-        privateOutput = null;
+        mReplyHeader = new HeaderSet();
 
-        replyHeaders = new HeaderSet();
-
-        requestHeaders = new HeaderSet();
+        mRequestHeader = new HeaderSet();
 
         int[] headerList = header.getHeaderList();
 
         if (headerList != null) {
 
             for (int i = 0; i < headerList.length; i++) {
-                requestHeaders.setHeader(headerList[i], header.getHeader(headerList[i]));
+                mRequestHeader.setHeader(headerList[i], header.getHeader(headerList[i]));
             }
         }
 
-        if ((header).authChall != null) {
-            requestHeaders.authChall = new byte[(header).authChall.length];
-            System.arraycopy((header).authChall, 0, requestHeaders.authChall, 0,
-                    (header).authChall.length);
+        if ((header).mAuthChall != null) {
+            mRequestHeader.mAuthChall = new byte[(header).mAuthChall.length];
+            System.arraycopy((header).mAuthChall, 0, mRequestHeader.mAuthChall, 0,
+                    (header).mAuthChall.length);
         }
 
-        if ((header).authResp != null) {
-            requestHeaders.authResp = new byte[(header).authResp.length];
-            System.arraycopy((header).authResp, 0, requestHeaders.authResp, 0,
-                    (header).authResp.length);
+        if ((header).mAuthResp != null) {
+            mRequestHeader.mAuthResp = new byte[(header).mAuthResp.length];
+            System.arraycopy((header).mAuthResp, 0, mRequestHeader.mAuthResp, 0,
+                    (header).mAuthResp.length);
 
         }
-        //        requestHeaders = (HeaderSet)header;
     }
 
     /**
@@ -163,24 +141,24 @@
         //	}
 
         //no compatible with sun-ri
-        if ((isDone) && (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE)) {
+        if ((mOperationDone) && (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE)) {
             throw new IOException("Operation has already ended");
         }
 
-        exceptionMessage = "Operation aborted";
-        if ((!isDone) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
-            isDone = true;
+        mExceptionMessage = "Operation aborted";
+        if ((!mOperationDone) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+            mOperationDone = true;
             /*
              * Since we are not sending any headers or returning any headers then
              * we just need to write and read the same bytes
              */
-            parent.sendRequest(0xFF, null, replyHeaders, null);
+            mParent.sendRequest(ObexHelper.OBEX_OPCODE_ABORT, null, mReplyHeader, null);
 
-            if (replyHeaders.responseCode != ResponseCodes.OBEX_HTTP_OK) {
+            if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_OK) {
                 throw new IOException("Invalid response code from server");
             }
 
-            exceptionMessage = null;
+            mExceptionMessage = null;
         }
 
         close();
@@ -199,12 +177,12 @@
      */
     public synchronized int getResponseCode() throws IOException {
         //avoid dup validateConnection
-        if ((replyHeaders.responseCode == -1)
-                || (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
+        if ((mReplyHeader.responseCode == -1)
+                || (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
             validateConnection();
         }
 
-        return replyHeaders.responseCode;
+        return mReplyHeader.responseCode;
     }
 
     /**
@@ -226,7 +204,7 @@
      */
     public String getType() {
         try {
-            return (String)replyHeaders.getHeader(HeaderSet.TYPE);
+            return (String)mReplyHeader.getHeader(HeaderSet.TYPE);
         } catch (IOException e) {
             return null;
         }
@@ -242,7 +220,7 @@
      */
     public long getLength() {
         try {
-            Long temp = (Long)replyHeaders.getHeader(HeaderSet.LENGTH);
+            Long temp = (Long)mReplyHeader.getHeader(HeaderSet.LENGTH);
 
             if (temp == null) {
                 return -1;
@@ -262,27 +240,23 @@
      * @throws IOException if an I/O error occurs
      */
     public InputStream openInputStream() throws IOException {
-        // TODO: this mode is not set yet.
-        // if ((parent.mode & Connector.READ) == 0)
-        // throw new IOException("write-only connection");
 
         ensureOpen();
 
-        if (inputStreamOpened)
+        if (mPrivateInputOpen)
             throw new IOException("no more input streams available");
-        if (isGet) {
+        if (mGetOperation) {
             // send the GET request here
             validateConnection();
-            isValidateConnected = true;
         } else {
-            if (privateInput == null) {
-                privateInput = new PrivateInputStream(this);
+            if (mPrivateInput == null) {
+                mPrivateInput = new PrivateInputStream(this);
             }
         }
 
-        inputStreamOpened = true;
+        mPrivateInputOpen = true;
 
-        return privateInput;
+        return mPrivateInput;
     }
 
     /**8
@@ -304,27 +278,25 @@
      * @throws IOException if an I/O error occurs
      */
     public OutputStream openOutputStream() throws IOException {
-        // TODO: this mode is not set yet.
-        //    	if ((parent.mode & Connector.WRITE) == 0)
-        //    		throw new IOException("read-only connection");
+
         ensureOpen();
         ensureNotDone();
 
-        if (outputStreamOpened)
+        if (mPrivateOutputOpen)
             throw new IOException("no more output streams available");
 
-        if (privateOutput == null) {
+        if (mPrivateOutput == null) {
             // there are 3 bytes operation headers and 3 bytes body headers //
-            privateOutput = new PrivateOutputStream(this, maxPacketSize - 6);
+            mPrivateOutput = new PrivateOutputStream(this, mMaxPacketSize - 6);
         }
 
-        outputStreamOpened = true;
+        mPrivateOutputOpen = true;
 
-        return privateOutput;
+        return mPrivateOutput;
     }
 
     public int getMaxPacketSize() {
-        return maxPacketSize - 6;
+        return mMaxPacketSize - 6;
     }
 
     /**
@@ -344,10 +316,10 @@
      * @throws IOException if the operation has already ended or is closed
      */
     public void close() throws IOException {
-        isClosed = true;
-        inputStreamOpened = false;
-        outputStreamOpened = false;
-        parent.setRequestInactive();
+        mInputOpen = false;
+        mPrivateInputOpen = false;
+        mPrivateOutputOpen = false;
+        mParent.setRequestInactive();
     }
 
     /**
@@ -359,10 +331,10 @@
      *
      * @throws IOException if this <code>Operation</code> has been closed
      */
-    public HeaderSet getReceivedHeaders() throws IOException {
+    public HeaderSet getReceivedHeader() throws IOException {
         ensureOpen();
 
-        return replyHeaders;
+        return mReplyHeader;
     }
 
     /**
@@ -381,18 +353,18 @@
      */
     public void sendHeaders(HeaderSet headers) throws IOException {
         ensureOpen();
-        if (isDone) {
+        if (mOperationDone) {
             throw new IOException("Operation has already exchanged all data");
         }
 
         if (headers == null) {
-            throw new NullPointerException("Headers may not be null");
+            throw new IOException("Headers may not be null");
         }
 
         int[] headerList = headers.getHeaderList();
         if (headerList != null) {
             for (int i = 0; i < headerList.length; i++) {
-                requestHeaders.setHeader(headerList[i], headers.getHeader(headerList[i]));
+                mRequestHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
             }
         }
     }
@@ -406,49 +378,50 @@
      *
      * @throws IOException if an IO error occurred
      */
+    /*
     private boolean readResponse() throws IOException {
-        replyHeaders.responseCode = socketInput.read();
-        int packetLength = socketInput.read();
-        packetLength = (packetLength << 8) + socketInput.read();
+        mReplyHeader.responseCode = mInput.read();
+        int packetLength = mInput.read();
+        packetLength = (packetLength << 8) + mInput.read();
 
         if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) {
-            if (exceptionMessage != null) {
+            if (mExceptionMessage != null) {
                 abort();
             }
             throw new IOException("Received a packet that was too big");
         }
 
-        if (packetLength > BASE_PACKET_LENGTH) {
-            int dataLength = packetLength - BASE_PACKET_LENGTH;
+        if (packetLength > ObexHelper.BASE_PACKET_LENGTH) {
+            int dataLength = packetLength - ObexHelper.BASE_PACKET_LENGTH;
             byte[] data = new byte[dataLength];
-            int readLength = socketInput.read(data);
+            int readLength = mInput.read(data);
             if (readLength != dataLength) {
                 throw new IOException("Received a packet without data as decalred length");
             }
-            byte[] body = ObexHelper.updateHeaderSet(replyHeaders, data);
+            byte[] body = ObexHelper.updateHeaderSet(mReplyHeader, data);
 
             if (body != null) {
-                privateInput.writeBytes(body, 1);
+                mPrivateInput.writeBytes(body, 1);
 
                 /*
                  * Determine if a body (0x48) header or an end of body (0x49)
                  * was received.  If we received an end of body and
                  * a response code of OBEX_HTTP_OK, then the operation should
                  * end.
-                 */
-                if ((body[0] == 0x49) && (replyHeaders.responseCode == ResponseCodes.OBEX_HTTP_OK)) {
+                 *
+                if ((body[0] == 0x49) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_OK)) {
                     return false;
                 }
             }
         }
 
-        if (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
+        if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
             return true;
         } else {
             return false;
         }
     }
-
+    */
     /**
      * Verifies that additional information may be sent.  In other words, the
      * operation is not done.
@@ -456,7 +429,7 @@
      * @throws IOException if the operation is completed
      */
     public void ensureNotDone() throws IOException {
-        if (isDone) {
+        if (mOperationDone) {
             throw new IOException("Operation has completed");
         }
     }
@@ -467,12 +440,12 @@
      * @throws IOException if an exception needs to be thrown
      */
     public void ensureOpen() throws IOException {
-        parent.ensureOpen();
+        mParent.ensureOpen();
 
-        if (exceptionMessage != null) {
-            throw new IOException(exceptionMessage);
+        if (mExceptionMessage != null) {
+            throw new IOException(mExceptionMessage);
         }
-        if (isClosed) {
+        if (!mInputOpen) {
             throw new IOException("Operation has already ended");
         }
     }
@@ -486,7 +459,7 @@
         ensureOpen();
 
         // to sure only one privateInput object exist.
-        if (privateInput == null) {
+        if (mPrivateInput == null) {
             startProcessing();
         }
     }
@@ -501,13 +474,13 @@
      *
      * @throws IOException if an IO error occurs
      */
-    protected boolean sendRequest(int type) throws IOException {
+    private boolean sendRequest(int type) throws IOException {
         boolean returnValue = false;
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         int bodyLength = -1;
-        byte[] headerArray = ObexHelper.createHeader(requestHeaders, true);
-        if (privateOutput != null) {
-            bodyLength = privateOutput.size();
+        byte[] headerArray = ObexHelper.createHeader(mRequestHeader, true);
+        if (mPrivateOutput != null) {
+            bodyLength = mPrivateOutput.size();
         }
 
         /*
@@ -518,40 +491,39 @@
          * length, but it is a waste of resources if we can't send much of
          * the body.
          */
-        if ((BASE_PACKET_LENGTH + headerArray.length) > maxPacketSize) {
+        if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketSize) {
             int end = 0;
             int start = 0;
             // split & send the headerArray in multiple packets.
 
             while (end != headerArray.length) {
                 //split the headerArray
-                end = ObexHelper.findHeaderEnd(headerArray, start, maxPacketSize
-                        - BASE_PACKET_LENGTH);
+                end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
+                        - ObexHelper.BASE_PACKET_LENGTH);
                 // can not split 
                 if (end == -1) {
-                    isDone = true;
+                    mOperationDone = true;
                     abort();
-                    // isDone = true;
-                    exceptionMessage = "Header larger then can be sent in a packet";
-                    isClosed = true;
+                    mExceptionMessage = "Header larger then can be sent in a packet";
+                    mInputOpen = false;
 
-                    if (privateInput != null) {
-                        privateInput.close();
+                    if (mPrivateInput != null) {
+                        mPrivateInput.close();
                     }
 
-                    if (privateOutput != null) {
-                        privateOutput.close();
+                    if (mPrivateOutput != null) {
+                        mPrivateOutput.close();
                     }
                     throw new IOException("OBEX Packet exceeds max packet size");
                 }
 
                 byte[] sendHeader = new byte[end - start];
                 System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
-                if (!parent.sendRequest(type, sendHeader, replyHeaders, privateInput)) {
+                if (!mParent.sendRequest(type, sendHeader, mReplyHeader, mPrivateInput)) {
                     return false;
                 }
 
-                if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) {
+                if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
                     return false;
                 }
 
@@ -569,27 +541,27 @@
 
         if (bodyLength > 0) {
             /*
-             * Determine if I can send the whole body or just part of
+             * Determine if we can send the whole body or just part of
              * the body.  Remember that there is the 3 bytes for the
              * response message and 3 bytes for the header ID and length
              */
-            if (bodyLength > (maxPacketSize - headerArray.length - 6)) {
+            if (bodyLength > (mMaxPacketSize - headerArray.length - 6)) {
                 returnValue = true;
 
-                bodyLength = maxPacketSize - headerArray.length - 6;
+                bodyLength = mMaxPacketSize - headerArray.length - 6;
             }
 
-            byte[] body = privateOutput.readBytes(bodyLength);
+            byte[] body = mPrivateOutput.readBytes(bodyLength);
 
             /*
              * Since this is a put request if the final bit is set or
              * the output stream is closed we need to send the 0x49
              * (End of Body) otherwise, we need to send 0x48 (Body)
              */
-            if ((privateOutput.isClosed()) && (!returnValue) && (!isEndOfBodySent)
+            if ((mPrivateOutput.isClosed()) && (!returnValue) && (!mEndOfBodySent)
                     && ((type & 0x80) != 0)) {
                 out.write(0x49);
-                isEndOfBodySent = true;
+                mEndOfBodySent = true;
             } else {
                 out.write(0x48);
             }
@@ -603,13 +575,13 @@
             }
         }
 
-        if (outputStreamOpened && bodyLength <= 0 && !isEndOfBodySent) {
+        if (mPrivateOutputOpen && bodyLength <= 0 && !mEndOfBodySent) {
             // only 0x82 or 0x83 can send 0x49
             if ((type & 0x80) == 0) {
                 out.write(0x48);
             } else {
                 out.write(0x49);
-                isEndOfBodySent = true;
+                mEndOfBodySent = true;
 
             }
 
@@ -619,19 +591,19 @@
         }
 
         if (out.size() == 0) {
-            if (!parent.sendRequest(type, null, replyHeaders, privateInput)) {
+            if (!mParent.sendRequest(type, null, mReplyHeader, mPrivateInput)) {
                 return false;
             }
             return returnValue;
         }
         if ((out.size() > 0)
-                && (!parent.sendRequest(type, out.toByteArray(), replyHeaders, privateInput))) {
+                && (!mParent.sendRequest(type, out.toByteArray(), mReplyHeader, mPrivateInput))) {
             return false;
         }
 
         // send all of the output data in 0x48, 
         // send 0x49 with empty body
-        if ((privateOutput != null) && (privateOutput.size() > 0))
+        if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
             returnValue = true;
 
         return returnValue;
@@ -646,41 +618,41 @@
      */
     private synchronized void startProcessing() throws IOException {
 
-        if (privateInput == null) {
-            privateInput = new PrivateInputStream(this);
+        if (mPrivateInput == null) {
+            mPrivateInput = new PrivateInputStream(this);
         }
         boolean more = true;
 
-        if (isGet) {
-            if (!isDone) {
-                replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
-                while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
+        if (mGetOperation) {
+            if (!mOperationDone) {
+                mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
                     more = sendRequest(0x03);
                 }
 
-                if (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
-                    parent.sendRequest(0x83, null, replyHeaders, privateInput);
+                if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
                 }
-                if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) {
-                    isDone = true;
+                if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    mOperationDone = true;
                 }
             }
         } else {
 
-            if (!isDone) {
-                replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
-                while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
+            if (!mOperationDone) {
+                mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
                     more = sendRequest(0x02);
 
                 }
             }
 
-            if (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
-                parent.sendRequest(0x82, null, replyHeaders, privateInput);
+            if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+                mParent.sendRequest(0x82, null, mReplyHeader, mPrivateInput);
             }
 
-            if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) {
-                isDone = true;
+            if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                mOperationDone = true;
             }
         }
     }
@@ -697,45 +669,45 @@
     public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
             throws IOException {
 
-        if (isGet) {
-            if ((inStream) && (!isDone)) {
+        if (mGetOperation) {
+            if ((inStream) && (!mOperationDone)) {
                 // to deal with inputstream in get operation
-                parent.sendRequest(0x83, null, replyHeaders, privateInput);
+                mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
                 /*
                   * Determine if that was not the last packet in the operation
                   */
-                if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) {
-                    isDone = true;
+                if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    mOperationDone = true;
                 }
 
                 return true;
 
-            } else if ((!inStream) && (!isDone)) {
+            } else if ((!inStream) && (!mOperationDone)) {
                 // to deal with outputstream in get operation
 
-                if (privateInput == null) {
-                    privateInput = new PrivateInputStream(this);
+                if (mPrivateInput == null) {
+                    mPrivateInput = new PrivateInputStream(this);
                 }
                 sendRequest(0x03);
                 return true;
 
-            } else if (isDone) {
+            } else if (mOperationDone) {
                 return false;
             }
 
         } else {
-            if ((!inStream) && (!isDone)) {
+            if ((!inStream) && (!mOperationDone)) {
                 // to deal with outputstream in put operation
-                if (replyHeaders.responseCode == -1) {
-                    replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
+                if (mReplyHeader.responseCode == -1) {
+                    mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
                 }
                 sendRequest(0x02);
                 return true;
-            } else if ((inStream) && (!isDone)) {
+            } else if ((inStream) && (!mOperationDone)) {
                 // How to deal with inputstream  in put operation ?
                 return false;
 
-            } else if (isDone) {
+            } else if (mOperationDone) {
                 return false;
             }
 
@@ -752,23 +724,23 @@
      * @throws IOException if an IO error occurs
      */
     public void streamClosed(boolean inStream) throws IOException {
-        if (!isGet) {
-            if ((!inStream) && (!isDone)) {
+        if (!mGetOperation) {
+            if ((!inStream) && (!mOperationDone)) {
                 // to deal with outputstream in put operation
 
                 boolean more = true;
 
-                if ((privateOutput != null) && (privateOutput.size() <= 0)) {
-                    byte[] headerArray = ObexHelper.createHeader(requestHeaders, false);
+                if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
+                    byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
                     if (headerArray.length <= 0)
                         more = false;
                 }
                 // If have not sent any data so send  all now
-                if (replyHeaders.responseCode == -1) {
-                    replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
+                if (mReplyHeader.responseCode == -1) {
+                    mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
                 }
 
-                while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
+                while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
                     more = sendRequest(0x02);
                 }
 
@@ -777,61 +749,60 @@
                  * only have a single reply to send.  so we don't need the while
                  * loop.
                  */
-                while (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
+                while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
 
                     sendRequest(0x82);
                 }
-                isDone = true;
-            } else if ((inStream) && (isDone)) {
+                mOperationDone = true;
+            } else if ((inStream) && (mOperationDone)) {
                 // how to deal with input stream in put stream ?
-                isDone = true;
+                mOperationDone = true;
             }
         } else {
-            isValidateConnected = false;
-            if ((inStream) && (!isDone)) {
+            if ((inStream) && (!mOperationDone)) {
 
                 // to deal with inputstream in get operation
                 // Have not sent any data so send it all now
 
-                if (replyHeaders.responseCode == -1) {
-                    replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
+                if (mReplyHeader.responseCode == -1) {
+                    mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
                 }
 
-                while (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
+                while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
                     if (!sendRequest(0x83)) {
                         break;
                     }
                 }
-                while (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
-                    parent.sendRequest(0x83, null, replyHeaders, privateInput);
+                while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
                 }
-                isDone = true;
-            } else if ((!inStream) && (!isDone)) {
+                mOperationDone = true;
+            } else if ((!inStream) && (!mOperationDone)) {
                 // to deal with outputstream in get operation
                 // part of the data may have been sent in continueOperation.
 
                 boolean more = true;
 
-                if ((privateOutput != null) && (privateOutput.size() <= 0)) {
-                    byte[] headerArray = ObexHelper.createHeader(requestHeaders, false);
+                if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
+                    byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
                     if (headerArray.length <= 0)
                         more = false;
                 }
 
-                if (privateInput == null) {
-                    privateInput = new PrivateInputStream(this);
+                if (mPrivateInput == null) {
+                    mPrivateInput = new PrivateInputStream(this);
                 }
-                if ((privateOutput != null) && (privateOutput.size() <= 0))
+                if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0))
                     more = false;
 
-                replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
-                while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
+                mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
                     more = sendRequest(0x03);
                 }
                 sendRequest(0x83);
                 //                parent.sendRequest(0x83, null, replyHeaders, privateInput);
-                if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) {
-                    isDone = true;
+                if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    mOperationDone = true;
                 }
 
             }
diff --git a/obex/javax/obex/ClientSession.java b/obex/javax/obex/ClientSession.java
index f65ded9..d554922 100644
--- a/obex/javax/obex/ClientSession.java
+++ b/obex/javax/obex/ClientSession.java
@@ -38,13 +38,11 @@
 import java.io.OutputStream;
 
 /**
- * This class implements the <code>Operation</code> interface.  It will read
- * and write data via puts and gets.
+ * This class in an implementation of the OBEX ClientSession.
  *
  * @hide
  */
-public final class ClientSession implements ObexSession {
-    private Authenticator mAuthenticator;
+public final class ClientSession extends ObexSession {
 
     private boolean mOpen;
 
@@ -53,8 +51,6 @@
 
     private byte[] mConnectionId = null;
 
-    private byte[] mChallengeDigest = null;
-
     /*
      * The max Packet size must be at least 256 according to the OBEX
      * specification.
@@ -67,14 +63,14 @@
 
     private final OutputStream mOutput;
 
-    public ClientSession(ObexTransport trans) throws IOException {
+    public ClientSession(final ObexTransport trans) throws IOException {
         mInput = trans.openInputStream();
         mOutput = trans.openOutputStream();
         mOpen = true;
         mRequestActive = false;
     }
 
-    public HeaderSet connect(HeaderSet header) throws IOException {
+    public HeaderSet connect(final HeaderSet header) throws IOException {
         ensureOpen();
         if (mObexConnected) {
             throw new IOException("Already connected to server");
@@ -119,7 +115,7 @@
         }
 
         HeaderSet returnHeaderSet = new HeaderSet();
-        sendRequest(0x80, requestPacket, returnHeaderSet, null);
+        sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null);
 
         /*
         * Read the response from the OBEX server.
@@ -147,21 +143,23 @@
 
         ensureOpen();
 
+        HeaderSet head;
         if (header == null) {
-            header = new HeaderSet();
+            head = new HeaderSet();
         } else {
-            if (header.nonce != null) {
+            head = header;
+            if (head.nonce != null) {
                 mChallengeDigest = new byte[16];
-                System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
+                System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
             }
         }
         // Add the connection ID if one exists
         if (mConnectionId != null) {
-            header.connectionID = new byte[4];
-            System.arraycopy(mConnectionId, 0, header.connectionID, 0, 4);
+            head.mConnectionID = new byte[4];
+            System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
         }
 
-        return new ClientOperation(mInput, maxPacketSize, this, header, true);
+        return new ClientOperation(maxPacketSize, this, head, true);
     }
 
     /**
@@ -178,7 +176,7 @@
 
         Operation op = put(header);
         op.getResponseCode();
-        HeaderSet returnValue = op.getReceivedHeaders();
+        HeaderSet returnValue = op.getReceivedHeader();
         op.close();
 
         return returnValue;
@@ -200,8 +198,8 @@
             }
             // Add the connection ID if one exists
             if (mConnectionId != null) {
-                header.connectionID = new byte[4];
-                System.arraycopy(mConnectionId, 0, header.connectionID, 0, 4);
+                header.mConnectionID = new byte[4];
+                System.arraycopy(mConnectionId, 0, header.mConnectionID, 0, 4);
             }
             head = ObexHelper.createHeader(header, false);
 
@@ -212,13 +210,13 @@
             // Add the connection ID if one exists
             if (mConnectionId != null) {
                 head = new byte[5];
-                head[0] = (byte)0xCB;
+                head[0] = (byte)HeaderSet.CONNECTION_ID;
                 System.arraycopy(mConnectionId, 0, head, 1, 4);
             }
         }
 
         HeaderSet returnHeaderSet = new HeaderSet();
-        sendRequest(0x81, head, returnHeaderSet, null);
+        sendRequest(ObexHelper.OBEX_OPCODE_DISCONNECT, head, returnHeaderSet, null);
 
         /*
          * An OBEX DISCONNECT reply from the server:
@@ -253,36 +251,36 @@
         setRequestActive();
 
         ensureOpen();
-
+        HeaderSet head;
         if (header == null) {
-            header = new HeaderSet();
+            head = new HeaderSet();
         } else {
-            // when auth is initated by client ,save the digest 
-            if (header.nonce != null) {
+            head = header;
+            // when auth is initiated by client ,save the digest
+            if (head.nonce != null) {
                 mChallengeDigest = new byte[16];
-                System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
+                System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
             }
         }
 
         // Add the connection ID if one exists
         if (mConnectionId != null) {
 
-            header.connectionID = new byte[4];
-            System.arraycopy(mConnectionId, 0, header.connectionID, 0, 4);
+            head.mConnectionID = new byte[4];
+            System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
         }
 
-        return new ClientOperation(mInput, maxPacketSize, this, header, false);
+        return new ClientOperation(maxPacketSize, this, head, false);
     }
 
-    public void setAuthenticator(Authenticator auth) {
+    public void setAuthenticator(Authenticator auth) throws IOException {
         if (auth == null) {
-            throw new NullPointerException("Authenticator may not be null");
+            throw new IOException("Authenticator may not be null");
         }
         mAuthenticator = auth;
     }
 
-    public HeaderSet setPath(HeaderSet header, boolean backup, boolean create)
-            throws IOException {
+    public HeaderSet setPath(HeaderSet header, boolean backup, boolean create) throws IOException {
         if (!mObexConnected) {
             throw new IOException("Not connected to the server");
         }
@@ -291,29 +289,30 @@
 
         int totalLength = 2;
         byte[] head = null;
-
+        HeaderSet headset;
         if (header == null) {
-            header = new HeaderSet();
+            headset = new HeaderSet();
         } else {
-            if (header.nonce != null) {
+            headset = header;
+            if (headset.nonce != null) {
                 mChallengeDigest = new byte[16];
-                System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
+                System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
             }
         }
 
         // when auth is initiated by client ,save the digest
-        if (header.nonce != null) {
+        if (headset.nonce != null) {
             mChallengeDigest = new byte[16];
-            System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
+            System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
         }
 
         // Add the connection ID if one exists
         if (mConnectionId != null) {
-            header.connectionID = new byte[4];
-            System.arraycopy(mConnectionId, 0, header.connectionID, 0, 4);
+            headset.mConnectionID = new byte[4];
+            System.arraycopy(mConnectionId, 0, headset.mConnectionID, 0, 4);
         }
 
-        head = ObexHelper.createHeader(header, false);
+        head = ObexHelper.createHeader(headset, false);
         totalLength += head.length;
 
         if (totalLength > maxPacketSize) {
@@ -345,12 +344,12 @@
         byte[] packet = new byte[totalLength];
         packet[0] = (byte)flags;
         packet[1] = (byte)0x00;
-        if (header != null) {
+        if (headset != null) {
             System.arraycopy(head, 0, packet, 2, head.length);
         }
 
         HeaderSet returnHeaderSet = new HeaderSet();
-        sendRequest(0x85, packet, returnHeaderSet, null);
+        sendRequest(ObexHelper.OBEX_OPCODE_SETPATH, packet, returnHeaderSet, null);
 
         /*
          * An OBEX SETPATH reply from the server:
@@ -380,7 +379,7 @@
      * Allows Put and get operation objects to tell this object when they are
      * done.
      */
-    /*package*/ synchronized void setRequestInactive() {
+    /*package*/synchronized void setRequestInactive() {
         mRequestActive = false;
     }
 
@@ -401,7 +400,7 @@
      * headers (i.e. authentication challenge or authentication response) are
      * received, they will be processed.
      *
-     * @param code the type of request to send to the client
+     * @param opCode the type of request to send to the client
      *
      * @param head the headers to send to the server
      *
@@ -419,7 +418,7 @@
      *
      * @throws IOException if an IO error occurs
      */
-    public boolean sendRequest(int code, byte[] head, HeaderSet header,
+    public boolean sendRequest(int opCode, byte[] head, HeaderSet header,
             PrivateInputStream privateInput) throws IOException {
         //check header length with local max size
         if (head != null) {
@@ -427,10 +426,10 @@
                 throw new IOException("header too large ");
             }
         }
-        //byte[] nonce;
+
         int bytesReceived;
         ByteArrayOutputStream out = new ByteArrayOutputStream();
-        out.write((byte)code);
+        out.write((byte)opCode);
 
         // Determine if there are any headers to send
         if (head == null) {
@@ -453,10 +452,12 @@
         if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
             throw new IOException("Packet received exceeds packet size limit");
         }
-        if (length > 3) {
+        if (length > ObexHelper.BASE_PACKET_LENGTH) {
             byte[] data = null;
-            if (code == 0x80) {
+            if (opCode == ObexHelper.OBEX_OPCODE_CONNECT) {
+                @SuppressWarnings("unused")
                 int version = mInput.read();
+                @SuppressWarnings("unused")
                 int flags = mInput.read();
                 maxPacketSize = (mInput.read() << 8) + mInput.read();
 
@@ -483,7 +484,7 @@
                 while (bytesReceived != (length - 3)) {
                     bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived);
                 }
-                if (code == 0xFF) {
+                if (opCode == ObexHelper.OBEX_OPCODE_ABORT) {
                     return true;
                 }
             }
@@ -493,33 +494,33 @@
                 privateInput.writeBytes(body, 1);
             }
 
-            if (header.connectionID != null) {
+            if (header.mConnectionID != null) {
                 mConnectionId = new byte[4];
-                System.arraycopy(header.connectionID, 0, mConnectionId, 0, 4);
+                System.arraycopy(header.mConnectionID, 0, mConnectionId, 0, 4);
             }
 
-            if (header.authResp != null) {
-                if (!handleAuthResp(header.authResp)) {
+            if (header.mAuthResp != null) {
+                if (!handleAuthResp(header.mAuthResp)) {
                     setRequestInactive();
                     throw new IOException("Authentication Failed");
                 }
             }
 
             if ((header.responseCode == ResponseCodes.OBEX_HTTP_UNAUTHORIZED)
-                    && (header.authChall != null)) {
+                    && (header.mAuthChall != null)) {
 
                 if (handleAuthChall(header)) {
-                    out.write((byte)0x4E);
-                    out.write((byte)((header.authResp.length + 3) >> 8));
-                    out.write((byte)(header.authResp.length + 3));
-                    out.write(header.authResp);
-                    header.authChall = null;
-                    header.authResp = null;
+                    out.write((byte)HeaderSet.AUTH_RESPONSE);
+                    out.write((byte)((header.mAuthResp.length + 3) >> 8));
+                    out.write((byte)(header.mAuthResp.length + 3));
+                    out.write(header.mAuthResp);
+                    header.mAuthChall = null;
+                    header.mAuthResp = null;
 
                     byte[] sendHeaders = new byte[out.size() - 3];
                     System.arraycopy(out.toByteArray(), 3, sendHeaders, 0, sendHeaders.length);
 
-                    return sendRequest(code, sendHeaders, header, privateInput);
+                    return sendRequest(opCode, sendHeaders, header, privateInput);
                 }
             }
         }
@@ -527,194 +528,6 @@
         return true;
     }
 
-    /**
-     * Called when the client received an authentication challenge header.  This
-     * will cause the authenticator to handle the authentication challenge.
-     *
-     * @param header the header with the authentication challenge
-     *
-     * @return <code>true</code> if the last request should be resent;
-     * <code>false</code> if the last request should not be resent
-     */
-    protected boolean handleAuthChall(HeaderSet header) {
-
-        if (mAuthenticator == null) {
-            return false;
-        }
-
-        /*
-         * An authentication challenge is made up of one required and two
-         * optional tag length value triplets.  The tag 0x00 is required to be
-         * in the authentication challenge and it represents the challenge
-         * digest that was received.  The tag 0x01 is the options tag.  This
-         * tag tracks if user ID is required and if full access will be
-         * granted.  The tag 0x02 is the realm, which provides a description of
-         * which user name and password to use.
-         */
-        byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.authChall);
-        byte[] option = ObexHelper.getTagValue((byte)0x01, header.authChall);
-        byte[] description = ObexHelper.getTagValue((byte)0x02, header.authChall);
-
-        String realm = "";
-        if (description != null) {
-            byte[] realmString = new byte[description.length - 1];
-            System.arraycopy(description, 1, realmString, 0, realmString.length);
-
-            switch (description[0] & 0xFF) {
-
-                case 0x00:
-                    // ASCII encoding
-                    // Fall through
-                case 0x01:
-                    // ISO-8859-1 encoding
-                    try {
-                        realm = new String(realmString, "ISO8859_1");
-                    } catch (Exception e) {
-                        throw new RuntimeException("Unsupported Encoding Scheme");
-                    }
-                    break;
-
-                case 0xFF:
-                    // UNICODE Encoding
-                    realm = ObexHelper.convertToUnicode(realmString, false);
-                    break;
-
-                case 0x02:
-                    // ISO-8859-2 encoding
-                    // Fall through
-                case 0x03:
-                    // ISO-8859-3 encoding
-                    // Fall through
-                case 0x04:
-                    // ISO-8859-4 encoding
-                    // Fall through
-                case 0x05:
-                    // ISO-8859-5 encoding
-                    // Fall through
-                case 0x06:
-                    // ISO-8859-6 encoding
-                    // Fall through
-                case 0x07:
-                    // ISO-8859-7 encoding
-                    // Fall through
-                case 0x08:
-                    // ISO-8859-8 encoding
-                    // Fall through
-                case 0x09:
-                    // ISO-8859-9 encoding
-                    // Fall through
-                default:
-                    throw new RuntimeException("Unsupported Encoding Scheme");
-            }
-        }
-
-        boolean isUserIDRequired = false;
-        boolean isFullAccess = true;
-        if (option != null) {
-            if ((option[0] & 0x01) != 0) {
-                isUserIDRequired = true;
-            }
-
-            if ((option[0] & 0x02) != 0) {
-                isFullAccess = false;
-            }
-        }
-
-        PasswordAuthentication result = null;
-        header.authChall = null;
-
-        try {
-            result = mAuthenticator.onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
-        } catch (Exception e) {
-            return false;
-        }
-
-        /*
-         * If no password was provided then do not resend the request
-         */
-        if (result == null) {
-            return false;
-        }
-
-        byte[] password = result.getPassword();
-        if (password == null) {
-            return false;
-        }
-
-        byte[] userName = result.getUserName();
-
-        /*
-         * Create the authentication response header.  It includes 1 required
-         * and 2 option tag length value triples.  The required triple has a
-         * tag of 0x00 and is the response digest.  The first optional tag is
-         * 0x01 and represents the user ID.  If no user ID is provided, then
-         * no user ID will be sent.  The second optional tag is 0x02 and is the
-         * challenge that was received.  This will always be sent
-         */
-        if (userName != null) {
-            header.authResp = new byte[38 + userName.length];
-            header.authResp[36] = (byte)0x01;
-            header.authResp[37] = (byte)userName.length;
-            System.arraycopy(userName, 0, header.authResp, 38, userName.length);
-        } else {
-            header.authResp = new byte[36];
-        }
-
-        // Create the secret String
-        byte[] digest = new byte[challenge.length + password.length];
-        System.arraycopy(challenge, 0, digest, 0, challenge.length);
-        System.arraycopy(password, 0, digest, challenge.length, password.length);
-
-        // Add the Response Digest
-        header.authResp[0] = (byte)0x00;
-        header.authResp[1] = (byte)0x10;
-
-        byte[] responseDigest = ObexHelper.computeMd5Hash(digest);
-        System.arraycopy(responseDigest, 0, header.authResp, 2, 16);
-
-        // Add the challenge
-        header.authResp[18] = (byte)0x02;
-        header.authResp[19] = (byte)0x10;
-        System.arraycopy(challenge, 0, header.authResp, 20, 16);
-
-        return true;
-    }
-
-    /**
-     * Called when the client received an authentication response header.  This
-     * will cause the authenticator to handle the authentication response.
-     *
-     * @param authResp the authentication response
-     *
-     * @return <code>true</code> if the response passed; <code>false</code> if
-     * the response failed
-     */
-    protected boolean handleAuthResp(byte[] authResp) {
-        if (mAuthenticator == null) {
-            return false;
-        }
-
-        byte[] correctPassword = mAuthenticator.onAuthenticationResponse(ObexHelper.getTagValue(
-                (byte)0x01, authResp));
-        if (correctPassword == null) {
-            return false;
-        }
-
-        byte[] temp = new byte[correctPassword.length + 16];
-        System.arraycopy(mChallengeDigest, 0, temp, 0, 16);
-        System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
-
-        byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
-        byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
-        for (int i = 0; i < 16; i++) {
-            if (correctResponse[i] != actualResponse[i]) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
     public void close() throws IOException {
         mOpen = false;
         mInput.close();
diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java
index 5dddf8f..f777da6 100644
--- a/obex/javax/obex/HeaderSet.java
+++ b/obex/javax/obex/HeaderSet.java
@@ -118,6 +118,20 @@
     public static final int HTTP = 0x47;
 
     /**
+     * Represents the OBEX BODY header.
+     * <P>
+     * The value of <code>BODY</code> is 0x48 (72).
+     */
+    public static final int BODY = 0x48;
+
+    /**
+     * Represents the OBEX End of BODY header.
+     * <P>
+     * The value of <code>BODY</code> is 0x49 (73).
+     */
+    public static final int END_OF_BODY = 0x49;
+
+    /**
      * Represents the OBEX Who header.  Identifies the OBEX application to
      * determine if the two peers are talking to each other.
      * <P>
@@ -126,12 +140,13 @@
     public static final int WHO = 0x4A;
 
     /**
-     * Represents the OBEX Object Class header.  This header specifies the
-     * OBEX object class of the object.
+     * Represents the OBEX Connection ID header. Identifies used for OBEX
+     * connection multiplexing.
      * <P>
-     * The value of <code>OBJECT_CLASS</code> is 0x4F (79).
+     * The value of <code>CONNECTION_ID</code> is 0xCB (203).
      */
-    public static final int OBJECT_CLASS = 0x4F;
+
+    public static final int CONNECTION_ID = 0xCB;
 
     /**
      * Represents the OBEX Application Parameter header.  This header specifies
@@ -141,49 +156,71 @@
      */
     public static final int APPLICATION_PARAMETER = 0x4C;
 
-    private Long count; // 4 byte unsigned integer
+    /**
+     * Represents the OBEX authentication digest-challenge.
+     * <P>
+     * The value of <code>AUTH_CHALLENGE</code> is 0x4D (77).
+     */
+    public static final int AUTH_CHALLENGE = 0x4D;
 
-    private String name; // null terminated Unicode text string
+    /**
+     * Represents the OBEX authentication digest-response.
+     * <P>
+     * The value of <code>AUTH_RESPONSE</code> is 0x4E (78).
+     */
+    public static final int AUTH_RESPONSE = 0x4E;
 
-    private String type; // null terminated ASCII text string
+    /**
+     * Represents the OBEX Object Class header.  This header specifies the
+     * OBEX object class of the object.
+     * <P>
+     * The value of <code>OBJECT_CLASS</code> is 0x4F (79).
+     */
+    public static final int OBJECT_CLASS = 0x4F;
 
-    private Long length; // 4 byte unsigend integer
+    private Long mCount; // 4 byte unsigned integer
 
-    private Calendar isoTime; // String of the form YYYYMMDDTHHMMSSZ
+    private String mName; // null terminated Unicode text string
 
-    private Calendar byteTime; // 4 byte unsigned integer
+    private String mType; // null terminated ASCII text string
 
-    private String description; // null terminated Unicode text String
+    private Long mLength; // 4 byte unsigend integer
 
-    private byte[] target; // byte sequence
+    private Calendar mIsoTime; // String of the form YYYYMMDDTHHMMSSZ
 
-    private byte[] http; // byte sequence
+    private Calendar mByteTime; // 4 byte unsigned integer
 
-    private byte[] who; // length prefixed byte sequence
+    private String mDescription; // null terminated Unicode text String
 
-    private byte[] appParam; // byte sequence of the form tag length value
+    private byte[] mTarget; // byte sequence
 
-    public byte[] authChall; // The authentication challenge header
+    private byte[] mHttpHeader; // byte sequence
 
-    public byte[] authResp; // The authentication response header
+    private byte[] mWho; // length prefixed byte sequence
 
-    public byte[] connectionID; // THe connection ID
+    private byte[] mAppParam; // byte sequence of the form tag length value
 
-    private byte[] objectClass; // byte sequence
+    public byte[] mAuthChall; // The authentication challenge header
 
-    private String[] unicodeUserDefined; //null terminated unicode string
+    public byte[] mAuthResp; // The authentication response header
 
-    private byte[][] sequenceUserDefined; // byte sequence user defined
+    public byte[] mConnectionID; // THe connection ID
 
-    private Byte[] byteUserDefined; // 1 byte
+    private byte[] mObjectClass; // byte sequence
 
-    private Long[] integerUserDefined; // 4 byte unsigned integer
+    private String[] mUnicodeUserDefined; //null terminated unicode string
 
-    /*package*/ int responseCode;
+    private byte[][] mSequenceUserDefined; // byte sequence user defined
 
-    /*package*/ byte[] nonce;
+    private Byte[] mByteUserDefined; // 1 byte
 
-    private final Random random;
+    private Long[] mIntegerUserDefined; // 4 byte unsigned integer
+
+    /*package*/int responseCode;
+
+    /*package*/byte[] nonce;
+
+    private final Random mRandom;
 
     /**
      * Creates new <code>HeaderSet</code> object.
@@ -191,12 +228,12 @@
      * @param size the max packet size for this connection
      */
     public HeaderSet() {
-        unicodeUserDefined = new String[16];
-        sequenceUserDefined = new byte[16][];
-        byteUserDefined = new Byte[16];
-        integerUserDefined = new Long[16];
+        mUnicodeUserDefined = new String[16];
+        mSequenceUserDefined = new byte[16][];
+        mByteUserDefined = new Byte[16];
+        mIntegerUserDefined = new Long[16];
         responseCode = -1;
-        random = new Random();
+        mRandom = new Random();
     }
 
     /**
@@ -222,7 +259,7 @@
             case COUNT:
                 if (!(headerValue instanceof Long)) {
                     if (headerValue == null) {
-                        count = null;
+                        mCount = null;
                         break;
                     }
                     throw new IllegalArgumentException("Count must be a Long");
@@ -231,24 +268,24 @@
                 if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
                     throw new IllegalArgumentException("Count must be between 0 and 0xFFFFFFFF");
                 }
-                count = (Long)headerValue;
+                mCount = (Long)headerValue;
                 break;
             case NAME:
                 if ((headerValue != null) && (!(headerValue instanceof String))) {
                     throw new IllegalArgumentException("Name must be a String");
                 }
-                name = (String)headerValue;
+                mName = (String)headerValue;
                 break;
             case TYPE:
                 if ((headerValue != null) && (!(headerValue instanceof String))) {
                     throw new IllegalArgumentException("Type must be a String");
                 }
-                type = (String)headerValue;
+                mType = (String)headerValue;
                 break;
             case LENGTH:
                 if (!(headerValue instanceof Long)) {
                     if (headerValue == null) {
-                        length = null;
+                        mLength = null;
                         break;
                     }
                     throw new IllegalArgumentException("Length must be a Long");
@@ -257,84 +294,84 @@
                 if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
                     throw new IllegalArgumentException("Length must be between 0 and 0xFFFFFFFF");
                 }
-                length = (Long)headerValue;
+                mLength = (Long)headerValue;
                 break;
             case TIME_ISO_8601:
                 if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
                     throw new IllegalArgumentException("Time ISO 8601 must be a Calendar");
                 }
-                isoTime = (Calendar)headerValue;
+                mIsoTime = (Calendar)headerValue;
                 break;
             case TIME_4_BYTE:
                 if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
                     throw new IllegalArgumentException("Time 4 Byte must be a Calendar");
                 }
-                byteTime = (Calendar)headerValue;
+                mByteTime = (Calendar)headerValue;
                 break;
             case DESCRIPTION:
                 if ((headerValue != null) && (!(headerValue instanceof String))) {
                     throw new IllegalArgumentException("Description must be a String");
                 }
-                description = (String)headerValue;
+                mDescription = (String)headerValue;
                 break;
             case TARGET:
                 if (headerValue == null) {
-                    target = null;
+                    mTarget = null;
                 } else {
                     if (!(headerValue instanceof byte[])) {
                         throw new IllegalArgumentException("Target must be a byte array");
                     } else {
-                        target = new byte[((byte[])headerValue).length];
-                        System.arraycopy(headerValue, 0, target, 0, target.length);
+                        mTarget = new byte[((byte[])headerValue).length];
+                        System.arraycopy(headerValue, 0, mTarget, 0, mTarget.length);
                     }
                 }
                 break;
             case HTTP:
                 if (headerValue == null) {
-                    http = null;
+                    mHttpHeader = null;
                 } else {
                     if (!(headerValue instanceof byte[])) {
                         throw new IllegalArgumentException("HTTP must be a byte array");
                     } else {
-                        http = new byte[((byte[])headerValue).length];
-                        System.arraycopy(headerValue, 0, http, 0, http.length);
+                        mHttpHeader = new byte[((byte[])headerValue).length];
+                        System.arraycopy(headerValue, 0, mHttpHeader, 0, mHttpHeader.length);
                     }
                 }
                 break;
             case WHO:
                 if (headerValue == null) {
-                    who = null;
+                    mWho = null;
                 } else {
                     if (!(headerValue instanceof byte[])) {
                         throw new IllegalArgumentException("WHO must be a byte array");
                     } else {
-                        who = new byte[((byte[])headerValue).length];
-                        System.arraycopy(headerValue, 0, who, 0, who.length);
+                        mWho = new byte[((byte[])headerValue).length];
+                        System.arraycopy(headerValue, 0, mWho, 0, mWho.length);
                     }
                 }
                 break;
             case OBJECT_CLASS:
                 if (headerValue == null) {
-                    objectClass = null;
+                    mObjectClass = null;
                 } else {
                     if (!(headerValue instanceof byte[])) {
                         throw new IllegalArgumentException("Object Class must be a byte array");
                     } else {
-                        objectClass = new byte[((byte[])headerValue).length];
-                        System.arraycopy(headerValue, 0, objectClass, 0, objectClass.length);
+                        mObjectClass = new byte[((byte[])headerValue).length];
+                        System.arraycopy(headerValue, 0, mObjectClass, 0, mObjectClass.length);
                     }
                 }
                 break;
             case APPLICATION_PARAMETER:
                 if (headerValue == null) {
-                    appParam = null;
+                    mAppParam = null;
                 } else {
                     if (!(headerValue instanceof byte[])) {
                         throw new IllegalArgumentException(
                                 "Application Parameter must be a byte array");
                     } else {
-                        appParam = new byte[((byte[])headerValue).length];
-                        System.arraycopy(headerValue, 0, appParam, 0, appParam.length);
+                        mAppParam = new byte[((byte[])headerValue).length];
+                        System.arraycopy(headerValue, 0, mAppParam, 0, mAppParam.length);
                     }
                 }
                 break;
@@ -345,7 +382,7 @@
                         throw new IllegalArgumentException(
                                 "Unicode String User Defined must be a String");
                     }
-                    unicodeUserDefined[headerID - 0x30] = (String)headerValue;
+                    mUnicodeUserDefined[headerID - 0x30] = (String)headerValue;
 
                     break;
                 }
@@ -353,15 +390,15 @@
                 if ((headerID >= 0x70) && (headerID <= 0x7F)) {
 
                     if (headerValue == null) {
-                        sequenceUserDefined[headerID - 0x70] = null;
+                        mSequenceUserDefined[headerID - 0x70] = null;
                     } else {
                         if (!(headerValue instanceof byte[])) {
                             throw new IllegalArgumentException(
                                     "Byte Sequence User Defined must be a byte array");
                         } else {
-                            sequenceUserDefined[headerID - 0x70] = new byte[((byte[])headerValue).length];
-                            System.arraycopy(headerValue, 0, sequenceUserDefined[headerID - 0x70],
-                                    0, sequenceUserDefined[headerID - 0x70].length);
+                            mSequenceUserDefined[headerID - 0x70] = new byte[((byte[])headerValue).length];
+                            System.arraycopy(headerValue, 0, mSequenceUserDefined[headerID - 0x70],
+                                    0, mSequenceUserDefined[headerID - 0x70].length);
                         }
                     }
                     break;
@@ -371,7 +408,7 @@
                     if ((headerValue != null) && (!(headerValue instanceof Byte))) {
                         throw new IllegalArgumentException("ByteUser Defined must be a Byte");
                     }
-                    byteUserDefined[headerID - 0xB0] = (Byte)headerValue;
+                    mByteUserDefined[headerID - 0xB0] = (Byte)headerValue;
 
                     break;
                 }
@@ -380,7 +417,7 @@
                 if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
                     if (!(headerValue instanceof Long)) {
                         if (headerValue == null) {
-                            integerUserDefined[headerID - 0xF0] = null;
+                            mIntegerUserDefined[headerID - 0xF0] = null;
                             break;
                         }
                         throw new IllegalArgumentException("Integer User Defined must be a Long");
@@ -390,7 +427,7 @@
                         throw new IllegalArgumentException(
                                 "Integer User Defined must be between 0 and 0xFFFFFFFF");
                     }
-                    integerUserDefined[headerID - 0xF0] = (Long)headerValue;
+                    mIntegerUserDefined[headerID - 0xF0] = (Long)headerValue;
                     break;
                 }
                 throw new IllegalArgumentException("Invalid Header Identifier");
@@ -417,45 +454,45 @@
 
         switch (headerID) {
             case COUNT:
-                return count;
+                return mCount;
             case NAME:
-                return name;
+                return mName;
             case TYPE:
-                return type;
+                return mType;
             case LENGTH:
-                return length;
+                return mLength;
             case TIME_ISO_8601:
-                return isoTime;
+                return mIsoTime;
             case TIME_4_BYTE:
-                return byteTime;
+                return mByteTime;
             case DESCRIPTION:
-                return description;
+                return mDescription;
             case TARGET:
-                return target;
+                return mTarget;
             case HTTP:
-                return http;
+                return mHttpHeader;
             case WHO:
-                return who;
+                return mWho;
             case OBJECT_CLASS:
-                return objectClass;
+                return mObjectClass;
             case APPLICATION_PARAMETER:
-                return appParam;
+                return mAppParam;
             default:
                 // Verify that it was not a Unicode String user Defined
                 if ((headerID >= 0x30) && (headerID <= 0x3F)) {
-                    return unicodeUserDefined[headerID - 0x30];
+                    return mUnicodeUserDefined[headerID - 0x30];
                 }
                 // Verify that it was not a byte sequence user defined header
                 if ((headerID >= 0x70) && (headerID <= 0x7F)) {
-                    return sequenceUserDefined[headerID - 0x70];
+                    return mSequenceUserDefined[headerID - 0x70];
                 }
                 // Verify that it was not a byte user defined header
                 if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
-                    return byteUserDefined[headerID - 0xB0];
+                    return mByteUserDefined[headerID - 0xB0];
                 }
-                // Verify that it was not a itneger user defined header
+                // Verify that it was not a integer user defined header
                 if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
-                    return integerUserDefined[headerID - 0xF0];
+                    return mIntegerUserDefined[headerID - 0xF0];
                 }
                 throw new IllegalArgumentException("Invalid Header Identifier");
         }
@@ -478,63 +515,63 @@
     public int[] getHeaderList() throws IOException {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
 
-        if (count != null) {
+        if (mCount != null) {
             out.write(COUNT);
         }
-        if (name != null) {
+        if (mName != null) {
             out.write(NAME);
         }
-        if (type != null) {
+        if (mType != null) {
             out.write(TYPE);
         }
-        if (length != null) {
+        if (mLength != null) {
             out.write(LENGTH);
         }
-        if (isoTime != null) {
+        if (mIsoTime != null) {
             out.write(TIME_ISO_8601);
         }
-        if (byteTime != null) {
+        if (mByteTime != null) {
             out.write(TIME_4_BYTE);
         }
-        if (description != null) {
+        if (mDescription != null) {
             out.write(DESCRIPTION);
         }
-        if (target != null) {
+        if (mTarget != null) {
             out.write(TARGET);
         }
-        if (http != null) {
+        if (mHttpHeader != null) {
             out.write(HTTP);
         }
-        if (who != null) {
+        if (mWho != null) {
             out.write(WHO);
         }
-        if (appParam != null) {
+        if (mAppParam != null) {
             out.write(APPLICATION_PARAMETER);
         }
-        if (objectClass != null) {
+        if (mObjectClass != null) {
             out.write(OBJECT_CLASS);
         }
 
         for (int i = 0x30; i < 0x40; i++) {
-            if (unicodeUserDefined[i - 0x30] != null) {
+            if (mUnicodeUserDefined[i - 0x30] != null) {
                 out.write(i);
             }
         }
 
         for (int i = 0x70; i < 0x80; i++) {
-            if (sequenceUserDefined[i - 0x70] != null) {
+            if (mSequenceUserDefined[i - 0x70] != null) {
                 out.write(i);
             }
         }
 
         for (int i = 0xB0; i < 0xC0; i++) {
-            if (byteUserDefined[i - 0xB0] != null) {
+            if (mByteUserDefined[i - 0xB0] != null) {
                 out.write(i);
             }
         }
 
         for (int i = 0xF0; i < 0x100; i++) {
-            if (integerUserDefined[i - 0xF0] != null) {
+            if (mIntegerUserDefined[i - 0xF0] != null) {
                 out.write(i);
             }
         }
@@ -572,18 +609,20 @@
      * @param access if <code>true</code> then full access will be granted if
      * successful; if <code>false</code> then read-only access will be granted
      * if successful
+     * @throws IOException
      */
-    public void createAuthenticationChallenge(String realm, boolean userID, boolean access) {
+    public void createAuthenticationChallenge(String realm, boolean userID, boolean access)
+            throws IOException {
 
         try {
             nonce = new byte[16];
             for (int i = 0; i < 16; i++) {
-                nonce[i] = (byte)random.nextInt();
+                nonce[i] = (byte)mRandom.nextInt();
             }
 
-            authChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
+            mAuthChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
         } catch (IOException e) {
-            throw new RuntimeException(e.getMessage());
+            throw e;
         }
     }
 
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index 6bf5e3e..511b7c6 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -48,15 +48,17 @@
  */
 public final class ObexHelper {
 
-    /** Prevent object construction of helper class */
-    private ObexHelper() {}
-
     /**
-     * Defines the OBEX CONTINUE response code.
-     * <P>
-     * The value of <code>OBEX_HTTP_CONTINUE</code> is 0x90 (144).
+     * Defines the basic packet length used by OBEX.  Every OBEX packet has the
+     * same basic format:<BR>
+     * Byte 0: Request or Response Code
+     * Byte 1&2: Length of the packet.
      */
-    public static final int OBEX_HTTP_CONTINUE = 0x90;
+    public static final int BASE_PACKET_LENGTH = 3;
+
+    /** Prevent object construction of helper class */
+    private ObexHelper() {
+    }
 
     /**
      * The maximum packet size for OBEX packets that this client can handle.
@@ -73,6 +75,48 @@
      */
     public static final int MAX_PACKET_SIZE_INT = 0xFFFE;
 
+    public static final int OBEX_OPCODE_CONNECT = 0x80;
+
+    public static final int OBEX_OPCODE_DISCONNECT = 0x81;
+
+    public static final int OBEX_OPCODE_PUT = 0x02;
+
+    public static final int OBEX_OPCODE_PUT_FINAL = 0x82;
+
+    public static final int OBEX_OPCODE_GET = 0x03;
+
+    public static final int OBEX_OPCODE_GET_FINAL = 0x83;
+
+    public static final int OBEX_OPCODE_RESERVED = 0x04;
+
+    public static final int OBEX_OPCODE_RESERVED_FINAL = 0x84;
+
+    public static final int OBEX_OPCODE_SETPATH = 0x85;
+
+    public static final int OBEX_OPCODE_ABORT = 0xFF;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ASCII = 0x00;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_1 = 0x01;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_2 = 0x02;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_3 = 0x03;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_4 = 0x04;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_5 = 0x05;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_6 = 0x06;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_7 = 0x07;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_8 = 0x08;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_9 = 0x09;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_UNICODE = 0xFF;
+
     /**
      * Updates the HeaderSet with the headers received in the byte array
      * provided.  Invalid headers are ignored.
@@ -153,37 +197,25 @@
                                                 value.length - 1, "ISO8859_1"));
                                     }
                                 } catch (UnsupportedEncodingException e) {
-                                    throw new RuntimeException("ISO8859_1 is not supported"
-                                            + e.getMessage());
+                                    throw e;
                                 }
                                 break;
 
-                            // This is the constant for the authentication challenge header
-                            // This header does not have a constant defined in the Java
-                            // OBEX API
-                            case 0x4D:
-                                headerImpl.authChall = new byte[length];
-                                System.arraycopy(headerArray, index, headerImpl.authChall, 0,
+                            case HeaderSet.AUTH_CHALLENGE:
+                                headerImpl.mAuthChall = new byte[length];
+                                System.arraycopy(headerArray, index, headerImpl.mAuthChall, 0,
                                         length);
                                 break;
 
-                            // This is the constant for the authentication response header
-                            // This header does not have a constant defined in the Java
-                            // OBEX API
-                            case 0x4E:
-                                headerImpl.authResp = new byte[length];
-                                System
-                                        .arraycopy(headerArray, index, headerImpl.authResp, 0,
-                                                length);
+                            case HeaderSet.AUTH_RESPONSE:
+                                headerImpl.mAuthResp = new byte[length];
+                                System.arraycopy(headerArray, index, headerImpl.mAuthResp, 0,
+                                        length);
                                 break;
 
-                            /*
-                            * These two case statements are for the body (0x48)
-                             * and end of body (0x49) headers.
-                            */
-                            case 0x48:
+                            case HeaderSet.BODY:
                                 /* Fall Through */
-                            case 0x49:
+                            case HeaderSet.END_OF_BODY:
                                 body = new byte[length + 1];
                                 body[0] = (byte)headerID;
                                 System.arraycopy(headerArray, index, body, 1, length);
@@ -211,24 +243,16 @@
                                             .substring(13, 15)));
                                     headerImpl.setHeader(HeaderSet.TIME_ISO_8601, temp);
                                 } catch (UnsupportedEncodingException e) {
-                                    throw new RuntimeException("ISO8859_1 is not supported"
-                                            + e.getMessage());
-                                } catch (Exception e) {
-                                    throw new IOException(
-                                            "Time Header does not follow ISO 8601 standard");
+                                    throw e;
                                 }
                                 break;
 
                             default:
-                                try {
-                                    if ((headerID & 0xC0) == 0x00) {
-                                        headerImpl.setHeader(headerID, ObexHelper.convertToUnicode(
-                                                value, true));
-                                    } else {
-                                        headerImpl.setHeader(headerID, value);
-                                    }
-                                } catch (Exception e) {
-                                    // Not a valid header so ignore
+                                if ((headerID & 0xC0) == 0x00) {
+                                    headerImpl.setHeader(headerID, ObexHelper.convertToUnicode(
+                                            value, true));
+                                } else {
+                                    headerImpl.setHeader(headerID, value);
                                 }
                         }
 
@@ -262,9 +286,9 @@
                             if (headerID != HeaderSet.TIME_4_BYTE) {
                                 // Determine if it is a connection ID.  These
                                 // need to be handled differently
-                                if (headerID == 0xCB) {
-                                    headerImpl.connectionID = new byte[4];
-                                    System.arraycopy(value, 0, headerImpl.connectionID, 0, 4);
+                                if (headerID == HeaderSet.CONNECTION_ID) {
+                                    headerImpl.mConnectionID = new byte[4];
+                                    System.arraycopy(value, 0, headerImpl.mConnectionID, 0, 4);
                                 } else {
                                     headerImpl.setHeader(headerID, Long
                                             .valueOf(convertToLong(value)));
@@ -328,10 +352,10 @@
              * Determine if there is a connection ID to send.  If there is,
              * then it should be the first header in the packet.
              */
-            if ((headImpl.connectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
+            if ((headImpl.mConnectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
 
-                out.write((byte)0xCB);
-                out.write(headImpl.connectionID);
+                out.write((byte)HeaderSet.CONNECTION_ID);
+                out.write(headImpl.mConnectionID);
             }
 
             // Count Header
@@ -351,8 +375,8 @@
                 out.write((byte)HeaderSet.NAME);
                 value = ObexHelper.convertToUnicodeByteArray(stringHeader);
                 length = value.length + 3;
-                lengthArray[0] = (byte)(255 & (length >> 8));
-                lengthArray[1] = (byte)(255 & length);
+                lengthArray[0] = (byte)(0xFF & (length >> 8));
+                lengthArray[1] = (byte)(0xFF & length);
                 out.write(lengthArray);
                 out.write(value);
                 if (nullOut) {
@@ -367,7 +391,7 @@
                 try {
                     value = stringHeader.getBytes("ISO8859_1");
                 } catch (UnsupportedEncodingException e) {
-                    throw new RuntimeException("Unsupported Encoding Scheme: " + e.getMessage());
+                    throw e;
                 }
 
                 length = value.length + 4;
@@ -440,7 +464,7 @@
                 try {
                     value = buffer.toString().getBytes("ISO8859_1");
                 } catch (UnsupportedEncodingException e) {
-                    throw new RuntimeException("UnsupportedEncodingException: " + e.getMessage());
+                    throw e;
                 }
 
                 length = value.length + 3;
@@ -612,28 +636,28 @@
             }
 
             // Add the authentication challenge header
-            if (headImpl.authChall != null) {
-                out.write((byte)0x4D);
-                length = headImpl.authChall.length + 3;
+            if (headImpl.mAuthChall != null) {
+                out.write((byte)HeaderSet.AUTH_CHALLENGE);
+                length = headImpl.mAuthChall.length + 3;
                 lengthArray[0] = (byte)(255 & (length >> 8));
                 lengthArray[1] = (byte)(255 & length);
                 out.write(lengthArray);
-                out.write(headImpl.authChall);
+                out.write(headImpl.mAuthChall);
                 if (nullOut) {
-                    headImpl.authChall = null;
+                    headImpl.mAuthChall = null;
                 }
             }
 
             // Add the authentication response header
-            if (headImpl.authResp != null) {
-                out.write((byte)0x4E);
-                length = headImpl.authResp.length + 3;
+            if (headImpl.mAuthResp != null) {
+                out.write((byte)HeaderSet.AUTH_RESPONSE);
+                length = headImpl.mAuthResp.length + 3;
                 lengthArray[0] = (byte)(255 & (length >> 8));
                 lengthArray[1] = (byte)(255 & length);
                 out.write(lengthArray);
-                out.write(headImpl.authResp);
+                out.write(headImpl.mAuthResp);
                 if (nullOut) {
-                    headImpl.authResp = null;
+                    headImpl.mAuthResp = null;
                 }
             }
 
diff --git a/obex/javax/obex/ObexSession.java b/obex/javax/obex/ObexSession.java
index 1dc50c6c..97d65e0 100644
--- a/obex/javax/obex/ObexSession.java
+++ b/obex/javax/obex/ObexSession.java
@@ -47,8 +47,180 @@
  * 
  * @hide
  */
-public interface ObexSession {
+public class ObexSession {
 
-    public void close() throws IOException;
+    protected Authenticator mAuthenticator;
 
+    protected byte[] mChallengeDigest;
+
+    /**
+     * Called when the server received an authentication challenge header. This
+     * will cause the authenticator to handle the authentication challenge.
+     *
+     * @param header
+     *            the header with the authentication challenge
+     *
+     * @return <code>true</code> if the last request should be resent;
+     *         <code>false</code> if the last request should not be resent
+     * @throws IOException
+     */
+    public boolean handleAuthChall(HeaderSet header) throws IOException {
+        if (mAuthenticator == null) {
+            return false;
+        }
+
+        /*
+         * An authentication challenge is made up of one required and two
+         * optional tag length value triplets. The tag 0x00 is required to be in
+         * the authentication challenge and it represents the challenge digest
+         * that was received. The tag 0x01 is the options tag. This tag tracks
+         * if user ID is required and if full access will be granted. The tag
+         * 0x02 is the realm, which provides a description of which user name
+         * and password to use.
+         */
+        byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.mAuthChall);
+        byte[] option = ObexHelper.getTagValue((byte)0x01, header.mAuthChall);
+        byte[] description = ObexHelper.getTagValue((byte)0x02, header.mAuthChall);
+
+        String realm = null;
+        if (description != null) {
+            byte[] realmString = new byte[description.length - 1];
+            System.arraycopy(description, 1, realmString, 0, realmString.length);
+
+            switch (description[0] & 0xFF) {
+
+                case ObexHelper.OBEX_AUTH_REALM_CHARSET_ASCII:
+                    // ASCII encoding
+                    // Fall through
+                case ObexHelper.OBEX_AUTH_REALM_CHARSET_ISO_8859_1:
+                    // ISO-8859-1 encoding
+                    try {
+                        realm = new String(realmString, "ISO8859_1");
+                    } catch (Exception e) {
+                        throw new IOException("Unsupported Encoding Scheme");
+                    }
+                    break;
+
+                case ObexHelper.OBEX_AUTH_REALM_CHARSET_UNICODE:
+                    // UNICODE Encoding
+                    realm = ObexHelper.convertToUnicode(realmString, false);
+                    break;
+
+                default:
+                    throw new IOException("Unsupported Encoding Scheme");
+            }
+        }
+
+        boolean isUserIDRequired = false;
+        boolean isFullAccess = true;
+        if (option != null) {
+            if ((option[0] & 0x01) != 0) {
+                isUserIDRequired = true;
+            }
+
+            if ((option[0] & 0x02) != 0) {
+                isFullAccess = false;
+            }
+        }
+
+        PasswordAuthentication result = null;
+        header.mAuthChall = null;
+
+        try {
+            result = mAuthenticator
+                    .onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
+        } catch (Exception e) {
+            return false;
+        }
+
+        /*
+         * If no password is provided then we not resent the request
+         */
+        if (result == null) {
+            return false;
+        }
+
+        byte[] password = result.getPassword();
+        if (password == null) {
+            return false;
+        }
+
+        byte[] userName = result.getUserName();
+
+        /*
+         * Create the authentication response header. It includes 1 required and
+         * 2 option tag length value triples. The required triple has a tag of
+         * 0x00 and is the response digest. The first optional tag is 0x01 and
+         * represents the user ID. If no user ID is provided, then no user ID
+         * will be sent. The second optional tag is 0x02 and is the challenge
+         * that was received. This will always be sent
+         */
+        if (userName != null) {
+            header.mAuthResp = new byte[38 + userName.length];
+            header.mAuthResp[36] = (byte)0x01;
+            header.mAuthResp[37] = (byte)userName.length;
+            System.arraycopy(userName, 0, header.mAuthResp, 38, userName.length);
+        } else {
+            header.mAuthResp = new byte[36];
+        }
+
+        // Create the secret String
+        byte[] digest = new byte[challenge.length + password.length + 1];
+        System.arraycopy(challenge, 0, digest, 0, challenge.length);
+        // Insert colon between challenge and password
+        digest[challenge.length] = (byte)0x3A;
+        System.arraycopy(password, 0, digest, challenge.length + 1, password.length);
+
+        // Add the Response Digest
+        header.mAuthResp[0] = (byte)0x00;
+        header.mAuthResp[1] = (byte)0x10;
+
+        System.arraycopy(ObexHelper.computeMd5Hash(digest), 0, header.mAuthResp, 2, 16);
+
+        // Add the challenge
+        header.mAuthResp[18] = (byte)0x02;
+        header.mAuthResp[19] = (byte)0x10;
+        System.arraycopy(challenge, 0, header.mAuthResp, 20, 16);
+
+        return true;
+    }
+
+    /**
+     * Called when the server received an authentication response header. This
+     * will cause the authenticator to handle the authentication response.
+     *
+     * @param authResp
+     *            the authentication response
+     *
+     * @return <code>true</code> if the response passed; <code>false</code> if
+     *         the response failed
+     */
+    public boolean handleAuthResp(byte[] authResp) {
+        if (mAuthenticator == null) {
+            return false;
+        }
+        // get the correct password from the application
+        byte[] correctPassword = mAuthenticator.onAuthenticationResponse(ObexHelper.getTagValue(
+                (byte)0x01, authResp));
+        if (correctPassword == null) {
+            return false;
+        }
+
+        byte[] temp = new byte[correctPassword.length + 16];
+
+        System.arraycopy(mChallengeDigest, 0, temp, 0, 16);
+        System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
+
+        byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
+        byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
+
+        // compare the MD5 hash array .
+        for (int i = 0; i < 16; i++) {
+            if (correctResponse[i] != actualResponse[i]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
 }
diff --git a/obex/javax/obex/Operation.java b/obex/javax/obex/Operation.java
index 5a8bcec..f265f53 100644
--- a/obex/javax/obex/Operation.java
+++ b/obex/javax/obex/Operation.java
@@ -137,7 +137,7 @@
      * @throws IOException if the transaction has already ended or if an
      * OBEX server calls this method
      */
-    public void abort() throws IOException;
+    void abort() throws IOException;
 
     /**
      * Returns the headers that have been received during the operation.
@@ -148,7 +148,7 @@
      *
      * @throws IOException if this <code>Operation</code> has been closed
      */
-    public HeaderSet getReceivedHeaders() throws IOException;
+    HeaderSet getReceivedHeader() throws IOException;
 
     /**
      * Specifies the headers that should be sent in the next OBEX message that
@@ -165,7 +165,7 @@
      *
      * @throws NullPointerException if <code>headers</code> if <code>null</code>
      */
-    public void sendHeaders(HeaderSet headers) throws IOException;
+    void sendHeaders(HeaderSet headers) throws IOException;
 
     /**
      * Returns the response code received from the server.  Response codes
@@ -178,23 +178,23 @@
      * @throws IOException if an error occurred in the transport layer during
      * the transaction; if this object was created by an OBEX server
      */
-    public int getResponseCode() throws IOException;
+    int getResponseCode() throws IOException;
 
-    public String getEncoding();
+    String getEncoding();
 
-    public long getLength();
+    long getLength();
 
-    public String getType();
+    String getType();
 
-    public InputStream openInputStream() throws IOException;
+    InputStream openInputStream() throws IOException;
 
-    public DataInputStream openDataInputStream() throws IOException;
+    DataInputStream openDataInputStream() throws IOException;
 
-    public OutputStream openOutputStream() throws IOException;
+    OutputStream openOutputStream() throws IOException;
 
-    public DataOutputStream openDataOutputStream() throws IOException;
+    DataOutputStream openDataOutputStream() throws IOException;
 
-    public void close() throws IOException;
+    void close() throws IOException;
 
-    public int getMaxPacketSize();
+    int getMaxPacketSize();
 }
diff --git a/obex/javax/obex/PasswordAuthentication.java b/obex/javax/obex/PasswordAuthentication.java
index 49833fe..e81a861 100644
--- a/obex/javax/obex/PasswordAuthentication.java
+++ b/obex/javax/obex/PasswordAuthentication.java
@@ -37,11 +37,11 @@
  *
  * @hide
  */
-public class PasswordAuthentication {
+public final class PasswordAuthentication {
 
-    private byte[] userName;
+    private byte[] mUserName;
 
-    private byte[] password;
+    private final byte[] mPassword;
 
     /**
      * Creates a new <code>PasswordAuthentication</code> with the user name
@@ -51,17 +51,17 @@
      *
      * @param password the password to include in the response
      *
-     * @exception NullPointerException if <code>password</code> is
+     * @throws NullPointerException if <code>password</code> is
      * <code>null</code>
      */
-    public PasswordAuthentication(byte[] userName, byte[] password) {
+    public PasswordAuthentication(final byte[] userName, final byte[] password) {
         if (userName != null) {
-            this.userName = new byte[userName.length];
-            System.arraycopy(userName, 0, this.userName, 0, userName.length);
+            mUserName = new byte[userName.length];
+            System.arraycopy(userName, 0, mUserName, 0, userName.length);
         }
 
-        this.password = new byte[password.length];
-        System.arraycopy(password, 0, this.password, 0, password.length);
+        mPassword = new byte[password.length];
+        System.arraycopy(password, 0, mPassword, 0, password.length);
     }
 
     /**
@@ -71,7 +71,7 @@
      * @return the user name
      */
     public byte[] getUserName() {
-        return this.userName;
+        return mUserName;
     }
 
     /**
@@ -80,6 +80,6 @@
      * @return the password
      */
     public byte[] getPassword() {
-        return this.password;
+        return mPassword;
     }
 }
diff --git a/obex/javax/obex/PrivateInputStream.java b/obex/javax/obex/PrivateInputStream.java
index 9602649..2dc02da 100644
--- a/obex/javax/obex/PrivateInputStream.java
+++ b/obex/javax/obex/PrivateInputStream.java
@@ -39,23 +39,17 @@
  * This object provides an input stream to the Operation objects used in this
  * package.
  *
- * TODO: Include the other read() methods defined in InputStream.
- *
  * @hide
  */
-public class PrivateInputStream extends InputStream {
+public final class PrivateInputStream extends InputStream {
 
-    private BaseStream parent;
+    private BaseStream mParent;
 
-    private byte[] data;
+    private byte[] mData;
 
-    private int index;
+    private int mIndex;
 
-    private boolean isOpen;
-
-    public PrivateInputStream() {
-
-    }
+    private boolean mOpen;
 
     /**
      * Creates an input stream for the <code>Operation</code> to read from
@@ -63,10 +57,10 @@
      * @param p the connection this input stream is for
      */
     public PrivateInputStream(BaseStream p) {
-        parent = p;
-        data = new byte[0];
-        index = 0;
-        isOpen = true;
+        mParent = p;
+        mData = new byte[0];
+        mIndex = 0;
+        mOpen = true;
     }
 
     /**
@@ -83,7 +77,7 @@
     @Override
     public synchronized int available() throws IOException {
         ensureOpen();
-        return data.length - index;
+        return mData.length - mIndex;
     }
 
     /**
@@ -101,12 +95,12 @@
     @Override
     public synchronized int read() throws IOException {
         ensureOpen();
-        while (data.length == index) {
-            if (!parent.continueOperation(true, true)) {
+        while (mData.length == mIndex) {
+            if (!mParent.continueOperation(true, true)) {
                 return -1;
             }
         }
-        return (data[index++] & 0xFF);
+        return (mData[mIndex++] & 0xFF);
     }
 
     @Override
@@ -118,33 +112,33 @@
     public synchronized int read(byte[] b, int offset, int length) throws IOException {
 
         if (b == null) {
-            throw new NullPointerException("buffer is null");
+            throw new IOException("buffer is null");
         }
         if ((offset | length) < 0 || length > b.length - offset) {
             throw new ArrayIndexOutOfBoundsException("index outof bound");
         }
         ensureOpen();
 
-        int currentDataLength = data.length - index;
+        int currentDataLength = mData.length - mIndex;
         int remainReadLength = length;
         int offset1 = offset;
         int result = 0;
 
         while (currentDataLength <= remainReadLength) {
-            System.arraycopy(data, index, b, offset1, currentDataLength);
-            index += currentDataLength;
+            System.arraycopy(mData, mIndex, b, offset1, currentDataLength);
+            mIndex += currentDataLength;
             offset1 += currentDataLength;
             result += currentDataLength;
             remainReadLength -= currentDataLength;
 
-            if (!parent.continueOperation(true, true)) {
+            if (!mParent.continueOperation(true, true)) {
                 return result == 0 ? -1 : result;
             }
-            currentDataLength = data.length - index;
+            currentDataLength = mData.length - mIndex;
         }
         if (remainReadLength > 0) {
-            System.arraycopy(data, index, b, offset1, remainReadLength);
-            index += remainReadLength;
+            System.arraycopy(mData, mIndex, b, offset1, remainReadLength);
+            mIndex += remainReadLength;
             result += remainReadLength;
         }
         return result;
@@ -160,14 +154,14 @@
      */
     public synchronized void writeBytes(byte[] body, int start) {
 
-        int length = (body.length - start) + (data.length - index);
+        int length = (body.length - start) + (mData.length - mIndex);
         byte[] temp = new byte[length];
 
-        System.arraycopy(data, index, temp, 0, data.length - index);
-        System.arraycopy(body, start, temp, data.length - index, body.length - start);
+        System.arraycopy(mData, mIndex, temp, 0, mData.length - mIndex);
+        System.arraycopy(body, start, temp, mData.length - mIndex, body.length - start);
 
-        data = temp;
-        index = 0;
+        mData = temp;
+        mIndex = 0;
         notifyAll();
     }
 
@@ -177,8 +171,8 @@
      * @throws IOException if the stream is not open
      */
     private void ensureOpen() throws IOException {
-        parent.ensureOpen();
-        if (!isOpen) {
+        mParent.ensureOpen();
+        if (!mOpen) {
             throw new IOException("Input stream is closed");
         }
     }
@@ -191,7 +185,7 @@
      */
     @Override
     public void close() throws IOException {
-        isOpen = false;
-        parent.streamClosed(true);
+        mOpen = false;
+        mParent.streamClosed(true);
     }
 }
diff --git a/obex/javax/obex/PrivateOutputStream.java b/obex/javax/obex/PrivateOutputStream.java
index 75220d6..d972f78 100644
--- a/obex/javax/obex/PrivateOutputStream.java
+++ b/obex/javax/obex/PrivateOutputStream.java
@@ -42,15 +42,15 @@
  *
  * @hide
  */
-class PrivateOutputStream extends OutputStream {
+public final class PrivateOutputStream extends OutputStream {
 
-    private BaseStream parent;
+    private BaseStream mParent;
 
-    private ByteArrayOutputStream output;
+    private ByteArrayOutputStream mArray;
 
-    private boolean isClosed;
+    private boolean mOpen;
 
-    private int maxPacketSize;
+    private int mMaxPacketSize;
 
     /**
      * Creates an empty <code>PrivateOutputStream</code> to write to.
@@ -58,9 +58,9 @@
      * @param p the connection that this stream runs over
      */
     public PrivateOutputStream(BaseStream p, int maxSize) {
-        parent = p;
-        output = new ByteArrayOutputStream();
-        maxPacketSize = maxSize;
+        mParent = p;
+        mArray = new ByteArrayOutputStream();
+        mMaxPacketSize = maxSize;
     }
 
     /**
@@ -68,8 +68,8 @@
      *
      * @return the number of bytes written to the output stream
      */
-    protected int size() {
-        return output.size();
+    public int size() {
+        return mArray.size();
     }
 
     /**
@@ -85,10 +85,10 @@
     @Override
     public synchronized void write(int b) throws IOException {
         ensureOpen();
-        parent.ensureNotDone();
-        output.write(b);
-        if (output.size() == maxPacketSize) {
-            parent.continueOperation(true, false);
+        mParent.ensureNotDone();
+        mArray.write(b);
+        if (mArray.size() == mMaxPacketSize) {
+            mParent.continueOperation(true, false);
         }
     }
 
@@ -103,25 +103,25 @@
         int remainLength = count;
 
         if (buffer == null) {
-            throw new NullPointerException("buffer is null");
+            throw new IOException("buffer is null");
         }
         if ((offset | count) < 0 || count > buffer.length - offset) {
             throw new IndexOutOfBoundsException("index outof bound");
         }
 
         ensureOpen();
-        parent.ensureNotDone();
-        if (count < maxPacketSize) {
-            output.write(buffer, offset, count);
+        mParent.ensureNotDone();
+        if (count < mMaxPacketSize) {
+            mArray.write(buffer, offset, count);
         } else {
-            while (remainLength >= maxPacketSize) {
-                output.write(buffer, offset1, maxPacketSize);
-                offset1 += maxPacketSize;
+            while (remainLength >= mMaxPacketSize) {
+                mArray.write(buffer, offset1, mMaxPacketSize);
+                offset1 += mMaxPacketSize;
                 remainLength = count - offset1;
-                parent.continueOperation(true, false);
+                mParent.continueOperation(true, false);
             }
             if (remainLength > 0) {
-                output.write(buffer, offset1, remainLength);
+                mArray.write(buffer, offset1, remainLength);
             }
         }
     }
@@ -129,33 +129,18 @@
     /**
      * Reads the bytes that have been written to this stream.
      *
-     * @return the byte array that is written
-     */
-    protected synchronized byte[] readBytes() {
-        if (output.size() > 0) {
-            byte[] result = output.toByteArray();
-            output.reset();
-            return result;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Reads the bytes that have been written to this stream.
-     *
      * @param size the size of the array to return
      *
      * @return the byte array that is written
      */
-    protected synchronized byte[] readBytes(int size) {
-        if (output.size() > 0) {
-            byte[] temp = output.toByteArray();
-            output.reset();
+    public synchronized byte[] readBytes(int size) {
+        if (mArray.size() > 0) {
+            byte[] temp = mArray.toByteArray();
+            mArray.reset();
             byte[] result = new byte[size];
             System.arraycopy(temp, 0, result, 0, size);
             if (temp.length != size) {
-                output.write(temp, size, temp.length - size);
+                mArray.write(temp, size, temp.length - size);
             }
             return result;
         } else {
@@ -169,8 +154,8 @@
      * @throws IOException if the stream is not open
      */
     private void ensureOpen() throws IOException {
-        parent.ensureOpen();
-        if (isClosed) {
+        mParent.ensureOpen();
+        if (!mOpen) {
             throw new IOException("Output stream is closed");
         }
     }
@@ -183,8 +168,8 @@
      */
     @Override
     public void close() throws IOException {
-        isClosed = true;
-        parent.streamClosed(false);
+        mOpen = false;
+        mParent.streamClosed(false);
     }
 
     /**
@@ -193,7 +178,7 @@
      * @return <code>true</code> if the connection is closed;
      * <code>false</code> if the connection is open
      */
-    protected boolean isClosed() {
-        return isClosed;
+    public boolean isClosed() {
+        return !mOpen;
     }
 }
diff --git a/obex/javax/obex/ResponseCodes.java b/obex/javax/obex/ResponseCodes.java
index 2d7627b..f6cc9c1 100644
--- a/obex/javax/obex/ResponseCodes.java
+++ b/obex/javax/obex/ResponseCodes.java
@@ -38,11 +38,8 @@
  * <P>
  * <STRONG>IMPORTANT NOTE</STRONG>
  * <P>
- * It is important to note that these values are different then those defined
- * in <code>javax.microedition.io.HttpConnection</code>.  The values in this
- * interface represent the values defined in the IrOBEX specification.  The
- * values in <code>javax.microedition.io.HttpConnection</code> represent values
- * defined in the HTTP specification.
+ * The values in this interface represent the values defined in the IrOBEX
+ * specification, which is different with the HTTP specification.
  * <P>
  * <code>OBEX_DATABASE_FULL</code> and <code>OBEX_DATABASE_LOCKED</code> require
  * further description since they are not defined in HTTP.  The server will send
@@ -54,7 +51,14 @@
  *
  * @hide
  */
-public class ResponseCodes {
+public final class ResponseCodes {
+
+    /**
+     * Defines the OBEX CONTINUE response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_CONTINUE</code> is 0x90 (144).
+     */
+    public static final int OBEX_HTTP_CONTINUE = 0x90;
 
     /**
      * Defines the OBEX SUCCESS response code.
@@ -318,5 +322,6 @@
     /**
      * Constructor does nothing.
      */
-    private ResponseCodes() {}
+    private ResponseCodes() {
+    }
 }
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
index 5dcbb93..6c3d9ba 100644
--- a/obex/javax/obex/ServerOperation.java
+++ b/obex/javax/obex/ServerOperation.java
@@ -48,7 +48,7 @@
  * additional OBEX packet.  0x82 is a PUT request that says that request is
  * complete.  In this case, the server can begin sending the response.  The
  * 0x03 is a GET request that signals that the request is not finished.  When
- * the server receives a 0x83, the client is signalling the server that it is
+ * the server receives a 0x83, the client is signaling the server that it is
  * done with its request.
  *
  * TODO: Extend the ClientOperation and reuse the methods defined
@@ -56,52 +56,44 @@
  *
  * @hide
  */
-public class ServerOperation implements Operation, BaseStream {
+public final class ServerOperation implements Operation, BaseStream {
 
-    private InputStream socketInput;
+    public boolean isAborted;
 
-    private ServerSession parent;
+    public HeaderSet requestHeader;
 
-    private int maxPacketLength;
+    public HeaderSet replyHeader;
 
-    private int responseSize;
+    public boolean finalBitSet;
 
-    private boolean isClosed;
+    private InputStream mInput;
 
-    boolean finalBitSet;
+    private ServerSession mParent;
 
-    // This variable defines when the end of body
-    // header has been received.  When this header
-    // is received, no further body data will be
-    // received from the client
-    private boolean endOfBody;
+    private int mMaxPacketLength;
 
-    private boolean isGet;
+    private int mResponseSize;
 
-    boolean isAborted;
+    private boolean mClosed;
 
-    HeaderSet requestHeaders;
+    private boolean mGetOperation;
 
-    HeaderSet replyHeaders;
+    private PrivateInputStream mPrivateInput;
 
-    PrivateInputStream privateInput;
+    private PrivateOutputStream mPrivateOutput;
 
-    private PrivateOutputStream privateOutput;
+    private boolean mPrivateOutputOpen;
 
-    private String exceptionString;
+    private String mExceptionString;
 
-    private ServerRequestHandler listener;
+    private ServerRequestHandler mListener;
 
-    private boolean outputStreamOpened;
+    private boolean mRequestFinished;
 
-    private boolean requestFinished;
-
-    private static final int BASE_PACKET_LENGTH = 3;
-
-    private boolean isHasBody;
+    private boolean mHasBody;
 
     /**
-     * Creates new PutServerOperation
+     * Creates new ServerOperation
      *
      * @param p the parent that created this object
      *
@@ -121,19 +113,18 @@
             ServerRequestHandler listen) throws IOException {
 
         isAborted = false;
-        parent = p;
-        socketInput = in;
-        maxPacketLength = maxSize;
-        isClosed = false;
-        requestHeaders = new HeaderSet();
-        replyHeaders = new HeaderSet();
-        privateInput = new PrivateInputStream(this);
-        endOfBody = false;
-        responseSize = 3;
-        listener = listen;
-        requestFinished = false;
-        outputStreamOpened = false;
-        isHasBody = false;
+        mParent = p;
+        mInput = in;
+        mMaxPacketLength = maxSize;
+        mClosed = false;
+        requestHeader = new HeaderSet();
+        replyHeader = new HeaderSet();
+        mPrivateInput = new PrivateInputStream(this);
+        mResponseSize = 3;
+        mListener = listen;
+        mRequestFinished = false;
+        mPrivateOutputOpen = false;
+        mHasBody = false;
         int bytesReceived;
 
         /*
@@ -143,12 +134,12 @@
             /*
              * It is a PUT request.
              */
-            isGet = false;
+            mGetOperation = false;
         } else {
             /*
              * It is a GET request.
              */
-            isGet = true;
+            mGetOperation = true;
         }
 
         /*
@@ -158,7 +149,7 @@
             finalBitSet = false;
         } else {
             finalBitSet = true;
-            requestFinished = true;
+            mRequestFinished = true;
         }
 
         int length = in.read();
@@ -168,7 +159,7 @@
          * Determine if the packet length is larger than this device can receive
          */
         if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
-            parent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
+            mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
             throw new IOException("Packet received was too large");
         }
 
@@ -183,81 +174,69 @@
                 bytesReceived += in.read(data, bytesReceived, data.length - bytesReceived);
             }
 
-            byte[] body = ObexHelper.updateHeaderSet(requestHeaders, data);
+            byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
 
             if (body != null) {
-                isHasBody = true;
+                mHasBody = true;
             }
 
-            if (requestHeaders.connectionID != null) {
-                listener.setConnectionID(ObexHelper.convertToLong(requestHeaders.connectionID));
+            if (requestHeader.mConnectionID != null) {
+                mListener.setConnectionId(ObexHelper.convertToLong(requestHeader.mConnectionID));
             } else {
-                listener.setConnectionID(0);
+                mListener.setConnectionId(0);
             }
 
-            if (requestHeaders.authResp != null) {
-                if (!parent.handleAuthResp(requestHeaders.authResp)) {
-                    exceptionString = "Authentication Failed";
-                    parent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
-                    isClosed = true;
-                    requestHeaders.authResp = null;
+            if (requestHeader.mAuthResp != null) {
+                if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
+                    mExceptionString = "Authentication Failed";
+                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
+                    mClosed = true;
+                    requestHeader.mAuthResp = null;
                     return;
                 }
             }
 
-            if (requestHeaders.authChall != null) {
-                parent.handleAuthChall(requestHeaders);
+            if (requestHeader.mAuthChall != null) {
+                mParent.handleAuthChall(requestHeader);
                 // send the  authResp to the client
-                replyHeaders.authResp = new byte[requestHeaders.authResp.length];
-                System.arraycopy(requestHeaders.authResp, 0, replyHeaders.authResp, 0,
-                        replyHeaders.authResp.length);
-                requestHeaders.authResp = null;
-                requestHeaders.authChall = null;
+                replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
+                System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
+                        replyHeader.mAuthResp.length);
+                requestHeader.mAuthResp = null;
+                requestHeader.mAuthChall = null;
 
             }
 
             if (body != null) {
-                /*
-                 * 0x49 is the end of body header.  This signifies that no more
-                 * body data will be sent from the client
-                 */
-                if (body[0] == 0x49) {
-                    endOfBody = true;
-                }
-                //privateInput.writeBytes(body, body.length);
-                //byte [] body_tmp = new byte[body.length-1];
-                //System.arraycopy(body,1,body_tmp,0,body.length-1);
-                //privateInput.writeBytes(body_tmp, body.length-1);
-                privateInput.writeBytes(body, 1);
+                mPrivateInput.writeBytes(body, 1);
             } else {
-                while ((!isGet) && (!finalBitSet)) {
-                    sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
-                    if (privateInput.available() > 0) {
+                while ((!mGetOperation) && (!finalBitSet)) {
+                    sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+                    if (mPrivateInput.available() > 0) {
                         break;
                     }
                 }
-            }//  if (body != null) 
+            }
+        }
 
-        }// if (length > 3)
-
-        while ((!isGet) && (!finalBitSet) && (privateInput.available() == 0)) {
-            sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
-            if (privateInput.available() > 0) {
+        while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) {
+            sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+            if (mPrivateInput.available() > 0) {
                 break;
             }
         }
 
         // wait for get request finished !!!!
-        while (isGet && !finalBitSet) {
-            sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
+        while (mGetOperation && !finalBitSet) {
+            sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
         }
-        if (finalBitSet && isGet) {
-            requestFinished = true;
+        if (finalBitSet && mGetOperation) {
+            mRequestFinished = true;
         }
     }
 
-    public synchronized boolean isValidBody() {
-        return isHasBody;
+    public boolean isValidBody() {
+        return mHasBody;
     }
 
     /**
@@ -268,21 +247,21 @@
      * operation even if no headers will be sent; if <code>false</code> then
      * this method will only continue the operation if there are headers to
      * send
-     * @param isStream  if<code>true</code> the stream is input stream or
-     * is outputstream
+     * @param isStream  if<code>true</code> the stream is input stream, otherwise
+     * output stream
      * @return <code>true</code> if the operation was completed;
      * <code>false</code> if no operation took place
      */
     public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
             throws IOException {
-        if (!isGet) {
+        if (!mGetOperation) {
             if (!finalBitSet) {
                 if (sendEmpty) {
-                    sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
+                    sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
                     return true;
                 } else {
-                    if ((responseSize > 3) || (privateOutput.size() > 0)) {
-                        sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
+                    if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) {
+                        sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
                         return true;
                     } else {
                         return false;
@@ -292,7 +271,7 @@
                 return false;
             }
         } else {
-            sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
+            sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
             return true;
         }
     }
@@ -309,52 +288,52 @@
      *
      * @throws IOException if an IO error occurs
      */
-    protected synchronized boolean sendReply(int type) throws IOException {
+    public synchronized boolean sendReply(int type) throws IOException {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         int bytesReceived;
 
-        long id = listener.getConnectionID();
+        long id = mListener.getConnectionId();
         if (id == -1) {
-            replyHeaders.connectionID = null;
+            replyHeader.mConnectionID = null;
         } else {
-            replyHeaders.connectionID = ObexHelper.convertToByteArray(id);
+            replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
         }
 
-        byte[] headerArray = ObexHelper.createHeader(replyHeaders, true);
+        byte[] headerArray = ObexHelper.createHeader(replyHeader, true);
         int bodyLength = -1;
         int orginalBodyLength = -1;
 
-        if (privateOutput != null) {
-            bodyLength = privateOutput.size();
+        if (mPrivateOutput != null) {
+            bodyLength = mPrivateOutput.size();
             orginalBodyLength = bodyLength;
         }
 
-        if ((BASE_PACKET_LENGTH + headerArray.length) > maxPacketLength) {
+        if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {
 
             int end = 0;
             int start = 0;
 
             while (end != headerArray.length) {
-                end = ObexHelper.findHeaderEnd(headerArray, start, maxPacketLength
-                        - BASE_PACKET_LENGTH);
+                end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketLength
+                        - ObexHelper.BASE_PACKET_LENGTH);
                 if (end == -1) {
 
-                    isClosed = true;
+                    mClosed = true;
 
-                    if (privateInput != null) {
-                        privateInput.close();
+                    if (mPrivateInput != null) {
+                        mPrivateInput.close();
                     }
 
-                    if (privateOutput != null) {
-                        privateOutput.close();
+                    if (mPrivateOutput != null) {
+                        mPrivateOutput.close();
                     }
-                    parent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
                     throw new IOException("OBEX Packet exceeds max packet size");
                 }
                 byte[] sendHeader = new byte[end - start];
                 System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
 
-                parent.sendResponse(type, sendHeader);
+                mParent.sendResponse(type, sendHeader);
                 start = end;
             }
 
@@ -368,48 +347,25 @@
             out.write(headerArray);
         }
 
-        /*
-         * Determine if there is space to add a body reply.  First, we need to
-         * verify that the client is finished sending the request.  Next, there
-         * needs to be enough space to send the headers already defined along
-         * with the reply header (3 bytes) and the body header identifier
-         * (3 bytes).
-         */
-
-        /*        if ((finalBitSet) &&
-                    ((bodyLength + 6 + headerArray.length) > maxPacketLength)) {
-
-                    exceptionString = "Header larger then can be sent in a packet";
-                    isClosed = true;
-                    privateInput.close();
-                    if (privateOutput != null) {
-                        privateOutput.close();
-                    }
-                    parent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR,
-                        null);
-                    throw new IOException("OBEX Packet exceeds max packet size");
-                }
-        */
-         
-        if ((finalBitSet) || (headerArray.length < (maxPacketLength - 20))) {
+        if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
             if (bodyLength > 0) {
                 /*
                  * Determine if I can send the whole body or just part of
                  * the body.  Remember that there is the 3 bytes for the
                  * response message and 3 bytes for the header ID and length
                  */
-                if (bodyLength > (maxPacketLength - headerArray.length - 6)) {
-                    bodyLength = maxPacketLength - headerArray.length - 6;
+                if (bodyLength > (mMaxPacketLength - headerArray.length - 6)) {
+                    bodyLength = mMaxPacketLength - headerArray.length - 6;
                 }
 
-                byte[] body = privateOutput.readBytes(bodyLength);
+                byte[] body = mPrivateOutput.readBytes(bodyLength);
 
                 /*
                  * Since this is a put request if the final bit is set or
                  * the output stream is closed we need to send the 0x49
                  * (End of Body) otherwise, we need to send 0x48 (Body)
                  */
-                if ((finalBitSet) || (privateOutput.isClosed())) {
+                if ((finalBitSet) || (mPrivateOutput.isClosed())) {
                     out.write(0x49);
                 } else {
                     out.write(0x48);
@@ -430,44 +386,46 @@
 
         }
 
-        responseSize = 3;
-        parent.sendResponse(type, out.toByteArray());
+        mResponseSize = 3;
+        mParent.sendResponse(type, out.toByteArray());
 
-        if (type == ObexHelper.OBEX_HTTP_CONTINUE) {
-            int headerID = socketInput.read();
-            int length = socketInput.read();
-            length = (length << 8) + socketInput.read();
-            if ((headerID != 0x02) && (headerID != 0x82) && (headerID != 0x03)
-                    && (headerID != 0x83)) {
+        if (type == ResponseCodes.OBEX_HTTP_CONTINUE) {
+            int headerID = mInput.read();
+            int length = mInput.read();
+            length = (length << 8) + mInput.read();
+            if ((headerID != ObexHelper.OBEX_OPCODE_PUT)
+                    && (headerID != ObexHelper.OBEX_OPCODE_PUT_FINAL)
+                    && (headerID != ObexHelper.OBEX_OPCODE_GET)
+                    && (headerID != ObexHelper.OBEX_OPCODE_GET_FINAL)) {
 
                 if (length > 3) {
                     byte[] temp = new byte[length];
-                    bytesReceived = socketInput.read(temp);
+                    bytesReceived = mInput.read(temp);
 
                     while (bytesReceived != length) {
-                        bytesReceived += socketInput.read(temp, bytesReceived, length
-                                - bytesReceived);
+                        bytesReceived += mInput.read(temp, bytesReceived, length - bytesReceived);
                     }
                 }
 
                 /*
                  * Determine if an ABORT was sent as the reply
                  */
-                if (headerID == 0xFF) {
-                    parent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
-                    isClosed = true;
+                if (headerID == ObexHelper.OBEX_OPCODE_ABORT) {
+                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
+                    mClosed = true;
                     isAborted = true;
-                    exceptionString = "Abort Received";
+                    mExceptionString = "Abort Received";
                     throw new IOException("Abort Received");
                 } else {
-                    parent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
-                    isClosed = true;
-                    exceptionString = "Bad Request Received";
+                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
+                    mClosed = true;
+                    mExceptionString = "Bad Request Received";
                     throw new IOException("Bad Request Received");
                 }
             } else {
 
-                if ((headerID == 0x82) || (headerID == 0x83)) {
+                if ((headerID == ObexHelper.OBEX_OPCODE_PUT_FINAL)
+                        || (headerID == ObexHelper.OBEX_OPCODE_GET_FINAL)) {
                     finalBitSet = true;
                 }
 
@@ -475,7 +433,7 @@
                  * Determine if the packet length is larger then this device can receive
                  */
                 if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
-                    parent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
+                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
                     throw new IOException("Packet received was too large");
                 }
 
@@ -484,54 +442,46 @@
                  */
                 if (length > 3) {
                     byte[] data = new byte[length - 3];
-                    bytesReceived = socketInput.read(data);
+                    bytesReceived = mInput.read(data);
 
                     while (bytesReceived != data.length) {
-                        bytesReceived += socketInput.read(data, bytesReceived, data.length
+                        bytesReceived += mInput.read(data, bytesReceived, data.length
                                 - bytesReceived);
                     }
-                    byte[] body = ObexHelper.updateHeaderSet(requestHeaders, data);
+                    byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
                     if (body != null) {
-                        isHasBody = true;
+                        mHasBody = true;
                     }
-                    if (requestHeaders.connectionID != null) {
-                        listener.setConnectionID(ObexHelper
-                                .convertToLong(requestHeaders.connectionID));
+                    if (requestHeader.mConnectionID != null) {
+                        mListener.setConnectionId(ObexHelper
+                                .convertToLong(requestHeader.mConnectionID));
                     } else {
-                        listener.setConnectionID(1);
+                        mListener.setConnectionId(1);
                     }
 
-                    if (requestHeaders.authResp != null) {
-                        if (!parent.handleAuthResp(requestHeaders.authResp)) {
-                            exceptionString = "Authentication Failed";
-                            parent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
-                            isClosed = true;
-                            requestHeaders.authResp = null;
+                    if (requestHeader.mAuthResp != null) {
+                        if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
+                            mExceptionString = "Authentication Failed";
+                            mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
+                            mClosed = true;
+                            requestHeader.mAuthResp = null;
                             return false;
                         }
-                        requestHeaders.authResp = null;
+                        requestHeader.mAuthResp = null;
                     }
 
-                    if (requestHeaders.authChall != null) {
-                        parent.handleAuthChall(requestHeaders);
+                    if (requestHeader.mAuthChall != null) {
+                        mParent.handleAuthChall(requestHeader);
                         // send the auhtResp to the client
-                        replyHeaders.authResp = new byte[requestHeaders.authResp.length];
-                        System.arraycopy(requestHeaders.authResp, 0, replyHeaders.authResp, 0,
-                                replyHeaders.authResp.length);
-                        requestHeaders.authResp = null;
-                        requestHeaders.authChall = null;
+                        replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
+                        System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
+                                replyHeader.mAuthResp.length);
+                        requestHeader.mAuthResp = null;
+                        requestHeader.mAuthChall = null;
                     }
 
                     if (body != null) {
-                        if (body[0] == 0x49) {
-                            endOfBody = true;
-                        }
-
-                        /*byte [] body_tmp = new byte[body.length-1];
-                        System.arraycopy(body,1,body_tmp,0,body.length-1);
-                        privateInput.writeBytes(body_tmp, body.length-1);*/
-                        privateInput.writeBytes(body, 1);
-
+                        mPrivateInput.writeBytes(body, 1);
                     }
                 }
             }
@@ -562,9 +512,9 @@
      *
      * @throws IOException if this <code>Operation</code> has been closed
      */
-    public HeaderSet getReceivedHeaders() throws IOException {
+    public HeaderSet getReceivedHeader() throws IOException {
         ensureOpen();
-        return requestHeaders;
+        return requestHeader;
     }
 
     /**
@@ -583,13 +533,13 @@
         ensureOpen();
 
         if (headers == null) {
-            throw new NullPointerException("Headers may not be null");
+            throw new IOException("Headers may not be null");
         }
 
         int[] headerList = headers.getHeaderList();
         if (headerList != null) {
             for (int i = 0; i < headerList.length; i++) {
-                replyHeaders.setHeader(headerList[i], headers.getHeader(headerList[i]));
+                replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
             }
 
         }
@@ -629,7 +579,7 @@
      */
     public String getType() {
         try {
-            return (String)requestHeaders.getHeader(HeaderSet.TYPE);
+            return (String)requestHeader.getHeader(HeaderSet.TYPE);
         } catch (IOException e) {
             return null;
         }
@@ -645,7 +595,7 @@
      */
     public long getLength() {
         try {
-            Long temp = (Long)requestHeaders.getHeader(HeaderSet.LENGTH);
+            Long temp = (Long)requestHeader.getHeader(HeaderSet.LENGTH);
 
             if (temp == null) {
                 return -1;
@@ -658,7 +608,7 @@
     }
 
     public int getMaxPacketSize() {
-        return maxPacketLength - 6;
+        return mMaxPacketLength - 6;
     }
 
     /**
@@ -670,7 +620,7 @@
      */
     public InputStream openInputStream() throws IOException {
         ensureOpen();
-        return privateInput;
+        return mPrivateInput;
     }
 
     /**
@@ -694,17 +644,19 @@
     public OutputStream openOutputStream() throws IOException {
         ensureOpen();
 
-        if (outputStreamOpened)
+        if (mPrivateOutputOpen) {
             throw new IOException("no more input streams available, stream already opened");
-
-        if (!requestFinished)
-            throw new IOException("no  output streams available ,request not finished");
-
-        if (privateOutput == null) {
-            privateOutput = new PrivateOutputStream(this, maxPacketLength - 6);
         }
-        outputStreamOpened = true;
-        return privateOutput;
+
+        if (!mRequestFinished) {
+            throw new IOException("no  output streams available ,request not finished");
+        }
+
+        if (mPrivateOutput == null) {
+            mPrivateOutput = new PrivateOutputStream(this, mMaxPacketLength - 6);
+        }
+        mPrivateOutputOpen = true;
+        return mPrivateOutput;
     }
 
     /**
@@ -725,7 +677,7 @@
      */
     public void close() throws IOException {
         ensureOpen();
-        isClosed = true;
+        mClosed = true;
     }
 
     /**
@@ -734,10 +686,10 @@
      * @throws IOException if an exception needs to be thrown
      */
     public void ensureOpen() throws IOException {
-        if (exceptionString != null) {
-            throw new IOException(exceptionString);
+        if (mExceptionString != null) {
+            throw new IOException(mExceptionString);
         }
-        if (isClosed) {
+        if (mClosed) {
             throw new IOException("Operation has already ended");
         }
     }
diff --git a/obex/javax/obex/ServerRequestHandler.java b/obex/javax/obex/ServerRequestHandler.java
index 955e916..e468b83 100644
--- a/obex/javax/obex/ServerRequestHandler.java
+++ b/obex/javax/obex/ServerRequestHandler.java
@@ -71,7 +71,7 @@
  */
 public class ServerRequestHandler {
 
-    private long connectionID;
+    private long mConnectionId;
 
     /**
       * Creates a <code>ServerRequestHandler</code>.
@@ -80,33 +80,23 @@
         /*
          * A connection ID of -1 implies there is no conenction ID
          */
-        connectionID = -1;
-    }
-
-    /**
-     * Creates a <code>HeaderSet</code> object that may be used in put and get
-     * operations.
-     *
-     * @return the <code>HeaderSet</code> object to use in put and get operations
-     */
-    public final HeaderSet createHeaderSet() {
-        return new HeaderSet();
+        mConnectionId = -1;
     }
 
     /**
      * Sets the connection ID header to include in the reply packets.
      *
-     * @param id the connection ID to use; -1 if no connection ID should be
+     * @param connectionId the connection ID to use; -1 if no connection ID should be
      * sent
      *
      * @throws IllegalArgumentException if <code>id</code> is not in the
      * range -1 to 2<sup>32</sup>-1
      */
-    public void setConnectionID(long id) {
-        if ((id < -1) || (id > 0xFFFFFFFFL)) {
+    public void setConnectionId(final long connectionId) {
+        if ((connectionId < -1) || (connectionId > 0xFFFFFFFFL)) {
             throw new IllegalArgumentException("Illegal Connection ID");
         }
-        connectionID = id;
+        mConnectionId = connectionId;
     }
 
     /**
@@ -116,8 +106,8 @@
      * @return the connection id being used or -1 if no connection ID is being
      * used
      */
-    public long getConnectionID() {
-        return connectionID;
+    public long getConnectionId() {
+        return mConnectionId;
     }
 
     /**
@@ -231,7 +221,7 @@
      * If an ABORT request is received during the processing of a PUT request,
      * <code>op</code> will be closed by the implementation.
      *
-     * @param op contains the headers sent by the client and allows new
+     * @param operation contains the headers sent by the client and allows new
      * headers to be sent in the reply; <code>op</code> will never be
      * <code>null</code>
      *
@@ -239,7 +229,7 @@
      * returned to the client; if an invalid response code is provided, the
      * <code>OBEX_HTTP_INTERNAL_ERROR</code> response code will be used
      */
-    public int onPut(Operation op) {
+    public int onPut(Operation operation) {
         return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
     }
 
@@ -253,7 +243,7 @@
      * If an ABORT request is received during the processing of a GET request,
      * <code>op</code> will be closed by the implementation.
      *
-     * @param op contains the headers sent by the client and allows new
+     * @param operation contains the headers sent by the client and allows new
      * headers to be sent in the reply; <code>op</code> will never be
      * <code>null</code>
      *
@@ -261,7 +251,7 @@
      * returned to the client; if an invalid response code is provided, the
      * <code>OBEX_HTTP_INTERNAL_ERROR</code> response code will be used
      */
-    public int onGet(Operation op) {
+    public int onGet(Operation operation) {
         return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
     }
 
@@ -279,10 +269,23 @@
     public void onAuthenticationFailure(byte[] userName) {
     }
 
-    /**Called by ServerSession to update the status of current transaction */
+    /**
+     * Called by ServerSession to update the status of current transaction
+     * <P>
+     * If this method is not implemented by the class that extends this class,
+     * this method will do nothing.
+     *
+     */
     public void updateStatus(String message) {
     }
 
+    /**
+     * Called when session is closed.
+     * <P>
+     * If this method is not implemented by the class that extends this class,
+     * this method will do nothing.
+     *
+     */
     public void onClose() {
     }
 }
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index 9daa6c0..3a0e8150 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -32,39 +32,39 @@
 
 package javax.obex;
 
+import android.util.Log;
+
 import java.io.InputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
 /**
- * This class in an implementation of the ServerSession interface.
+ * This class in an implementation of the OBEX ServerSession.
  * 
  * @hide
  */
-public class ServerSession implements Runnable, ObexSession {
+public final class ServerSession extends ObexSession implements Runnable {
 
-    private ObexTransport client;
+    private static final String TAG = "Obex ServerSession";
 
-    private InputStream input;
+    private ObexTransport mTransport;
 
-    private OutputStream output;
+    private InputStream mInput;
 
-    private ServerRequestHandler listener;
+    private OutputStream mOutput;
 
-    private Thread processThread;
+    private ServerRequestHandler mListener;
 
-    private int maxPacketLength;
+    private Thread mProcessThread;
 
-    private Authenticator authenticator;
+    private int mMaxPacketLength;
 
-    byte[] challengeDigest;
-
-    private boolean isClosed;
+    private boolean mClosed;
 
     /**
      * Creates new ServerSession.
      *
-     * @param conn
+     * @param trans
      *            the connection to the client
      *
      * @param handler
@@ -77,50 +77,20 @@
      *                if an error occurred while opening the input and output
      *                streams
      */
-    public ServerSession(ObexTransport conn, ServerRequestHandler handler, Authenticator auth)
+    public ServerSession(ObexTransport trans, ServerRequestHandler handler, Authenticator auth)
             throws IOException {
-        authenticator = auth;
-        client = conn;
-        input = client.openInputStream();
-        output = client.openOutputStream();
-        listener = handler;
-        maxPacketLength = 256;
+        mAuthenticator = auth;
+        mTransport = trans;
+        mInput = mTransport.openInputStream();
+        mOutput = mTransport.openOutputStream();
+        mListener = handler;
+        mMaxPacketLength = 256;
 
-        isClosed = false;
-        processThread = new Thread(this);
-        processThread.start();
+        mClosed = false;
+        mProcessThread = new Thread(this);
+        mProcessThread.start();
     }
 
-    /* removed as they're provided to the API user. Not used internally. */
-    /*
-     public boolean isCreatedServer() {
-        if (client instanceof BTConnection)
-            return ((BTConnection)client).isServerCreated();
-        else
-            return false;
-    }
-
-    public boolean isClosed() {
-        if (client instanceof BTConnection)
-            return ((BTConnection)client).isClosed();
-        else
-            return false;
-    }
-
-    public int getConnectionHandle() {
-        if (client instanceof BTConnection)
-            return ((BTConnection)client).getConnectionHandle();
-        else
-            return -1;
-    }
-
-    public RemoteDevice getRemoteDevice() {
-        if (client instanceof BTConnection)
-            return ((BTConnection)client).getRemoteDevice();
-        else
-            return null;
-    }*/
-
     /**
      * Processes requests made to the server and forwards them to the
      * appropriate event listener.
@@ -129,29 +99,29 @@
         try {
 
             boolean done = false;
-            while (!done && !isClosed) {
-                int requestType = input.read();
+            while (!done && !mClosed) {
+                int requestType = mInput.read();
                 switch (requestType) {
-                    case 0x80:
+                    case ObexHelper.OBEX_OPCODE_CONNECT:
                         handleConnectRequest();
                         break;
 
-                    case 0x81:
+                    case ObexHelper.OBEX_OPCODE_DISCONNECT:
                         handleDisconnectRequest();
                         done = true;
                         break;
 
-                    case 0x03:
-                    case 0x83:
+                    case ObexHelper.OBEX_OPCODE_GET:
+                    case ObexHelper.OBEX_OPCODE_GET_FINAL:
                         handleGetRequest(requestType);
                         break;
 
-                    case 0x02:
-                    case 0x82:
+                    case ObexHelper.OBEX_OPCODE_PUT:
+                    case ObexHelper.OBEX_OPCODE_PUT_FINAL:
                         handlePutRequest(requestType);
                         break;
 
-                    case 0x85:
+                    case ObexHelper.OBEX_OPCODE_SETPATH:
                         handleSetPathRequest();
                         break;
 
@@ -166,19 +136,19 @@
                          * just going to read the packet and send a not implemented
                          * to the client
                          */
-                        int length = input.read();
-                        length = (length << 8) + input.read();
+                        int length = mInput.read();
+                        length = (length << 8) + mInput.read();
                         for (int i = 3; i < length; i++) {
-                            input.read();
+                            mInput.read();
                         }
                         sendResponse(ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED, null);
-
-                        // done = true;
                 }
             }
 
         } catch (NullPointerException e) {
+            Log.d(TAG, e.toString());
         } catch (Exception e) {
+            Log.d(TAG, e.toString());
         }
         close();
     }
@@ -201,24 +171,24 @@
      *                if an error occurred at the transport layer
      */
     private void handlePutRequest(int type) throws IOException {
-        ServerOperation client = new ServerOperation(this, input, type, maxPacketLength, listener);
+        ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
         try {
             int response = -1;
 
-            if ((client.finalBitSet) && !client.isValidBody()) {
-                response = validateResponseCode(listener.onDelete(client.requestHeaders,
-                        client.replyHeaders));
+            if ((op.finalBitSet) && !op.isValidBody()) {
+                response = validateResponseCode(mListener
+                        .onDelete(op.requestHeader, op.replyHeader));
             } else {
-                response = validateResponseCode(listener.onPut(client));
+                response = validateResponseCode(mListener.onPut(op));
             }
             if (response != ResponseCodes.OBEX_HTTP_OK) {
-                client.sendReply(response);
-            } else if (!client.isAborted) {
+                op.sendReply(response);
+            } else if (!op.isAborted) {
                 // wait for the final bit
-                while (!client.finalBitSet) {
-                    client.sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
+                while (!op.finalBitSet) {
+                    op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
                 }
-                client.sendReply(response);
+                op.sendReply(response);
             }
         } catch (Exception e) {
             sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
@@ -243,12 +213,12 @@
      *                if an error occurred at the transport layer
      */
     private void handleGetRequest(int type) throws IOException {
-        ServerOperation client = new ServerOperation(this, input, type, maxPacketLength, listener);
+        ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
         try {
-            int response = validateResponseCode(listener.onGet(client));
+            int response = validateResponseCode(mListener.onGet(op));
 
-            if (!client.isAborted) {
-                client.sendReply(response);
+            if (!op.isAborted) {
+                op.sendReply(response);
             }
         } catch (Exception e) {
             sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
@@ -267,7 +237,7 @@
      * @throws IOException
      *                if an IO error occurs
      */
-    protected void sendResponse(int code, byte[] header) throws IOException {
+    public void sendResponse(int code, byte[] header) throws IOException {
         int totalLength = 3;
         byte[] data = null;
 
@@ -284,8 +254,8 @@
             data[1] = (byte)0x00;
             data[2] = (byte)totalLength;
         }
-        output.write(data);
-        output.flush();
+        mOutput.write(data);
+        mOutput.flush();
     }
 
     /**
@@ -302,6 +272,7 @@
     private void handleSetPathRequest() throws IOException {
         int length;
         int flags;
+        @SuppressWarnings("unused")
         int constants;
         int totalLength = 3;
         byte[] head = null;
@@ -310,10 +281,10 @@
         HeaderSet request = new HeaderSet();
         HeaderSet reply = new HeaderSet();
 
-        length = input.read();
-        length = (length << 8) + input.read();
-        flags = input.read();
-        constants = input.read();
+        length = mInput.read();
+        length = (length << 8) + mInput.read();
+        flags = mInput.read();
+        constants = mInput.read();
 
         if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
             code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
@@ -321,41 +292,41 @@
         } else {
             if (length > 5) {
                 byte[] headers = new byte[length - 5];
-                bytesReceived = input.read(headers);
+                bytesReceived = mInput.read(headers);
 
                 while (bytesReceived != headers.length) {
-                    bytesReceived += input.read(headers, bytesReceived, headers.length
+                    bytesReceived += mInput.read(headers, bytesReceived, headers.length
                             - bytesReceived);
                 }
 
                 ObexHelper.updateHeaderSet(request, headers);
 
-                if (request.connectionID != null) {
-                    listener.setConnectionID(ObexHelper.convertToLong(request.connectionID));
+                if (request.mConnectionID != null) {
+                    mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
                 } else {
-                    listener.setConnectionID(-1);
+                    mListener.setConnectionId(-1);
                 }
-                // the Auth chan is initiated by the server.
-                // client sent back the authResp .
-                if (request.authResp != null) {
-                    if (!handleAuthResp(request.authResp)) {
+                // the Auth chan is initiated by the server, client sent back the authResp .
+                if (request.mAuthResp != null) {
+                    if (!handleAuthResp(request.mAuthResp)) {
                         code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
-                        listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
-                                request.authResp));
+                        mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+                                request.mAuthResp));
                     }
-                    request.authResp = null;
+                    request.mAuthResp = null;
                 }
             }
 
             if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
-                // the Auth chan is initiated by the client
+                // the Auth challenge is initiated by the client
                 // the server will send back the authResp to the client
-                if (request.authChall != null) {
+                if (request.mAuthChall != null) {
                     handleAuthChall(request);
-                    reply.authResp = new byte[request.authResp.length];
-                    System.arraycopy(request.authResp, 0, reply.authResp, 0, reply.authResp.length);
-                    request.authChall = null;
-                    request.authResp = null;
+                    reply.mAuthResp = new byte[request.mAuthResp.length];
+                    System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
+                            reply.mAuthResp.length);
+                    request.mAuthChall = null;
+                    request.mAuthResp = null;
                 }
                 boolean backup = false;
                 boolean create = true;
@@ -367,7 +338,7 @@
                 }
 
                 try {
-                    code = listener.onSetPath(request, reply, backup, create);
+                    code = mListener.onSetPath(request, reply, backup, create);
                 } catch (Exception e) {
                     sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
                     return;
@@ -376,23 +347,23 @@
                 code = validateResponseCode(code);
 
                 if (reply.nonce != null) {
-                    challengeDigest = new byte[16];
-                    System.arraycopy(reply.nonce, 0, challengeDigest, 0, 16);
+                    mChallengeDigest = new byte[16];
+                    System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
                 } else {
-                    challengeDigest = null;
+                    mChallengeDigest = null;
                 }
 
-                long id = listener.getConnectionID();
+                long id = mListener.getConnectionId();
                 if (id == -1) {
-                    reply.connectionID = null;
+                    reply.mConnectionID = null;
                 } else {
-                    reply.connectionID = ObexHelper.convertToByteArray(id);
+                    reply.mConnectionID = ObexHelper.convertToByteArray(id);
                 }
 
                 head = ObexHelper.createHeader(reply, false);
                 totalLength += head.length;
 
-                if (totalLength > maxPacketLength) {
+                if (totalLength > mMaxPacketLength) {
                     totalLength = 3;
                     head = null;
                     code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -412,8 +383,8 @@
          * Write the OBEX SETPATH packet to the server. Byte 0: response code
          * Byte 1&2: Connect Packet Length Byte 3 to n: headers
          */
-        output.write(replyData);
-        output.flush();
+        mOutput.write(replyData);
+        mOutput.flush();
     }
 
     /**
@@ -435,8 +406,8 @@
         HeaderSet request = new HeaderSet();
         HeaderSet reply = new HeaderSet();
 
-        length = input.read();
-        length = (length << 8) + input.read();
+        length = mInput.read();
+        length = (length << 8) + mInput.read();
 
         if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
             code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
@@ -444,66 +415,56 @@
         } else {
             if (length > 3) {
                 byte[] headers = new byte[length - 3];
-                bytesReceived = input.read(headers);
+                bytesReceived = mInput.read(headers);
 
                 while (bytesReceived != headers.length) {
-                    bytesReceived += input.read(headers, bytesReceived, headers.length
+                    bytesReceived += mInput.read(headers, bytesReceived, headers.length
                             - bytesReceived);
                 }
 
                 ObexHelper.updateHeaderSet(request, headers);
             }
 
-            if (request.connectionID != null) {
-                listener.setConnectionID(ObexHelper.convertToLong(request.connectionID));
+            if (request.mConnectionID != null) {
+                mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
             } else {
-                listener.setConnectionID(1);
+                mListener.setConnectionId(1);
             }
 
-            if (request.authResp != null) {
-                if (!handleAuthResp(request.authResp)) {
+            if (request.mAuthResp != null) {
+                if (!handleAuthResp(request.mAuthResp)) {
                     code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
-                    listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
-                            request.authResp));
+                    mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+                            request.mAuthResp));
                 }
-                request.authResp = null;
+                request.mAuthResp = null;
             }
 
             if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
 
-                if (request.authChall != null) {
+                if (request.mAuthChall != null) {
                     handleAuthChall(request);
-                    request.authChall = null;
+                    request.mAuthChall = null;
                 }
 
                 try {
-                    listener.onDisconnect(request, reply);
+                    mListener.onDisconnect(request, reply);
                 } catch (Exception e) {
                     sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
                     return;
                 }
 
-                /*
-                 * Since a client will never response to an authentication
-                 * challenge on a DISCONNECT, there is no reason to keep track
-                 * of the challenge.
-                 *
-                 * if (reply.nonce != null) { challengeDigest = new byte[16];
-                 * System.arraycopy(reply.nonce, 0, challengeDigest, 0, 16); }
-                 * else { challengeDigest = null; }
-                 */
-
-                long id = listener.getConnectionID();
+                long id = mListener.getConnectionId();
                 if (id == -1) {
-                    reply.connectionID = null;
+                    reply.mConnectionID = null;
                 } else {
-                    reply.connectionID = ObexHelper.convertToByteArray(id);
+                    reply.mConnectionID = ObexHelper.convertToByteArray(id);
                 }
 
                 head = ObexHelper.createHeader(reply, false);
                 totalLength += head.length;
 
-                if (totalLength > maxPacketLength) {
+                if (totalLength > mMaxPacketLength) {
                     totalLength = 3;
                     head = null;
                     code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -528,8 +489,8 @@
          * Write the OBEX DISCONNECT packet to the server. Byte 0: response code
          * Byte 1&2: Connect Packet Length Byte 3 to n: headers
          */
-        output.write(replyData);
-        output.flush();
+        mOutput.write(replyData);
+        mOutput.flush();
     }
 
     /**
@@ -545,7 +506,9 @@
      */
     private void handleConnectRequest() throws IOException {
         int packetLength;
+        @SuppressWarnings("unused")
         int version;
+        @SuppressWarnings("unused")
         int flags;
         int totalLength = 7;
         byte[] head = null;
@@ -558,16 +521,16 @@
          * Read in the length of the OBEX packet, OBEX version, flags, and max
          * packet length
          */
-        packetLength = input.read();
-        packetLength = (packetLength << 8) + input.read();
-        version = input.read();
-        flags = input.read();
-        maxPacketLength = input.read();
-        maxPacketLength = (maxPacketLength << 8) + input.read();
+        packetLength = mInput.read();
+        packetLength = (packetLength << 8) + mInput.read();
+        version = mInput.read();
+        flags = mInput.read();
+        mMaxPacketLength = mInput.read();
+        mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read();
 
         // should we check it?
-        if (maxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
-            maxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
+        if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
+            mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
         }
 
         if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) {
@@ -576,61 +539,62 @@
         } else {
             if (packetLength > 7) {
                 byte[] headers = new byte[packetLength - 7];
-                bytesReceived = input.read(headers);
+                bytesReceived = mInput.read(headers);
 
                 while (bytesReceived != headers.length) {
-                    bytesReceived += input.read(headers, bytesReceived, headers.length
+                    bytesReceived += mInput.read(headers, bytesReceived, headers.length
                             - bytesReceived);
                 }
 
                 ObexHelper.updateHeaderSet(request, headers);
             }
 
-            if (request.connectionID != null) {
-                listener.setConnectionID(ObexHelper.convertToLong(request.connectionID));
+            if (request.mConnectionID != null) {
+                mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
             } else {
-                listener.setConnectionID(1);
+                mListener.setConnectionId(1);
             }
 
-            if (request.authResp != null) {
-                if (!handleAuthResp(request.authResp)) {
+            if (request.mAuthResp != null) {
+                if (!handleAuthResp(request.mAuthResp)) {
                     code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
-                    listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
-                            request.authResp));
+                    mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+                            request.mAuthResp));
                 }
-                request.authResp = null;
+                request.mAuthResp = null;
             }
 
             if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
-                if (request.authChall != null) {
+                if (request.mAuthChall != null) {
                     handleAuthChall(request);
-                    reply.authResp = new byte[request.authResp.length];
-                    System.arraycopy(request.authResp, 0, reply.authResp, 0, reply.authResp.length);
-                    request.authChall = null;
-                    request.authResp = null;
+                    reply.mAuthResp = new byte[request.mAuthResp.length];
+                    System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
+                            reply.mAuthResp.length);
+                    request.mAuthChall = null;
+                    request.mAuthResp = null;
                 }
 
                 try {
-                    code = listener.onConnect(request, reply);
+                    code = mListener.onConnect(request, reply);
                     code = validateResponseCode(code);
 
                     if (reply.nonce != null) {
-                        challengeDigest = new byte[16];
-                        System.arraycopy(reply.nonce, 0, challengeDigest, 0, 16);
+                        mChallengeDigest = new byte[16];
+                        System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
                     } else {
-                        challengeDigest = null;
+                        mChallengeDigest = null;
                     }
-                    long id = listener.getConnectionID();
+                    long id = mListener.getConnectionId();
                     if (id == -1) {
-                        reply.connectionID = null;
+                        reply.mConnectionID = null;
                     } else {
-                        reply.connectionID = ObexHelper.convertToByteArray(id);
+                        reply.mConnectionID = ObexHelper.convertToByteArray(id);
                     }
 
                     head = ObexHelper.createHeader(reply, false);
                     totalLength += head.length;
 
-                    if (totalLength > maxPacketLength) {
+                    if (totalLength > mMaxPacketLength) {
                         totalLength = 7;
                         head = null;
                         code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -667,8 +631,8 @@
             System.arraycopy(head, 0, sendData, 7, head.length);
         }
 
-        output.write(sendData);
-        output.flush();
+        mOutput.write(sendData);
+        mOutput.flush();
     }
 
     /**
@@ -677,20 +641,20 @@
      * attempt to read/write will throw an exception.
      */
     public synchronized void close() {
-        if (listener != null) {
-            listener.onClose();
+        if (mListener != null) {
+            mListener.onClose();
         }
         try {
-            input.close();
-            output.close();
-            client.close();
-            isClosed = true;
+            mInput.close();
+            mOutput.close();
+            mTransport.close();
+            mClosed = true;
         } catch (Exception e) {
         }
-        client = null;
-        input = null;
-        output = null;
-        listener = null;
+        mTransport = null;
+        mInput = null;
+        mOutput = null;
+        mListener = null;
     }
 
     /**
@@ -727,196 +691,4 @@
         return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
     }
 
-    /**
-     * Called when the server received an authentication challenge header. This
-     * will cause the authenticator to handle the authentication challenge.
-     *
-     * @param header
-     *            the header with the authentication challenge
-     *
-     * @return <code>true</code> if the last request should be resent;
-     *         <code>false</code> if the last request should not be resent
-     */
-    protected boolean handleAuthChall(HeaderSet header) {
-        if (authenticator == null) {
-            return false;
-        }
-
-        /*
-         * An authentication challenge is made up of one required and two
-         * optional tag length value triplets. The tag 0x00 is required to be in
-         * the authentication challenge and it represents the challenge digest
-         * that was received. The tag 0x01 is the options tag. This tag tracks
-         * if user ID is required and if full access will be granted. The tag
-         * 0x02 is the realm, which provides a description of which user name
-         * and password to use.
-         */
-        byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.authChall);
-        byte[] option = ObexHelper.getTagValue((byte)0x01, header.authChall);
-        byte[] description = ObexHelper.getTagValue((byte)0x02, header.authChall);
-
-        String realm = "";
-        if (description != null) {
-            byte[] realmString = new byte[description.length - 1];
-            System.arraycopy(description, 1, realmString, 0, realmString.length);
-
-            switch (description[0] & 0xFF) {
-
-                case 0x00:
-                    // ASCII encoding
-                    // Fall through
-                case 0x01:
-                    // ISO-8859-1 encoding
-                    try {
-                        realm = new String(realmString, "ISO8859_1");
-                    } catch (Exception e) {
-                        throw new RuntimeException("Unsupported Encoding Scheme");
-                    }
-                    break;
-
-                case 0xFF:
-                    // UNICODE Encoding
-                    realm = ObexHelper.convertToUnicode(realmString, false);
-                    break;
-
-                case 0x02:
-                    // ISO-8859-2 encoding
-                    // Fall through
-                case 0x03:
-                    // ISO-8859-3 encoding
-                    // Fall through
-                case 0x04:
-                    // ISO-8859-4 encoding
-                    // Fall through
-                case 0x05:
-                    // ISO-8859-5 encoding
-                    // Fall through
-                case 0x06:
-                    // ISO-8859-6 encoding
-                    // Fall through
-                case 0x07:
-                    // ISO-8859-7 encoding
-                    // Fall through
-                case 0x08:
-                    // ISO-8859-8 encoding
-                    // Fall through
-                case 0x09:
-                    // ISO-8859-9 encoding
-                    // Fall through
-                default:
-                    throw new RuntimeException("Unsupported Encoding Scheme");
-            }
-        }
-
-        boolean isUserIDRequired = false;
-        boolean isFullAccess = true;
-        if (option != null) {
-            if ((option[0] & 0x01) != 0) {
-                isUserIDRequired = true;
-            }
-
-            if ((option[0] & 0x02) != 0) {
-                isFullAccess = false;
-            }
-        }
-
-        PasswordAuthentication result = null;
-        header.authChall = null;
-
-        try {
-            result = authenticator.onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
-        } catch (Exception e) {
-            return false;
-        }
-
-        /*
-         * If no password is provided then we not resent the request
-         */
-        if (result == null) {
-            return false;
-        }
-
-        byte[] password = result.getPassword();
-        if (password == null) {
-            return false;
-        }
-
-        byte[] userName = result.getUserName();
-
-        /*
-         * Create the authentication response header. It includes 1 required and
-         * 2 option tag length value triples. The required triple has a tag of
-         * 0x00 and is the response digest. The first optional tag is 0x01 and
-         * represents the user ID. If no user ID is provided, then no user ID
-         * will be sent. The second optional tag is 0x02 and is the challenge
-         * that was received. This will always be sent
-         */
-        if (userName != null) {
-            header.authResp = new byte[38 + userName.length];
-            header.authResp[36] = (byte)0x01;
-            header.authResp[37] = (byte)userName.length;
-            System.arraycopy(userName, 0, header.authResp, 38, userName.length);
-        } else {
-            header.authResp = new byte[36];
-        }
-
-        // Create the secret String
-        byte[] digest = new byte[challenge.length + password.length + 1];
-        System.arraycopy(challenge, 0, digest, 0, challenge.length);
-        // Insert colon between challenge and password
-        digest[challenge.length] = (byte)0x3A;
-        System.arraycopy(password, 0, digest, challenge.length + 1, password.length);
-
-        // Add the Response Digest
-        header.authResp[0] = (byte)0x00;
-        header.authResp[1] = (byte)0x10;
-
-        System.arraycopy(ObexHelper.computeMd5Hash(digest), 0, header.authResp, 2, 16);
-
-        // Add the challenge
-        header.authResp[18] = (byte)0x02;
-        header.authResp[19] = (byte)0x10;
-        System.arraycopy(challenge, 0, header.authResp, 20, 16);
-
-        return true;
-    }
-
-    /**
-     * Called when the server received an authentication response header. This
-     * will cause the authenticator to handle the authentication response.
-     *
-     * @param authResp
-     *            the authentication response
-     *
-     * @return <code>true</code> if the response passed; <code>false</code> if
-     *         the response failed
-     */
-    protected boolean handleAuthResp(byte[] authResp) {
-        if (authenticator == null) {
-            return false;
-        }
-        // get the correct password from the application
-        byte[] correctPassword = authenticator.onAuthenticationResponse(ObexHelper.getTagValue(
-                (byte)0x01, authResp));
-        if (correctPassword == null) {
-            return false;
-        }
-
-        byte[] temp = new byte[correctPassword.length + 16];
-
-        System.arraycopy(challengeDigest, 0, temp, 0, 16);
-        System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
-
-        byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
-        byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
-
-        // compare the MD5 hash array .
-        for (int i = 0; i < 16; i++) {
-            if (correctResponse[i] != actualResponse[i]) {
-                return false;
-            }
-        }
-
-        return true;
-    }
 }
diff --git a/obex/javax/obex/SessionNotifier.java b/obex/javax/obex/SessionNotifier.java
index fd574c0..36e0ebf 100644
--- a/obex/javax/obex/SessionNotifier.java
+++ b/obex/javax/obex/SessionNotifier.java
@@ -61,7 +61,7 @@
      * does not have a <code>ServiceRecord</code> in the SDDB, the
      * <code>ServiceRecord</code> for this object will be added to the SDDB.
      * This method requests the BCC to put the
-     * local device in connectable mode so that it will respond to
+     * local device in connectible mode so that it will respond to
      * connection attempts by clients.
      * <P>
      * The following checks are done to verify that the service record
@@ -101,10 +101,10 @@
      * be due to insufficient disk space, database locks, etc.
      *
      * @throws BluetoothStateException if the server device could
-     * not be placed in connectable mode because the device user has
-     * configured the device to be non-connectable
+     * not be placed in connectible mode because the device user has
+     * configured the device to be non-connectible
      */
-    public ObexSession acceptAndOpen(ServerRequestHandler handler) throws IOException;
+    ObexSession acceptAndOpen(ServerRequestHandler handler) throws IOException;
 
     /**
      * Waits for a transport layer connection to be established and specifies
@@ -117,7 +117,7 @@
      * does not have a <code>ServiceRecord</code> in the SDDB, the
      * <code>ServiceRecord</code> for this object will be added to the SDDB.
      * This method requests the BCC to put the
-     * local device in connectable mode so that it will respond to
+     * local device in connectible mode so that it will respond to
      * connection attempts by clients.
      * <P>
      * The following checks are done to verify that the service record
@@ -160,9 +160,8 @@
      * be due to insufficient disk space, database locks, etc.
      *
      * @throws BluetoothStateException if the server device could
-     * not be placed in connectable mode because the device user has
-     * configured the device to be non-connectable
+     * not be placed in connectible mode because the device user has
+     * configured the device to be non-connectible
      */
-    public ObexSession acceptAndOpen(ServerRequestHandler handler, Authenticator auth)
-            throws IOException;
+    ObexSession acceptAndOpen(ServerRequestHandler handler, Authenticator auth) throws IOException;
 }
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 4f9939f..7f3f114 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -139,7 +139,7 @@
     char path[PATH_MAX];
     int index = int(display);
     driver_t* hnd = 0;
-    const char* const format = "egl/lib%s_%s.so";
+    const char* const format = "/system/lib/egl/lib%s_%s.so";
     
     char const* tag = getTag(index, impl);
     if (tag) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index f9e98ef..b6bc8a5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -50,6 +50,7 @@
     private static final String KEY_SYSTEM = "system";
     private static final String KEY_SECURE = "secure";
     private static final String KEY_SYNC = "sync_providers";
+    private static final String KEY_LOCALE = "locale";
 
     private static String[] sortedSystemKeys = null;
     private static String[] sortedSecureKeys = null;
@@ -85,6 +86,7 @@
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
         byte[] syncProviders = mSettingsHelper.getSyncProviders();
+        byte[] locale = mSettingsHelper.getLocaleData();
         
         data.writeEntityHeader(KEY_SYSTEM, systemSettingsData.length);
         data.writeEntityData(systemSettingsData, systemSettingsData.length);
@@ -94,7 +96,10 @@
 
         data.writeEntityHeader(KEY_SYNC, syncProviders.length);
         data.writeEntityData(syncProviders, syncProviders.length);
-        
+
+        data.writeEntityHeader(KEY_LOCALE, locale.length);
+        data.writeEntityData(locale, locale.length);
+
         backupFile(FILE_WIFI_SUPPLICANT, data);
     }
 
@@ -107,14 +112,20 @@
 
         while (data.readNextHeader()) {
             final String key = data.getKey();
+            final int size = data.getDataSize();
             if (KEY_SYSTEM.equals(key)) {
                 restoreSettings(data, Settings.System.CONTENT_URI);
             } else if (KEY_SECURE.equals(key)) {
                 restoreSettings(data, Settings.Secure.CONTENT_URI);
-            } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
-                restoreFile(FILE_WIFI_SUPPLICANT, data);
+// TODO: Re-enable WIFI restore when we figure out a solution for the permissions
+//            } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
+//                restoreFile(FILE_WIFI_SUPPLICANT, data);
             } else if (KEY_SYNC.equals(key)) {
                 mSettingsHelper.setSyncProviders(data);
+            } else if (KEY_LOCALE.equals(key)) {
+                byte[] localeData = new byte[size];
+                data.readEntityData(localeData, 0, size);
+                mSettingsHelper.setLocaleData(localeData);
             } else {
                 data.skipEntityData();
             }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 0becaa3..dc66420 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -16,16 +16,22 @@
 
 package com.android.providers.settings;
 
+import java.util.Locale;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
 import android.backup.BackupDataInput;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IContentService;
+import android.content.res.Configuration;
 import android.location.LocationManager;
 import android.media.AudioManager;
 import android.os.IHardwareService;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.Log;
 
 public class SettingsHelper {
@@ -110,7 +116,6 @@
         }
     }
 
-    /* TODO: Get a list of all sync providers and save/restore the settings */
     byte[] getSyncProviders() {
         byte[] sync = new byte[1 + PROVIDERS.length];
         // TODO: Sync backup needs to be moved to SystemBackupAgent
@@ -147,4 +152,53 @@
             Log.w(TAG, "Unable to read sync settings");
         }
     }
+
+    byte[] getLocaleData() {
+        Configuration conf = mContext.getResources().getConfiguration();
+        final Locale loc = conf.locale;
+        String localeString = loc.getLanguage();
+        String country = loc.getCountry();
+        if (!TextUtils.isEmpty(country)) {
+            localeString += "_" + country;
+        }
+        return localeString.getBytes();
+    }
+
+    /**
+     * Sets the locale specified. Input data is the equivalent of "ll_cc".getBytes(), where
+     * "ll" is the language code and "cc" is the country code.
+     * @param data the locale string in bytes.
+     */
+    void setLocaleData(byte[] data) {
+        // Check if locale was set by the user:
+        Configuration conf = mContext.getResources().getConfiguration();
+        Locale loc = conf.locale;
+        if (conf.userSetLocale) return; // Don't change if user set it in the SetupWizard
+
+        final String[] availableLocales = mContext.getAssets().getLocales();
+        String localeCode = new String(data);
+        String language = new String(data, 0, 2);
+        String country = data.length > 4 ? new String(data, 3, 2) : "";
+        loc = null;
+        for (int i = 0; i < availableLocales.length; i++) {
+            if (availableLocales[i].equals(localeCode)) {
+                loc = new Locale(language, country);
+                break;
+            }
+        }
+        if (loc == null) return; // Couldn't find the saved locale in this version of the software
+
+        try {
+            IActivityManager am = ActivityManagerNative.getDefault();
+            Configuration config = am.getConfiguration();
+            config.locale = loc;
+            // indicate this isn't some passing default - the user wants this remembered
+            config.userSetLocale = true;
+
+            am.updateConfiguration(config);
+        } catch (RemoteException e) {
+            // Intentionally left blank
+        }
+
+    }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 8f2b2cb..4dfd3c2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -18,7 +18,7 @@
 
 import java.io.FileNotFoundException;
 
-import android.backup.IBackupManager;
+import android.backup.BackupManager;
 import android.content.ContentProvider;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -46,6 +46,7 @@
     private static final String TABLE_OLD_FAVORITES = "old_favorites";
 
     protected DatabaseHelper mOpenHelper;
+    private BackupManager mBackupManager;
 
     /**
      * Decode a content URL into the table, projection, and arguments
@@ -140,16 +141,7 @@
         }
 
         // Inform the backup manager about a data change
-        IBackupManager ibm = IBackupManager.Stub.asInterface(
-                ServiceManager.getService(Context.BACKUP_SERVICE));
-        if (ibm != null) {
-            try {
-                ibm.dataChanged(getContext().getPackageName());
-            } catch (Exception e) {
-                // Try again later
-            }
-        }
-
+        mBackupManager.dataChanged();
         // Now send the notification through the content framework.
 
         String notify = uri.getQueryParameter("notify");
@@ -189,6 +181,7 @@
     @Override
     public boolean onCreate() {
         mOpenHelper = new DatabaseHelper(getContext());
+        mBackupManager = new BackupManager(getContext());
         return true;
     }
 
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 058c033..1958ba9 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -133,7 +133,7 @@
               delete mAudioOut;
               mAudioOut = NULL;
             } else {
-              LOGI("AudioTrack OK");
+              //LOGI("AudioTrack OK");
               mAudioOut->start();
               LOGI("AudioTrack started");
             }
@@ -168,7 +168,7 @@
 static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
                            AudioSystem::audio_format format, int channel,
                            int8_t *&wav, size_t &bufferSize, tts_synth_status status) {
-    LOGV("ttsSynthDoneCallback: %d bytes", bufferSize);
+    //LOGV("ttsSynthDoneCallback: %d bytes", bufferSize);
 
     if (userdata == NULL){
         LOGE("userdata == NULL");
@@ -178,7 +178,7 @@
     SynthProxyJniStorage* pJniData = (SynthProxyJniStorage*)(pForAfter->jniStorage);
 
     if (pForAfter->usageMode == USAGEMODE_PLAY_IMMEDIATELY){
-        LOGV("Direct speech");
+        //LOGV("Direct speech");
 
         if (wav == NULL) {
             delete pForAfter;
@@ -610,7 +610,7 @@
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
     short* wav = (short*) bufferPointer;
     pSynthData->mAudioOut->write(wav, bufferSize);
-    LOGI("AudioTrack wrote: %d bytes", bufferSize);
+    //LOGI("AudioTrack wrote: %d bytes", bufferSize);
 }
 
 
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 0bed72bd..a713edf 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -36,6 +36,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.concurrent.locks.ReentrantLock;
 
 /**
@@ -51,7 +52,7 @@
         public static final int EARCON = 1;
         public static final int SILENCE = 2;
         public static final int TEXT_TO_FILE = 3;
-        public String mText = null;
+        public String mText = "";
         public ArrayList<String> mParams = null;
         public int mType = TEXT;
         public long mDuration = 0;
@@ -65,6 +66,7 @@
 
         public SpeechItem(long silenceTime) {
             mDuration = silenceTime;
+            mType = SILENCE;
         }
 
         public SpeechItem(String text, ArrayList<String> params, int itemType, String filename) {
@@ -124,7 +126,7 @@
     @Override
     public void onCreate() {
         super.onCreate();
-        Log.i("TTS", "TTS starting");
+        //Log.i("TTS", "TTS starting");
 
         mResolver = getContentResolver();
 
@@ -183,7 +185,8 @@
         String defaultLang = android.provider.Settings.Secure.getString(mResolver,
                 android.provider.Settings.Secure.TTS_DEFAULT_LANG);
         if (defaultLang == null) {
-            return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_LANG;
+            // no setting found, use the current Locale to determine the default language
+            return Locale.getDefault().getISO3Language();
         } else {
             return defaultLang;
         }
@@ -194,7 +197,8 @@
         String defaultCountry = android.provider.Settings.Secure.getString(mResolver,
                 android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY);
         if (defaultCountry == null) {
-            return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
+            // no setting found, use the current Locale to determine the default country
+            return Locale.getDefault().getISO3Country();
         } else {
             return defaultCountry;
         }
@@ -205,7 +209,8 @@
         String defaultVar = android.provider.Settings.Secure.getString(mResolver,
                 android.provider.Settings.Secure.TTS_DEFAULT_VARIANT);
         if (defaultVar == null) {
-            return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
+            // no setting found, use the current Locale to determine the default variant
+            return Locale.getDefault().getVariant();
         } else {
             return defaultVar;
         }
@@ -227,7 +232,7 @@
 
 
     private int isLanguageAvailable(String lang, String country, String variant) {
-        Log.v("TTS", "TtsService.isLanguageAvailable(" + lang + ", " + country + ", " +variant+")");
+        //Log.v("TTS", "TtsService.isLanguageAvailable(" + lang + ", " + country + ", " +variant+")");
         return nativeSynth.isLanguageAvailable(lang, country, variant);
     }
 
@@ -238,7 +243,7 @@
 
 
     private int setLanguage(String lang, String country, String variant) {
-        Log.v("TTS", "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
+        //Log.v("TTS", "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
         if (isDefaultEnforced()) {
             return nativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(),
                     getDefaultLocVariant());
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 2ae9fc5..6e28515 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -810,17 +810,25 @@
 
                 // Now propagate the newly-backed-up data to the transport
                 if (success) {
-                    if (DEBUG) Log.v(TAG, "doBackup() success; calling transport");
-                    backupData =
-                        ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY);
-                    if (!transport.performBackup(packInfo, backupData)) {
-                        // STOPSHIP TODO: handle errors
-                        Log.e(TAG, "Backup failure in performBackup()");
+                    if (DEBUG) Log.v(TAG, "doBackup() success");
+                    if (backupDataName.length() > 0) {
+                        backupData =
+                            ParcelFileDescriptor.open(backupDataName,
+                                    ParcelFileDescriptor.MODE_READ_ONLY);
+                        if (!transport.performBackup(packInfo, backupData)) {
+                            // STOPSHIP TODO: handle errors
+                            Log.e(TAG, "Backup failure in performBackup()");
+                        }
+                    } else {
+                        if (DEBUG) {
+                            Log.i(TAG, "no backup data written; not calling transport");
+                        }
                     }
 
-                    // !!! TODO: After successful transport, delete the now-stale data
-                    // and juggle the files so that next time the new state is passed
-                    //backupDataName.delete();
+                    // After successful transport, delete the now-stale data
+                    // and juggle the files so that next time we supply the agent
+                    // with the new state file it just created.
+                    backupDataName.delete();
                     newStateName.renameTo(savedStateName);
                 }
             } catch (Exception e) {
@@ -985,8 +993,7 @@
                 // Verify that the backup set includes metadata.  If not, we can't do
                 // signature/version verification etc, so we simply do not proceed with
                 // the restore operation.
-                Metadata pmMeta = pmAgent.getRestoredMetadata(packageName);
-                if (pmMeta == null) {
+                if (!pmAgent.hasMetadata()) {
                     Log.i(TAG, "No restore metadata available, so not restoring settings");
                     return;
                 }
@@ -1182,8 +1189,6 @@
         // may share a uid, we need to note all candidates within that uid and schedule
         // a backup pass for each of them.
 
-        Log.d(TAG, "dataChanged packageName=" + packageName);
-
         // If the caller does not hold the BACKUP permission, it can only request a
         // backup of its own data.
         HashSet<ApplicationInfo> targets;
@@ -1193,7 +1198,6 @@
         } else {
             // a caller with full permission can ask to back up any participating app
             // !!! TODO: allow backup of ANY app?
-            if (DEBUG) Log.v(TAG, "Privileged caller, allowing backup of other apps");
             targets = new HashSet<ApplicationInfo>();
             int N = mBackupParticipants.size();
             for (int i = 0; i < N; i++) {
@@ -1213,23 +1217,25 @@
                         // Add the caller to the set of pending backups.  If there is
                         // one already there, then overwrite it, but no harm done.
                         BackupRequest req = new BackupRequest(app, false);
-                        mPendingBackups.put(app, req);
+                        if (mPendingBackups.put(app, req) == null) {
+                            // Journal this request in case of crash.  The put()
+                            // operation returned null when this package was not already
+                            // in the set; we want to avoid touching the disk redundantly.
+                            writeToJournalLocked(packageName);
 
-                        // Journal this request in case of crash
-                        writeToJournalLocked(packageName);
-                    }
-                }
-
-                if (DEBUG) {
-                    int numKeys = mPendingBackups.size();
-                    Log.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
-                    for (BackupRequest b : mPendingBackups.values()) {
-                        Log.d(TAG, "    + " + b + " agent=" + b.appInfo.backupAgentName);
+                            if (DEBUG) {
+                                int numKeys = mPendingBackups.size();
+                                Log.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
+                                for (BackupRequest b : mPendingBackups.values()) {
+                                    Log.d(TAG, "    + " + b + " agent=" + b.appInfo.backupAgentName);
+                                }
+                            }
+                        }
                     }
                 }
             }
         } else {
-            Log.w(TAG, "dataChanged but no participant pkg " + packageName);
+            Log.w(TAG, "dataChanged but no participant pkg='" + packageName + "'");
         }
     }
 
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 0f5b3fd..fab97b1 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -648,14 +648,14 @@
 
     private void checkPermissionsSafe(String provider) {
         if (LocationManager.GPS_PROVIDER.equals(provider)
-            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
         }
         if (LocationManager.NETWORK_PROVIDER.equals(provider)
-            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)
-            && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             throw new SecurityException(
                 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
@@ -664,14 +664,14 @@
 
     private boolean isAllowedProviderSafe(String provider) {
         if (LocationManager.GPS_PROVIDER.equals(provider)
-            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             return false;
         }
         if (LocationManager.NETWORK_PROVIDER.equals(provider)
-            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)
-            && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             return false;
         }
@@ -1075,7 +1075,7 @@
         if (mGpsStatusProvider == null) {
             return false;
         }
-        if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
+        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
                 PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
         }
@@ -1103,7 +1103,7 @@
         // first check for permission to the provider
         checkPermissionsSafe(provider);
         // and check for ACCESS_LOCATION_EXTRA_COMMANDS
-        if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
+        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
                 != PackageManager.PERMISSION_GRANTED)) {
             throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
         }
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 854138c..190d3e6 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -88,7 +88,8 @@
 
     private NotificationRecord mSoundNotification;
     private AsyncPlayer mSound;
-    private int mDisabledNotifications;
+    private boolean mSystemReady;
+    private int mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
 
     private NotificationRecord mVibrateNotification;
     private Vibrator mVibrator = new Vibrator();
@@ -377,6 +378,11 @@
         mSettingsObserver.observe();
     }
 
+    void systemReady() {
+        // no beeping until we're basically done booting
+        mSystemReady = true;
+    }
+
     // Toasts
     // ============================================================================
     public void enqueueToast(String pkg, ITransientNotification callback, int duration)
@@ -637,7 +643,7 @@
                     }
                 }
 
-                sendAccessibilityEventTypeNotificationChangedDoCheck(notification, pkg);
+                sendAccessibilityEvent(notification, pkg);
 
             } else {
                 if (old != null && old.statusBarKey != null) {
@@ -654,7 +660,8 @@
             // If we're not supposed to beep, vibrate, etc. then don't.
             if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
                     && (!(old != null
-                        && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))) {
+                        && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
+                    && mSystemReady) {
                 // sound
                 final boolean useDefaultSound =
                     (notification.defaults & Notification.DEFAULT_SOUND) != 0; 
@@ -721,8 +728,7 @@
         idOut[0] = id;
     }
 
-    private void sendAccessibilityEventTypeNotificationChangedDoCheck(Notification notification,
-            CharSequence packageName) {
+    private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
         AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
         if (!manager.isEnabled()) {
             return;
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
index a1b4c268..786f423 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -67,6 +67,7 @@
     private final HashSet<String> mExisting = new HashSet<String>();
     private int mStoredSdkVersion;
     private String mStoredIncrementalVersion;
+    private boolean mHasMetadata;
 
     public class Metadata {
         public int versionCode;
@@ -84,6 +85,11 @@
         mPackageManager = packageMgr;
         mAllPackages = packages;
         mRestoredSignatures = null;
+        mHasMetadata = false;
+    }
+
+    public boolean hasMetadata() {
+        return mHasMetadata;
     }
 
     public Metadata getRestoredMetadata(String packageName) {
@@ -259,6 +265,7 @@
                 }
                 mStoredSdkVersion = storedSdkVersion;
                 mStoredIncrementalVersion = in.readUTF();
+                mHasMetadata = true;
                 // !!! TODO: remove this debugging output
                 if (DEBUG) {
                     Log.i(TAG, "Restore set version " + storedSystemVersion
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c26ba5c..48d97ec 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -194,6 +194,7 @@
         StatusBarService statusBar = null;
         InputMethodManagerService imm = null;
         AppWidgetService appWidget = null;
+        NotificationManagerService notification = null;
 
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
             try {
@@ -244,8 +245,8 @@
 
             try {
                 Log.i(TAG, "Starting Notification Manager.");
-                ServiceManager.addService(Context.NOTIFICATION_SERVICE,
-                        new NotificationManagerService(context, statusBar, hardware));
+                notification = new NotificationManagerService(context, statusBar, hardware);
+                ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
             } catch (Throwable e) {
                 Log.e(TAG, "Failure starting Notification Manager", e);
             }
@@ -352,6 +353,11 @@
 
         // It is now time to start up the app processes...
         boolean safeMode = wm.detectSafeMode();
+
+        if (notification != null) {
+            notification.systemReady();
+        }
+
         if (statusBar != null) {
             statusBar.systemReady();
         }
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index ab6e49c1..9da29fa 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -38,6 +38,7 @@
 import android.net.wifi.WifiStateTracker;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SupplicantState;
 import android.net.NetworkStateTracker;
 import android.net.DhcpInfo;
 import android.os.Binder;
@@ -1577,8 +1578,9 @@
                  * or plugged in to AC).
                  */
                 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
-                    if (!mWifiStateTracker.hasIpAddress()) {
-                        // do not keep Wifi awake when screen is off if Wifi is not fully active
+                    WifiInfo info = mWifiStateTracker.requestConnectionInfo();
+                    if (info.getSupplicantState() != SupplicantState.COMPLETED) {
+                        // do not keep Wifi awake when screen is off if Wifi is not associated
                         mDeviceIdle = true;
                         updateWifiState();
                     } else {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 0c75251..25aff5c 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -53,6 +53,7 @@
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
@@ -420,7 +421,13 @@
 
     final Configuration mTempConfiguration = new Configuration();
     int screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
-    
+
+    // The frame use to limit the size of the app running in compatibility mode.
+    Rect mCompatibleScreenFrame = new Rect();
+    // The surface used to fill the outer rim of the app running in compatibility mode.
+    Surface mBackgroundFillerSurface = null;
+    boolean mBackgroundFillerShown = false;
+
     public static WindowManagerService main(Context context,
             PowerManagerService pm, boolean haveInputMethods) {
         WMThread thr = new WMThread(context, pm, haveInputMethods);
@@ -3745,12 +3752,14 @@
         }
         config.orientation = orientation;
         
+        DisplayMetrics dm = new DisplayMetrics();
+        mDisplay.getMetrics(dm);
+        CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
+
         if (screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
             // Note we only do this once because at this point we don't
             // expect the screen to change in this way at runtime, and want
             // to avoid all of this computation for every config change.
-            DisplayMetrics dm = new DisplayMetrics();
-            mDisplay.getMetrics(dm);
             int longSize = dw;
             int shortSize = dh;
             if (longSize < shortSize) {
@@ -3760,7 +3769,7 @@
             }
             longSize = (int)(longSize/dm.density);
             shortSize = (int)(shortSize/dm.density);
-            
+
             // These semi-magic numbers define our compatibility modes for
             // applications with different screens.  Don't change unless you
             // make sure to test lots and lots of apps!
@@ -5894,8 +5903,19 @@
         public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
             mHaveFrame = true;
 
-            final int pw = pf.right-pf.left;
-            final int ph = pf.bottom-pf.top;
+            final Rect container = mContainingFrame;
+            container.set(pf);
+
+            final Rect display = mDisplayFrame;
+            display.set(df);
+
+            if ((mAttrs.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW) != 0) {
+                container.intersect(mCompatibleScreenFrame);
+                display.intersect(mCompatibleScreenFrame);
+            }
+
+            final int pw = container.right - container.left;
+            final int ph = container.bottom - container.top;
 
             int w,h;
             if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
@@ -5906,12 +5926,6 @@
                 h = mAttrs.height== mAttrs.FILL_PARENT ? ph : mRequestedHeight;
             }
 
-            final Rect container = mContainingFrame;
-            container.set(pf);
-
-            final Rect display = mDisplayFrame;
-            display.set(df);
-
             final Rect content = mContentFrame;
             content.set(cf);
 
@@ -5931,7 +5945,7 @@
 
             // Now make sure the window fits in the overall display.
             Gravity.applyDisplay(mAttrs.gravity, df, frame);
-
+            
             // Make sure the content and visible frames are inside of the
             // final window frame.
             if (content.left < frame.left) content.left = frame.left;
@@ -6622,16 +6636,29 @@
             return false;
         }
 
-        boolean isFullscreenOpaque(int screenWidth, int screenHeight) {
-            if (mAttrs.format != PixelFormat.OPAQUE || mSurface == null
-                    || mAnimation != null || mDrawPending || mCommitDrawPending) {
-                return false;
-            }
-            if (mFrame.left <= 0 && mFrame.top <= 0 &&
-                mFrame.right >= screenWidth && mFrame.bottom >= screenHeight) {
-                return true;
-            }
-            return false;
+        /**
+         * Return true if the window is opaque and fully drawn.
+         */
+        boolean isOpaqueDrawn() {
+            return mAttrs.format == PixelFormat.OPAQUE && mSurface != null
+                    && mAnimation == null && !mDrawPending && !mCommitDrawPending;
+        }
+
+        boolean needsBackgroundFiller(int screenWidth, int screenHeight) {
+            return
+                 // only if the application is requesting compatible window
+                 (mAttrs.flags & mAttrs.FLAG_COMPATIBLE_WINDOW) != 0 &&
+                 // and only if the application wanted to fill the screen
+                 mAttrs.width == mAttrs.FILL_PARENT &&
+                 mAttrs.height == mAttrs.FILL_PARENT &&
+                 // and only if the screen is bigger
+                 ((mFrame.right - mFrame.right) < screenWidth ||
+                         (mFrame.bottom - mFrame.top) < screenHeight);
+        }
+
+        boolean isFullscreen(int screenWidth, int screenHeight) {
+            return mFrame.left <= 0 && mFrame.top <= 0 &&
+                mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
         }
 
         void removeLocked() {
@@ -8151,6 +8178,7 @@
             boolean dimming = false;
             boolean covered = false;
             boolean syswin = false;
+            boolean backgroundFillerShown = false;
 
             for (i=N-1; i>=0; i--) {
                 WindowState w = (WindowState)mWindows.get(i);
@@ -8420,11 +8448,39 @@
                             syswin = true;
                         }
                     }
-                    if (w.isFullscreenOpaque(dw, dh)) {
+
+                    boolean opaqueDrawn = w.isOpaqueDrawn();
+                    if (opaqueDrawn && w.isFullscreen(dw, dh)) {
                         // This window completely covers everything behind it,
                         // so we want to leave all of them as unblurred (for
                         // performance reasons).
                         obscured = true;
+                    } else if (opaqueDrawn && w.needsBackgroundFiller(dw, dh)) {
+                        if (SHOW_TRANSACTIONS) Log.d(TAG, "showing background filler");
+                                                // This window is in compatibility mode, and needs background filler. 
+                        obscured = true;
+                        if (mBackgroundFillerSurface == null) {
+                            try {
+                                mBackgroundFillerSurface = new Surface(mFxSession, 0,
+                                        0, dw, dh,
+                                        PixelFormat.OPAQUE,
+                                        Surface.FX_SURFACE_NORMAL);
+                            } catch (Exception e) {
+                                Log.e(TAG, "Exception creating filler surface", e);
+                            }
+                        }
+                        try {
+                            mBackgroundFillerSurface.setPosition(0, 0);
+                            mBackgroundFillerSurface.setSize(dw, dh);
+                            // Using the same layer as Dim because they will never be shown at the
+                            // same time.
+                            mBackgroundFillerSurface.setLayer(w.mAnimLayer - 1);
+                            mBackgroundFillerSurface.show();
+                        } catch (RuntimeException e) {
+                            Log.e(TAG, "Exception showing filler surface");
+                        }
+                        backgroundFillerShown = true;
+                        mBackgroundFillerShown = true;
                     } else if (canBeSeen && !obscured &&
                             (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
                         if (localLOGV) Log.v(TAG, "Win " + w
@@ -8521,6 +8577,16 @@
                     }
                 }
             }
+            
+            if (backgroundFillerShown == false && mBackgroundFillerShown) {
+                mBackgroundFillerShown = false;
+                if (SHOW_TRANSACTIONS) Log.d(TAG, "hiding background filler");
+                try {
+                    mBackgroundFillerSurface.hide();
+                } catch (RuntimeException e) {
+                    Log.e(TAG, "Exception hiding filler surface", e);
+                }
+            }
 
             if (!dimming && mDimShown) {
                 // Time to hide the dim surface...  start fading.
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 25c512e..7b6124c 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -82,15 +82,6 @@
         }
     }
 
-    enum IccStatus {
-        ICC_ABSENT,
-        ICC_NOT_READY,
-        ICC_READY,
-        ICC_PIN,
-        ICC_PUK,
-        ICC_NETWORK_PERSONALIZATION
-    }
-
     //***** Constants
 
     // Used as parameter to dial() and setCLIR() below
@@ -534,15 +525,6 @@
      void unregisterForCdmaOtaProvision(Handler h);
 
     /**
-     * Returns current ICC status.
-     *
-     * AsyncResult.result is IccStatus
-     *
-     */
-
-    void getIccStatus(Message result);
-
-    /**
      * Supply the ICC PIN to the ICC card
      *
      *  returned message
@@ -1366,4 +1348,12 @@
      * @param response callback message
      */
     public void exitEmergencyCallbackMode(Message response);
+
+    /**
+     * Request the status of the ICC and UICC cards.
+     *
+     * @param response
+     *          Callback message containing {@link IccCardStatus} structure for the card.
+     */
+    public void getIccCardStatus(Message result);
 }
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index d7ad492..be4c72c 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -16,13 +16,40 @@
 
 package com.android.internal.telephony;
 
-import android.os.Message;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import android.app.ActivityManagerNative;
+import android.content.Intent;
+import android.os.AsyncResult;
 import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.util.Log;
+
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.CommandsInterface.RadioState;
 
 /**
  * {@hide}
  */
-public interface IccCard {
+public abstract class IccCard {
+    protected String mLogTag;
+    protected boolean mDbg;
+
+    private IccCardStatus mIccCardStatus = null;
+    protected State mState = null;
+    protected PhoneBase mPhone;
+    private RegistrantList mAbsentRegistrants = new RegistrantList();
+    private RegistrantList mPinLockedRegistrants = new RegistrantList();
+    private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
+
+    private boolean mDesiredPinLocked;
+    private boolean mDesiredFdnEnabled;
+    private boolean mIccPinLocked = true; // Default to locked
+    private boolean mIccFdnEnabled = false; // Default to disabled.
+                                            // Will be updated when SIM_READY.
+
+
     /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */
     static public final String INTENT_KEY_ICC_STATE = "ss";
     /* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */
@@ -46,6 +73,17 @@
     /* NETWORK means ICC is locked on NETWORK PERSONALIZATION */
     static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK";
 
+    protected static final int EVENT_ICC_LOCKED_OR_ABSENT = 1;
+    private static final int EVENT_GET_ICC_STATUS_DONE = 2;
+    protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
+    private static final int EVENT_PINPUK_DONE = 4;
+    private static final int EVENT_REPOLL_STATUS_DONE = 5;
+    protected static final int EVENT_ICC_READY = 6;
+    private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
+    private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
+    private static final int EVENT_CHANGE_ICC_PASSWORD_DONE = 9;
+    private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
+    private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
 
     /*
       UNKNOWN is a transient state, for example, after uesr inputs ICC pin under
@@ -58,33 +96,108 @@
         PIN_REQUIRED,
         PUK_REQUIRED,
         NETWORK_LOCKED,
-        READY;
+        READY,
+        NOT_READY;
 
         public boolean isPinLocked() {
             return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
         }
     }
 
-    State getState();
+    public State getState() {
+        if (mState == null) {
+            switch(mPhone.mCM.getRadioState()) {
+                /* This switch block must not return anything in
+                 * State.isLocked() or State.ABSENT.
+                 * If it does, handleSimStatus() may break
+                 */
+                case RADIO_OFF:
+                case RADIO_UNAVAILABLE:
+                case SIM_NOT_READY:
+                case RUIM_NOT_READY:
+                    return State.UNKNOWN;
+                case SIM_LOCKED_OR_ABSENT:
+                case RUIM_LOCKED_OR_ABSENT:
+                    //this should be transient-only
+                    return State.UNKNOWN;
+                case SIM_READY:
+                case RUIM_READY:
+                    return State.READY;
+                case NV_READY:
+                case NV_NOT_READY:
+                    return State.ABSENT;
+            }
+        } else {
+            return mState;
+        }
 
+        Log.e(mLogTag, "IccCard.getState(): case should never be reached");
+        return State.UNKNOWN;
+    }
+
+    public IccCard(PhoneBase phone, String logTag, Boolean dbg) {
+        mPhone = phone;
+        mLogTag = logTag;
+        mDbg = dbg;
+    }
+
+    abstract public void dispose();
+
+    protected void finalize() {
+        if(mDbg) Log.d(mLogTag, "IccCard finalized");
+    }
 
     /**
      * Notifies handler of any transition into State.ABSENT
      */
-    void registerForAbsent(Handler h, int what, Object obj);
-    void unregisterForAbsent(Handler h);
+    public void registerForAbsent(Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
 
-    /**
-     * Notifies handler of any transition into State.isPinLocked()
-     */
-    void registerForLocked(Handler h, int what, Object obj);
-    void unregisterForLocked(Handler h);
+        mAbsentRegistrants.add(r);
+
+        if (getState() == State.ABSENT) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForAbsent(Handler h) {
+        mAbsentRegistrants.remove(h);
+    }
 
     /**
      * Notifies handler of any transition into State.NETWORK_LOCKED
      */
-    void registerForNetworkLocked(Handler h, int what, Object obj);
-    void unregisterForNetworkLocked(Handler h);
+    public void registerForNetworkLocked(Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
+
+        mNetworkLockedRegistrants.add(r);
+
+        if (getState() == State.NETWORK_LOCKED) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForNetworkLocked(Handler h) {
+        mNetworkLockedRegistrants.remove(h);
+    }
+
+    /**
+     * Notifies handler of any transition into State.isPinLocked()
+     */
+    public void registerForLocked(Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
+
+        mPinLockedRegistrants.add(r);
+
+        if (getState().isPinLocked()) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForLocked(Handler h) {
+        mPinLockedRegistrants.remove(h);
+    }
+
 
     /**
      * Supply the ICC PIN to the ICC
@@ -107,10 +220,30 @@
      *
      */
 
-    void supplyPin (String pin, Message onComplete);
-    void supplyPuk (String puk, String newPin, Message onComplete);
-    void supplyPin2 (String pin2, Message onComplete);
-    void supplyPuk2 (String puk2, String newPin2, Message onComplete);
+    public void supplyPin (String pin, Message onComplete) {
+        mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+    }
+
+    public void supplyPuk (String puk, String newPin, Message onComplete) {
+        mPhone.mCM.supplyIccPuk(puk, newPin,
+                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+    }
+
+    public void supplyPin2 (String pin2, Message onComplete) {
+        mPhone.mCM.supplyIccPin2(pin2,
+                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+    }
+
+    public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
+        mPhone.mCM.supplyIccPuk2(puk2, newPin2,
+                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+    }
+
+    public void supplyNetworkDepersonalization (String pin, Message onComplete) {
+        if(mDbg) log("Network Despersonalization: " + pin);
+        mPhone.mCM.supplyNetworkDepersonalization(pin,
+                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+    }
 
     /**
      * Check whether ICC pin lock is enabled
@@ -119,35 +252,9 @@
      * @return true for ICC locked enabled
      *         false for ICC locked disabled
      */
-    boolean getIccLockEnabled ();
-
-    /**
-     * Set the ICC pin lock enabled or disabled
-     * When the operation is complete, onComplete will be sent to its handler
-     *
-     * @param enabled "true" for locked "false" for unlocked.
-     * @param password needed to change the ICC pin state, aka. Pin1
-     * @param onComplete
-     *        onComplete.obj will be an AsyncResult
-     *        ((AsyncResult)onComplete.obj).exception == null on success
-     *        ((AsyncResult)onComplete.obj).exception != null on fail
-     */
-    void setIccLockEnabled(boolean enabled, String password, Message onComplete);
-
-
-    /**
-     * Change the ICC password used in ICC pin lock
-     * When the operation is complete, onComplete will be sent to its handler
-     *
-     * @param oldPassword is the old password
-     * @param newPassword is the new password
-     * @param onComplete
-     *        onComplete.obj will be an AsyncResult
-     *        ((AsyncResult)onComplete.obj).exception == null on success
-     *        ((AsyncResult)onComplete.obj).exception != null on fail
-     */
-    void changeIccLockPassword(String oldPassword, String newPassword,
-                           Message onComplete);
+    public boolean getIccLockEnabled() {
+        return mIccPinLocked;
+     }
 
     /**
      * Check whether ICC fdn (fixed dialing number) is enabled
@@ -156,36 +263,99 @@
      * @return true for ICC fdn enabled
      *         false for ICC fdn disabled
      */
-    boolean getIccFdnEnabled ();
+     public boolean getIccFdnEnabled() {
+        return mIccFdnEnabled;
+     }
 
-    /**
-     * Set the ICC fdn enabled or disabled
-     * When the operation is complete, onComplete will be sent to its handler
-     *
-     * @param enabled "true" for locked "false" for unlocked.
-     * @param password needed to change the ICC fdn enable, aka Pin2
-     * @param onComplete
-     *        onComplete.obj will be an AsyncResult
-     *        ((AsyncResult)onComplete.obj).exception == null on success
-     *        ((AsyncResult)onComplete.obj).exception != null on fail
-     */
-    void setIccFdnEnabled(boolean enabled, String password, Message onComplete);
+     /**
+      * Set the ICC pin lock enabled or disabled
+      * When the operation is complete, onComplete will be sent to its handler
+      *
+      * @param enabled "true" for locked "false" for unlocked.
+      * @param password needed to change the ICC pin state, aka. Pin1
+      * @param onComplete
+      *        onComplete.obj will be an AsyncResult
+      *        ((AsyncResult)onComplete.obj).exception == null on success
+      *        ((AsyncResult)onComplete.obj).exception != null on fail
+      */
+     public void setIccLockEnabled (boolean enabled,
+             String password, Message onComplete) {
+         int serviceClassX;
+         serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
+                 CommandsInterface.SERVICE_CLASS_DATA +
+                 CommandsInterface.SERVICE_CLASS_FAX;
 
-    /**
-     * Change the ICC password used in ICC fdn enable
-     * When the operation is complete, onComplete will be sent to its handler
-     *
-     * @param oldPassword is the old password
-     * @param newPassword is the new password
-     * @param onComplete
-     *        onComplete.obj will be an AsyncResult
-     *        ((AsyncResult)onComplete.obj).exception == null on success
-     *        ((AsyncResult)onComplete.obj).exception != null on fail
-     */
-    void changeIccFdnPassword(String oldPassword, String newPassword,
-                           Message onComplete);
+         mDesiredPinLocked = enabled;
 
-    void supplyNetworkDepersonalization (String pin, Message onComplete);
+         mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,
+                 enabled, password, serviceClassX,
+                 mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
+     }
+
+     /**
+      * Set the ICC fdn enabled or disabled
+      * When the operation is complete, onComplete will be sent to its handler
+      *
+      * @param enabled "true" for locked "false" for unlocked.
+      * @param password needed to change the ICC fdn enable, aka Pin2
+      * @param onComplete
+      *        onComplete.obj will be an AsyncResult
+      *        ((AsyncResult)onComplete.obj).exception == null on success
+      *        ((AsyncResult)onComplete.obj).exception != null on fail
+      */
+     public void setIccFdnEnabled (boolean enabled,
+             String password, Message onComplete) {
+         int serviceClassX;
+         serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
+                 CommandsInterface.SERVICE_CLASS_DATA +
+                 CommandsInterface.SERVICE_CLASS_FAX +
+                 CommandsInterface.SERVICE_CLASS_SMS;
+
+         mDesiredFdnEnabled = enabled;
+
+         mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD,
+                 enabled, password, serviceClassX,
+                 mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
+     }
+
+     /**
+      * Change the ICC password used in ICC pin lock
+      * When the operation is complete, onComplete will be sent to its handler
+      *
+      * @param oldPassword is the old password
+      * @param newPassword is the new password
+      * @param onComplete
+      *        onComplete.obj will be an AsyncResult
+      *        ((AsyncResult)onComplete.obj).exception == null on success
+      *        ((AsyncResult)onComplete.obj).exception != null on fail
+      */
+     public void changeIccLockPassword(String oldPassword, String newPassword,
+             Message onComplete) {
+         if(mDbg) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
+         mPhone.mCM.changeIccPin(oldPassword, newPassword,
+                 mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete));
+
+     }
+
+     /**
+      * Change the ICC password used in ICC fdn enable
+      * When the operation is complete, onComplete will be sent to its handler
+      *
+      * @param oldPassword is the old password
+      * @param newPassword is the new password
+      * @param onComplete
+      *        onComplete.obj will be an AsyncResult
+      *        ((AsyncResult)onComplete.obj).exception == null on success
+      *        ((AsyncResult)onComplete.obj).exception != null on fail
+      */
+     public void changeIccFdnPassword(String oldPassword, String newPassword,
+             Message onComplete) {
+         if(mDbg) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
+         mPhone.mCM.changeIccPin2(oldPassword, newPassword,
+                 mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete));
+
+     }
+
 
     /**
      * Returns service provider name stored in ICC card.
@@ -203,5 +373,301 @@
      *         yet available
      *
      */
-    String getServiceProviderName();
+    public abstract String getServiceProviderName();
+
+    protected void updateStateProperty() {
+        mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString());
+    }
+
+    private void getIccCardStatusDone(AsyncResult ar) {
+        if (ar.exception != null) {
+            Log.e(mLogTag,"Error getting ICC status. "
+                    + "RIL_REQUEST_GET_ICC_STATUS should "
+                    + "never return an error", ar.exception);
+            return;
+        }
+        handleIccCardStatus((IccCardStatus) ar.result);
+    }
+
+    private void handleIccCardStatus(IccCardStatus newCardStatus) {
+        boolean transitionedIntoPinLocked;
+        boolean transitionedIntoAbsent;
+        boolean transitionedIntoNetworkLocked;
+
+        State oldState, newState;
+
+        oldState = mState;
+        mIccCardStatus = newCardStatus;
+        newState = getIccCardState();
+        mState = newState;
+
+        updateStateProperty();
+
+        transitionedIntoPinLocked = (
+                 (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED)
+              || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED));
+        transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
+        transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
+                && newState == State.NETWORK_LOCKED);
+
+        if (transitionedIntoPinLocked) {
+            if(mDbg) log("Notify SIM pin or puk locked.");
+            mPinLockedRegistrants.notifyRegistrants();
+            broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
+                    (newState == State.PIN_REQUIRED) ?
+                       INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
+        } else if (transitionedIntoAbsent) {
+            if(mDbg) log("Notify SIM missing.");
+            mAbsentRegistrants.notifyRegistrants();
+            broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT, null);
+        } else if (transitionedIntoNetworkLocked) {
+            if(mDbg) log("Notify SIM network locked.");
+            mNetworkLockedRegistrants.notifyRegistrants();
+            broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
+                  INTENT_VALUE_LOCKED_NETWORK);
+        }
+    }
+
+    /**
+     * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
+     * @param ar is asyncResult of Query_Facility_Locked
+     */
+    private void onQueryFdnEnabled(AsyncResult ar) {
+        if(ar.exception != null) {
+            if(mDbg) log("Error in querying facility lock:" + ar.exception);
+            return;
+        }
+
+        int[] ints = (int[])ar.result;
+        if(ints.length != 0) {
+            mIccFdnEnabled = (0!=ints[0]);
+            if(mDbg) log("Query facility lock : "  + mIccFdnEnabled);
+        } else {
+            Log.e(mLogTag, "[IccCard] Bogus facility lock response");
+        }
+    }
+
+    /**
+     * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
+     * @param ar is asyncResult of Query_Facility_Locked
+     */
+    private void onQueryFacilityLock(AsyncResult ar) {
+        if(ar.exception != null) {
+            if (mDbg) log("Error in querying facility lock:" + ar.exception);
+            return;
+        }
+
+        int[] ints = (int[])ar.result;
+        if(ints.length != 0) {
+            mIccPinLocked = (0!=ints[0]);
+            if(mDbg) log("Query facility lock : "  + mIccPinLocked);
+        } else {
+            Log.e(mLogTag, "[IccCard] Bogus facility lock response");
+        }
+    }
+
+    public void broadcastIccStateChangedIntent(String value, String reason) {
+        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(Phone.PHONE_NAME_KEY, mPhone.getPhoneName());
+        intent.putExtra(INTENT_KEY_ICC_STATE, value);
+        intent.putExtra(INTENT_KEY_LOCKED_REASON, reason);
+        if(mDbg) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
+                + " reason " + reason);
+        ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE);
+    }
+
+    protected Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg){
+            AsyncResult ar;
+            int serviceClassX;
+
+            serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
+                            CommandsInterface.SERVICE_CLASS_DATA +
+                            CommandsInterface.SERVICE_CLASS_FAX;
+
+            switch (msg.what) {
+                case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
+                    mState = null;
+                    updateStateProperty();
+                    broadcastIccStateChangedIntent(INTENT_VALUE_ICC_NOT_READY, null);
+                    break;
+                case EVENT_ICC_READY:
+                    //TODO: put facility read in SIM_READY now, maybe in REG_NW
+                    mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
+                    mPhone.mCM.queryFacilityLock (
+                            CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
+                            obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
+                    mPhone.mCM.queryFacilityLock (
+                            CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
+                            obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
+                    break;
+                case EVENT_ICC_LOCKED_OR_ABSENT:
+                    mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
+                    mPhone.mCM.queryFacilityLock (
+                            CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
+                            obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
+                    break;
+                case EVENT_GET_ICC_STATUS_DONE:
+                    ar = (AsyncResult)msg.obj;
+
+                    getIccCardStatusDone(ar);
+                    break;
+                case EVENT_PINPUK_DONE:
+                    // a PIN/PUK/PIN2/PUK2/Network Personalization
+                    // request has completed. ar.userObj is the response Message
+                    // Repoll before returning
+                    ar = (AsyncResult)msg.obj;
+                    // TODO should abstract these exceptions
+                    AsyncResult.forMessage(((Message)ar.userObj)).exception
+                                                        = ar.exception;
+                    mPhone.mCM.getIccCardStatus(
+                        obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
+                    break;
+                case EVENT_REPOLL_STATUS_DONE:
+                    // Finished repolling status after PIN operation
+                    // ar.userObj is the response messaeg
+                    // ar.userObj.obj is already an AsyncResult with an
+                    // appropriate exception filled in if applicable
+
+                    ar = (AsyncResult)msg.obj;
+                    getIccCardStatusDone(ar);
+                    ((Message)ar.userObj).sendToTarget();
+                    break;
+                case EVENT_QUERY_FACILITY_LOCK_DONE:
+                    ar = (AsyncResult)msg.obj;
+                    onQueryFacilityLock(ar);
+                    break;
+                case EVENT_QUERY_FACILITY_FDN_DONE:
+                    ar = (AsyncResult)msg.obj;
+                    onQueryFdnEnabled(ar);
+                    break;
+                case EVENT_CHANGE_FACILITY_LOCK_DONE:
+                    ar = (AsyncResult)msg.obj;
+                    if (ar.exception == null) {
+                        mIccPinLocked = mDesiredPinLocked;
+                        if (mDbg) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
+                                "mIccPinLocked= " + mIccPinLocked);
+                    } else {
+                        Log.e(mLogTag, "Error change facility lock with exception "
+                            + ar.exception);
+                    }
+                    AsyncResult.forMessage(((Message)ar.userObj)).exception
+                                                        = ar.exception;
+                    ((Message)ar.userObj).sendToTarget();
+                    break;
+                case EVENT_CHANGE_FACILITY_FDN_DONE:
+                    ar = (AsyncResult)msg.obj;
+
+                    if (ar.exception == null) {
+                        mIccFdnEnabled = mDesiredFdnEnabled;
+                        if (mDbg) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
+                                "mIccFdnEnabled=" + mIccFdnEnabled);
+                    } else {
+                        Log.e(mLogTag, "Error change facility fdn with exception "
+                                + ar.exception);
+                    }
+                    AsyncResult.forMessage(((Message)ar.userObj)).exception
+                                                        = ar.exception;
+                    ((Message)ar.userObj).sendToTarget();
+                    break;
+                case EVENT_CHANGE_ICC_PASSWORD_DONE:
+                    ar = (AsyncResult)msg.obj;
+                    if(ar.exception != null) {
+                        Log.e(mLogTag, "Error in change sim password with exception"
+                            + ar.exception);
+                    }
+                    AsyncResult.forMessage(((Message)ar.userObj)).exception
+                                                        = ar.exception;
+                    ((Message)ar.userObj).sendToTarget();
+                    break;
+                default:
+                    Log.e(mLogTag, "[IccCard] Unknown Event " + msg.what);
+            }
+        }
+    };
+
+    public State getIccCardState() {
+        if (mIccCardStatus == null) {
+            Log.e(mLogTag, "[IccCard] IccCardStatus is null");
+            return IccCard.State.ABSENT;
+        }
+
+        // this is common for all radio technologies
+        if (!mIccCardStatus.getCardState().isCardPresent()) {
+            return IccCard.State.NOT_READY;
+        }
+
+        RadioState currentRadioState = mPhone.mCM.getRadioState();
+        // check radio technology
+        if( currentRadioState == RadioState.RADIO_OFF         ||
+            currentRadioState == RadioState.RADIO_UNAVAILABLE ||
+            currentRadioState == RadioState.SIM_NOT_READY     ||
+            currentRadioState == RadioState.RUIM_NOT_READY    ||
+            currentRadioState == RadioState.NV_NOT_READY      ||
+            currentRadioState == RadioState.NV_READY) {
+            return IccCard.State.NOT_READY;
+        }
+
+        if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT  ||
+            currentRadioState == RadioState.SIM_READY             ||
+            currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
+            currentRadioState == RadioState.RUIM_READY) {
+
+            int index;
+
+            // check for CDMA radio technology
+            if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
+                currentRadioState == RadioState.RUIM_READY) {
+                index = mIccCardStatus.getCdmaSubscriptionAppIndex();
+            }
+            else {
+                index = mIccCardStatus.getGsmUmtsSubscriptionAppIndex();
+            }
+
+            IccCardApplication app = mIccCardStatus.getApplication(index);
+
+            if (app == null) {
+                Log.e(mLogTag, "[IccCard] Subscription Application in not present");
+                return IccCard.State.ABSENT;
+            }
+
+            // check if PIN required
+            if (app.app_state.isPinRequired()) {
+                return IccCard.State.PIN_REQUIRED;
+            }
+            if (app.app_state.isPukRequired()) {
+                return IccCard.State.PUK_REQUIRED;
+            }
+            if (app.app_state.isSubscriptionPersoEnabled()) {
+                return IccCard.State.NETWORK_LOCKED;
+            }
+            if (app.app_state.isAppReady()) {
+                return IccCard.State.READY;
+            }
+            if (app.app_state.isAppNotReady()) {
+                return IccCard.State.NOT_READY;
+            }
+            return IccCard.State.NOT_READY;
+        }
+
+        return IccCard.State.ABSENT;
+    }
+
+
+    public boolean hasApplicationType(IccCardApplication.AppType type) {
+        if (mIccCardStatus == null) return false;
+
+        for (int i = 0 ; i < mIccCardStatus.getNumApplications(); i++) {
+            IccCardApplication app = mIccCardStatus.getApplication(i);
+            if (app != null && app.app_type == type) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void log(String msg) {
+        Log.d(mLogTag, "[IccCard] " + msg);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java
index b602b1c..0e7bad7 100644
--- a/telephony/java/com/android/internal/telephony/IccCardStatus.java
+++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java
@@ -45,42 +45,89 @@
         PINSTATE_ENABLED_PERM_BLOCKED
     };
 
-    public CardState  card_state;
-    public PinState   universal_pin_state;
-    public int        gsm_umts_subscription_app_index;
-    public int        cdma_subscription_app_index;
-    public int        num_applications;
+    private CardState  mCardState;
+    private PinState   mUniversalPinState;
+    private int        mGsmUmtsSubscriptionAppIndex;
+    private int        mCdmaSubscriptionAppIndex;
+    private int        mNumApplications;
 
-    ArrayList<IccCardApplication> application = new ArrayList<IccCardApplication>(CARD_MAX_APPS);
+    private ArrayList<IccCardApplication> mApplications =
+            new ArrayList<IccCardApplication>(CARD_MAX_APPS);
 
-    CardState CardStateFromRILInt(int state) {
-        CardState newState;
-        /* RIL_CardState ril.h */
-        switch(state) {
-            case 0: newState = CardState.CARDSTATE_ABSENT; break;
-            case 1: newState = CardState.CARDSTATE_PRESENT; break;
-            case 2: newState = CardState.CARDSTATE_ERROR; break;
-            default:
-                throw new RuntimeException(
-                            "Unrecognized RIL_CardState: " +state);
-        }
-        return newState;
+    public CardState getCardState() {
+        return mCardState;
     }
 
-    PinState PinStateFromRILInt(int state) {
-        PinState newState;
-        /* RIL_PinState ril.h */
+    public void setCardState(int state) {
         switch(state) {
-            case 0: newState = PinState.PINSTATE_UNKNOWN; break;
-            case 1: newState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; break;
-            case 2: newState = PinState.PINSTATE_ENABLED_VERIFIED; break;
-            case 3: newState = PinState.PINSTATE_DISABLED; break;
-            case 4: newState = PinState.PINSTATE_ENABLED_BLOCKED; break;
-            case 5: newState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; break;
-            default:
-                throw new RuntimeException(
-                            "Unrecognized RIL_PinState: " +state);
+        case 0:
+            mCardState = CardState.CARDSTATE_ABSENT;
+            break;
+        case 1:
+            mCardState = CardState.CARDSTATE_PRESENT;
+            break;
+        case 2:
+            mCardState = CardState.CARDSTATE_ERROR;
+            break;
+        default:
+            throw new RuntimeException("Unrecognized RIL_CardState: " + state);
         }
-        return newState;
+    }
+
+    public void setUniversalPinState(int state) {
+        switch(state) {
+        case 0:
+            mUniversalPinState = PinState.PINSTATE_UNKNOWN;
+            break;
+        case 1:
+            mUniversalPinState = PinState.PINSTATE_ENABLED_NOT_VERIFIED;
+            break;
+        case 2:
+            mUniversalPinState = PinState.PINSTATE_ENABLED_VERIFIED;
+            break;
+        case 3:
+            mUniversalPinState = PinState.PINSTATE_DISABLED;
+            break;
+        case 4:
+            mUniversalPinState = PinState.PINSTATE_ENABLED_BLOCKED;
+            break;
+        case 5:
+            mUniversalPinState = PinState.PINSTATE_ENABLED_PERM_BLOCKED;
+            break;
+        default:
+            throw new RuntimeException("Unrecognized RIL_PinState: " + state);
+        }
+    }
+
+    public int getGsmUmtsSubscriptionAppIndex() {
+        return mGsmUmtsSubscriptionAppIndex;
+    }
+
+    public void setGsmUmtsSubscriptionAppIndex(int gsmUmtsSubscriptionAppIndex) {
+        mGsmUmtsSubscriptionAppIndex = gsmUmtsSubscriptionAppIndex;
+    }
+
+    public int getCdmaSubscriptionAppIndex() {
+        return mCdmaSubscriptionAppIndex;
+    }
+
+    public void setCdmaSubscriptionAppIndex(int cdmaSubscriptionAppIndex) {
+        mCdmaSubscriptionAppIndex = cdmaSubscriptionAppIndex;
+    }
+
+    public int getNumApplications() {
+        return mNumApplications;
+    }
+
+    public void setNumApplications(int numApplications) {
+        mNumApplications = numApplications;
+    }
+
+    public void addApplication(IccCardApplication application) {
+        mApplications.add(application);
+    }
+
+    public IccCardApplication getApplication(int index) {
+        return mApplications.get(index);
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 4db3e5b..1add40e 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -630,7 +630,7 @@
     }
 
     public void
-    getIccStatus(Message result) {
+    getIccCardStatus(Message result) {
         //Note: This RIL request has not been renamed to ICC,
         //       but this request is also valid for SIM and RUIM
         RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);
@@ -2732,24 +2732,22 @@
 
     private Object
     responseIccCardStatus(Parcel p) {
-        RadioState currentRadioState;
         IccCardApplication ca;
 
-        currentRadioState = getRadioState();
-
         IccCardStatus status = new IccCardStatus();
-        status.card_state                      = status.CardStateFromRILInt(p.readInt());
-        status.universal_pin_state             = status.PinStateFromRILInt(p.readInt());
-        status.gsm_umts_subscription_app_index = p.readInt();
-        status.cdma_subscription_app_index     = p.readInt();
-        status.num_applications                = p.readInt();
+        status.setCardState(p.readInt());
+        status.setUniversalPinState(p.readInt());
+        status.setGsmUmtsSubscriptionAppIndex(p.readInt());
+        status.setCdmaSubscriptionAppIndex(p.readInt());
+        int numApplications = p.readInt();
 
         // limit to maximum allowed applications
-        if (status.num_applications > IccCardStatus.CARD_MAX_APPS) {
-            status.num_applications = IccCardStatus.CARD_MAX_APPS;
+        if (numApplications > IccCardStatus.CARD_MAX_APPS) {
+            numApplications = IccCardStatus.CARD_MAX_APPS;
         }
+        status.setNumApplications(numApplications);
 
-        for (int i = 0 ; i < status.num_applications ; i++) {
+        for (int i = 0 ; i < numApplications ; i++) {
             ca = new IccCardApplication();
             ca.app_type       = ca.AppTypeFromRILInt(p.readInt());
             ca.app_state      = ca.AppStateFromRILInt(p.readInt());
@@ -2759,62 +2757,9 @@
             ca.pin1_replaced  = p.readInt();
             ca.pin1           = p.readInt();
             ca.pin2           = p.readInt();
-            status.application.add(ca);
+            status.addApplication(ca);
         }
-
-        // this is common for all radio technologies
-        if (!status.card_state.isCardPresent()) {
-            return IccStatus.ICC_ABSENT;
-        }
-
-        // check radio technology
-        if( currentRadioState == RadioState.RADIO_OFF         ||
-            currentRadioState == RadioState.RADIO_UNAVAILABLE ||
-            currentRadioState == RadioState.SIM_NOT_READY     ||
-            currentRadioState == RadioState.RUIM_NOT_READY    ||
-            currentRadioState == RadioState.NV_NOT_READY      ||
-            currentRadioState == RadioState.NV_READY            ) {
-            return IccStatus.ICC_NOT_READY;
-        }
-
-        if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT  ||
-            currentRadioState == RadioState.SIM_READY             ||
-            currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
-            currentRadioState == RadioState.RUIM_READY) {
-
-            int index;
-
-            // check for CDMA radio technology
-            if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
-                currentRadioState == RadioState.RUIM_READY) {
-                index = status.cdma_subscription_app_index;
-            }
-            else {
-                index = status.gsm_umts_subscription_app_index;
-            }
-
-            // check if PIN required
-            if (status.application.get(index).app_state.isPinRequired()) {
-                return IccStatus.ICC_PIN;
-            }
-            if (status.application.get(index).app_state.isPukRequired()) {
-                return IccStatus.ICC_PUK;
-            }
-            if (status.application.get(index).app_state.isSubscriptionPersoEnabled()) {
-                return IccStatus.ICC_NETWORK_PERSONALIZATION;
-            }
-            if (status.application.get(index).app_state.isAppReady()) {
-                return IccStatus.ICC_READY;
-            }
-            if (status.application.get(index).app_state.isAppNotReady()) {
-                return IccStatus.ICC_NOT_READY;
-            }
-            return IccStatus.ICC_NOT_READY;
-        }
-
-        // Unrecognized ICC status. Treat it like a missing ICC.
-        Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status);
-        return IccStatus.ICC_ABSENT;
+        return status;
     }
 
     private Object
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 0be09b9..b45a9b2 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -456,7 +456,7 @@
             Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION);
             msg.arg1 = 1; // tearDown is true
             msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF;
-            sendMessage(msg);
+            dcTracker.sendMessage(msg);
 
             // Poll data state up to 15 times, with a 100ms delay
             // totaling 1.5 sec. Normal data disable action will finish in 100ms.
@@ -592,7 +592,10 @@
                 }
 
                 mRegistrationState = registrationState;
-                mCdmaRoaming = regCodeIsRoaming(registrationState);
+                // mCdmaRoaming is true when registration state is roaming and TSB58 roaming
+                // indicator is not in the carrier-specified list of ERIs for home system
+                mCdmaRoaming =
+                        regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]);
                 newSS.setState (regCodeToServiceState(registrationState));
 
                 this.newCdmaDataConnectionState = radioTechnologyToDataServiceState(radioTechnology);
@@ -1169,6 +1172,33 @@
     }
 
     /**
+     * Determine whether a roaming indicator is in the carrier-specified list of ERIs for
+     * home system
+     *
+     * @param roamInd roaming indicator in String
+     * @return true if the roamInd is in the carrier-specified list of ERIs for home network
+     */
+    private boolean isRoamIndForHomeSystem(String roamInd) {
+        // retrieve the carrier-specified list of ERIs for home system
+        String homeRoamIndcators = SystemProperties.get("ro.cdma.homesystem");
+
+        if (!TextUtils.isEmpty(homeRoamIndcators)) {
+            // searches through the comma-separated list for a match,
+            // return true if one is found.
+            for (String homeRoamInd : homeRoamIndcators.split(",")) {
+                if (homeRoamInd.equals(roamInd)) {
+                    return true;
+                }
+            }
+            // no matches found against the list!
+            return false;
+        }
+
+        // no system property found for the roaming indicators for home system
+        return false;
+    }
+
+    /**
      * Set roaming state when cdmaRoaming is true and ons is different from spn
      * @param cdmaRoaming TS 27.007 7.2 CREG registered roaming
      * @param s ServiceState hold current ons
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
index 9d9f479..734badd 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
@@ -16,507 +16,34 @@
 
 package com.android.internal.telephony.cdma;
 
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneProxy;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-
-import android.app.ActivityManagerNative;
-import android.content.Intent;
-import android.content.res.Configuration;
-
-import static android.Manifest.permission.READ_PHONE_STATE;
 
 /**
  * Note: this class shares common code with SimCard, consider a base class to minimize code
  * duplication.
  * {@hide}
  */
-public final class RuimCard extends Handler implements IccCard {
-    static final String LOG_TAG="CDMA";
-
-    //***** Instance Variables
-    private static final boolean DBG = true;
-
-    private CDMAPhone phone;
-
-    private CommandsInterface.IccStatus status = null;
-    private boolean mDesiredPinLocked;
-    private boolean mDesiredFdnEnabled;
-    private boolean mRuimPinLocked = true; // default to locked
-    private boolean mRuimFdnEnabled = false; // Default to disabled.
-                                            // Will be updated when RUIM_READY.
-//    //***** Constants
-
-//    // FIXME I hope this doesn't conflict with the Dialer's notifications
-//    Nobody is using this at the moment
-//    static final int NOTIFICATION_ID_ICC_STATUS = 33456;
-
-    //***** Event Constants
-
-    static final int EVENT_RUIM_LOCKED_OR_ABSENT = 1;
-    static final int EVENT_GET_RUIM_STATUS_DONE = 2;
-    static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
-    static final int EVENT_PINPUK_DONE = 4;
-    static final int EVENT_REPOLL_STATUS_DONE = 5;
-    static final int EVENT_RUIM_READY = 6;
-    static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
-    static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
-    static final int EVENT_CHANGE_RUIM_PASSWORD_DONE = 9;
-    static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
-    static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
-
-
-    //***** Constructor
+public final class RuimCard extends IccCard {
 
     RuimCard(CDMAPhone phone) {
-        this.phone = phone;
-
-        phone.mCM.registerForRUIMLockedOrAbsent(
-                        this, EVENT_RUIM_LOCKED_OR_ABSENT, null);
-
-        phone.mCM.registerForOffOrNotAvailable(
-                        this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
-
-        phone.mCM.registerForRUIMReady(
-                        this, EVENT_RUIM_READY, null);
-
+        super(phone, "CDMA", true);
+        mPhone.mCM.registerForRUIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null);
+        mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+        mPhone.mCM.registerForRUIMReady(mHandler, EVENT_ICC_READY, null);
         updateStateProperty();
     }
 
-    //***** RuimCard implementation
-
-    public State
-    getState() {
-        if (status == null) {
-            switch(phone.mCM.getRadioState()) {
-                /* This switch block must not return anything in
-                 * State.isLocked() or State.ABSENT.
-                 * If it does, handleSimStatus() may break
-                 */
-                case RADIO_OFF:
-                case RADIO_UNAVAILABLE:
-                case RUIM_NOT_READY:
-                    return State.UNKNOWN;
-                case RUIM_LOCKED_OR_ABSENT:
-                    //this should be transient-only
-                    return State.UNKNOWN;
-                case RUIM_READY:
-                    return State.READY;
-                case NV_READY:
-                case NV_NOT_READY:
-                    return State.ABSENT;
-            }
-        } else {
-            switch (status) {
-                case ICC_ABSENT:            return State.ABSENT;
-                case ICC_NOT_READY:         return State.UNKNOWN;
-                case ICC_READY:             return State.READY;
-                case ICC_PIN:               return State.PIN_REQUIRED;
-                case ICC_PUK:               return State.PUK_REQUIRED;
-                case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED;
-            }
-        }
-
-        Log.e(LOG_TAG, "RuimCard.getState(): case should never be reached");
-        return State.UNKNOWN;
-    }
-
+    @Override
     public void dispose() {
         //Unregister for all events
-        phone.mCM.unregisterForRUIMLockedOrAbsent(this);
-        phone.mCM.unregisterForOffOrNotAvailable(this);
-        phone.mCM.unregisterForRUIMReady(this);
+        mPhone.mCM.unregisterForRUIMLockedOrAbsent(mHandler);
+        mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
+        mPhone.mCM.unregisterForRUIMReady(mHandler);
     }
 
-    protected void finalize() {
-        if(DBG) Log.d(LOG_TAG, "RuimCard finalized");
-    }
-
-    private RegistrantList absentRegistrants = new RegistrantList();
-    private RegistrantList pinLockedRegistrants = new RegistrantList();
-    private RegistrantList networkLockedRegistrants = new RegistrantList();
-
-
-    public void registerForAbsent(Handler h, int what, Object obj) {
-        Registrant r = new Registrant (h, what, obj);
-
-        absentRegistrants.add(r);
-
-        if (getState() == State.ABSENT) {
-            r.notifyRegistrant();
-        }
-    }
-
-    public void unregisterForAbsent(Handler h) {
-        absentRegistrants.remove(h);
-    }
-
-    public void registerForNetworkLocked(Handler h, int what, Object obj) {
-        Registrant r = new Registrant (h, what, obj);
-
-        networkLockedRegistrants.add(r);
-
-        if (getState() == State.NETWORK_LOCKED) {
-            r.notifyRegistrant();
-        }
-    }
-
-    public void unregisterForNetworkLocked(Handler h) {
-        networkLockedRegistrants.remove(h);
-    }
-
-    public void registerForLocked(Handler h, int what, Object obj) {
-        Registrant r = new Registrant (h, what, obj);
-
-        pinLockedRegistrants.add(r);
-
-        if (getState().isPinLocked()) {
-            r.notifyRegistrant();
-        }
-    }
-
-    public void unregisterForLocked(Handler h) {
-        pinLockedRegistrants.remove(h);
-    }
-
-    public void supplyPin (String pin, Message onComplete) {
-        phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete));
-    }
-
-    public void supplyPuk (String puk, String newPin, Message onComplete) {
-        phone.mCM.supplyIccPuk(puk, newPin, obtainMessage(EVENT_PINPUK_DONE, onComplete));
-    }
-
-    public void supplyPin2 (String pin2, Message onComplete) {
-        phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete));
-    }
-
-    public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
-        phone.mCM.supplyIccPuk2(puk2, newPin2, obtainMessage(EVENT_PINPUK_DONE, onComplete));
-    }
-
-    public void supplyNetworkDepersonalization (String pin, Message onComplete) {
-        if(DBG) log("Network Despersonalization: " + pin);
-        phone.mCM.supplyNetworkDepersonalization(pin,
-                obtainMessage(EVENT_PINPUK_DONE, onComplete));
-    }
-
-    public boolean getIccLockEnabled() {
-       return mRuimPinLocked;
-    }
-
-    public boolean getIccFdnEnabled() {
-       return mRuimFdnEnabled;
-    }
-
-    public void setIccLockEnabled (boolean enabled,
-            String password, Message onComplete) {
-        int serviceClassX;
-        serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
-                CommandsInterface.SERVICE_CLASS_DATA +
-                CommandsInterface.SERVICE_CLASS_FAX;
-
-        mDesiredPinLocked = enabled;
-
-        phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,
-                enabled, password, serviceClassX,
-                obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
-    }
-
-    public void setIccFdnEnabled (boolean enabled,
-            String password, Message onComplete) {
-        int serviceClassX;
-        serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
-                CommandsInterface.SERVICE_CLASS_DATA +
-                CommandsInterface.SERVICE_CLASS_FAX +
-                CommandsInterface.SERVICE_CLASS_SMS;
-
-        mDesiredFdnEnabled = enabled;
-
-        phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD,
-                enabled, password, serviceClassX,
-                obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
-    }
-
-    public void changeIccLockPassword(String oldPassword, String newPassword,
-            Message onComplete) {
-        if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
-        phone.mCM.changeIccPin(oldPassword, newPassword,
-                obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete));
-    }
-
-    public void changeIccFdnPassword(String oldPassword, String newPassword,
-            Message onComplete) {
-        if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
-        phone.mCM.changeIccPin2(oldPassword, newPassword,
-                obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete));
-    }
-
-    public String getServiceProviderName() {
-        return phone.mRuimRecords.getServiceProviderName();
-    }
-
-    //***** Handler implementation
     @Override
-    public void handleMessage(Message msg){
-        AsyncResult ar;
-        int serviceClassX;
-
-        serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
-                        CommandsInterface.SERVICE_CLASS_DATA +
-                        CommandsInterface.SERVICE_CLASS_FAX;
-
-        switch (msg.what) {
-            case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
-                Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
-                status = null;
-                updateStateProperty();
-                broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_NOT_READY, null);
-                break;
-            case EVENT_RUIM_READY:
-                Log.d(LOG_TAG, "Event EVENT_RUIM_READY Received");
-                //TODO: put facility read in SIM_READY now, maybe in REG_NW
-                phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE));
-                phone.mCM.queryFacilityLock (
-                        CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
-                        obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
-                phone.mCM.queryFacilityLock (
-                        CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
-                        obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
-                break;
-            case EVENT_RUIM_LOCKED_OR_ABSENT:
-                Log.d(LOG_TAG, "Event EVENT_RUIM_LOCKED_OR_ABSENT Received");
-                phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE));
-                phone.mCM.queryFacilityLock (
-                        CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
-                        obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
-                break;
-            case EVENT_GET_RUIM_STATUS_DONE:
-                Log.d(LOG_TAG, "Event EVENT_GET_RUIM_STATUS_DONE Received");
-                ar = (AsyncResult)msg.obj;
-
-                getRuimStatusDone(ar);
-                break;
-            case EVENT_PINPUK_DONE:
-                Log.d(LOG_TAG, "Event EVENT_PINPUK_DONE Received");
-                // a PIN/PUK/PIN2/PUK2/Network Personalization
-                // request has completed. ar.userObj is the response Message
-                // Repoll before returning
-                ar = (AsyncResult)msg.obj;
-                // TODO should abstract these exceptions
-                AsyncResult.forMessage(((Message)ar.userObj)).exception
-                                                    = ar.exception;
-                phone.mCM.getIccStatus(
-                    obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
-                break;
-            case EVENT_REPOLL_STATUS_DONE:
-                Log.d(LOG_TAG, "Event EVENT_REPOLL_STATUS_DONE Received");
-                // Finished repolling status after PIN operation
-                // ar.userObj is the response messaeg
-                // ar.userObj.obj is already an AsyncResult with an
-                // appropriate exception filled in if applicable
-
-                ar = (AsyncResult)msg.obj;
-                getRuimStatusDone(ar);
-                ((Message)ar.userObj).sendToTarget();
-                break;
-            case EVENT_QUERY_FACILITY_LOCK_DONE:
-                Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_LOCK_DONE Received");
-                ar = (AsyncResult)msg.obj;
-                onQueryFacilityLock(ar);
-                break;
-            case EVENT_QUERY_FACILITY_FDN_DONE:
-                Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_FDN_DONE Received");
-                ar = (AsyncResult)msg.obj;
-                onQueryFdnEnabled(ar);
-                break;
-            case EVENT_CHANGE_FACILITY_LOCK_DONE:
-                Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_LOCK_DONE Received");
-                ar = (AsyncResult)msg.obj;
-                if (ar.exception == null) {
-                    mRuimPinLocked = mDesiredPinLocked;
-                    if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
-                            "mRuimPinLocked= " + mRuimPinLocked);
-                } else {
-                    Log.e(LOG_TAG, "Error change facility lock with exception "
-                        + ar.exception);
-                }
-                AsyncResult.forMessage(((Message)ar.userObj)).exception
-                                                    = ar.exception;
-                ((Message)ar.userObj).sendToTarget();
-                break;
-            case EVENT_CHANGE_FACILITY_FDN_DONE:
-                Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_FDN_DONE Received");
-                ar = (AsyncResult)msg.obj;
-
-                if (ar.exception == null) {
-                    mRuimFdnEnabled = mDesiredFdnEnabled;
-                    if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
-                            "mRuimFdnEnabled=" + mRuimFdnEnabled);
-                } else {
-                    Log.e(LOG_TAG, "Error change facility fdn with exception "
-                            + ar.exception);
-                }
-                AsyncResult.forMessage(((Message)ar.userObj)).exception
-                                                    = ar.exception;
-                ((Message)ar.userObj).sendToTarget();
-                break;
-            case EVENT_CHANGE_RUIM_PASSWORD_DONE:
-                Log.d(LOG_TAG, "Event EVENT_CHANGE_RUIM_PASSWORD_DONE Received");
-                ar = (AsyncResult)msg.obj;
-                if(ar.exception != null) {
-                    Log.e(LOG_TAG, "Error in change sim password with exception"
-                        + ar.exception);
-                }
-                AsyncResult.forMessage(((Message)ar.userObj)).exception
-                                                    = ar.exception;
-                ((Message)ar.userObj).sendToTarget();
-                break;
-            default:
-                Log.e(LOG_TAG, "[CdmaRuimCard] Unknown Event " + msg.what);
-        }
+    public String getServiceProviderName () {
+        return ((CDMAPhone)mPhone).mRuimRecords.getServiceProviderName();
     }
-
-    //***** Private methods
-
-    /**
-     * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
-     * @param ar is asyncResult of Query_Facility_Locked
-     */
-    private void onQueryFacilityLock(AsyncResult ar) {
-        if(ar.exception != null) {
-            if (DBG) log("Error in querying facility lock:" + ar.exception);
-            return;
-        }
-
-        int[] ints = (int[])ar.result;
-        if(ints.length != 0) {
-            mRuimPinLocked = (0!=ints[0]);
-            if(DBG) log("Query facility lock : "  + mRuimPinLocked);
-        } else {
-            Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response");
-        }
-    }
-
-    /**
-     * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
-     * @param ar is asyncResult of Query_Facility_Locked
-     */
-    private void onQueryFdnEnabled(AsyncResult ar) {
-        if(ar.exception != null) {
-            if(DBG) log("Error in querying facility lock:" + ar.exception);
-            return;
-        }
-
-        int[] ints = (int[])ar.result;
-        if(ints.length != 0) {
-            mRuimFdnEnabled = (0!=ints[0]);
-            if(DBG) log("Query facility lock : "  + mRuimFdnEnabled);
-        } else {
-            Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response");
-        }
-    }
-
-    private void
-    getRuimStatusDone(AsyncResult ar) {
-        if (ar.exception != null) {
-            Log.e(LOG_TAG,"Error getting SIM status. "
-                    + "RIL_REQUEST_GET_SIM_STATUS should "
-                    + "never return an error", ar.exception);
-            return;
-        }
-
-        CommandsInterface.IccStatus newStatus
-            = (CommandsInterface.IccStatus)  ar.result;
-
-        handleRuimStatus(newStatus);
-    }
-
-    private void
-    handleRuimStatus(CommandsInterface.IccStatus newStatus) {
-        boolean transitionedIntoPinLocked;
-        boolean transitionedIntoAbsent;
-        boolean transitionedIntoNetworkLocked;
-
-        RuimCard.State oldState, newState;
-
-        oldState = getState();
-        status = newStatus;
-        newState = getState();
-
-        updateStateProperty();
-
-        transitionedIntoPinLocked = (
-                 (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED)
-              || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED));
-        transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
-        transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
-                && newState == State.NETWORK_LOCKED);
-
-        if (transitionedIntoPinLocked) {
-            if(DBG) log("Notify RUIM pin or puk locked.");
-            pinLockedRegistrants.notifyRegistrants();
-            broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED,
-                    (newState == State.PIN_REQUIRED) ?
-                       INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
-        } else if (transitionedIntoAbsent) {
-            if(DBG) log("Notify RUIM missing.");
-            absentRegistrants.notifyRegistrants();
-            broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_ABSENT, null);
-        } else if (transitionedIntoNetworkLocked) {
-            if(DBG) log("Notify RUIM network locked.");
-            networkLockedRegistrants.notifyRegistrants();
-            broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED,
-                  INTENT_VALUE_LOCKED_NETWORK);
-        }
-    }
-
-    public void broadcastRuimStateChangedIntent(String value, String reason) {
-        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-        intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName());
-        intent.putExtra(RuimCard.INTENT_KEY_ICC_STATE, value);
-        intent.putExtra(RuimCard.INTENT_KEY_LOCKED_REASON, reason);
-        if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " +  value
-                + " reason " + reason);
-        ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE);
-    }
-
-    public void updateImsiConfiguration(String imsi) {
-        if (imsi.length() >= 6) {
-            Configuration config = new Configuration();
-            config.mcc = ((imsi.charAt(0)-'0')*100)
-                    + ((imsi.charAt(1)-'0')*10)
-                    + (imsi.charAt(2)-'0');
-            config.mnc = ((imsi.charAt(3)-'0')*100)
-                    + ((imsi.charAt(4)-'0')*10)
-                    + (imsi.charAt(5)-'0');
-            try {
-                ActivityManagerNative.getDefault().updateConfiguration(config);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    private void
-    updateStateProperty() {
-        phone.setSystemProperty(
-            TelephonyProperties.PROPERTY_SIM_STATE,
-            getState().toString());
-    }
-
-    private void log(String msg) {
-        Log.d(LOG_TAG, "[RuimCard] " + msg);
-    }
-}
+ }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index c7e61da..38a92cd 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -342,7 +342,7 @@
 
         recordsLoadedRegistrants.notifyRegistrants(
             new AsyncResult(null, null, null));
-        ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent(
+        ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent(
                 RuimCard.INTENT_VALUE_ICC_LOADED, null);
     }
 
@@ -351,7 +351,7 @@
           READY is sent before IMSI ready
         */
 
-        ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent(
+        ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent(
                 RuimCard.INTENT_VALUE_ICC_READY, null);
 
         fetchRuimRecords();
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
old mode 100644
new mode 100755
index 1b83e5c..c085739
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -587,9 +587,24 @@
     private static CdmaSmsAddress parseCdmaSmsAddr(String addrStr) {
         // see C.S0015-B, v2.0, 3.4.3.3
         CdmaSmsAddress addr = new CdmaSmsAddress();
-        addr.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR;
+        addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF;
         try {
             addr.origBytes = addrStr.getBytes("UTF-8");
+            for (int index = 0; index < addr.origBytes.length; index++) {
+                if (addr.origBytes[index] >= '0' && addr.origBytes[index] <= '9') {
+                    if (addr.origBytes[index] == '0') {
+                        addr.origBytes[index] = 10;
+                    } else {
+                        addr.origBytes[index] -= '0';
+                    }
+                } else if (addr.origBytes[index] == '*') {
+                    addr.origBytes[index] = 11;
+                } else if (addr.origBytes[index] == '#') {
+                    addr.origBytes[index] = 12;
+                } else {
+                    return null;
+                }
+            }
         } catch  (java.io.UnsupportedEncodingException ex) {
             Log.e(LOG_TAG, "CDMA address parsing failed: " + ex);
             return null;
@@ -597,7 +612,7 @@
         addr.numberOfDigits = (byte)addr.origBytes.length;
         addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK;
         addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY;
-        addr.ton = CdmaSmsAddress.TON_INTERNATIONAL_OR_IP;
+        addr.ton = CdmaSmsAddress.TON_UNKNOWN;
         return addr;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 066f782..b3b4345 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -540,7 +540,7 @@
             Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION);
             msg.arg1 = 1; // tearDown is true
             msg.obj = GSMPhone.REASON_RADIO_TURNED_OFF;
-            sendMessage(msg);
+            dcTracker.sendMessage(msg);
 
             // poll data state up to 15 times, with a 100ms delay
             // totaling 1.5 sec. Normal data disable action will finish in 100ms.
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 3c8c10a..4272faa 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -16,41 +16,29 @@
 
 package com.android.internal.telephony.gsm;
 
-import android.app.ActivityManagerNative;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
 import android.app.AlarmManager;
-import android.app.IActivityManager;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.net.wifi.WifiManager;
 import android.os.AsyncResult;
-import android.os.Handler;
 import android.os.Message;
 import android.os.SystemProperties;
-import android.os.Registrant;
 import android.provider.Settings;
 import android.util.Log;
-import java.util.ArrayList;
-
-
-import static com.android.internal.telephony.TelephonyProperties.*;
 
 import com.android.internal.telephony.AdnRecord;
 import com.android.internal.telephony.AdnRecordCache;
 import com.android.internal.telephony.AdnRecordLoader;
 import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.gsm.SimCard;
-import com.android.internal.telephony.gsm.SmsMessage;
 import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.IccVmFixedException;
 import com.android.internal.telephony.IccVmNotSupportedException;
-import com.android.internal.telephony.PhoneProxy;
 
-
-
-
-
+import java.util.ArrayList;
 
 
 /**
@@ -577,7 +565,7 @@
 
                 Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx");
                 ((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi);
-                ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+                ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
                         SimCard.INTENT_VALUE_ICC_IMSI, null);
 
                 int mcc = Integer.parseInt(imsi.substring(0, 3));
@@ -1204,7 +1192,7 @@
 
         recordsLoadedRegistrants.notifyRegistrants(
             new AsyncResult(null, null, null));
-        ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+        ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
                 SimCard.INTENT_VALUE_ICC_LOADED, null);
     }
 
@@ -1229,7 +1217,7 @@
         /* broadcast intent SIM_READY here so that we can make sure
           READY is sent before IMSI ready
         */
-        ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+        ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
                 SimCard.INTENT_VALUE_ICC_READY, null);
 
         fetchSimRecords();
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index 9af3aa6..6c56682 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -17,469 +17,37 @@
 package com.android.internal.telephony.gsm;
 
 import android.app.ActivityManagerNative;
-import android.content.Intent;
 import android.content.res.Configuration;
-import android.os.AsyncResult;
 import android.os.RemoteException;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
 import android.util.Log;
 
-import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneProxy;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-
-import static android.Manifest.permission.READ_PHONE_STATE;
 
 /**
- * Note: this class shares common code with RuimCard, consider a base class to minimize code
- * duplication.
  * {@hide}
  */
-public final class SimCard extends Handler implements IccCard {
-    static final String LOG_TAG="GSM";
-
-    //***** Instance Variables
-    private static final boolean DBG = true;
-
-    private GSMPhone phone;
-    private CommandsInterface.IccStatus status = null;
-    private boolean mDesiredPinLocked;
-    private boolean mDesiredFdnEnabled;
-    private boolean mSimPinLocked = true; // Default to locked
-    private boolean mSimFdnEnabled = false; // Default to disabled.
-                                            // Will be updated when SIM_READY.
-
-    //***** Constants
-
-    // FIXME I hope this doesn't conflict with the Dialer's notifications
-    static final int NOTIFICATION_ID_SIM_STATUS = 33456;
-
-    //***** Event Constants
-
-    static final int EVENT_SIM_LOCKED_OR_ABSENT = 1;
-    static final int EVENT_GET_SIM_STATUS_DONE = 2;
-    static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
-    static final int EVENT_PINPUK_DONE = 4;
-    static final int EVENT_REPOLL_STATUS_DONE = 5;
-    static final int EVENT_SIM_READY = 6;
-    static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
-    static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
-    static final int EVENT_CHANGE_SIM_PASSWORD_DONE = 9;
-    static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
-    static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
-
-
-    //***** Constructor
+public final class SimCard extends IccCard {
 
     SimCard(GSMPhone phone) {
-        this.phone = phone;
+        super(phone, "GSM", true);
 
-        phone.mCM.registerForSIMLockedOrAbsent(
-                        this, EVENT_SIM_LOCKED_OR_ABSENT, null);
-
-        phone.mCM.registerForOffOrNotAvailable(
-                        this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
-
-        phone.mCM.registerForSIMReady(
-                        this, EVENT_SIM_READY, null);
-
+        mPhone.mCM.registerForSIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null);
+        mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+        mPhone.mCM.registerForSIMReady(mHandler, EVENT_ICC_READY, null);
         updateStateProperty();
     }
 
+    @Override
     public void dispose() {
         //Unregister for all events
-        phone.mCM.unregisterForSIMLockedOrAbsent(this);
-        phone.mCM.unregisterForOffOrNotAvailable(this);
-        phone.mCM.unregisterForSIMReady(this);
+        mPhone.mCM.unregisterForSIMLockedOrAbsent(mHandler);
+        mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
+        mPhone.mCM.unregisterForSIMReady(mHandler);
     }
 
-    protected void finalize() {
-        if(DBG) Log.d(LOG_TAG, "SimCard finalized");
-    }
-
-    //***** SimCard implementation
-
-    public State
-    getState() {
-        if (status == null) {
-            switch(phone.mCM.getRadioState()) {
-                /* This switch block must not return anything in
-                 * State.isLocked() or State.ABSENT.
-                 * If it does, handleSimStatus() may break
-                 */
-                case RADIO_OFF:
-                case RADIO_UNAVAILABLE:
-                case SIM_NOT_READY:
-                    return State.UNKNOWN;
-                case SIM_LOCKED_OR_ABSENT:
-                    //this should be transient-only
-                    return State.UNKNOWN;
-                case SIM_READY:
-                    return State.READY;
-            }
-        } else {
-            switch (status) {
-                case ICC_ABSENT:            return State.ABSENT;
-                case ICC_NOT_READY:         return State.UNKNOWN;
-                case ICC_READY:             return State.READY;
-                case ICC_PIN:               return State.PIN_REQUIRED;
-                case ICC_PUK:               return State.PUK_REQUIRED;
-                case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED;
-            }
-        }
-
-        Log.e(LOG_TAG, "GsmSimCard.getState(): case should never be reached");
-        return State.UNKNOWN;
-    }
-
-    private RegistrantList absentRegistrants = new RegistrantList();
-    private RegistrantList pinLockedRegistrants = new RegistrantList();
-    private RegistrantList networkLockedRegistrants = new RegistrantList();
-
-
-    public void registerForAbsent(Handler h, int what, Object obj) {
-        Registrant r = new Registrant (h, what, obj);
-
-        absentRegistrants.add(r);
-
-        if (getState() == State.ABSENT) {
-            r.notifyRegistrant();
-        }
-    }
-
-    public void unregisterForAbsent(Handler h) {
-        absentRegistrants.remove(h);
-    }
-
-    public void registerForNetworkLocked(Handler h, int what, Object obj) {
-        Registrant r = new Registrant (h, what, obj);
-
-        networkLockedRegistrants.add(r);
-
-        if (getState() == State.NETWORK_LOCKED) {
-            r.notifyRegistrant();
-        }
-    }
-
-    public void unregisterForNetworkLocked(Handler h) {
-        networkLockedRegistrants.remove(h);
-    }
-
-    public void registerForLocked(Handler h, int what, Object obj) {
-        Registrant r = new Registrant (h, what, obj);
-
-        pinLockedRegistrants.add(r);
-
-        if (getState().isPinLocked()) {
-            r.notifyRegistrant();
-        }
-    }
-
-    public void unregisterForLocked(Handler h) {
-        pinLockedRegistrants.remove(h);
-    }
-
-
-    public void supplyPin (String pin, Message onComplete) {
-        phone.mCM.supplyIccPin(pin,
-                            obtainMessage(EVENT_PINPUK_DONE, onComplete));
-    }
-
-    public void supplyPuk (String puk, String newPin, Message onComplete) {
-        phone.mCM.supplyIccPuk(puk, newPin,
-                        obtainMessage(EVENT_PINPUK_DONE, onComplete));
-    }
-    public void supplyPin2 (String pin2, Message onComplete) {
-        phone.mCM.supplyIccPin2(pin2,
-                        obtainMessage(EVENT_PINPUK_DONE, onComplete));
-    }
-    public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
-        phone.mCM.supplyIccPuk2(puk2, newPin2,
-                obtainMessage(EVENT_PINPUK_DONE, onComplete));
-    }
-
-    public void supplyNetworkDepersonalization (String pin, Message onComplete) {
-        if(DBG) log("Network Despersonalization: " + pin);
-        phone.mCM.supplyNetworkDepersonalization(pin,
-                        obtainMessage(EVENT_PINPUK_DONE, onComplete));
-    }
-
-    public boolean getIccLockEnabled() {
-       return mSimPinLocked;
-    }
-
-    public boolean getIccFdnEnabled() {
-       return mSimFdnEnabled;
-    }
-
-    public void setIccLockEnabled (boolean enabled,
-            String password, Message onComplete) {
-        int serviceClassX;
-        serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
-                CommandsInterface.SERVICE_CLASS_DATA +
-                CommandsInterface.SERVICE_CLASS_FAX;
-
-        mDesiredPinLocked = enabled;
-
-        phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,
-                enabled, password, serviceClassX,
-                obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
-    }
-
-    public void setIccFdnEnabled (boolean enabled,
-            String password, Message onComplete) {
-        int serviceClassX;
-        serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
-                CommandsInterface.SERVICE_CLASS_DATA +
-                CommandsInterface.SERVICE_CLASS_FAX +
-                CommandsInterface.SERVICE_CLASS_SMS;
-
-        mDesiredFdnEnabled = enabled;
-
-        phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD,
-                enabled, password, serviceClassX,
-                obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
-    }
-
-    public void changeIccLockPassword(String oldPassword, String newPassword,
-            Message onComplete) {
-        if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
-        phone.mCM.changeIccPin(oldPassword, newPassword,
-                obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete));
-
-    }
-
-    public void changeIccFdnPassword(String oldPassword, String newPassword,
-            Message onComplete) {
-        if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
-        phone.mCM.changeIccPin2(oldPassword, newPassword,
-                obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete));
-
-    }
-
-    public String getServiceProviderName () {
-        return phone.mSIMRecords.getServiceProviderName();
-    }
-
-    //***** Handler implementation
     @Override
-    public void handleMessage(Message msg){
-        AsyncResult ar;
-        int serviceClassX;
-
-        serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
-                        CommandsInterface.SERVICE_CLASS_DATA +
-                        CommandsInterface.SERVICE_CLASS_FAX;
-
-        switch (msg.what) {
-            case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
-                status = null;
-                updateStateProperty();
-                broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_NOT_READY, null);
-                break;
-            case EVENT_SIM_READY:
-                //TODO: put facility read in SIM_READY now, maybe in REG_NW
-                phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE));
-                phone.mCM.queryFacilityLock (
-                        CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
-                        obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
-                phone.mCM.queryFacilityLock (
-                        CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
-                        obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
-                break;
-            case EVENT_SIM_LOCKED_OR_ABSENT:
-                phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE));
-                phone.mCM.queryFacilityLock (
-                        CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
-                        obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
-                break;
-            case EVENT_GET_SIM_STATUS_DONE:
-                ar = (AsyncResult)msg.obj;
-
-                getSimStatusDone(ar);
-                break;
-            case EVENT_PINPUK_DONE:
-                // a PIN/PUK/PIN2/PUK2/Network Personalization
-                // request has completed. ar.userObj is the response Message
-                // Repoll before returning
-                ar = (AsyncResult)msg.obj;
-                // TODO should abstract these exceptions
-                AsyncResult.forMessage(((Message)ar.userObj)).exception
-                                                    = ar.exception;
-                phone.mCM.getIccStatus(
-                    obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
-                break;
-            case EVENT_REPOLL_STATUS_DONE:
-                // Finished repolling status after PIN operation
-                // ar.userObj is the response messaeg
-                // ar.userObj.obj is already an AsyncResult with an
-                // appropriate exception filled in if applicable
-
-                ar = (AsyncResult)msg.obj;
-                getSimStatusDone(ar);
-                ((Message)ar.userObj).sendToTarget();
-                break;
-            case EVENT_QUERY_FACILITY_LOCK_DONE:
-                ar = (AsyncResult)msg.obj;
-                onQueryFacilityLock(ar);
-                break;
-            case EVENT_QUERY_FACILITY_FDN_DONE:
-                ar = (AsyncResult)msg.obj;
-                onQueryFdnEnabled(ar);
-                break;
-            case EVENT_CHANGE_FACILITY_LOCK_DONE:
-                ar = (AsyncResult)msg.obj;
-                if (ar.exception == null) {
-                    mSimPinLocked = mDesiredPinLocked;
-                    if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
-                            "mSimPinLocked= " + mSimPinLocked);
-                } else {
-                    Log.e(LOG_TAG, "Error change facility lock with exception "
-                        + ar.exception);
-                }
-                AsyncResult.forMessage(((Message)ar.userObj)).exception
-                                                    = ar.exception;
-                ((Message)ar.userObj).sendToTarget();
-                break;
-            case EVENT_CHANGE_FACILITY_FDN_DONE:
-                ar = (AsyncResult)msg.obj;
-
-                if (ar.exception == null) {
-                    mSimFdnEnabled = mDesiredFdnEnabled;
-                    if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
-                            "mSimFdnEnabled=" + mSimFdnEnabled);
-                } else {
-                    Log.e(LOG_TAG, "Error change facility fdn with exception "
-                            + ar.exception);
-                }
-                AsyncResult.forMessage(((Message)ar.userObj)).exception
-                                                    = ar.exception;
-                ((Message)ar.userObj).sendToTarget();
-                break;
-            case EVENT_CHANGE_SIM_PASSWORD_DONE:
-                ar = (AsyncResult)msg.obj;
-                if(ar.exception != null) {
-                    Log.e(LOG_TAG, "Error in change sim password with exception"
-                        + ar.exception);
-                }
-                AsyncResult.forMessage(((Message)ar.userObj)).exception
-                                                    = ar.exception;
-                ((Message)ar.userObj).sendToTarget();
-                break;
-            default:
-                Log.e(LOG_TAG, "[GsmSimCard] Unknown Event " + msg.what);
-        }
-    }
-
-
-    //***** Private methods
-
-    /**
-     * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
-     * @param ar is asyncResult of Query_Facility_Locked
-     */
-    private void onQueryFacilityLock(AsyncResult ar) {
-        if(ar.exception != null) {
-            if (DBG) log("Error in querying facility lock:" + ar.exception);
-            return;
-        }
-
-        int[] ints = (int[])ar.result;
-        if(ints.length != 0) {
-            mSimPinLocked = (0!=ints[0]);
-            if(DBG) log("Query facility lock : "  + mSimPinLocked);
-        } else {
-            Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response");
-        }
-    }
-
-    /**
-     * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
-     * @param ar is asyncResult of Query_Facility_Locked
-     */
-    private void onQueryFdnEnabled(AsyncResult ar) {
-        if(ar.exception != null) {
-            if(DBG) log("Error in querying facility lock:" + ar.exception);
-            return;
-        }
-
-        int[] ints = (int[])ar.result;
-        if(ints.length != 0) {
-            mSimFdnEnabled = (0!=ints[0]);
-            if(DBG) log("Query facility lock : "  + mSimFdnEnabled);
-        } else {
-            Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response");
-        }
-    }
-
-    private void
-    getSimStatusDone(AsyncResult ar) {
-        if (ar.exception != null) {
-            Log.e(LOG_TAG,"Error getting ICC status. "
-                    + "RIL_REQUEST_GET_ICC_STATUS should "
-                    + "never return an error", ar.exception);
-            return;
-        }
-
-        CommandsInterface.IccStatus newStatus
-            = (CommandsInterface.IccStatus)  ar.result;
-
-        handleSimStatus(newStatus);
-    }
-
-    private void
-    handleSimStatus(CommandsInterface.IccStatus newStatus) {
-        boolean transitionedIntoPinLocked;
-        boolean transitionedIntoAbsent;
-        boolean transitionedIntoNetworkLocked;
-
-        SimCard.State oldState, newState;
-
-        oldState = getState();
-        status = newStatus;
-        newState = getState();
-
-        updateStateProperty();
-
-        transitionedIntoPinLocked = (
-                 (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED)
-              || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED));
-        transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
-        transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
-                && newState == State.NETWORK_LOCKED);
-
-        if (transitionedIntoPinLocked) {
-            if(DBG) log("Notify SIM pin or puk locked.");
-            pinLockedRegistrants.notifyRegistrants();
-            broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED,
-                    (newState == State.PIN_REQUIRED) ?
-                       INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
-        } else if (transitionedIntoAbsent) {
-            if(DBG) log("Notify SIM missing.");
-            absentRegistrants.notifyRegistrants();
-            broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_ABSENT, null);
-        } else if (transitionedIntoNetworkLocked) {
-            if(DBG) log("Notify SIM network locked.");
-            networkLockedRegistrants.notifyRegistrants();
-            broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED,
-                  INTENT_VALUE_LOCKED_NETWORK);
-        }
-    }
-
-    public void broadcastSimStateChangedIntent(String value, String reason) {
-        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-        intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName());
-        intent.putExtra(SimCard.INTENT_KEY_ICC_STATE, value);
-        intent.putExtra(SimCard.INTENT_KEY_LOCKED_REASON, reason);
-        if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " +  value
-                + " reason " + reason);
-        ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE);
+    public String getServiceProviderName () {
+        return ((GSMPhone)mPhone).mSIMRecords.getServiceProviderName();
     }
 
     public void updateImsiConfiguration(String imsi) {
@@ -494,19 +62,8 @@
             try {
                 ActivityManagerNative.getDefault().updateConfiguration(config);
             } catch (RemoteException e) {
+                Log.e(mLogTag, "[SimCard] Remote Exception when updating imsi configuration");
             }
         }
     }
-
-    private void
-    updateStateProperty() {
-        phone.setSystemProperty(
-            TelephonyProperties.PROPERTY_SIM_STATE,
-            getState().toString());
-    }
-
-    private void log(String msg) {
-        Log.d(LOG_TAG, "[GsmSimCard] " + msg);
-    }
 }
-
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index 22adc19..e444203 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -27,10 +27,11 @@
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.DataCallState;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.gsm.CallFailCause;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
-import com.android.internal.telephony.Phone;
 
 import java.util.ArrayList;
 
@@ -103,39 +104,8 @@
 
     //***** CommandsInterface implementation
 
-    public void getIccStatus(Message result) {
-        switch (mState) {
-            case SIM_READY:
-                resultSuccess(result, IccStatus.ICC_READY);
-                break;
-
-            case SIM_LOCKED_OR_ABSENT:
-                returnSimLockedStatus(result);
-                break;
-
-            default:
-                resultSuccess(result, IccStatus.ICC_NOT_READY);
-                break;
-        }
-    }
-
-    private void returnSimLockedStatus(Message result) {
-        switch (mSimLockedState) {
-            case REQUIRE_PIN:
-                Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PIN");
-                resultSuccess(result, IccStatus.ICC_PIN);
-                break;
-
-            case REQUIRE_PUK:
-                Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PUK");
-                resultSuccess(result, IccStatus.ICC_PUK);
-                break;
-
-            default:
-                Log.i(LOG_TAG,
-                        "[SimCmd] returnSimLockedStatus: mSimLockedState==NONE !?");
-                break;
-        }
+    public void getIccCardStatus(Message result) {
+        unimplemented(result);
     }
 
     public void supplyIccPin(String pin, Message result)  {
diff --git a/tests/AndroidTests/src/com/android/unit_tests/NeighboringCellInfoTest.java b/tests/AndroidTests/src/com/android/unit_tests/NeighboringCellInfoTest.java
new file mode 100644
index 0000000..2bdf1dd
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/NeighboringCellInfoTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.unit_tests;
+
+import android.test.AndroidTestCase;
+import android.telephony.NeighboringCellInfo;
+import android.test. suitebuilder.annotation.SmallTest;
+
+public class NeighboringCellInfoTest extends AndroidTestCase {
+    @SmallTest
+    public void testConstructor() {
+        NeighboringCellInfo empty = new NeighboringCellInfo();
+        assertEquals(NeighboringCellInfo.UNKNOWN_RSSI, empty.getRssi());
+        assertEquals(NeighboringCellInfo.UNKNOWN_CID, empty.getCid());
+
+        int rssi = 31;
+        int cid = 0xffffffff;
+        NeighboringCellInfo max = new NeighboringCellInfo(rssi, cid);
+        assertEquals(rssi, max.getRssi());
+        assertEquals(cid, max.getCid());
+    }
+
+    @SmallTest
+    public void testGetAndSet() {
+        int rssi = 16;
+        int cid = 0x12345678;
+        NeighboringCellInfo nc = new NeighboringCellInfo();
+        nc.setRssi(rssi);
+        nc.setCid(cid);
+        assertEquals(rssi, nc.getRssi());
+        assertEquals(cid, nc.getCid());
+    }
+
+    @SmallTest
+    public void testToString() {
+        NeighboringCellInfo empty = new NeighboringCellInfo();
+        assertEquals("[/ at /]", empty.toString());
+
+        NeighboringCellInfo nc = new NeighboringCellInfo(16, 0x12345678);
+        assertEquals("[12345678 at 16]", nc.toString());
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
index c4f1ab6..4c5fefc 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
@@ -107,8 +107,6 @@
     }
 
     // Checks that the search UI is not visible.
-    // This checks both the SearchManager and the SearchManagerService,
-    // since SearchManager keeps a local variable for the visibility.
     private void assertSearchNotVisible() {
         SearchManager searchManager = (SearchManager)
                 mContext.getSystemService(Context.SEARCH_SERVICE);
@@ -245,22 +243,4 @@
         assertSearchNotVisible();
     }
 
-    @MediumTest
-    public void testSearchDialogState() throws Exception {
-        SearchManager searchManager = (SearchManager)
-                mContext.getSystemService(Context.SEARCH_SERVICE);
-        assertNotNull(searchManager);
-
-        Bundle searchState;
-
-        // search dialog not visible, so no state should be stored
-        searchState = searchManager.saveSearchDialog();
-        assertNull(searchState);
-
-        searchManager.startSearch("test search string", true, SEARCHABLE_ACTIVITY, null, false);
-        searchState = searchManager.saveSearchDialog();
-        assertNotNull(searchState);
-        searchManager.stopSearch();
-    }
-
 }
diff --git a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
index 6f89fce..5ae960a 100644
--- a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
+++ b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
@@ -18,6 +18,7 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
+import android.test.FlakyTest;
 import android.test.suitebuilder.annotation.MediumTest;
 
 /**
@@ -149,6 +150,7 @@
     }
     
     /** Test the show/hide behavior of the drop-down. */
+    @FlakyTest(tolerance=5)
     @MediumTest
     public void testPopupShow() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
diff --git a/tests/backup/src/com/android/backuptest/BackupTestActivity.java b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
index 7f30c91..afbc703 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestActivity.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
@@ -52,6 +52,8 @@
     static final String PREF_KEY = "pref";
     static final String FILE_NAME = "file.txt";
 
+    BackupManager sBm = new BackupManager(this);
+
     Test[] mTests = new Test[] {
         new Test("Show File") {
             void run() {
@@ -85,8 +87,7 @@
                         output.close();
                     }
                 }
-                BackupManager bm = new BackupManager(BackupTestActivity.this);
-                bm.dataChanged();
+                sBm.dataChanged();
             }
         },
         new Test("Clear File") {
@@ -100,14 +101,12 @@
                         output.close();
                     }
                 }
-                BackupManager bm = new BackupManager(BackupTestActivity.this);
-                bm.dataChanged();
+                sBm.dataChanged();
             }
         },
         new Test("Poke") {
             void run() {
-                BackupManager bm = new BackupManager(BackupTestActivity.this);
-                bm.dataChanged();
+                sBm.dataChanged();
             }
         },
         new Test("Show Shared Pref") {
@@ -126,8 +125,7 @@
                 SharedPreferences.Editor editor = prefs.edit();
                 editor.putInt(PREF_KEY, val+1);
                 editor.commit();
-                BackupManager bm = new BackupManager(BackupTestActivity.this);
-                bm.dataChanged();
+                sBm.dataChanged();
             }
         },
         new Test("Backup Helpers") {