Merge change 3015 into donut

* changes:
  make sms calculateLength radio-independent
diff --git a/api/current.xml b/api/current.xml
index cb348e1..f30c505 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -3518,17 +3518,6 @@
  visibility="public"
 >
 </field>
-<field name="donut_resource_pad30"
- type="int"
- transient="false"
- volatile="false"
- value="16843394"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="donut_resource_pad4"
  type="int"
  transient="false"
@@ -6840,6 +6829,17 @@
  visibility="public"
 >
 </field>
+<field name="queryAfterZeroResults"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843394"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="radioButtonStyle"
  type="int"
  transient="false"
@@ -62837,7 +62837,7 @@
  type="float"
  transient="false"
  volatile="false"
- value="0.0010f"
+ value="0.001f"
  static="true"
  final="true"
  deprecated="not deprecated"
diff --git a/cmds/keystore/commands.c b/cmds/keystore/commands.c
index 7474d81..e53cece 100644
--- a/cmds/keystore/commands.c
+++ b/cmds/keystore/commands.c
@@ -40,7 +40,7 @@
     reply[0]=0;
     while ((de = readdir(d))) {
         if (de->d_type != DT_REG) continue;
-        strlcat(reply, " ", REPLY_MAX);
+        if (reply[0] != 0) strlcat(reply, " ", REPLY_MAX);
         if (strlcat(reply, de->d_name, REPLY_MAX) >= REPLY_MAX) {
             LOGE("reply is too long(too many files under '%s'\n", dir);
             return -1;
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index dbb62b37..5193b3d 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -113,7 +113,7 @@
     unsigned i;
     unsigned n = 0;
     unsigned short count;
-    int ret = -1;
+    short ret = -1;
 
     /* default reply is "" */
     reply[0] = 0;
@@ -139,7 +139,7 @@
                 LOGE("%s requires %d arguments (%d given)\n",
                      cmds[i].name, cmds[i].numargs, n);
             } else {
-                ret = cmds[i].func(arg + 1, reply);
+                ret = (short) cmds[i].func(arg + 1, reply);
             }
             goto done;
         }
@@ -148,24 +148,26 @@
 
 done:
     if (reply[0]) {
-        n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);
+        strlcpy(cmd, reply, BUFFER_MAX);
+        count = strlen(cmd);
     } else {
-        n = snprintf(cmd, BUFFER_MAX, "%d", ret);
+        count = 0;
     }
