Merge change 1057 into donut

* changes:
  * Add regoin scaling for transparent support
diff --git a/api/current.xml b/api/current.xml
index 14faadc..71b5bc2 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -33542,7 +33542,7 @@
 </method>
 <method name="installPackage"
  return="void"
- abstract="true"
+ abstract="false"
  native="false"
  synchronized="false"
  static="false"
@@ -53318,6 +53318,32 @@
 <parameter name="path" type="java.lang.String">
 </parameter>
 </method>
+<method name="createFromFile"
+ return="android.graphics.Typeface"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.io.File">
+</parameter>
+</method>
+<method name="createFromFile"
+ return="android.graphics.Typeface"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
 <method name="defaultFromStyle"
  return="android.graphics.Typeface"
  abstract="false"
@@ -112313,6 +112339,8 @@
 </parameter>
 <parameter name="flags" type="int">
 </parameter>
+<parameter name="installerPackageName" type="java.lang.String">
+</parameter>
 </method>
 <method name="isSafeMode"
  return="boolean"
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 04e69e3..ac62757 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -579,6 +579,7 @@
     
     private void runInstall() {
         int installFlags = 0;
+        String installerPackageName = null;
 
         String opt;
         while ((opt=nextOption()) != null) {
@@ -586,6 +587,13 @@
                 installFlags |= PackageManager.FORWARD_LOCK_PACKAGE;
             } else if (opt.equals("-r")) {
                 installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE;
+            } else if (opt.equals("-i")) {
+                installerPackageName = nextOptionData();
+                if (installerPackageName == null) {
+                    System.err.println("Error: no value specified for -i");
+                    showUsage();
+                    return;
+                }
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 showUsage();
@@ -603,7 +611,8 @@
 
         PackageInstallObserver obs = new PackageInstallObserver();
         try {
-            mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags);
+            mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,
+                    installerPackageName);
             
             synchronized (obs) {
                 while (!obs.finished) {
@@ -812,7 +821,7 @@
         System.err.println("       pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
         System.err.println("       pm list instrumentation [-f] [TARGET-PACKAGE]");        
         System.err.println("       pm path PACKAGE");
-        System.err.println("       pm install [-l] [-r] PATH");
+        System.err.println("       pm install [-l] [-r] [-i INSTALLER_PACKAGE_NAME] PATH");
         System.err.println("       pm uninstall [-k] PACKAGE");
         System.err.println("       pm enable PACKAGE_OR_COMPONENT");
         System.err.println("       pm disable PACKAGE_OR_COMPONENT");
@@ -840,6 +849,7 @@
         System.err.println("The install command installs a package to the system.  Use");
         System.err.println("the -l option to install the package with FORWARD_LOCK. Use");
         System.err.println("the -r option to reinstall an exisiting app, keeping its data.");
+        System.err.println("the -i option to specify the installer package name.");
         System.err.println("");
         System.err.println("The uninstall command removes a package from the system. Use");
         System.err.println("the -k option to keep the data and cache directories around");
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5cb9fe2..1e15d14 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3498,7 +3498,6 @@
                     if (r != null) {
                         // keep the original density based on application cale.
                         appDm.updateDensity(r.getDisplayMetrics().density);
-                        Log.i("oshima", "Updated app display metrics " + appDm);
                         r.updateConfiguration(config, appDm);
                         // reset
                         appDm.setTo(dm);
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index a1f5a58..bb17dc3 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -2310,15 +2310,26 @@
         }
 
         @Override
-        public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags) {
+        public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
+                String installerPackageName) {
             try {
-                mPM.installPackage(packageURI, observer, flags);
+                mPM.installPackage(packageURI, observer, flags, installerPackageName);
             } catch (RemoteException e) {
                 // Should never happen!
             }
         }
 
         @Override
+        public String getInstallerPackageName(String packageName) {
+            try {
+                return mPM.getInstallerPackageName(packageName);
+            } catch (RemoteException e) {
+                // Should never happen!
+            }
+            return null;
+        }
+
+        @Override
         public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
             try {
                 mPM.deletePackage(packageName, observer, flags);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index d3f6f3c5..c199619 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -139,8 +139,11 @@
      * @param observer a callback to use to notify when the package installation in finished.
      * @param flags - possible values: {@link #FORWARD_LOCK_PACKAGE},
      * {@link #REPLACE_EXISITING_PACKAGE}
+     * @param installerPackageName Optional package name of the application that is performing the
+     * installation. This identifies which market the package came from.
      */
-    void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags);
+    void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags,
+            in String installerPackageName);
 
     /**
      * Delete a package.
@@ -151,6 +154,8 @@
      */
     void deletePackage(in String packageName, IPackageDeleteObserver observer, int flags);
 
+    String getInstallerPackageName(in String packageName);
+
     void addPackageToPreferred(String packageName);
     
     void removePackageFromPreferred(String packageName);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e2f0ce4..3695516 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1354,8 +1354,35 @@
      *
      * @see #installPackage(android.net.Uri)
      */
+    public void installPackage(
+            Uri packageURI, IPackageInstallObserver observer, int flags) {
+        installPackage(packageURI, observer, flags, null);
+    }
+
+    /**
+     * Install a package. Since this may take a little while, the result will
+     * be posted back to the given observer.  An installation will fail if the calling context
+     * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the
+     * package named in the package file's manifest is already installed, or if there's no space
+     * available on the device.
+     *
+     * @param packageURI The location of the package file to install.  This can be a 'file:' or a
+     * 'content:' URI.
+     * @param observer An observer callback to get notified when the package installation is
+     * complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be
+     * called when that happens.  observer may be null to indicate that no callback is desired.
+     * @param flags - possible values: {@link #FORWARD_LOCK_PACKAGE},
+     * {@link #REPLACE_EXISTING_PACKAGE}
+     * @param installerPackageName Optional package name of the application that is performing the
+     * installation. This identifies which market the package came from.
+     *
+     * @see #installPackage(android.net.Uri)
+     * 
+     * @hide
+     */
     public abstract void installPackage(
-            Uri packageURI, IPackageInstallObserver observer, int flags);
+            Uri packageURI, IPackageInstallObserver observer, int flags,
+            String installerPackageName);
 
     /**
      * Attempts to delete a package.  Since this may take a little while, the result will
@@ -1374,6 +1401,17 @@
      */
     public abstract void deletePackage(
             String packageName, IPackageDeleteObserver observer, int flags);
+
+    /**
+     * Retrieve the package name of the application that installed a package. This identifies
+     * which market the package came from.
+     * 
+     * @param packageName The name of the package to query
+     *
+     * @hide
+     */
+    public abstract String getInstallerPackageName(String packageName);
+    
     /**
      * Attempts to clear the user data directory of an application.
      * Since this may take a little while, the result will
@@ -1483,7 +1521,7 @@
      *
      * @param packageURI The location of the package file to install
      *
-     * @see #installPackage(android.net.Uri, IPackageInstallObserver, int)
+     * @see #installPackage(android.net.Uri, IPackageInstallObserver, int, String)
      */
     public void installPackage(Uri packageURI) {
         installPackage(packageURI, null, 0);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 410adb0..335b43c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4556,6 +4556,7 @@
      *
      * @hide Pending API council approval
      */
+    @ViewDebug.ExportedProperty
     public boolean isOpaque() {
         return mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE;
     }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index ffb6785..4f503b4 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -433,7 +433,9 @@
 
     private InputConnection mDefInputConnection;
     private InputConnectionWrapper mPublicInputConnection;
-    
+
+    private Runnable mClearScrollingCache;
+
     /**
      * Interface definition for a callback to be invoked when the list or grid
      * has been scrolled.
@@ -1947,7 +1949,7 @@
                 if (y != mLastY) {
                     deltaY -= mMotionCorrection;
                     int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
-                    trackMotionScroll(deltaY, incrementalDeltaY, true);
+                    trackMotionScroll(deltaY, incrementalDeltaY);
 
                     // Check to see if we have bumped into the scroll limit
                     View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
@@ -2286,7 +2288,7 @@
                 delta = Math.max(-(getHeight() - mPaddingBottom - mPaddingTop - 1), delta);
             }
 
-            trackMotionScroll(delta, delta, false);
+            trackMotionScroll(delta, delta);
 
             // Check to see if we have bumped into the scroll limit
             View motionView = getChildAt(mMotionPosition - mFirstPosition);
@@ -2323,16 +2325,23 @@
     }
 
     private void clearScrollingCache() {
-        if (mCachingStarted) {
-            mCachingStarted = false;
-            setChildrenDrawnWithCacheEnabled(false);
-            if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
-                setChildrenDrawingCacheEnabled(false);
-            }
-            if (!isAlwaysDrawnWithCacheEnabled()) {
-                invalidate();
-            }
+        if (mClearScrollingCache == null) {
+            mClearScrollingCache = new Runnable() {
+                public void run() {
+                    if (mCachingStarted) {
+                        mCachingStarted = false;
+                        setChildrenDrawnWithCacheEnabled(false);
+                        if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
+                            setChildrenDrawingCacheEnabled(false);
+                        }
+                        if (!isAlwaysDrawnWithCacheEnabled()) {
+                            invalidate();
+                        }
+                    }
+                }
+            };
         }
+        post(mClearScrollingCache);
     }
 
     /**
@@ -2341,9 +2350,8 @@
      * @param deltaY Amount to offset mMotionView. This is the accumulated delta since the motion
      *        began. Positive numbers mean the user's finger is moving down the screen.
      * @param incrementalDeltaY Change in deltaY from the previous event.
-     * @param invalidate True to make this method call invalidate(), false otherwise.
      */
-    void trackMotionScroll(int deltaY, int incrementalDeltaY, boolean invalidate) {
+    void trackMotionScroll(int deltaY, int incrementalDeltaY) {
         final int childCount = getChildCount();
         if (childCount == 0) {
             return;
@@ -2377,7 +2385,7 @@
         if (spaceAbove >= absIncrementalDeltaY && spaceBelow >= absIncrementalDeltaY) {
             hideSelector();
             offsetChildrenTopAndBottom(incrementalDeltaY);
-            if (invalidate) invalidate();
+            invalidate();
             mMotionViewNewTop = mMotionViewOriginalTop + deltaY;
         } else {
             final int firstPosition = mFirstPosition;
@@ -2455,7 +2463,7 @@
                 mFirstPosition += count;
             }
 
-            if (invalidate) invalidate();
+            invalidate();
             fillGap(down);
             mBlockLayoutRequests = false;
 
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index c4f0abd..edbb3db 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -823,7 +823,7 @@
             @ViewDebug.IntToString(from = RIGHT_OF,            to = "rightOf")
         }, mapping = {
             @ViewDebug.IntToString(from = TRUE, to = "true"),
-            @ViewDebug.IntToString(from = 0,    to = "NO_ID")
+            @ViewDebug.IntToString(from = 0,    to = "FALSE/NO_ID")
         })
         private int[] mRules = new int[VERB_COUNT];
 
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index e951431..21dde63 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -133,6 +133,14 @@
     return SkTypeface::CreateFromStream(new AssetStream(asset, true));
 }
 
+static SkTypeface* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) {
+    NPE_CHECK_RETURN_ZERO(env, jpath);
+
+    AutoJavaStringToUTF8 str(env, jpath);
+
+    return SkTypeface::CreateFromFile(str.c_str());
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gTypefaceMethods[] = {
@@ -140,9 +148,10 @@
     { "nativeCreateFromTypeface", "(II)I", (void*)Typeface_createFromTypeface },
     { "nativeUnref",              "(I)V",  (void*)Typeface_unref },
     { "nativeGetStyle",           "(I)I",  (void*)Typeface_getStyle },
-    { "nativeCreateFromAsset",
-                        "(Landroid/content/res/AssetManager;Ljava/lang/String;)I",
-                                            (void*)Typeface_createFromAsset }
+    { "nativeCreateFromAsset",    "(Landroid/content/res/AssetManager;Ljava/lang/String;)I",
+                                           (void*)Typeface_createFromAsset },
+    { "nativeCreateFromFile",     "(Ljava/lang/String;)I",
+                                           (void*)Typeface_createFromFile }
 };
 
 int register_android_graphics_Typeface(JNIEnv* env);
@@ -153,4 +162,3 @@
                                                        gTypefaceMethods,
                                                        SK_ARRAY_COUNT(gTypefaceMethods));
 }
-
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index b8d6586..42ada54 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -335,7 +335,7 @@
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for start()");
     }
-    
+
     lpTrack->start();
 }
 
