Merge "In theory the package manager now scans /vendor/app" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 8651c4d..af91389 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -96356,6 +96356,17 @@
  visibility="public"
 >
 </field>
+<field name="ERROR_FILE_ALREADY_EXISTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1009"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ERROR_FILE_ERROR"
  type="int"
  transient="false"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6e6e86f..72bf825 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1427,7 +1427,9 @@
      * <li> The function will be called between {@link #onStop} and
      * {@link #onDestroy}.
      * <li> A new instance of the activity will <em>always</em> be immediately
-     * created after this one's {@link #onDestroy()} is called.
+     * created after this one's {@link #onDestroy()} is called.  In particular,
+     * <em>no</em> messages will be dispatched during this time (when the returned
+     * object does not have an activity to be associated with).
      * <li> The object you return here will <em>always</em> be available from
      * the {@link #getLastNonConfigurationInstance()} method of the following
      * activity instance as described there.
@@ -1440,6 +1442,15 @@
      * may change based on the configuration, including any data loaded from
      * resources such as strings, layouts, or drawables.
      * 
+     * <p>The guarantee of no message handling during the switch to the next
+     * activity simplifies use with active objects.  For example if your retained
+     * state is an {@link android.os.AsyncTask} you are guaranteed that its
+     * call back functions (like {@link android.os.AsyncTask#onPostExecute}) will
+     * not be called from the call here until you execute the next instance's
+     * {@link #onCreate(Bundle)}.  (Note however that there is of course no such
+     * guarantee for {@link android.os.AsyncTask#doInBackground} since that is
+     * running in a separate thread.)
+     *
      * @return Return any Object holding the desired state to propagate to the
      * next activity instance.
      */
diff --git a/core/java/android/app/backup/package.html b/core/java/android/app/backup/package.html
index ae29994..e140349 100644
--- a/core/java/android/app/backup/package.html
+++ b/core/java/android/app/backup/package.html
@@ -3,6 +3,9 @@
 <p>Contains the backup and restore functionality available to
 applications. If a user wipes the data on their device or upgrades to a new Android-powered
 device, all applications that have enabled backup will restore the user's previous data.</p>
+
+<p>For a detailed guide to using the backup APIs, see the <a
+href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p>
 {@more}
 
 <p>All backup and restore operations are controlled by the {@link
@@ -22,8 +25,5 @@
   <li>Restore the data saved to remote storage</li>
 </ul>
 
-<p>For a detailed guide to using the backup APIs, see the <a
-href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p>
-
 </BODY>
 </HTML>
diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java
index 5320da3..8bb747e 100644
--- a/core/java/android/net/DownloadManager.java
+++ b/core/java/android/net/DownloadManager.java
@@ -25,7 +25,6 @@
 import android.provider.BaseColumns;
 import android.provider.Downloads;
 
-import java.io.File;
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -195,6 +194,12 @@
     public final static int ERROR_CANNOT_RESUME = 1008;
 
     /**
+     * Value of {@link #COLUMN_ERROR_CODE} when the requested destination file already exists (the
+     * download manager will not overwrite an existing file).
+     */
+    public final static int ERROR_FILE_ALREADY_EXISTS = 1009;
+
+    /**
      * Broadcast intent action sent by the download manager when a download completes.
      */
     public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
@@ -235,10 +240,11 @@
         Downloads.COLUMN_URI,
         Downloads.COLUMN_MIME_TYPE,
         Downloads.COLUMN_TOTAL_BYTES,
-        Downloads._DATA,
         Downloads.COLUMN_STATUS,
         Downloads.COLUMN_CURRENT_BYTES,
         Downloads.COLUMN_LAST_MODIFICATION,
+        Downloads.COLUMN_DESTINATION,
+        Downloads.Impl.COLUMN_FILE_NAME_HINT,
     };
 
     private static final Set<String> LONG_COLUMNS = new HashSet<String>(
@@ -820,15 +826,10 @@
         }
 
         private String getLocalUri() {
-            String localUri = getUnderlyingString(Downloads.Impl._DATA);
-            if (localUri == null) {
-                return null;
-            }
-
             long destinationType = getUnderlyingLong(Downloads.Impl.COLUMN_DESTINATION);
             if (destinationType == Downloads.Impl.DESTINATION_FILE_URI) {
-                // return file URI for external download
-                return Uri.fromFile(new File(localUri)).toString();
+                // return client-provided file URI for external download
+                return getUnderlyingString(Downloads.Impl.COLUMN_FILE_NAME_HINT);
             }
 
             // return content URI for cache download
@@ -894,6 +895,9 @@
                 case Downloads.Impl.STATUS_CANNOT_RESUME:
                     return ERROR_CANNOT_RESUME;
 
+                case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR:
+                    return ERROR_FILE_ALREADY_EXISTS;
+
                 default:
                     return ERROR_UNKNOWN;
             }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 1e88c56..ba8014f2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -397,7 +397,7 @@
         }
     }
 
-    public final class HistoryItem implements Parcelable {
+    public final static class HistoryItem implements Parcelable {
         public HistoryItem next;
         
         public long time;
@@ -482,6 +482,18 @@
             dest.writeInt(states);
         }
         
+        public void setTo(HistoryItem o) {
+            time = o.time;
+            cmd = o.cmd;
+            batteryLevel = o.batteryLevel;
+            batteryStatus = o.batteryStatus;
+            batteryHealth = o.batteryHealth;
+            batteryPlugType = o.batteryPlugType;
+            batteryTemperature = o.batteryTemperature;
+            batteryVoltage = o.batteryVoltage;
+            states = o.states;
+        }
+
         public void setTo(long time, byte cmd, HistoryItem o) {
             this.time = time;
             this.cmd = cmd;
@@ -526,6 +538,10 @@
         }
     }
     
+    public abstract boolean startIteratingHistoryLocked();
+
+    public abstract boolean getNextHistoryLocked(HistoryItem out);
+
     /**
      * Return the current history of battery state changes.
      */
@@ -1688,8 +1704,8 @@
      */
     @SuppressWarnings("unused")
     public void dumpLocked(PrintWriter pw) {
-        HistoryItem rec = getHistory();
-        if (rec != null) {
+        final HistoryItem rec = new HistoryItem();
+        if (startIteratingHistoryLocked()) {
             pw.println("Battery History:");
             long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
             int oldState = 0;
@@ -1698,7 +1714,7 @@
             int oldPlug = -1;
             int oldTemp = -1;
             int oldVolt = -1;
-            while (rec != null) {
+            while (getNextHistoryLocked(rec)) {
                 pw.print("  ");
                 TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
                 pw.print(" ");
@@ -1803,7 +1819,6 @@
                     pw.println();
                 }
                 oldState = rec.states;
-                rec = rec.next;
             }
             pw.println("");
         }
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 74c7372..871a0441 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -1077,7 +1077,12 @@
         /**
          * The lowest-valued error status that is not an actual HTTP status code.
          */
-        public static final int MIN_ARTIFICIAL_ERROR_STATUS = 489;
+        public static final int MIN_ARTIFICIAL_ERROR_STATUS = 488;
+
+        /**
+         * The requested destination file already exists.
+         */
+        public static final int STATUS_FILE_ALREADY_EXISTS_ERROR = 488;
 
         /**
          * Some possibly transient error occurred, but we can't resume the download.
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index c2d003e..6e5c47f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -51,6 +51,7 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * All information we are collecting about things that can happen that impact
@@ -3834,6 +3835,22 @@
         }
     }
 
+    private HistoryItem mHistoryIterator;
+
+    public boolean startIteratingHistoryLocked() {
+        return (mHistoryIterator = mHistory) != null;
+    }
+
+    public boolean getNextHistoryLocked(HistoryItem out) {
+        HistoryItem cur = mHistoryIterator;
+        if (cur == null) {
+            return false;
+        }
+        out.setTo(cur);
+        mHistoryIterator = cur.next;
+        return true;
+    }
+
     @Override
     public HistoryItem getHistory() {
         return mHistory;
@@ -3960,7 +3977,7 @@
             }
             if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
                 if (mFile != null) {
-                    writeLocked();
+                    writeAsyncLocked();
                 }
             }
         }
@@ -4356,11 +4373,22 @@
     }
 
     public void shutdownLocked() {
-        writeLocked();
+        writeSyncLocked();
         mShuttingDown = true;
     }
     
-    public void writeLocked() {
+    Parcel mPendingWrite = null;
+    final ReentrantLock mWriteLock = new ReentrantLock();
+
+    public void writeAsyncLocked() {
+        writeLocked(false);
+    }
+
+    public void writeSyncLocked() {
+        writeLocked(true);
+    }
+
+    void writeLocked(boolean sync) {
         if (mFile == null) {
             Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
             return;
@@ -4370,23 +4398,51 @@
             return;
         }
         
+        Parcel out = Parcel.obtain();
+        writeSummaryToParcel(out);
+        mLastWriteTime = SystemClock.elapsedRealtime();
+
+        if (mPendingWrite != null) {
+            mPendingWrite.recycle();
+        }
+        mPendingWrite = out;
+
+        if (sync) {
+            commitPendingDataToDisk();
+        } else {
+            Thread thr = new Thread("BatteryStats-Write") {
+                @Override
+                public void run() {
+                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                    commitPendingDataToDisk();
+                }
+            };
+            thr.start();
+        }
+    }
+
+    public void commitPendingDataToDisk() {
+        Parcel next;
+        synchronized (this) {
+            next = mPendingWrite;
+            mPendingWrite = null;
+
+            mWriteLock.lock();
+        }
+
         try {
             FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
-            Parcel out = Parcel.obtain();
-            writeSummaryToParcel(out);
-            stream.write(out.marshall());
-            out.recycle();
-
+            stream.write(next.marshall());
             stream.flush();
             stream.close();
             mFile.commit();
-
-            mLastWriteTime = SystemClock.elapsedRealtime();
-            return;
         } catch (IOException e) {
             Slog.w("BatteryStats", "Error writing battery statistics", e);
+            mFile.rollback();
+        } finally {
+            next.recycle();
+            mWriteLock.unlock();
         }
-        mFile.rollback();
     }
 
     static byte[] readFully(FileInputStream stream) throws java.io.IOException {
diff --git a/core/res/res/drawable-mdpi/overscroll_edge.png b/core/res/res/drawable-mdpi/overscroll_edge.png
new file mode 100644
index 0000000..22f4ef8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/overscroll_edge.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/overscroll_glow.png b/core/res/res/drawable-mdpi/overscroll_glow.png
new file mode 100644
index 0000000..761fb74
--- /dev/null
+++ b/core/res/res/drawable-mdpi/overscroll_glow.png
Binary files differ
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 5d6ac26..747c829 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -136,30 +136,24 @@
      */
     
     void* dso;
-    char path[PATH_MAX];
     int index = int(display);
     driver_t* hnd = 0;
-    const char* const format = "/system/lib/egl/lib%s_%s.so";
     
     char const* tag = getTag(index, impl);
     if (tag) {
-        snprintf(path, PATH_MAX, format, "GLES", tag);
-        dso = load_driver(path, cnx, EGL | GLESv1_CM | GLESv2);
+        dso = load_driver("GLES", tag, cnx, EGL | GLESv1_CM | GLESv2);
         if (dso) {
             hnd = new driver_t(dso);
         } else {
             // Always load EGL first
-            snprintf(path, PATH_MAX, format, "EGL", tag);
-            dso = load_driver(path, cnx, EGL);
+            dso = load_driver("EGL", tag, cnx, EGL);
             if (dso) {
                 hnd = new driver_t(dso);
 
                 // TODO: make this more automated
-                snprintf(path, PATH_MAX, format, "GLESv1_CM", tag);
-                hnd->set( load_driver(path, cnx, GLESv1_CM), GLESv1_CM );
+                hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM );
 
-                snprintf(path, PATH_MAX, format, "GLESv2", tag);
-                hnd->set( load_driver(path, cnx, GLESv2), GLESv2 );
+                hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 );
             }
         }
     }
@@ -222,12 +216,20 @@
     }
 }
 
-void *Loader::load_driver(const char* driver_absolute_path,
+void *Loader::load_driver(const char* kind, const char *tag,
         egl_connection_t* cnx, uint32_t mask)
 {
+    char driver_absolute_path[PATH_MAX];
+    const char* const search1 = "/vendor/lib/egl/lib%s_%s.so";
+    const char* const search2 = "/system/lib/egl/lib%s_%s.so";
+
+    snprintf(driver_absolute_path, PATH_MAX, search1, kind, tag);
     if (access(driver_absolute_path, R_OK)) {
-        // this happens often, we don't want to log an error
-        return 0;
+        snprintf(driver_absolute_path, PATH_MAX, search2, kind, tag);
+        if (access(driver_absolute_path, R_OK)) {
+            // this happens often, we don't want to log an error
+            return 0;
+        }
     }
 
     void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 8659b0b..580d6e4 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -74,7 +74,7 @@
     
 private:
     Loader();
-    void *load_driver(const char* driver, egl_connection_t* cnx, uint32_t mask);
+    void *load_driver(const char* kind, const char *tag, egl_connection_t* cnx, uint32_t mask);
 
     static __attribute__((noinline))
     void init_api(void* dso, 
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 9835098..d7a1ac25 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -8316,6 +8316,11 @@
             return;
         }
         
+        if (mDisplay == null) {
+            // Not yet initialized, nothing to do.
+            return;
+        }
+
         boolean recoveringMemory = false;
         if (mForceRemoves != null) {
             recoveringMemory = true;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index cf767ca..3172077 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1383,7 +1383,7 @@
         mBatteryStatsService = new BatteryStatsService(new File(
                 systemDir, "batterystats.bin").toString());
         mBatteryStatsService.getActiveStatistics().readLocked();
-        mBatteryStatsService.getActiveStatistics().writeLocked();
+        mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
         mOnBattery = mBatteryStatsService.getActiveStatistics().getIsOnBattery();
         mBatteryStatsService.getActiveStatistics().setCallback(this);
         
@@ -1536,7 +1536,7 @@
 
                 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
                     mLastWriteTime = now;
-                    mBatteryStatsService.getActiveStatistics().writeLocked();
+                    mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
                 }
             }
         }
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 4d8cbf0..9f86378 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -82,7 +82,7 @@
     // Singleton instance
     private static final CallManager INSTANCE = new CallManager();
 
-    // list of registered phones
+    // list of registered phones, which are PhoneBase objs
     private final ArrayList<Phone> mPhones;
 
     // list of supported ringing calls
@@ -97,7 +97,7 @@
     // empty connection list
     private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>();
 
-    // default phone as the first phone registered
+    // default phone as the first phone registered, which is PhoneBase obj
     private Phone mDefaultPhone;
 
     // state registrants
@@ -181,6 +181,46 @@
     }
 
     /**
+     * Get the corresponding PhoneBase obj
+     *
+     * @param phone a Phone object
+     * @return the corresponding PhoneBase obj in Phone if Phone
+     * is a PhoneProxy obj
+     * or the Phone itself if Phone is not a PhoneProxy obj
+     */
+    private static Phone getPhoneBase(Phone phone) {
+        if (phone instanceof PhoneProxy) {
+            return phone.getForegroundCall().getPhone();
+        }
+        return phone;
+    }
+
+    /**
+     * Check if two phones refer to the same PhoneBase obj
+     *
+     * Note: PhoneBase, not PhoneProxy, is to be used inside of CallManager
+     *
+     * Both PhoneBase and PhoneProxy implement Phone interface, so
+     * they have same phone APIs, such as dial(). The real implementation, for
+     * example in GSM,  is in GSMPhone as extend from PhoneBase, so that
+     * foregroundCall.getPhone() returns GSMPhone obj. On the other hand,
+     * PhoneFactory.getDefaultPhone() returns PhoneProxy obj, which has a class
+     * member of GSMPhone.
+     *
+     * So for phone returned by PhoneFacotry, which is used by PhoneApp,
+     *        phone.getForegroundCall().getPhone() != phone
+     * but
+     *        isSamePhone(phone, phone.getForegroundCall().getPhone()) == true
+     *
+     * @param p1 is the first Phone obj
+     * @param p2 is the second Phone obj
+     * @return true if p1 and p2 refer to the same phone
+     */
+    public static boolean isSamePhone(Phone p1, Phone p2) {
+        return (getPhoneBase(p1) == getPhoneBase(p2));
+    }
+
+    /**
      * Returns all the registered phone objects.
      * @return all the registered phone objects.
      */
@@ -246,25 +286,50 @@
 
     /**
      * Register phone to CallManager
-     * @param phone
+     * @param phone to be registered
      * @return true if register successfully
      */
     public boolean registerPhone(Phone phone) {
-        if (phone != null && !mPhones.contains(phone)) {
+        Phone basePhone = getPhoneBase(phone);
+
+        if (basePhone != null && !mPhones.contains(basePhone)) {
             if (mPhones.isEmpty()) {
-                mDefaultPhone = phone;
+                mDefaultPhone = basePhone;
             }
-            mPhones.add(phone);
-            mRingingCalls.add(phone.getRingingCall());
-            mBackgroundCalls.add(phone.getBackgroundCall());
-            mForegroundCalls.add(phone.getForegroundCall());
-            registerForPhoneStates(phone);
+            mPhones.add(basePhone);
+            mRingingCalls.add(basePhone.getRingingCall());
+            mBackgroundCalls.add(basePhone.getBackgroundCall());
+            mForegroundCalls.add(basePhone.getForegroundCall());
+            registerForPhoneStates(basePhone);
             return true;
         }
         return false;
     }
 
     /**
+     * unregister phone from CallManager
+     * @param phone to be unregistered
+     */
+    public void unregisterPhone(Phone phone) {
+        Phone basePhone = getPhoneBase(phone);
+
+        if (basePhone != null && mPhones.contains(basePhone)) {
+            mPhones.remove(basePhone);
+            mRingingCalls.remove(basePhone.getRingingCall());
+            mBackgroundCalls.remove(basePhone.getBackgroundCall());
+            mForegroundCalls.remove(basePhone.getForegroundCall());
+            unregisterForPhoneStates(basePhone);
+            if (basePhone == mDefaultPhone) {
+                if (mPhones.isEmpty()) {
+                    mDefaultPhone = null;
+                } else {
+                    mDefaultPhone = mPhones.get(0);
+                }
+            }
+        }
+    }
+
+    /**
      * return the default phone or null if no phone available
      */
     public Phone getDefaultPhone() {
@@ -304,26 +369,7 @@
         return null;
     }
 
-    /**
-     * unregister phone from CallManager
-     * @param phone
-     */
-    public void unregisterPhone(Phone phone) {
-        if (phone != null && mPhones.contains(phone)) {
-            mPhones.remove(phone);
-            mRingingCalls.remove(phone.getRingingCall());
-            mBackgroundCalls.remove(phone.getBackgroundCall());
-            mForegroundCalls.remove(phone.getForegroundCall());
-            unregisterForPhoneStates(phone);
-            if (phone == mDefaultPhone) {
-                if (mPhones.isEmpty()) {
-                    mDefaultPhone = null;
-                } else {
-                    mDefaultPhone = mPhones.get(0);
-                }
-            }
-        }
-    }
+
 
     public void setAudioMode() {
         Context context = getContext();
@@ -592,8 +638,9 @@
      * handled asynchronously.
      */
     public Connection dial(Phone phone, String dialString) throws CallStateException {
+        Phone basePhone = getPhoneBase(phone);
         if (VDBG) {
-            Log.d(LOG_TAG, "CallManager.dial( phone=" + phone + ", dialString="+ dialString + ")");
+            Log.d(LOG_TAG, "CallManager.dial( phone=" + basePhone + ", dialString="+ dialString + ")");
             Log.d(LOG_TAG, this.toString());
         }
         if ( hasActiveFgCall() ) {
@@ -601,10 +648,10 @@
             boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
 
             if (DBG) {
-                Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == phone));
+                Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone));
             }
 
-            if (activePhone != phone) {
+            if (activePhone != basePhone) {
                 if (hasBgCall) {
                     Log.d(LOG_TAG, "Hangup");
                     getActiveFgCall().hangup();
@@ -614,7 +661,7 @@
                 }
             }
         }
-        return phone.dial(dialString);
+        return basePhone.dial(dialString);
     }
 
     /**