Merge "Add a getter for the active tag"
diff --git a/api/current.txt b/api/current.txt
index 79ce4f8..72cfe71 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -673,6 +673,8 @@
     field public static final int minHeight = 16843072; // 0x1010140
     field public static final int minLevel = 16843185; // 0x10101b1
     field public static final int minLines = 16843094; // 0x1010156
+    field public static final int minResizeHeight = 16843690; // 0x10103aa
+    field public static final int minResizeWidth = 16843689; // 0x10103a9
     field public static final int minSdkVersion = 16843276; // 0x101020c
     field public static final int minWidth = 16843071; // 0x101013f
     field public static final int mode = 16843134; // 0x101017e
@@ -3929,6 +3931,8 @@
     field public int initialLayout;
     field public java.lang.String label;
     field public int minHeight;
+    field public int minResizeHeight;
+    field public int minResizeWidth;
     field public int minWidth;
     field public int previewImage;
     field public android.content.ComponentName provider;
@@ -11913,6 +11917,7 @@
     field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
     field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
     field public static final java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
+    field public static final java.lang.String EXTRA_WIFI_INFO = "wifiInfo";
     field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_state";
     field public static final java.lang.String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
     field public static final java.lang.String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index fdf4a3a..2a731a3 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1514,6 +1514,14 @@
             return true;
         }
 
+        case UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            Configuration config = Configuration.CREATOR.createFromParcel(data);
+            updatePersistentConfiguration(config);
+            reply.writeNoException();
+            return true;
+        }
+
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3410,5 +3418,17 @@
         return res;
     }
 
+    public void updatePersistentConfiguration(Configuration values) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        values.writeToParcel(data, 0);
+        mRemote.transact(UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 9e20764..93c821c 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -363,6 +363,8 @@
 
     public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException;
 
+    public void updatePersistentConfiguration(Configuration values) throws RemoteException;
+    
     /*
      * Private non-Binder interfaces
      */
@@ -590,4 +592,5 @@
     int REGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+132;
     int UNREGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+133;
     int IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+134;
+    int UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+135;
 }
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 8204a4f..08bc0ac 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -261,6 +261,10 @@
             TypedValue.complexToDimensionPixelSize(appWidget.minWidth, mDisplayMetrics);
         appWidget.minHeight =
             TypedValue.complexToDimensionPixelSize(appWidget.minHeight, mDisplayMetrics);