@@ -433,6 +433,45 @@
 
 
 // ----------------------------------------------------------------------------
+jint writeToTrack(AudioTrack* pTrack, jint audioFormat, jbyte* data,
+                  jint offsetInBytes, jint sizeInBytes) {
+    // give the data to the native AudioTrack object (the data starts at the offset)
+    ssize_t written = 0;
+    // regular write() or copy the data to the AudioTrack's shared memory?
+    if (pTrack->sharedBuffer() == 0) {
+        written = pTrack->write(data + offsetInBytes, sizeInBytes);
+    } else {
+        if (audioFormat == javaAudioTrackFields.PCM16) {
+            // writing to shared memory, check for capacity
+            if ((size_t)sizeInBytes > pTrack->sharedBuffer()->size()) {
+                sizeInBytes = pTrack->sharedBuffer()->size();
+            }
+            memcpy(pTrack->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
+            written = sizeInBytes;
+        } else if (audioFormat == javaAudioTrackFields.PCM8) {
+            // data contains 8bit data we need to expand to 16bit before copying
+            // to the shared memory
+            // writing to shared memory, check for capacity,
+            // note that input data will occupy 2X the input space due to 8 to 16bit conversion
+            if (((size_t)sizeInBytes)*2 > pTrack->sharedBuffer()->size()) {
+                sizeInBytes = pTrack->sharedBuffer()->size() / 2;
+            }
+            int count = sizeInBytes;
+            int16_t *dst = (int16_t *)pTrack->sharedBuffer()->pointer();
+            const int8_t *src = (const int8_t *)(data + offsetInBytes);
+            while(count--) {
+                *dst++ = (int16_t)(*src++^0x80) << 8;
+            }
+            // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
+            // the 8bit mixer restriction from the user of this function
+            written = sizeInBytes;
+        }
+    }
+    return written;
+
+}
+
+// ----------------------------------------------------------------------------
 static jint android_media_AudioTrack_native_write(JNIEnv *env,  jobject thiz,
                                                   jbyteArray javaAudioData,
                                                   jint offsetInBytes, jint sizeInBytes,
@@ -461,35 +500,13 @@
         return 0;
     }
 
-    // give the data to the native AudioTrack object (the data starts at the offset)
-    ssize_t written = 0;
-    // regular write() or copy the data to the AudioTrack's shared memory?
-    if (lpTrack->sharedBuffer() == 0) {
-        written = lpTrack->write(cAudioData + offsetInBytes, sizeInBytes);
-    } else {
-        if (javaAudioFormat == javaAudioTrackFields.PCM16) {
-            memcpy(lpTrack->sharedBuffer()->pointer(), cAudioData + offsetInBytes, sizeInBytes);
-            written = sizeInBytes;
-        } else if (javaAudioFormat == javaAudioTrackFields.PCM8) {
-            // cAudioData contains 8bit data we need to expand to 16bit before copying
-            // to the shared memory
-            int count = sizeInBytes;
-            int16_t *dst = (int16_t *)lpTrack->sharedBuffer()->pointer();
-            const int8_t *src = (const int8_t *)(cAudioData + offsetInBytes);            
-            while(count--) {
-                *dst++ = (int16_t)(*src++^0x80) << 8;
-            }
-            // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
-            // the 8bit mixer restriction from the user of this function
-            written = sizeInBytes;
-        }
-    }
+    jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
 
     env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0);
 
     //LOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
     //     (int)written, (int)(sizeInBytes), (int)offsetInBytes);