-    if (n > BUFFER_MAX) n = BUFFER_MAX;
-    count = n;
-
-    if (writex(s, &count, sizeof(count))) return -1;
-    if (writex(s, cmd, count)) return -1;
+    if (writex(s, &ret, sizeof(ret))) return -1;
+    if (ret == 0) {
+        if (writex(s, &count, sizeof(count))) return -1;
+        if (writex(s, cmd, count)) return -1;
+    }
 
     return 0;
 }
 
 int shell_command(const int argc, const char **argv)
 {
-    int fd, i, r;
+    int fd, i;
+    short ret;
     unsigned short count;
-    char cmd[BUFFER_MAX]="";
+    char buf[BUFFER_MAX]="";
 
     fd = socket_local_client(SOCKET_PATH,
                              ANDROID_SOCKET_NAMESPACE_RESERVED,
@@ -175,19 +177,24 @@
         exit(1);
     }
     for(i = 0; i < argc; i++) {
-        if (i > 0) strlcat(cmd, " ", BUFFER_MAX);
-        if(strlcat(cmd, argv[i], BUFFER_MAX) >= BUFFER_MAX) {
+        if (i > 0) strlcat(buf, " ", BUFFER_MAX);
+        if(strlcat(buf, argv[i], BUFFER_MAX) >= BUFFER_MAX) {
             fprintf(stderr, "Arguments are too long\n");
             exit(1);
         }
     }
-    count = strlen(cmd);
+    count = strlen(buf);
     if (writex(fd, &count, sizeof(count))) return -1;
-    if (writex(fd, cmd, strlen(cmd))) return -1;
-    if (readx(fd, &count, sizeof(count))) return -1;
-    if (readx(fd, cmd, count)) return -1;
-    cmd[count]=0;
-    fprintf(stdout, "%s\n", cmd);
+    if (writex(fd, buf, strlen(buf))) return -1;
+    if (readx(fd, &ret, sizeof(ret))) return -1;
+    if (ret == 0) {
+        if (readx(fd, &count, sizeof(count))) return -1;
+        if (readx(fd, buf, count)) return -1;
+        buf[count]=0;
+        fprintf(stdout, "%s\n", buf);
+    } else {
+        fprintf(stderr, "Failed, please check log!\n");
+    }
     return 0;
 }
 
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 3f0aa95..820f192 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1402,6 +1402,16 @@
      * @hide For internal use, not part of the public API.
      */
     public final static String SUGGEST_COLUMN_BACKGROUND_COLOR = "suggest_background_color";
+    
+    /**
+     * Column name for suggestions cursor. <i>Optional.</i> This column is used to specify
+     * that a spinner should be shown in lieu of an icon2 while the shortcut of this suggestion
+     * is being refreshed.
+     * 
+     * @hide Pending API council approval.
+     */
+    public final static String SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING =
+            "suggest_spinner_while_refreshing";
 
     /**
      * Column value for suggestion column {@link #SUGGEST_COLUMN_SHORTCUT_ID} when a suggestion
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 6e8bd78..8c5cee3 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -20,16 +20,19 @@
 import android.content.Context;
 import android.content.res.Resources.NotFoundException;
 import android.database.Cursor;
+import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.server.search.SearchableInfo;
 import android.text.Html;
 import android.text.TextUtils;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.AbsListView;
 import android.widget.ImageView;
 import android.widget.ResourceCursorAdapter;
 import android.widget.TextView;
@@ -255,7 +258,7 @@
      */
     @Override
     public View newView(Context context, Cursor cursor, ViewGroup parent) {
-        View v = super.newView(context, cursor, parent);
+        View v = new SuggestionItemView(context, cursor);
         v.setTag(new ChildViewCache(v));
         return v;
     }
@@ -303,7 +306,7 @@
         if (backgroundColor == 0) {
             backgroundColor = mDefaultBackgroundColor;
         }
-        view.setBackgroundColor(backgroundColor);
+        ((SuggestionItemView)view).setColor(backgroundColor);
 
         final boolean isHtml = mFormatCol > 0 && "html".equals(cursor.getString(mFormatCol));
         setViewText(cursor, views.mText1, mText1Col, isHtml);
@@ -506,4 +509,68 @@
         return cursor.getString(col);
     }
 
+    /**
+     * A parent viewgroup class which holds the actual suggestion item as a child.
+     *
+     * The sole purpose of this class is to draw the given background color when the item is in
+     * normal state and not draw the background color when it is pressed, so that when pressed the
+     * list view's selection highlight will be displayed properly (if we draw our background it
+     * draws on top of the list view selection highlight).
+     */
+    private class SuggestionItemView extends ViewGroup {
+        private int mBackgroundColor;  // the background color to draw in normal state.
+        private View mView;  // the suggestion item's view.
+
+        protected SuggestionItemView(Context context, Cursor cursor) {
+            // Initialize ourselves
+            super(context);
+
+            // For our layout use the default list item height from the current theme.
+            TypedValue lineHeight = new TypedValue();
+            context.getTheme().resolveAttribute(
+                    com.android.internal.R.attr.searchResultListItemHeight, lineHeight, true);
+            DisplayMetrics metrics = new DisplayMetrics();
+            metrics.setToDefaults();
+            AbsListView.LayoutParams layout = new AbsListView.LayoutParams(
+                    AbsListView.LayoutParams.FILL_PARENT,
+                    (int)lineHeight.getDimension(metrics));
+
+            setLayoutParams(layout);
+
+            // Initialize the child view
+            mView = SuggestionsAdapter.super.newView(context, cursor, this);
+            if (mView != null) {
+                addView(mView, layout.width, layout.height);
+                mView.setVisibility(View.VISIBLE);
+            }
+        }
+
+        public void setColor(int backgroundColor) {
+            mBackgroundColor = backgroundColor;
+        }
+
+        @Override
+        public void dispatchDraw(Canvas canvas) {
+            if (!isPressed()) {
+                canvas.drawColor(mBackgroundColor);
+            }
+            super.dispatchDraw(canvas);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            if (mView != null) {
+                mView.measure(widthMeasureSpec, heightMeasureSpec);
+            }
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+            if (mView != null) {
+                mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
+            }
+        }
+    }
+
 }
diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java
index c083142..4df7368 100644
--- a/core/java/android/server/search/SearchableInfo.java
+++ b/core/java/android/server/search/SearchableInfo.java
@@ -66,6 +66,7 @@
     private final int mSearchInputType;
     private final int mSearchImeOptions;
     private final boolean mIncludeInGlobalSearch;
+    private final boolean mQueryAfterZeroResults;
     private final String mSuggestAuthority;
     private final String mSuggestPath;
     private final String mSuggestSelection;
@@ -276,6 +277,8 @@
                 EditorInfo.IME_ACTION_SEARCH);
         mIncludeInGlobalSearch = a.getBoolean(
                 com.android.internal.R.styleable.Searchable_includeInGlobalSearch, false);
+        mQueryAfterZeroResults = a.getBoolean(
+                com.android.internal.R.styleable.Searchable_queryAfterZeroResults, false);
 
         mSuggestAuthority = a.getString(
                 com.android.internal.R.styleable.Searchable_searchSuggestAuthority);
@@ -637,6 +640,17 @@
     }
 
     /**
+     * Checks whether this searchable activity should be invoked after a query returned zero
+     * results.
+     *
+     * @return The value of the <code>queryAfterZeroResults</code> attribute,
+     *         or <code>false</code> if the attribute is not set.
+     */
+    public boolean queryAfterZeroResults() {
+        return mQueryAfterZeroResults;
+    }
+
+    /**
      * Support for parcelable and aidl operations.
      */
     public static final Parcelable.Creator<SearchableInfo> CREATOR
@@ -667,6 +681,7 @@
         mSearchInputType = in.readInt();
         mSearchImeOptions = in.readInt();
         mIncludeInGlobalSearch = in.readInt() != 0;
+        mQueryAfterZeroResults = in.readInt() != 0;
 
         mSuggestAuthority = in.readString();
         mSuggestPath = in.readString();
@@ -702,6 +717,7 @@
         dest.writeInt(mSearchInputType);
         dest.writeInt(mSearchImeOptions);
         dest.writeInt(mIncludeInGlobalSearch ? 1 : 0);
+        dest.writeInt(mQueryAfterZeroResults ? 1 : 0);
         
         dest.writeString(mSuggestAuthority);
         dest.writeString(mSuggestPath);
diff --git a/core/java/android/speech/tts/Tts.java b/core/java/android/speech/tts/TextToSpeech.java
similarity index 76%
rename from core/java/android/speech/tts/Tts.java
rename to core/java/android/speech/tts/TextToSpeech.java
index 085b030..11be75d 100755
--- a/core/java/android/speech/tts/Tts.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -28,21 +28,16 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.util.HashMap;
+
 /**
  *
- * Synthesizes speech from text. This abstracts away the complexities of using
- * the TTS service such as setting up the IBinder connection and handling
- * RemoteExceptions, etc.
- *
- * The TTS should always be safe the use; if the user does not have the
- * necessary TTS apk installed, the behavior is that all calls to the TTS act as
- * no-ops.
+ * Synthesizes speech from text.
  *
  * {@hide}
  */