+        appWidget.minResizeWidth =
+            TypedValue.complexToDimensionPixelSize(appWidget.minResizeWidth, mDisplayMetrics);
+        appWidget.minResizeHeight =
+            TypedValue.complexToDimensionPixelSize(appWidget.minResizeHeight, mDisplayMetrics);
 
         synchronized (mViews) {
             v = mViews.get(appWidgetId);
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index b46802e..b8c5b02 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -54,7 +54,8 @@
     public ComponentName provider;
 
     /**
-     * Minimum width of the AppWidget, in dp.
+     * The default height of the widget when added to a host, in dp. The widget will get
+     * at least this width, and will often be given more, depending on the host.
      *
      * <p>This field corresponds to the <code>android:minWidth</code> attribute in
      * the AppWidget meta-data file.
@@ -62,7 +63,8 @@
     public int minWidth;
 
     /**
-     * Minimum height of the AppWidget, in dp.
+     * The default height of the widget when added to a host, in dp. The widget will get
+     * at least this height, and will often be given more, depending on the host.
      *
      * <p>This field corresponds to the <code>android:minHeight</code> attribute in
      * the AppWidget meta-data file.
@@ -70,6 +72,24 @@
     public int minHeight;
 
     /**
+     * Minimum width (in dp) which the widget can be resized to. This field has no effect if it
+     * is greater than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
+     *
+     * <p>This field corresponds to the <code>android:minResizeWidth</code> attribute in
+     * the AppWidget meta-data file.
+     */
+    public int minResizeWidth;
+
+    /**
+     * Minimum height (in dp) which the widget can be resized to. This field has no effect if it
+     * is greater than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
+     *
+     * <p>This field corresponds to the <code>android:minResizeHeight</code> attribute in
+     * the AppWidget meta-data file.
+     */
+    public int minResizeHeight;
+
+    /**
      * How often, in milliseconds, that this AppWidget wants to be updated.
      * The AppWidget manager may place a limit on how often a AppWidget is updated.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 34699e2..ad32047 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1045,6 +1045,14 @@
         }
 
         /**
+         * @hide Erase the fields in the Configuration that should be applied
+         * by the settings.
+         */
+        public static void clearConfiguration(Configuration inoutConfig) {
+            inoutConfig.fontScale = 0;
+        }
+        
+        /**
          * Convenience function to write a batch of configuration-related
          * settings from a {@link Configuration} object.
          *
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 70b61de..c88b922 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5068,6 +5068,8 @@
      */
     @Override
     protected int getFadeTop(boolean offsetRequired) {
+        if (mLayout == null) return 0;
+
         int voffset = 0;
         if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
             voffset = getVerticalOffset(true);
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index f0a9441..95f1f98 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -76,7 +76,9 @@
     private TabImpl mSelectedTab;
     private int mSavedTabPosition = INVALID_POSITION;
     
-    private ActionMode mActionMode;
+    ActionModeImpl mActionMode;
+    ActionMode mDeferredDestroyActionMode;
+    ActionMode.Callback mDeferredModeDestroyCallback;
     
     private boolean mLastMenuVisibility;
     private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
@@ -104,10 +106,12 @@
         public void onAnimationEnd(Animator animation) {
             if (mContentView != null) {
                 mContentView.setTranslationY(0);
+                mContainerView.setTranslationY(0);
             }
             mContainerView.setVisibility(View.GONE);
             mContainerView.setTransitioning(false);
             mCurrentShowAnim = null;
+            completeDeferredDestroyActionMode();
         }
     };
 
@@ -207,6 +211,14 @@
         mTabScrollView = tabScroller;
     }
 