-    return (int)written;
+    return written;
 }
 
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index c69c92c..e40e84a 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -18,6 +18,8 @@
 
 import android.content.res.AssetManager;
 
+import java.io.File;
+
 /**
  * The Typeface class specifies the typeface and intrinsic style of a font.
  * This is used in the paint, along with optionally Paint settings like
@@ -118,7 +120,27 @@
     public static Typeface createFromAsset(AssetManager mgr, String path) {
         return new Typeface(nativeCreateFromAsset(mgr, path));
     }
-    
+
+    /**
+     * Create a new typeface from the specified font file.
+     *
+     * @param path The path to the font data. 
+     * @return The new typeface.
+     */
+    public static Typeface createFromFile(File path) {
+        return new Typeface(nativeCreateFromFile(path.getAbsolutePath()));
+    }
+
+    /**
+     * Create a new typeface from the specified font file.
+     *
+     * @param path The full path to the font data. 
+     * @return The new typeface.
+     */
+    public static Typeface createFromFile(String path) {
+        return new Typeface(nativeCreateFromFile(path));
+    }
+
     // don't allow clients to call this directly
     private Typeface(int ni) {
         native_instance = ni;
@@ -140,14 +162,14 @@
     }
 
     protected void finalize() throws Throwable {
+        super.finalize();
         nativeUnref(native_instance);
     }
 
     private static native int  nativeCreate(String familyName, int style);