-//FIXME #TTS# review + complete javadoc
-//FIXME RENAME TO TextToSpeech.java
-public class Tts {
+//TODO #TTS# review + complete javadoc
+public class TextToSpeech {
 
 
     /**
@@ -82,31 +77,6 @@
     private OnSpeechCompletedListener speechCompletedCallback = null;
 
 
-    /**
-     * The constructor for the TTS.
-     *
-     * @param context
-     *            The context
-     * @param callback
-     *            The InitListener that should be called when the TTS has
-     *            initialized successfully.
-     * @param displayInstallMessage
-     *            Boolean indicating whether or not an installation prompt
-     *            should be displayed to users who do not have the TTS library.
-     *            If this is true, a generic alert asking the user to install
-     *            the TTS will be used. If you wish to specify the exact message
-     *            of that prompt, please use TTS(Context context, InitListener
-     *            callback, TTSVersionAlert alert) as the constructor instead.
-     */
-    public Tts(Context context, OnInitListener callback,
-                boolean displayInstallMessage) {
-        showInstaller = displayInstallMessage;
-        ctx = context;
-        cb = callback;
-        if (dataFilesCheck()) {
-            initTts();
-        }
-    }
 
     /**
      * The constructor for the TTS.
@@ -117,15 +87,13 @@
      *            The InitListener that should be called when the TTS has
      *            initialized successfully.
      */
-    public Tts(Context context, OnInitListener callback) {
-        // FIXME #TTS# support TtsVersionAlert
+    public TextToSpeech(Context context, OnInitListener callback) {
+        // TODO #TTS# support TtsVersionAlert
         //     showInstaller = true;
         //     versionAlert = alert;
         ctx = context;
         cb = callback;
-        if (dataFilesCheck()) {
-            initTts();
-        }
+        initTts();
     }
 
 
@@ -136,9 +104,9 @@
 
 
     private boolean dataFilesCheck() {
-        // FIXME #TTS# config manager will be in settings
+        // TODO #TTS# config manager will be in settings
         Log.i("TTS_FIXME", "FIXME in Tts: config manager will be in settings");
-        // FIXME #TTS# implement checking of the correct installation of
+        // TODO #TTS# implement checking of the correct installation of
         //             the data files.
 
         return true;
@@ -193,15 +161,9 @@
 
         Intent intent = new Intent("android.intent.action.USE_TTS");
         intent.addCategory("android.intent.category.TTS");
-        // Binding will fail only if the TTS doesn't exist;
-        // the TTSVersionAlert will give users a chance to install
-        // the needed TTS.
-        if (!ctx.bindService(intent, serviceConnection,
-                Context.BIND_AUTO_CREATE)) {
-            if (showInstaller) {
-                // FIXME #TTS# show version alert
-            }
-        }
+        ctx.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+        // TODO handle case where the binding works (should always work) but
+        //      the plugin fails
     }
 
 
@@ -316,21 +278,18 @@
      *            The queuing strategy to use. Use 0 for no queuing, and 1 for
      *            queuing.
      * @param params
-     *            The array of speech parameters to be used. Currently, only
-     *            params[0] is defined - it is for setting the type of voice if
-     *            the engine allows it. Possible values are "VOICE_MALE",
-     *            "VOICE_FEMALE", and "VOICE_ROBOT". Note that right now only
-     *            the pre-recorded voice has this support - this setting has no
-     *            effect on eSpeak.
+     *            The hashmap of speech parameters to be used.
      */
-    public void speak(String text, int queueMode, String[] params) {
+    public void speak(String text, int queueMode, HashMap<String,String> params)
+    {
         synchronized (startLock) {
             Log.i("TTS received: ", text);
             if (!started) {
                 return;
             }
             try {
-                itts.speak(text, queueMode, params);
+                // TODO support extra parameters, passing null for the moment
+                itts.speak(text, queueMode, null);
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 started = false;
@@ -357,15 +316,17 @@
      *            0 for no queue (interrupts all previous utterances), 1 for
      *            queued
      * @param params
-     *            An ArrayList of parameters.
+     *            The hashmap of parameters to be used.
      */
-    public void playEarcon(String earcon, int queueMode, String[] params) {
+    public void playEarcon(String earcon, int queueMode, 
+            HashMap<String,String> params) {
         synchronized (startLock) {
             if (!started) {
                 return;
             }
             try {
-                itts.playEarcon(earcon, queueMode, params);
+                // TODO support extra parameters, passing null for the moment
+                itts.playEarcon(earcon, queueMode, null);
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 started = false;
@@ -381,6 +342,11 @@
             }
         }
     }
+    
+    
+    public void playSilence(long durationInMs, int queueMode) {
+        // TODO implement, already present in TTS service
+    }
 
 
     /**
@@ -440,17 +406,6 @@
     }
 
 
-    /**
-     * Returns the version number of the TTS library that the user has
-     * installed.
-     *
-     * @return The version number of the TTS library that the user has
-     *         installed.
-     */
-    public int getVersion() {
-        return version;
-    }
-
 
     /**
      * Sets the speech rate for the TTS engine.
@@ -519,21 +474,21 @@
      * @param text
      *            The String of text that should be synthesized
      * @param params
-     *            An ArrayList of parameters. The first element of this array
-     *            controls the type of voice to use.
+     *            A hashmap of parameters.
      * @param filename
      *            The string that gives the full output filename; it should be
      *            something like "/sdcard/myappsounds/mysound.wav".
      * @return A boolean that indicates if the synthesis succeeded
      */
-    public boolean synthesizeToFile(String text, String[] params,
+    public boolean synthesizeToFile(String text, HashMap<String,String> params,
             String filename) {
         synchronized (startLock) {
             if (!started) {
                 return false;
             }
             try {
-                return itts.synthesizeToFile(text, params, filename);
+                // TODO support extra parameters, passing null for the moment
+                return itts.synthesizeToFile(text, null, filename);
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 started = false;
@@ -552,36 +507,4 @@
     }
 
 
-    /**
-     * Displays an alert that prompts users to install the TTS engine.
-     * This is useful if the application expects a newer version
-     * of the TTS than what the user has.
-     */
-    public void showVersionAlert() {
-        if (!started) {
-            return;
-        }
-        // FIXME #TTS# implement show version alert
-    }
-
-
-    /**
-     * Checks if the TTS service is installed or not
-     *
-     * @return A boolean that indicates whether the TTS service is installed
-     */
-    // TODO: TTS Service itself will always be installed. Factor this out
-    // (may need to add another method to see if there are any working
-    // TTS engines on the device).
-    public static boolean isInstalled(Context ctx) {
-        PackageManager pm = ctx.getPackageManager();
-        Intent intent = new Intent("android.intent.action.USE_TTS");
-        intent.addCategory("android.intent.category.TTS");
-        ResolveInfo info = pm.resolveService(intent, 0);
-        if (info == null) {
-            return false;
-        }
-        return true;
-    }
-
 }
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index f376ce5..585ce3d 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -123,10 +123,6 @@
 
     private AutoCompleteTextView.ListSelectorHider mHideSelector;
 
-    // Indicates whether this AutoCompleteTextView is attached to a window or not
-    // The widget is attached to a window when mAttachCount > 0
-    private int mAttachCount;
-
     private AutoCompleteTextView.PassThroughClickListener mPassThroughClickListener;
 
     public AutoCompleteTextView(Context context) {
@@ -960,7 +956,8 @@
 
     /** {@inheritDoc} */
     public void onFilterComplete(int count) {
-        if (mAttachCount <= 0) return;
+        // Not attached to window, don't update drop-down
+        if (getWindowVisibility() == View.GONE) return;
 
         /*
          * This checks enoughToFilter() again because filtering requests
@@ -999,13 +996,11 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mAttachCount++;
     }
 
     @Override
     protected void onDetachedFromWindow() {
         dismissDropDown();
-        mAttachCount--;
         super.onDetachedFromWindow();
     }
 
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index 0858741..5c4fb22 100644
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -270,6 +270,12 @@
     sGpsInterface->inject_time(time, timeReference, uncertainty);
 }
 
+static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj,
+        jdouble latitude, jdouble longitude, jfloat accuracy)
+{
+    sGpsInterface->inject_location(latitude, longitude, accuracy);
+}
+
 static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
 {
     if (!sGpsXtraInterface) {
@@ -353,6 +359,7 @@
     {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
     {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
     {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
+    {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
     {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
     {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
     {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c13bf775..99fe9c8 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2849,6 +2849,14 @@
              The default value is <code>false</code>. <i>Optional attribute.</i>. -->
         <attr name="includeInGlobalSearch" format="boolean" />
 
+        <!-- If provided and <code>true</code>, this searchable activity will be invoked for all
+             queries in a particular session. If set to <code>false</code> and the activity
+             returned zero results for a query, it will not be invoked again in that session for
+             supersets of that zero-results query. For example, if the activity returned zero
+             results for "bo", it would not be queried again for "bob".
+             The default value is <code>false</code>. <i>Optional attribute.</i>. -->
+        <attr name="queryAfterZeroResults" 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 a50f3f9..e5a58b1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1115,6 +1115,7 @@
   <public type="attr" name="backupAgent" />
   <public type="attr" name="allowBackup" />
   <public type="attr" name="glEsVersion" />
+  <public type="attr" name="queryAfterZeroResults" />
   
   <public-padding type="attr" name="donut_resource_pad" end="0x0101029f" />
 
diff --git a/docs/html/search.jd b/docs/html/search.jd
index 0a802a6..defba30 100644
--- a/docs/html/search.jd
+++ b/docs/html/search.jd
@@ -2,7 +2,7 @@
 @jd:body

 

 <script src="http://www.google.com/jsapi" type="text/javascript"></script>

-<script src="/assets/jquery-history.js" type="text/javascript"></script>

+<script src="{@docRoot}assets/jquery-history.js" type="text/javascript"></script>

 <script type="text/javascript">

       google.load('search', '1');

 

diff --git a/keystore/java/android/security/Keystore.java b/keystore/java/android/security/Keystore.java
new file mode 100644
index 0000000..3f83473
--- /dev/null
+++ b/keystore/java/android/security/Keystore.java
@@ -0,0 +1,103 @@
+/*
+ * 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.security;
+
+/**
+ * The Keystore class provides the functions to list the certs/keys in keystore.
+ * {@hide}
+ */
+public abstract class Keystore {
+    private static final String TAG = "Keystore";
+    private static final String[] NOTFOUND = new String[0];
+
+    /**
+     */
+    public static Keystore getInstance() {
+        return new FileKeystore();
+    }
+
+    /**
+     */
+    public abstract String getUserkey(String key);
+
+    /**
+     */
+    public abstract String getCertificate(String key);
+
+    /**
+     */
+    public abstract String[] getAllCertificateKeys();
+
+    /**
+     */
+    public abstract String[] getAllUserkeyKeys();
+
+    private static class FileKeystore extends Keystore {
+        private static final String SERVICE_NAME = "keystore";
+        private static final String LIST_CERTIFICATES = "listcerts";
+        private static final String LIST_USERKEYS = "listuserkeys";
+        private static final String PATH = "/data/misc/keystore/";
+        private static final String USERKEY_PATH = PATH + "userkeys/";
+        private static final String CERT_PATH = PATH + "certs/";
+        private static final ServiceCommand mServiceCommand =
+                new ServiceCommand(SERVICE_NAME);
+
+        @Override
+        public String getUserkey(String key) {
+            return USERKEY_PATH + key;
+        }
+
+        @Override
+        public String getCertificate(String key) {
+            return CERT_PATH + key;
+        }
+
+        /**
+         * Returns the array of the certificate names in keystore if successful.
+         * Or return an empty array if error.
+         *
+         * @return array of the certificates
+         */
+        @Override
+        public String[] getAllCertificateKeys() {
+            try {
+                String result = mServiceCommand.execute(LIST_CERTIFICATES);
+                if (result != null) return result.split("\\s+");
+                return NOTFOUND;
+            } catch (NumberFormatException ex) {
+                return NOTFOUND;
+            }
+        }
+
+        /**
+         * Returns the array of the names of private keys in keystore if successful.
+         * Or return an empty array if errors.
+         *
+         * @return array of the user keys
+         */
+        @Override
+        public String[] getAllUserkeyKeys() {
+            try {
+                String result = mServiceCommand.execute(LIST_USERKEYS);
+                if (result != null) return result.split("\\s+");
+                return NOTFOUND;
+            } catch (NumberFormatException ex) {
+                return NOTFOUND;
+            }
+        }
+    }
+}
diff --git a/keystore/java/android/security/ServiceCommand.java b/keystore/java/android/security/ServiceCommand.java
new file mode 100644
index 0000000..f1d4302
--- /dev/null
+++ b/keystore/java/android/security/ServiceCommand.java
@@ -0,0 +1,178 @@
+/*
+ * 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.security;
+
+import android.net.LocalSocketAddress;
+import android.net.LocalSocket;
+import android.util.Config;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/*
+ * ServiceCommand is used to connect to a service throught the local socket,
+ * and send out the command, return the result to the caller.
+ * {@hide}
+ */
+public class ServiceCommand {
+    public static final String SUCCESS = "0";
+    public static final String FAILED = "-1";
+
+    private String mServiceName;
+    private String mTag;
+    private InputStream mIn;
+    private OutputStream mOut;
+    private LocalSocket mSocket;
+    private static final int BUFFER_LENGTH = 1024;
+
+    private byte buf[] = new byte[BUFFER_LENGTH];
+    private int buflen = 0;
+
+    private boolean connect() {
+        if (mSocket != null) {
+            return true;
+        }
+        Log.i(mTag, "connecting...");
+        try {
+            mSocket = new LocalSocket();
+
+            LocalSocketAddress address = new LocalSocketAddress(
+                    mServiceName, LocalSocketAddress.Namespace.RESERVED);
+
+            mSocket.connect(address);
+
+            mIn = mSocket.getInputStream();
+            mOut = mSocket.getOutputStream();
+        } catch (IOException ex) {
+            disconnect();
+            return false;
+        }
+        return true;
+    }
+
+    private void disconnect() {
+        Log.i(mTag,"disconnecting...");
+        try {
+            if (mSocket != null) mSocket.close();
+        } catch (IOException ex) { }
+        try {
+            if (mIn != null) mIn.close();
+        } catch (IOException ex) { }
+        try {
+            if (mOut != null) mOut.close();
+        } catch (IOException ex) { }
+        mSocket = null;
+        mIn = null;
+        mOut = null;
+    }
+
+    private boolean readBytes(byte buffer[], int len) {
+        int off = 0, count;
+        if (len < 0) return false;
+        while (off != len) {
+            try {
+                count = mIn.read(buffer, off, len - off);
+                if (count <= 0) {
+                    Log.e(mTag, "read error " + count);
+                    break;
+                }
+                off += count;
+            } catch (IOException ex) {
+                Log.e(mTag,"read exception");
+                break;
+            }
+        }
+        if (off == len) return true;
+        disconnect();
+        return false;
+    }
+
+    private boolean readReply() {
+        int len, ret;
+        buflen = 0;
+
+        if (!readBytes(buf, 2)) return false;
+        ret = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
+        if (ret != 0) return false;
+
+        if (!readBytes(buf, 2)) return false;
+        len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
+        if (len > BUFFER_LENGTH) {
+            Log.e(mTag,"invalid reply length (" + len + ")");
+            disconnect();
+            return false;
+        }
+        if (!readBytes(buf, len)) return false;
+        buflen = len;
+        return true;
+    }
+
+    private boolean writeCommand(String _cmd) {
+        byte[] cmd = _cmd.getBytes();
+        int len = cmd.length;
+        if ((len < 1) || (len > BUFFER_LENGTH)) return false;
+        buf[0] = (byte) (len & 0xff);
+        buf[1] = (byte) ((len >> 8) & 0xff);
+        try {
+            mOut.write(buf, 0, 2);
+            mOut.write(cmd, 0, len);
+        } catch (IOException ex) {
+            Log.e(mTag,"write error");
+            disconnect();
+            return false;
+        }
+        return true;
+    }
+
+    private String executeCommand(String cmd) {
+        if (!writeCommand(cmd)) {
+            /* If service died and restarted in the background
+             * (unlikely but possible) we'll fail on the next
+             * write (this one).  Try to reconnect and write
+             * the command one more time before giving up.
+             */
+            Log.e(mTag, "write command failed? reconnect!");
+            if (!connect() || !writeCommand(cmd)) {
+                return null;
+            }
+        }
+        if (readReply()) {
+            return new String(buf, 0, buflen);
+        } else {
+            return null;
+        }
+    }
+
+    public synchronized String execute(String cmd) {
+      String result;
+      if (!connect()) {
+          Log.e(mTag, "connection failed");
+          return null;
+      }
+      result = executeCommand(cmd);
+      disconnect();
+      return result;
+    }
+
+    public ServiceCommand(String service) {
+        mServiceName = service;
+        mTag = service;
+    }
+}
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 725fbf9..9698553 100644
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -410,6 +410,10 @@
      * Someday we might use this for network location injection to aid the GPS
      */
     public void updateLocation(Location location) {
+        if (location.hasAccuracy()) {
+            native_inject_location(location.getLatitude(), location.getLongitude(),
+                    location.getAccuracy());
+        }
     }
 
     /**
@@ -1210,7 +1214,8 @@
     // mask[0] is ephemeris mask and mask[1] is almanac mask
     private native int native_read_sv_status(int[] svs, float[] snrs,
             float[] elevations, float[] azimuths, int[] masks);
-    
+    private native void native_inject_location(double latitude, double longitude, float accuracy);
+
     // XTRA Support    
     private native void native_inject_time(long time, long timeReference, int uncertainty);
     private native boolean native_supports_xtra();