+    void completeDeferredDestroyActionMode() {
+        if (mDeferredModeDestroyCallback != null) {
+            mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode);
+            mDeferredDestroyActionMode = null;
+            mDeferredModeDestroyCallback = null;
+        }
+    }
+
     /**
      * Enables or disables animation between show/hide states.
      * If animation is disabled using this method, animations in progress
@@ -357,14 +369,16 @@
     }
 
     public ActionMode startActionMode(ActionMode.Callback callback) {
+        boolean wasHidden = false;
         if (mActionMode != null) {
+            wasHidden = mWasHiddenBeforeMode;
             mActionMode.finish();
         }
 
         mContextView.killMode();
         ActionModeImpl mode = new ActionModeImpl(callback);
         if (mode.dispatchOnCreate()) {
-            mWasHiddenBeforeMode = !isShowing();
+            mWasHiddenBeforeMode = !isShowing() || wasHidden;
             mode.invalidate();
             mContextView.initForMode(mode);
             animateToMode(true);
@@ -577,7 +591,9 @@
     }
 
     void animateToMode(boolean toActionMode) {
-        show(false);
+        if (toActionMode) {
+            show(false);
+        }
         if (mCurrentModeAnim != null) {
             mCurrentModeAnim.end();
         }
@@ -621,7 +637,16 @@
                 return;
             }
 
-            mCallback.onDestroyActionMode(this);
+            // If we were hidden before the mode was shown, defer the onDestroy
+            // callback until the animation is finished and associated relayout
+            // is about to happen. This lets apps better anticipate visibility
+            // and layout behavior.
+            if (mWasHiddenBeforeMode) {
+                mDeferredDestroyActionMode = this;
+                mDeferredModeDestroyCallback = mCallback;
+            } else {
+                mCallback.onDestroyActionMode(this);
+            }
             mCallback = null;
             animateToMode(false);
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d0361ca..082284a 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4913,6 +4913,10 @@
         <attr name="minWidth"/>
         <!-- Minimum height of the AppWidget. -->
         <attr name="minHeight"/>
+        <!-- Minimum width that the AppWidget can be resized to. -->
+        <attr name="minResizeWidth" format="dimension"/>
+        <!-- Minimum height that the AppWidget can be resized to. -->
+        <attr name="minResizeHeight" format="dimension"/>
         <!-- Update period in milliseconds, or 0 if the AppWidget will update itself. -->
         <attr name="updatePeriodMillis" format="integer" />
         <!-- A resource id of a layout. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f464623..ba2a036 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1831,4 +1831,6 @@
   <public type="color" name="holo_purple" />
   <public type="color" name="holo_blue_bright" />
 
+  <public type="attr" name="minResizeWidth" />
+  <public type="attr" name="minResizeHeight" />
 </resources>
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 0b15221..438883e 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -1022,6 +1022,12 @@
             info.minWidth = value != null ? value.data : 0; 
             value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
             info.minHeight = value != null ? value.data : 0;
+            value = sa.peekValue(
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth);
+            info.minResizeWidth = value != null ? value.data : info.minWidth;
+            value = sa.peekValue(
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight);
+            info.minResizeHeight = value != null ? value.data : info.minHeight;
 
             info.updatePeriodMillis = sa.getInt(
                     com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 94af46d..0924b86 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2439,7 +2439,7 @@
                     r.mayFreezeScreenLocked(r.app) ? r : null);
             if (config != null) {
                 r.frozenBeforeDestroy = true;
-                if (!updateConfigurationLocked(config, r)) {
+                if (!updateConfigurationLocked(config, r, false)) {
                     mMainStack.resumeTopActivityLocked(null);
                 }
             }
@@ -12398,6 +12398,22 @@
         return ci;
     }
 
+    public void updatePersistentConfiguration(Configuration values) {
+        enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+                "updateConfiguration()");
+        enforceCallingPermission(android.Manifest.permission.WRITE_SETTINGS,
+                "updateConfiguration()");
+        if (values == null) {
+            throw new NullPointerException("Configuration must not be null");
+        }
+
+        synchronized(this) {
+            final long origId = Binder.clearCallingIdentity();
+            updateConfigurationLocked(values, null, true);
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
     public void updateConfiguration(Configuration values) {
         enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                 "updateConfiguration()");
@@ -12409,7 +12425,10 @@
             }
             
             final long origId = Binder.clearCallingIdentity();
-            updateConfigurationLocked(values, null);
+            if (values != null) {
+                Settings.System.clearConfiguration(values);
+            }
+            updateConfigurationLocked(values, null, false);
             Binder.restoreCallingIdentity(origId);
         }
     }
@@ -12420,9 +12439,10 @@
      * configuration.  Returns true if the activity has been left running, or
      * false if <var>starting</var> is being destroyed to match the new
      * configuration.
+     * @param persistent TODO
      */
     public boolean updateConfigurationLocked(Configuration values,
-            ActivityRecord starting) {
+            ActivityRecord starting, boolean persistent) {
         int changes = 0;
         
         boolean kept = true;
@@ -12465,7 +12485,7 @@
                 // code is executed.
                 mSystemThread.applyConfigurationToResources(newConfig);
 
-                if (Settings.System.hasInterestingConfigurationChanges(changes)) {
+                if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
                     Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
                     msg.obj = new Configuration(mConfiguration);
                     mHandler.sendMessage(msg);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 93d8164..0d89081 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -518,7 +518,7 @@
             Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
                     mService.mConfiguration,
                     r.mayFreezeScreenLocked(app) ? r : null);
-            mService.updateConfigurationLocked(config, r);
+            mService.updateConfigurationLocked(config, r, false);
         }
 
         r.app = app;
@@ -1424,7 +1424,7 @@
                     if (config != null) {
                         next.frozenBeforeDestroy = true;
                     }
-                    updated = mService.updateConfigurationLocked(config, next);
+                    updated = mService.updateConfigurationLocked(config, next, false);
                 }
             }
             if (!updated) {
@@ -2817,7 +2817,7 @@
                 mConfigWillChange = false;
                 if (DEBUG_CONFIGURATION) Slog.v(TAG,
                         "Updating to new configuration after starting activity.");
-                mService.updateConfigurationLocked(config, null);
+                mService.updateConfigurationLocked(config, null, false);
             }
             
             Binder.restoreCallingIdentity(origId);
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 5ed7988..f270003 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1093,8 +1093,7 @@
             serializer.attribute(null, "uidError", "true");
         }
         if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
