             // Dispatch the close event before removing from the PopUpManager.
             dispatchEvent(closeEvent);
             closeEvent = null;
-            
+
             if (softKeyboardEffectEnabled && smStage)
             {
                 // Uninstall soft keyboard event handling
-                smStage.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, 
-                    softKeyboardActivateHandler, true);
-                smStage.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, 
-                    softKeyboardDeactivateHandler, true);
+                smStage.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE,
+                    stage_softKeyboardActivateHandler, true);
+                smStage.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE,
+                    stage_softKeyboardDeactivateHandler, true);
+                systemManager.removeEventListener(Event.RESIZE, systemManagerResizeHandler);
             }
 
             // We just finished closing, remove from the PopUpManager.
             PopUpManager.removePopUp(this);
             addedToPopUpManager = false;
             owner = null;
+
+            // Position and size may be invalid if the close transition
+            // completes before (a) deactivate is fired or (b) a pending
+            // soft keyboard change is still queued. Update immediately.
+            updateSoftKeyboardEffect(true);
+        }
+    }
+
+    /**
+     *  @private
+     */
+    private function stage_softKeyboardActivateHandler(event:SoftKeyboardEvent=null):void
+    {
+        var isFirstActivate:Boolean = false;
+
+        // Reset state
+        softKeyboardEffectPendingEventType = null;
+
+        // Save the original y-position and height if this is the first
+        // ACTIVATE event and an existing effect is not already in progress.
+        if (!isSoftKeyboardEffectActive && !softKeyboardEffect)
+            isFirstActivate = true;
+
+        if (isFirstActivate)
+        {
+            // Play the activate effect with animation
+            updateSoftKeyboardEffect(false);
+        }
+        else
+        {
+            // Keyboard height has changed. However, the effect can be delayed if
+            // a mouseUp within the pop-up is pending. An additional activate can
+            // occur while the keyboard is open to reflect size changes due to auto
+            // correction or orientation changes.
             
-            // Reset size and position if a deactivate effect was aborted while
-            // the close transition was playing. This allows the pop-up to open
-            // again later without any side effects from the aborted deactivate
-            // effect. See SDK-31534.
-            if (!isNaN(cachedYPosition))
-                this.y = cachedYPosition;
+            // As in the deactivate case, the move and resize effects should be
+            // delayed until the user can complete any mouse interaction. This
+            // allows the size and position of the pop-up to stay stable allowing
+            // events like a button press to complete normally.
             
-            // If explicit height wasn't used originally, then set height=NaN
-            // so that the next call to open() will re-measure.
-            if (softKeyboardEffectCachedHeightExplicit)
-                this.height = softKeyboardEffectCachedHeight;
+            if (isMouseDown)
+                setPendingSoftKeyboardEvent(event);
             else
-                this.height = NaN;
-            
-            if (!isNaN(cachedYPosition) || softKeyboardEffectCachedHeightExplicit)
-                effectCleanup();
-        }
-    }
-    
-    /**
-     *  @private
-     */
-    private function softKeyboardActivateHandler(event:SoftKeyboardEvent=null):void
-    {
-        var isFirstActivate:Boolean = false;
-        
-        // Save the original y-position and height if this is the first 
-        // ACTIVATE event and an existing deactivate effect is not already in
-        // progress.
-        if (!isSoftKeyboardEffectActive && !effect)
-        {
-            cachedYPosition = this.y;
-            setSoftKeyboardEffectCachedHeight(this.height);
-            
-            // Initialize softKeyboardEffectCachedHeightExplicit
-            explicitHeightChangedHandler();
-            
-            // reset cached keyboard height
-            cachedKeyboardHeight = 0;
-            
-            isFirstActivate = true;
-        }
-        
-        var smStage:Stage = systemManager.stage;
-        var softKeyboardRect:Rectangle = smStage.softKeyboardRect;
-        
-        // Do not update if the keyboard has no height or if the height
-        // is unchanged
-        if ((softKeyboardRect.height == 0) ||
-            (cachedKeyboardHeight == softKeyboardRect.height))
-            return;
-        
-        cachedKeyboardHeight = softKeyboardRect.height;
-        
-        var sandboxRoot:DisplayObject = systemManager.getSandboxRoot();
-        var scaleFactor:Number = 1;
-        
-        if (systemManager as SystemManager)
-            scaleFactor = SystemManager(systemManager).densityScale;
-        
-        // All calculations are done in stage coordinates and converted back to
-        // application coordinates when playing effects. Also note that
-        // softKeyboardRect is also in stage coordinates.
-        var popUpY:Number = this.y * scaleFactor;
-        var popUpHeight:Number = softKeyboardEffectCachedHeight * scaleFactor;
-        var overlapGlobal:Number = (popUpY + popUpHeight) - softKeyboardRect.y;
-        
-        var yToGlobal:Number = popUpY;
-        var heightToGlobal:Number = popUpHeight;
-        
-        if (overlapGlobal > 0)
-        {
-            // shift y-position up to remove offset overlap
-            if (moveForSoftKeyboard)
-                yToGlobal = Math.max((softKeyboardEffectMarginTop * scaleFactor), (popUpY - overlapGlobal));
-            
-            // adjust height based on new y-position
-            if (resizeForSoftKeyboard)
-            {
-                // compute new overlap
-                overlapGlobal = (yToGlobal + popUpHeight) - softKeyboardRect.y;
-                
-                // adjust height if there is overlap
-                if (overlapGlobal > 0)
-                    heightToGlobal = popUpHeight - overlapGlobal - (softKeyboardEffectMarginBottom * scaleFactor);
-            }
-        }
-        
-        // only play the effect if y-position or height changes
-        if ((yToGlobal != popUpY) || 
-            (heightToGlobal != popUpHeight))
-        {
-            // update state
-            _isSoftKeyboardEffectActive = true;
-            
-            // convert to application coordinates, move to pixel boundaries
-            var yToLocal:Number = Math.floor(yToGlobal / scaleFactor);
-            var heightToLocal:Number = Math.floor(heightToGlobal / scaleFactor);
-            
-            // preserve minimum height
-            heightToLocal = Math.max(heightToLocal, getMinBoundsHeight());
-            
-            if (!deactiveTriggersAdded)
-            {
-                // Listen for mouseDown event on the pop-up and delay the soft 
-                // keyboard deactivate effect. This allows button click events
-                // to complete normally before the button is re-positioned. 
-                // See SDK-31534.
-                addEventListener(MouseEvent.MOUSE_DOWN, mouseHandler);
-                
-                // Listen for mouseUp events anywhere to play the deactivate effect.
-                // See SDK-31534.
-                sandboxRoot.addEventListener(MouseEvent.MOUSE_UP, 
-                    mouseHandler, true /* useCapture */);
-                sandboxRoot.addEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE, 
-                    systemManager_mouseUpHandler);
-                
-                deactiveTriggersAdded = true;
-            }
-            
-            // Listen for orientationChanging and orientationChange to suspend
-            // soft keyboard effects until the change is complete. On iOS, an
-            // the keyboard is deactivated after orientationChanging, then
-            // immediately activated after orientationChange is complete.
-            if (isIOS && systemManager.isTopLevelRoot())
-            {
-                orientationHandlerAdded = true;
-                orientationChanging = false;
-                
-                smStage.addEventListener("orientationChanging", stage_orientationHandler);
-                smStage.addEventListener("orientationChange", stage_orientationHandler);
-            }
-
-            // Disable the effect and instead snap the pop-up position when 
-            // the keyboard size changes after the first activation. This 
-            // allows the StageText instance to stay active instead of being
-            // hidden by a bitmap proxy. This solves an issue on Android
-            // where a keyboard size change causes a pop-up resize, then the
-            // resize effect and subsequent bitmap proxy cause the keyboard
-            // size to revert, effectively killing auto correction.
-            // See SDK-31834.
-            prepareEffect(yToLocal, heightToLocal, !isFirstActivate);
-        }
-    }
-    
-    /**
-     *  @private
-     */
-    private function stage_orientationHandler(event:Event):void
-    {
-        orientationChanging = (event.type == "orientationChanging");
-    }
-    /**
-     *  @private
-     *  Listens for mouse events while the soft keyboard effect is active.
-     */
-    private function mouseHandler(event:MouseEvent):void
-    {
-        isMouseDown = (event.type == MouseEvent.MOUSE_DOWN);
-    }
-    
-    private function systemManager_mouseUpHandler(event:Event):void
-    {
-        isMouseDown = false;
-    }
-    
-    /**
-     *  @private
-     */
-    private function softKeyboardDeactivateHandler(event:SoftKeyboardEvent=null):void
-    {
-        // If the pop-up didn't move, do nothing. If we're in the middle of an
-        // orientation change, also do nothing.
-        if (!isSoftKeyboardEffectActive || orientationChanging)
+                updateSoftKeyboardEffect(true);
+        }
+    }
+    
+    /**
+     *  @private
+     */
+    private function stage_softKeyboardDeactivateHandler(event:SoftKeyboardEvent=null):void
+    {
+        // If the effect is not active (no move or resize was needed), do 
+        // nothing. If we're in the middle of an orientation change, also do 
+        // nothing.
+        if (!isSoftKeyboardEffectActive || softKeyboardEffectOrientationChanging)
             return;
         
         // Reset state
-        deactivateEffectIsPending = false;
+        softKeyboardEffectPendingEventType = null;
         
         if (event.triggerType == SoftKeyboardTrigger.USER_TRIGGERED)
         {
             // userTriggered indicates they keyboard was closed explicitly (soft
             // button on soft keyboard) or on Android, pressing the back button.
             // Play the deactivate effect immediately.
-            playDeactivateEffect(false);
+            updateSoftKeyboardEffect(false);
         }
         else // if (event.triggerType == SoftKeyboardTrigger.CONTENT_TRIGGERED)
         {
             // contentTriggered indicates focus was lost by tapping away from
-            // StageText or a programmatic call. Unfortunately, this 
+            // StageText or a programmatic call. Unfortunately, this
             // distinction isn't entirely intuitive. We only care about delaying
-            // the deactivate effect when due to a mouse event. Delaying the 
+            // the deactivate effect when due to a mouse event. Delaying the
             // effect allows the pop-up position and size to stay static until
             // any mouse interaction is complete (e.g. button click).
-            // However, the softKeyboardDeactivate event is fired before 
+            // However, the softKeyboardDeactivate event is fired before
             // the mouseDown event:
             //   deactivate -> mouseDown -> mouseUp
             
             // The approach here is to assume that a mouseDown was the trigger
             // for the softKeyboardDeactivate event. Continue to delay the
-            // deactivate effect until a mouseDown and mouseUp sequence is 
-            // received. In the event that the deactivation was due to a 
+            // deactivate effect until a mouseDown and mouseUp sequence is
+            // received. In the event that the deactivation was due to a
             // programmatic call, we'll stop this process after a specified
             // delay time.
             

        // We get called directly with null if there's no skin to listen to.
        if (event)
            event.target.removeEventListener(FlexEvent.STATE_CHANGE_COMPLETE, stateChangeComplete_handler);
        
        // Check for soft keyboard support
        var topLevelApp:Application = FlexGlobals.topLevelApplication as Application;
        var softKeyboardEffectEnabled:Boolean = (topLevelApp && Application.softKeyboardBehavior == "none");
        var smStage:Stage = systemManager.stage;
        
        if (isOpen)
        {
            dispatchEvent(new PopUpEvent(PopUpEvent.OPEN, false, false));
            
            if (softKeyboardEffectEnabled)
            {
                // Reset state
                _isSoftKeyboardEffectActive = false;
                
                if (smStage)
                {
                    // Install soft keyboard event handling on the stage
                    smStage.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, 
                        softKeyboardActivateHandler, true, EventPriority.DEFAULT, true);
                    smStage.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, 
                        softKeyboardDeactivateHandler, true, EventPriority.DEFAULT, true);
                    
                    // move and resize immediately if the soft keyboard is active
                    if (smStage.softKeyboardRect.height > 0)
                        softKeyboardActivateHandler();
                }
            }
        }

    //--------------------------------------------------------------------------

    /**
     *  Storage for the close event while waiting for the close transition to
     *  complete before dispatching it.
     *
     *  @private
     */
    private var closeEvent:PopUpEvent;

    /**
     *  Track whether the container is added to the PopUpManager.
     *
     *  @private
     */
    private var addedToPopUpManager:Boolean = false;
    
    //--------------------------------------------------------------------------
    //
    //  Soft Keyboard Effect Variables
    //
    //--------------------------------------------------------------------------

    /**
     *  @private
     *  The current soft keyboard effect instance. This field is only set in
     *  cases where the position and size are not snapped during (a) initial
     *  activation and (b) deactivation.
     */
    private var softKeyboardEffect:IEffect;

    /**
     *  @private
     *  Original pop-up y-position.
     */
    private var softKeyboardEffectCachedYPosition:Number;

    /**
     *  @private
     *  Indicates a soft keyboard event was received but the effect is delayed
     *  while waiting for a mouseDown and mouseUp event sequence.
     */
    private var softKeyboardEffectPendingEventType:String = null;

    /**
     *  @private
     *  Number of milliseconds to wait for a mouseDown and mouseUp event
     *  sequence before playing the deactivate effect.
     */
    mx_internal var softKeyboardEffectPendingEffectDelay:Number = 100;

    /**
     *  @private
     *  Timer used for awaiting a mouseDown event after a pending soft keyboard
     *  effect.
     */
    private var softKeyboardEffectPendingEventTimer:Timer;

    /**
     *  @private
     *  Flag when orientationChanging is dispatched and orientationChange has
     *  not been received.
     */
    private var softKeyboardEffectOrientationChanging:Boolean = false;

    /**
     *  @private
     *  Flag when orientation change handlers are installed to suppress
     *  excess soft keyboard effects during orientation change on iOS.
     */
    private var softKeyboardEffectOrientationHandlerAdded:Boolean = false;
    
    /**
     *  @private
     *  Flag when mouse and orientation listeners are installed before
     *  the soft keyboard activate effect is played.
     */
    private var softKeyboardStateChangeListenersInstalled:Boolean;
    
    /**
     *  @private
     *  Flag when resize listers are installed after ACTIVATE and uninstalled
     *  just before DEACTIVATE.
     */
    private var resizeListenerInstalled:Boolean = false;

    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    //  isOpen
    //----------------------------------

    /**
     *  Storage for the isOpen property.
     *
     *  @private
     */
    private var _isOpen:Boolean = false;

    [Inspectable(category="General", defaultValue="false")]

    /**
     *  Contains <code>true</code> when the container is open and is currently showing as a pop-up.
     *
     *  @see #open
     *  @see #close
     *
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 2.5