-    private static native int  nativeCreateFromTypeface(int native_instance,
-                                                        int style);
+    private static native int  nativeCreateFromTypeface(int native_instance, int style); 
     private static native void nativeUnref(int native_instance);
     private static native int  nativeGetStyle(int native_instance);
-    private static native int  nativeCreateFromAsset(AssetManager mgr,
-                                                     String path);
+    private static native int  nativeCreateFromAsset(AssetManager mgr, String path);
+    private static native int nativeCreateFromFile(String path);
 }
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 29f2a00..f8b88d0 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -181,7 +181,8 @@
 
     @Override
     public int getOpacity() {
-        return mDrawableContainerState.getOpacity();
+        return mCurrDrawable == null || !mCurrDrawable.isVisible() ? PixelFormat.TRANSPARENT :
+                mDrawableContainerState.getOpacity();
     }
 
     public boolean selectDrawable(int idx)
@@ -336,13 +337,11 @@
             return pos;
         }
 
-        public final int getChildCount()
-        {
+        public final int getChildCount() {
             return mNumChildren;
         }
 
-        public final Drawable[] getChildren()
-        {
+        public final Drawable[] getChildren() {
             return mDrawables;
         }
 
@@ -350,13 +349,11 @@
           * all frames in the set (false), or to use the padding value of the frame 
           * being shown (true). Default value is false. 
           */
-        public final void setVariablePadding(boolean variable)
-        {
+        public final void setVariablePadding(boolean variable) {
             mVariablePadding = variable;
         }
 
-        public final Rect getConstantPadding()
-        {
+        public final Rect getConstantPadding() {
             if (mVariablePadding) {
                 return null;
             }
@@ -364,11 +361,12 @@
                 return mConstantPadding;
             }
 
-            Rect r = new Rect(0, 0, 0, 0);
-            Rect t = new Rect();
+            final Rect r = new Rect(0, 0, 0, 0);
+            final Rect t = new Rect();
             final int N = getChildCount();
-            for (int i=0; i<N; i++) {
-                if (mDrawables[i].getPadding(t)) {
+            final Drawable[] drawables = mDrawables;
+            for (int i = 0; i < N; i++) {
+                if (drawables[i].getPadding(t)) {
                     if (t.left > r.left) r.left = t.left;
                     if (t.top > r.top) r.top = t.top;
                     if (t.right > r.right) r.right = t.right;
@@ -378,18 +376,15 @@
             return (mConstantPadding=r);
         }
 
-        public final void setConstantSize(boolean constant)
-        {
+        public final void setConstantSize(boolean constant) {
             mConstantSize = constant;
         }
 
-        public final boolean isConstantSize()
-        {
+        public final boolean isConstantSize() {
             return mConstantSize;
         }
 
-        public final int getConstantWidth()
-        {
+        public final int getConstantWidth() {
             if (!mComputedConstantSize) {
                 computeConstantSize();
             }
@@ -397,8 +392,7 @@
             return mConstantWidth;
         }
 
-        public final int getConstantHeight()
-        {
+        public final int getConstantHeight() {
             if (!mComputedConstantSize) {
                 computeConstantSize();
             }
@@ -406,8 +400,7 @@
             return mConstantHeight;
         }
 
-        public final int getConstantMinimumWidth()
-        {
+        public final int getConstantMinimumWidth() {
             if (!mComputedConstantSize) {
                 computeConstantSize();
             }
@@ -415,8 +408,7 @@
             return mConstantMinimumWidth;
         }
 
-        public final int getConstantMinimumHeight()
-        {
+        public final int getConstantMinimumHeight() {
             if (!mComputedConstantSize) {
                 computeConstantSize();
             }
@@ -424,15 +416,15 @@
             return mConstantMinimumHeight;
         }
 
-        private void computeConstantSize()
-        {
+        private void computeConstantSize() {
             mComputedConstantSize = true;
 
             final int N = getChildCount();
+            final Drawable[] drawables = mDrawables;
             mConstantWidth = mConstantHeight = 0;
             mConstantMinimumWidth = mConstantMinimumHeight = 0;
-            for (int i=0; i<N; i++) {
-                Drawable dr = mDrawables[i];
+            for (int i = 0; i < N; i++) {
+                Drawable dr = drawables[i];
                 int s = dr.getIntrinsicWidth();
                 if (s > mConstantWidth) mConstantWidth = s;
                 s = dr.getIntrinsicHeight();
@@ -444,23 +436,22 @@
             }
         }
 
-        public final int getOpacity()
-        {
+        public final int getOpacity() {
             if (mHaveOpacity) {
                 return mOpacity;
             }
 
             final int N = getChildCount();
-            int op = N > 0
-                ? mDrawables[0].getOpacity() : PixelFormat.TRANSPARENT;
-            for (int i=1; i<N; i++) {
-                op = Drawable.resolveOpacity(op, mDrawables[i].getOpacity());
+            final Drawable[] drawables = mDrawables;
+            int op = N > 0 ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT;
+            for (int i = 1; i < N; i++) {
+                op = Drawable.resolveOpacity(op, drawables[i].getOpacity());
             }
             mOpacity = op;
             mHaveOpacity = true;
             return op;
         }
-        
+
         public final boolean isStateful() {
             if (mHaveStateful) {
                 return mStateful;
@@ -480,8 +471,7 @@
             return stateful;
         }
 
-        public void growArray(int oldSize, int newSize)
-        {
+        public void growArray(int oldSize, int newSize) {
             Drawable[] newDrawables = new Drawable[newSize];
             System.arraycopy(mDrawables, 0, newDrawables, 0, oldSize);
             mDrawables = newDrawables;
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index aef8985..872838c 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1257,7 +1257,7 @@
     }
 
     /**
-     * Installs a network location provider.
+     * Installs a location provider.
      *
      * @param name of the location provider
      * @param provider Binder interface for the location provider
diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/location/java/com/android/internal/location/LocationProviderProxy.java
index 80303f4..b40cdca 100644
--- a/location/java/com/android/internal/location/LocationProviderProxy.java
+++ b/location/java/com/android/internal/location/LocationProviderProxy.java
@@ -21,6 +21,7 @@
 import android.location.Location;
 import android.location.LocationManager;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -31,7 +32,7 @@
  *
  * {@hide}
  */
-public class LocationProviderProxy {
+public class LocationProviderProxy implements IBinder.DeathRecipient {
 
     private static final String TAG = "LocationProviderProxy";
 
@@ -39,16 +40,27 @@
     private final ILocationProvider mProvider;
     private boolean mLocationTracking = false;
     private long mMinTime = 0;
+    private boolean mDead;
 
     public LocationProviderProxy(String name, ILocationProvider provider) {
         mName = name;
         mProvider = provider;
+        try {
+            provider.asBinder().linkToDeath(this, 0);
+        } catch (RemoteException e) {
+            Log.e(TAG, "linkToDeath failed", e);
+            mDead = true;
+        }
     }
 
     public String getName() {
         return mName;
     }
 
+    public boolean isDead() {
+        return mDead;
+    }
+
     public boolean requiresNetwork() {
         try {
             return mProvider.requiresNetwork();
@@ -231,4 +243,9 @@
             Log.e(TAG, "removeListener failed", e);
         }
     }
+
+    public void binderDied() {
+        Log.w(TAG, "Location Provider " + mName + " died");
+        mDead = true;
+    }
 }
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 14c834b..05888e0 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -215,8 +215,7 @@
         public int hashCode() {
             return mKey.hashCode();
         }
-        
-        
+
         @Override
         public String toString() {
             if (mListener != null) {
@@ -611,6 +610,17 @@
         }
 
         synchronized (mLock) {
+            // check to see if we are reinstalling a dead provider
+            LocationProviderProxy oldProvider = mProvidersByName.get(name);
+            if (oldProvider != null) {
+                if (oldProvider.isDead()) {
+                    Log.d(TAG, "replacing dead provider");
+                    removeProvider(oldProvider);
+                } else {
+                    throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
+                }
+            }
+
             LocationProviderProxy proxy = new LocationProviderProxy(name, provider);
             addProvider(proxy);
             updateProvidersLocked();
@@ -1616,6 +1626,7 @@
                                 mCollector.updateLocation(location);
                             } catch (RemoteException e) {
                                 Log.w(TAG, "mCollector.updateLocation failed");
+                                mCollector = null;
                             }
                         }
 
@@ -1750,6 +1761,7 @@
                         variant, appName,  addrs);
             } catch (RemoteException e) {
                 Log.e(TAG, "getFromLocation failed", e);
+                mGeocodeProvider = null;
             }
         }
         return null;
@@ -1768,6 +1780,7 @@
                         maxResults, language, country, variant, appName, addrs);
             } catch (RemoteException e) {
                 Log.e(TAG, "getFromLocationName failed", e);
+                mGeocodeProvider = null;
             }
         }
         return null;
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 237b70d..b17a941 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3231,20 +3231,27 @@
         private final String mRootDir;
         private final boolean mIsRom;
     }
-    
+
     /* Called when a downloaded package installation has been confirmed by the user */
     public void installPackage(
             final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
+        installPackage(packageURI, observer, flags, null);
+    }
+    
+    /* Called when a downloaded package installation has been confirmed by the user */
+    public void installPackage(
+            final Uri packageURI, final IPackageInstallObserver observer, final int flags,
+            final String installerPackageName) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.INSTALL_PACKAGES, null);
-
+        
         // Queue up an async operation since the package installation may take a little while.
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
                 PackageInstalledInfo res;
                 synchronized (mInstallLock) {
-                    res = installPackageLI(packageURI, flags, true);
+                    res = installPackageLI(packageURI, flags, true, installerPackageName);
                 }
                 if (observer != null) {
                     try {
@@ -3292,7 +3299,7 @@
             File tmpPackageFile, 
             String destFilePath, File destPackageFile, File destResourceFile,
             PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
-            PackageInstalledInfo res) {
+            String installerPackageName, PackageInstalledInfo res) {
         // Remember this for later, in case we need to rollback this install
         boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists();
         res.name = pkgName;
@@ -3328,7 +3335,8 @@
                     destResourceFile, pkg, 
                     newPackage,
                     true,
-                    forwardLocked,  
+                    forwardLocked,
+                    installerPackageName,
                     res);
             // delete the partially installed application. the data directory will have to be
             // restored if it was already existing
@@ -3349,7 +3357,8 @@
             File tmpPackageFile, 
             String destFilePath, File destPackageFile, File destResourceFile,
             PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
-            PackageInstalledInfo res) {
+            String installerPackageName, PackageInstalledInfo res) {
+
         PackageParser.Package oldPackage;
         // First find the old package info and check signatures
         synchronized(mPackages) {
@@ -3364,11 +3373,11 @@
             replaceSystemPackageLI(oldPackage,
                     tmpPackageFile, destFilePath, 
                     destPackageFile, destResourceFile, pkg, forwardLocked,
-                    newInstall, res);
+                    newInstall, installerPackageName, res);
         } else {
             replaceNonSystemPackageLI(oldPackage, tmpPackageFile, destFilePath,
                     destPackageFile, destResourceFile, pkg, forwardLocked,
-                    newInstall, res);
+                    newInstall, installerPackageName, res);
         }
     }
     
@@ -3376,11 +3385,17 @@
             File tmpPackageFile, 
             String destFilePath, File destPackageFile, File destResourceFile,
             PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
-            PackageInstalledInfo res) {
+            String installerPackageName, PackageInstalledInfo res) {
         PackageParser.Package newPackage = null;
         String pkgName = deletedPackage.packageName;
         boolean deletedPkg = true;
         boolean updatedSettings = false;
+        
+        String oldInstallerPackageName = null;
+        synchronized (mPackages) {
+            oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
+        }
+        
         int parseFlags = PackageManager.REPLACE_EXISTING_PACKAGE;
         // First delete the existing package while retaining the data directory
         if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
@@ -3409,6 +3424,7 @@
                         newPackage,
                         true,
                         forwardLocked,  
+                        installerPackageName,
                         res);
                 updatedSettings = true;
             }
@@ -3453,7 +3469,7 @@
                         Uri.fromFile(new File(deletedPackage.mPath)),
                         isForwardLocked(deletedPackage)
                         ? PackageManager.FORWARD_LOCK_PACKAGE
-                                : 0, false);
+                                : 0, false, oldInstallerPackageName);
             }
         }
     }
@@ -3462,7 +3478,7 @@
             File tmpPackageFile, 
             String destFilePath, File destPackageFile, File destResourceFile,
             PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
-            PackageInstalledInfo res) {
+            String installerPackageName, PackageInstalledInfo res) {
         PackageParser.Package newPackage = null;
         boolean updatedSettings = false;
         int parseFlags = PackageManager.REPLACE_EXISTING_PACKAGE |
@@ -3512,7 +3528,8 @@
                     destResourceFile, pkg, 
                     newPackage,
                     true,
-                    forwardLocked,  
+                    forwardLocked,
+                    installerPackageName,
                     res);
             updatedSettings = true;
         }
@@ -3539,6 +3556,8 @@
             synchronized(mPackages) {
                 if(updatedSettings) {
                     mSettings.enableSystemPackageLP(packageName);
+                    mSettings.setInstallerPackageName(packageName,
+                            oldPkgSetting.installerPackageName);
                 }
                 mSettings.writeLP();
             }
@@ -3552,7 +3571,7 @@
             PackageParser.Package newPackage,
             boolean replacingExistingPackage,
             boolean forwardLocked,  
-            PackageInstalledInfo res) {
+            String installerPackageName, PackageInstalledInfo res) {
         synchronized (mPackages) {
             //write settings. the installStatus will be incomplete at this stage.
             //note that the new package setting would have already been
@@ -3599,6 +3618,7 @@
             res.uid = newPackage.applicationInfo.uid;
             res.pkg = newPackage;
             mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE);
+            mSettings.setInstallerPackageName(pkgName, installerPackageName);
             res.returnCode = PackageManager.INSTALL_SUCCEEDED;
             //to update install status
             mSettings.writeLP();
@@ -3606,7 +3626,7 @@
     }
     
     private PackageInstalledInfo installPackageLI(Uri pPackageURI,
-            int pFlags, boolean newInstall) {
+            int pFlags, boolean newInstall, String installerPackageName) {
         File tmpPackageFile = null;
         String pkgName = null;
         boolean forwardLocked = false;
@@ -3719,13 +3739,13 @@
                 replacePackageLI(pkgName,
                         tmpPackageFile, 
                         destFilePath, destPackageFile, destResourceFile,
-                        pkg, forwardLocked, newInstall,
+                        pkg, forwardLocked, newInstall, installerPackageName,
                         res);
             } else {
                 installNewPackageLI(pkgName,
                         tmpPackageFile, 
                         destFilePath, destPackageFile, destResourceFile,
-                        pkg, forwardLocked, newInstall,
+                        pkg, forwardLocked, newInstall, installerPackageName,
                         res);
             }
         } finally {
@@ -4543,6 +4563,16 @@
         }
     }
 