-            serializer.attribute(null, "enabled",
-                    pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED ? "true" : "false");
+            serializer.attribute(null, "enabled", Integer.toString(pkg.enabled));
         }
         if (pkg.installStatus == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
             serializer.attribute(null, "installStatus", "false");
@@ -1644,17 +1643,21 @@
             packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
             final String enabledStr = parser.getAttributeValue(null, "enabled");
             if (enabledStr != null) {
-                if (enabledStr.equalsIgnoreCase("true")) {
-                    packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED;
-                } else if (enabledStr.equalsIgnoreCase("false")) {
-                    packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED;
-                } else if (enabledStr.equalsIgnoreCase("default")) {
-                    packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
-                } else {
-                    PackageManagerService.reportSettingsProblem(Log.WARN,
-                            "Error in package manager settings: package " + name
-                                    + " has bad enabled value: " + idStr + " at "
-                                    + parser.getPositionDescription());
+                try {
+                    packageSetting.enabled = Integer.parseInt(enabledStr);
+                } catch (NumberFormatException e) {
+                    if (enabledStr.equalsIgnoreCase("true")) {
+                        packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED;
+                    } else if (enabledStr.equalsIgnoreCase("false")) {
+                        packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED;
+                    } else if (enabledStr.equalsIgnoreCase("default")) {
+                        packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+                    } else {
+                        PackageManagerService.reportSettingsProblem(Log.WARN,
+                                "Error in package manager settings: package " + name
+                                        + " has bad enabled value: " + idStr + " at "
+                                        + parser.getPositionDescription());
+                    }
                 }
             } else {
                 packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index e3661bf..7bb927b 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -81,6 +81,24 @@
         mHiddenSSID = false;
     }
 
+    /**
+     * Copy constructor
+     * @hide
+     */
+    public WifiInfo(WifiInfo source) {
+        if (source != null) {
+            mSupplicantState = source.mSupplicantState;
+            mBSSID = source.mBSSID;
+            mSSID = source.mSSID;
+            mNetworkId = source.mNetworkId;
+            mHiddenSSID = source.mHiddenSSID;
+            mRssi = source.mRssi;
+            mLinkSpeed = source.mLinkSpeed;
+            mIpAddress = source.mIpAddress;
+            mMacAddress = source.mMacAddress;
+        }
+    }
+
     void setSSID(String SSID) {
         mSSID = SSID;
         // network is considered not hidden by default
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9d1bdd4..cd6621f 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -230,11 +230,13 @@
     /**
      * Broadcast intent action indicating that the state of Wi-Fi connectivity
      * has changed. One extra provides the new state
-     * in the form of a {@link android.net.NetworkInfo} object. If the new state is
-     * CONNECTED, a second extra may provide the BSSID of the access point,
+     * in the form of a {@link android.net.NetworkInfo} object. If the new
+     * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of
+     * the access point.
      * as a {@code String}.
      * @see #EXTRA_NETWORK_INFO
      * @see #EXTRA_BSSID
+     * @see #EXTRA_WIFI_INFO
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
@@ -252,6 +254,13 @@
      */
     public static final String EXTRA_BSSID = "bssid";
     /**
+     * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
+     * information about the access point to which we are connected. Only present
+     * when the new state is CONNECTED.  Retrieve with
+     * {@link android.content.Intent#getParcelableExtra(String)}.
+     */
+    public static final String EXTRA_WIFI_INFO = "wifiInfo";
+    /**
      * Broadcast intent action indicating that the state of establishing a connection to
      * an access point has changed.One extra provides the new
      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 8c28319..12efeb1 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1374,6 +1374,8 @@
         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
         if (bssid != null)
             intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
+        if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED)
+            intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo));
         mContext.sendStickyBroadcast(intent);
     }