+    public String getInstallerPackageName(String packageName) {
+        synchronized (mPackages) {
+            PackageSetting pkg = mSettings.mPackages.get(packageName);
+            if (pkg == null) {
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            return pkg.installerPackageName;
+        }
+    }
+    
     public int getApplicationEnabledSetting(String appPackageName) {
         synchronized (mPackages) {
             PackageSetting pkg = mSettings.mPackages.get(appPackageName);
@@ -5192,6 +5222,9 @@
         HashSet<String> enabledComponents = new HashSet<String>(0);
         int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
         int installStatus = PKG_INSTALL_COMPLETE;
+        
+        /* package name of the app that installed this package */
+        String installerPackageName;
 
         PackageSettingBase(String name, File codePath, File resourcePath,
                 int pVersionCode, int pkgFlags) {
@@ -5204,6 +5237,14 @@
             this.versionCode = pVersionCode;
         }
 
+        public void setInstallerPackageName(String packageName) {
+            installerPackageName = packageName;
+        }
+        
+        String getInstallerPackageName() {
+            return installerPackageName;
+        }
+        
         public void setInstallStatus(int newStatus) {
             installStatus = newStatus;
         }
@@ -5434,6 +5475,19 @@
             }
         }
         
+        void setInstallerPackageName(String pkgName,
+                String installerPkgName) {
+            PackageSetting p = mPackages.get(pkgName);
+            if(p != null) {
+                p.setInstallerPackageName(installerPkgName);
+            }
+        }
+        
+        String getInstallerPackageName(String pkgName) {
+            PackageSetting p = mPackages.get(pkgName);
+            return (p == null) ? null : p.getInstallerPackageName(); 
+        }
+
         int getInstallStatus(String pkgName) {
             PackageSetting p = mPackages.get(pkgName);
             if(p != null) {
@@ -5909,6 +5963,9 @@
             if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) {
                 serializer.attribute(null, "installStatus", "false");
             }
+            if (pkg.installerPackageName != null) {
+                serializer.attribute(null, "installer", pkg.installerPackageName);
+            }
             pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
             if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
                 serializer.startTag(null, "perms");
@@ -5943,6 +6000,7 @@
                 }
                 serializer.endTag(null, "enabled-components");
             }
+            
             serializer.endTag(null, "package");
         }
         
@@ -6264,6 +6322,7 @@
             String codePathStr = null;
             String resourcePathStr = null;
             String systemStr = null;
+            String installerPackageName = null;
             int pkgFlags = 0;
             String timeStampStr;
             long timeStamp = 0;
@@ -6284,6 +6343,7 @@
                     }
                 }
                 systemStr = parser.getAttributeValue(null, "system");
+                installerPackageName = parser.getAttributeValue(null, "installer");
                 if (systemStr != null) {
                     if ("true".equals(systemStr)) {
                         pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
@@ -6357,6 +6417,7 @@
                         + parser.getPositionDescription());
             }
             if (packageSetting != null) {
+                packageSetting.installerPackageName = installerPackageName;
                 final String enabledStr = parser.getAttributeValue(null, "enabled");
                 if (enabledStr != null) {
                     if (enabledStr.equalsIgnoreCase("true")) {
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index ea190e2..4769057 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -286,7 +286,15 @@
 
     @Override
     public void installPackage(Uri packageURI, IPackageInstallObserver observer,
-            int flags) {
+            int flags, String installerPackageName) {
+        throw new UnsupportedOperationException();
+    }
+    
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public String getInstallerPackageName(String packageName) {
         throw new UnsupportedOperationException();
     }