flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bigosma...@apache.org
Subject [26/47] git commit: [flex-sdk] [refs/heads/develop] - StageTextInput and StageTextArea skins. Contributed by Aaron Nash. Details here: https://issues.apache.org/jira/browse/FLEX-34395
Date Sun, 17 Aug 2014 08:24:25 GMT
StageTextInput and StageTextArea skins. Contributed by Aaron Nash.  Details here: https://issues.apache.org/jira/browse/FLEX-34395


Project: http://git-wip-us.apache.org/repos/asf/flex-sdk/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-sdk/commit/75236aa8
Tree: http://git-wip-us.apache.org/repos/asf/flex-sdk/tree/75236aa8
Diff: http://git-wip-us.apache.org/repos/asf/flex-sdk/diff/75236aa8

Branch: refs/heads/develop
Commit: 75236aa867f3962452d1a4497923b5b653372cb5
Parents: 4eec881
Author: Om <bigosmallm@gmail.com>
Authored: Wed Jul 2 16:52:14 2014 -0700
Committer: Om <bigosmallm@gmail.com>
Committed: Wed Jul 2 16:52:14 2014 -0700

----------------------------------------------------------------------
 .../projects/mobiletheme/src/android4x.css      |  28 +
 .../spark/skins/android4/StageTextAreaSkin.as   | 190 ++++
 .../spark/skins/android4/StageTextInputSkin.as  | 134 +++
 .../src/spark/skins/android4/TextAreaSkin.as    | 892 +++++++++++++++++++
 .../src/spark/skins/android4/TextInputSkin.as   | 376 ++++++++
 .../src/spark/skins/android4/TextSkinBase.as    | 212 +++++
 .../supportClasses/StageTextSkinBase.as         | 402 +++++++++
 7 files changed, 2234 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/75236aa8/frameworks/projects/mobiletheme/src/android4x.css
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/android4x.css b/frameworks/projects/mobiletheme/src/android4x.css
index 956a78c..02511c1 100644
--- a/frameworks/projects/mobiletheme/src/android4x.css
+++ b/frameworks/projects/mobiletheme/src/android4x.css
@@ -192,6 +192,34 @@ TabbedViewNavigator #tabBar
 	textShadowColor: #000000;
 }
 
+TextInput
+{ 
+	skinClass: ClassReference("spark.skins.android4.StageTextInputSkin");
+	contentBackgroundAlpha: 0; 
+	focusColor: #33B5E5;
+	borderColor: #4e4e4e;
+	contentBackgroundColor: #DEDEDD;
+	contentBackgroundBorder: "flat";
+	fontFamily: RobotoRegular;
+	selectionHighlighting: "never";
+	focusEnabled:"false";
+	focusThickness: 0;
+}
+
+TextArea
+{ 
+	skinClass: ClassReference("spark.skins.android4.StageTextAreaSkin");
+	contentBackgroundAlpha: 1;
+	contentBackgroundBorder: "rectangle";
+	contentBackgroundColor: #DEDEDD;
+	focusColor: #33B5E5;
+	fontFamily: RobotoRegular;
+	borderColor: #4e4e4e;
+	selectionHighlighting: "never";
+	focusEnabled:"false";
+	focusThickness: 0;
+} 
+
 ToggleSwitch
 {
 	accentColor: #3F7FBA;

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/75236aa8/frameworks/projects/mobiletheme/src/spark/skins/android4/StageTextAreaSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/android4/StageTextAreaSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/android4/StageTextAreaSkin.as
new file mode 100644
index 0000000..d48377d
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/android4/StageTextAreaSkin.as
@@ -0,0 +1,190 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.skins.android4
+{
+	
+	import mx.core.DPIClassification;
+	import mx.core.mx_internal;
+	
+	import spark.components.TextArea;
+	import spark.components.supportClasses.IStyleableEditableText;
+	import spark.components.supportClasses.ScrollableStageText;
+	import spark.components.supportClasses.StyleableTextField;
+	import spark.skins.android4.supportClasses.StageTextSkinBase;
+	
+	use namespace mx_internal;
+	
+	/**
+	 *  ActionScript-based skin for TextArea controls in mobile applications that uses a
+	 *  StyleableStageText class for the text display. 
+	 * 
+	 *  @see spark.components.TextArea
+	 *  @see spark.components.supportClasses.StyleableStageText
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion AIR 3.0 
+	 *  @productversion Flex 4.6
+	 */
+	public class StageTextAreaSkin extends StageTextSkinBase
+	{
+		//--------------------------------------------------------------------------
+		//
+		//  Class variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  The underlying native text control on iOS has internal margins of its
+		 *  own. In order to remain faithful to the paddingTop and paddingBottom
+		 *  style values that developers may specify, those internal margins need to
+		 *  be compensated for. This variable contains size of that compensation in
+		 *  pixels.
+		 */
+		mx_internal static var iOSVerticalPaddingAdjustment:Number = 5;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3.0
+		 *  @productversion Flex 4.6
+		 */
+		public function StageTextAreaSkin()
+		{
+			super();
+			multiline = true;
+			
+			switch (applicationDPI)
+			{
+				case DPIClassification.DPI_640:
+				{
+					measuredDefaultHeight = 212;
+					break;
+				}
+				case DPIClassification.DPI_480:
+				{
+					measuredDefaultHeight = 140;
+					break;
+				}
+				case DPIClassification.DPI_320:
+				{
+					measuredDefaultHeight = 106;
+					break;
+				}
+				case DPIClassification.DPI_240:
+				{
+					measuredDefaultHeight = 70;
+					break;
+				}
+				case DPIClassification.DPI_120:
+				{
+					measuredDefaultHeight = 35;
+					break;
+				}
+				default:
+				{
+					measuredDefaultHeight = 48;
+					break;
+				}
+			}
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/** 
+		 *  @copy spark.skins.spark.ApplicationSkin#hostComponent
+		 */
+		public var hostComponent:TextArea;  // SkinnableComponent will populate
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		override protected function measure():void
+		{
+			super.measure();
+			measureTextComponent(hostComponent);
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function layoutContents(unscaledWidth:Number, 
+												   unscaledHeight:Number):void
+		{
+			// base class handles border position & size
+			super.layoutContents(unscaledWidth, unscaledHeight);
+			
+			// position & size the text
+			var paddingLeft:Number = getStyle("paddingLeft");
+			var paddingRight:Number = getStyle("paddingRight");
+			var paddingTop:Number = getStyle("paddingTop");
+			var paddingBottom:Number = getStyle("paddingBottom");
+			
+			var unscaledTextWidth:Number = Math.max(0, unscaledWidth - paddingLeft - paddingRight);
+			var unscaledTextHeight:Number = Math.max(0, unscaledHeight - paddingTop - paddingBottom);
+			
+			if (textDisplay)
+			{
+				var verticalPosAdjustment:Number = 0;
+				var heightAdjustment:Number = 0;
+				
+				/*   if (Platform.isIOS)
+				{
+				verticalPosAdjustment = Math.min(iOSVerticalPaddingAdjustment, paddingTop);
+				heightAdjustment = verticalPosAdjustment + Math.min(iOSVerticalPaddingAdjustment, paddingBottom);
+				}*/
+				
+				textDisplay.commitStyles();
+				setElementSize(textDisplay, unscaledTextWidth, unscaledTextHeight + heightAdjustment);
+				setElementPosition(textDisplay, paddingLeft, paddingTop - verticalPosAdjustment);
+			}
+			
+			if (promptDisplay)
+			{
+				if (promptDisplay is StyleableTextField)
+					StyleableTextField(promptDisplay).commitStyles();
+				
+				setElementSize(promptDisplay, unscaledTextWidth, unscaledTextHeight);
+				setElementPosition(promptDisplay, paddingLeft, paddingTop);
+			}
+		}
+		
+		override protected function createTextDisplay():IStyleableEditableText
+		{
+			return new ScrollableStageText(multiline);
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/75236aa8/frameworks/projects/mobiletheme/src/spark/skins/android4/StageTextInputSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/android4/StageTextInputSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/android4/StageTextInputSkin.as
new file mode 100644
index 0000000..7f92647
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/android4/StageTextInputSkin.as
@@ -0,0 +1,134 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.skins.android4
+{
+	import spark.components.TextInput;
+	import spark.components.supportClasses.IStyleableEditableText;
+	import spark.components.supportClasses.ScrollableStageText;
+	import spark.components.supportClasses.StyleableTextField;
+	import spark.skins.android4.supportClasses.StageTextSkinBase;
+	
+	/**
+	 *  ActionScript-based skin for TextInput controls in mobile applications that uses a
+	 *  StyleableStageText class for the text input. 
+	 * 
+	 *  @see spark.components.TextInput
+	 *  @see spark.components.supportClasses.StyleableStageText
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion AIR 3.0 
+	 *  @productversion Flex 4.6
+	 */
+	public class StageTextInputSkin extends StageTextSkinBase
+	{
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3.0
+		 *  @productversion Flex 4.6
+		 */
+		public function StageTextInputSkin()
+		{
+			super();
+			multiline = false;
+		}    
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/** 
+		 *  @copy spark.skins.spark.ApplicationSkin#hostComponent
+		 */
+		public var hostComponent:TextInput;  // SkinnableComponent will populate
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */	
+		override protected function measure():void
+		{
+			super.measure();
+			measureTextComponent(hostComponent);
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function layoutContents(unscaledWidth:Number, 
+												   unscaledHeight:Number):void
+		{
+			// base class handles border position & size
+			super.layoutContents(unscaledWidth, unscaledHeight);
+			
+			// position & size the text
+			var paddingLeft:Number = getStyle("paddingLeft");
+			var paddingRight:Number = getStyle("paddingRight");
+			var paddingTop:Number = getStyle("paddingTop");
+			var paddingBottom:Number = getStyle("paddingBottom");
+			
+			var unscaledTextWidth:Number = Math.max(0, unscaledWidth - paddingLeft - paddingRight);
+			var unscaledTextHeight:Number = Math.max(0, unscaledHeight - paddingTop - paddingBottom);
+			
+			// default vertical positioning is centered
+			var textHeight:Number = getElementPreferredHeight(textDisplay);
+			var textY:Number = Math.round(0.5 * (unscaledTextHeight - textHeight)) + paddingTop;
+			
+			if (textDisplay)
+			{
+				textDisplay.commitStyles();
+				setElementSize(textDisplay, unscaledTextWidth, unscaledTextHeight);
+				setElementPosition(textDisplay, paddingLeft, textY);
+			}
+			
+			if (promptDisplay)
+			{
+				if (promptDisplay is StyleableTextField)
+					StyleableTextField(promptDisplay).commitStyles();
+				
+				var promptHeight:Number = getElementPreferredHeight(promptDisplay);
+				var promptY:Number = Math.round(0.5 * (unscaledTextHeight - promptHeight)) + paddingTop;
+				
+				setElementSize(promptDisplay, unscaledTextWidth, promptHeight);
+				setElementPosition(promptDisplay, paddingLeft, promptY);
+			}
+		}
+		
+		override protected function createTextDisplay():IStyleableEditableText
+		{
+			return new ScrollableStageText(multiline);
+		}
+		
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/75236aa8/frameworks/projects/mobiletheme/src/spark/skins/android4/TextAreaSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/android4/TextAreaSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/android4/TextAreaSkin.as
new file mode 100644
index 0000000..0c231a6
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/android4/TextAreaSkin.as
@@ -0,0 +1,892 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.skins.android4
+{
+
+import flash.events.Event;
+import flash.events.FocusEvent;
+import flash.events.KeyboardEvent;
+import flash.events.MouseEvent;
+import flash.events.SoftKeyboardEvent;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+import flash.system.Capabilities;
+import flash.text.TextLineMetrics;
+import flash.ui.Keyboard;
+
+import mx.core.DPIClassification;
+import mx.core.EventPriority;
+import mx.core.FlexGlobals;
+import mx.core.mx_internal;
+import mx.events.FlexEvent;
+import mx.utils.Platform;
+
+import spark.components.Group;
+import spark.components.Scroller;
+import spark.components.TextArea;
+import spark.components.supportClasses.StyleableTextField;
+import spark.events.CaretBoundsChangeEvent;
+import spark.skins.android4.supportClasses.TextSkinBase;
+
+use namespace mx_internal;
+
+/**
+ *  ActionScript-based skin for TextArea components in mobile applications.
+ * 
+ * @see spark.components.TextArea
+ * 
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.5 
+ *  @productversion Flex 4.5
+ */
+public class TextAreaSkin extends TextSkinBase 
+{
+    /**
+     *  @private
+     *  Right-margin of iOS native text control when editing on a retina display
+     *  based on fontSize 32.
+     */
+    mx_internal static var IOS_RIGHT_MARGIN_320:Number = 19;
+    
+    /**
+     *  @private
+     *  Right-margin of iOS native text control when editing on a retina display
+     *  based on fontSize 16 scaling from applicationDPI 160.
+     */
+    mx_internal static var IOS_RIGHT_MARGIN_160_SCALED_TO_320:Number = 9.4;
+    
+    /**
+     *  @private
+     *  Right-margin of iOS native text control when editing on a standard display
+     *  based on fontSize 16 and runtimeDPI 160.
+     */
+    mx_internal static var IOS_RIGHT_MARGIN_160:Number = 20.6;
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  Constructor.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5
+     *  @productversion Flex 4.5
+     */
+    public function TextAreaSkin()
+    {
+        super();
+        
+        addEventListener(Event.RESIZE, resizeHandler);
+        
+        switch (applicationDPI)
+        {
+			case DPIClassification.DPI_640:
+			{
+				measuredDefaultWidth = 1024;
+				measuredDefaultHeight = 212;
+				layoutBorderSize = 4;
+				flatheight = 9;
+				break;
+			}
+			case DPIClassification.DPI_480:
+			{
+				measuredDefaultWidth = 880;
+				measuredDefaultHeight = 140;
+				layoutBorderSize = 3;
+				flatheight = 7;	
+				break;
+			}
+            case DPIClassification.DPI_320:
+            {
+                measuredDefaultWidth = 612;
+                measuredDefaultHeight = 106;
+				layoutBorderSize = 2;
+				flatheight = 6;		
+                break;
+            }
+			case DPIClassification.DPI_240:
+			{
+				measuredDefaultWidth = 440;
+				measuredDefaultHeight = 70;
+				layoutBorderSize = 2;
+				flatheight = 5;
+				break;
+			}
+			case DPIClassification.DPI_120:
+			{
+				measuredDefaultWidth = 220;
+				measuredDefaultHeight = 35;
+				layoutBorderSize = 1;
+				flatheight = 2;
+				break;
+			}
+            default:
+            {
+                measuredDefaultWidth = 306;
+                measuredDefaultHeight = 53;
+				layoutBorderSize = 1;
+				flatheight = 3; 
+                break;
+            }
+        }
+		addEventListener(FocusEvent.FOCUS_IN, focusChangeHandler);
+		addEventListener(FocusEvent.FOCUS_OUT, focusChangeHandler);
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Skin parts
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  Scroller skin part.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5 
+     *  @productversion Flex 4.5
+     */ 
+    public var scroller:Scroller;
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------
+    
+    /** 
+     *  @copy spark.skins.spark.ApplicationSkin#hostComponent
+     */
+    public var hostComponent:TextArea;
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Variables
+    //
+    //--------------------------------------------------------------------------
+	
+	protected var isFocused:Boolean = false;
+	
+	protected var flatheight:uint;
+	
+    /**
+     *  @private
+     *  The width of the component on the previous layout manager 
+     *  pass.  This gets set in updateDisplayList() and used in measure() on 
+     *  the next layout pass.  This is so our "guessed width" in measure() 
+     *  will be as accurate as possible since textDisplay is multiline and 
+     *  the textDisplay height is dependent on the width.
+     * 
+     *  In the constructor this is actually set based on the DPI.
+     */
+    mx_internal var oldUnscaledWidth:Number;
+    
+    private var textDisplayGroup:Group;
+    private var _isIOS:Boolean;
+    private var invalidateCaretPosition:Boolean = true;
+    private var oldCaretBounds:Rectangle = new Rectangle(-1, -1, -1, -1);
+    private var lastTextHeight:Number;
+    private var lastTextWidth:Number;
+    
+    private var isTextDisplayTall:Boolean = true;
+    private var growTextDisplay:Boolean = false;
+    private var shrinkTextDisplay:Boolean = false;
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden methods
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+    override protected function createChildren():void
+    {
+        if (!textDisplay)
+        {
+            // wrap StyleableTextField in UIComponent
+            textDisplay = StyleableTextField(createInFontContext(StyleableTextField));
+            textDisplay.styleName = this;
+            textDisplay.multiline = true;
+            textDisplay.editable = true;
+            textDisplay.lineBreak = getStyle("lineBreak");
+            textDisplay.useTightTextBounds = false;
+            textDisplay.scrollToRangeDelegate = scrollToRange;
+            
+            // on iOS, resize the TextField and let the native control handle scrolling
+            _isIOS = Platform.isIOS;
+            
+            if (_isIOS)
+            {
+                // hard-coded rightMargin for iOS native text control
+                // this value is independent of the paddingRight style
+                var rightMargin:Number = 0;
+                var isRetina:Boolean = false;
+                var isScaling160to320:Boolean = false;
+                
+                // check for scaling
+                if ("runtimeDPI" in FlexGlobals.topLevelApplication)
+                {
+                    var runtimeDPI:Number = FlexGlobals.topLevelApplication.runtimeDPI as Number;
+                    isRetina = (runtimeDPI == DPIClassification.DPI_320);
+                    isScaling160to320 = isRetina
+                        && (applicationDPI == DPIClassification.DPI_160);
+                }
+                
+                if (isRetina && !isScaling160to320)
+                    rightMargin = IOS_RIGHT_MARGIN_320;
+                else if (isRetina && isScaling160to320)
+                    rightMargin = IOS_RIGHT_MARGIN_160_SCALED_TO_320;
+                else
+                    rightMargin = IOS_RIGHT_MARGIN_160;
+                
+                textDisplay.rightMargin = rightMargin;
+            }
+            else
+            {
+                textDisplay.addEventListener(KeyboardEvent.KEY_DOWN, textDisplay_keyHandler);
+            }
+            
+            textDisplay.addEventListener(Event.CHANGE, textDisplay_changeHandler);
+            textDisplay.addEventListener(FlexEvent.VALUE_COMMIT, textDisplay_changeHandler);
+            textDisplay.addEventListener(Event.SCROLL, textDisplay_scrollHandler);
+            // Use a lower priority so that the StyleableTextField event handler is called first. 
+            // That handler cancels the event and we need to check for that case
+            textDisplay.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATING, textDisplay_softKeyboardActivatingHandler, false, EventPriority.DEFAULT_HANDLER);
+            textDisplay.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, textDisplay_softKeyboardActivateHandler);
+            textDisplay.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, textDisplay_softKeyboardDeactivateHandler);
+            
+            textDisplay.left = getStyle("paddingLeft");
+            textDisplay.top = getStyle("paddingTop");
+            textDisplay.right = getStyle("paddingRight");
+            textDisplay.bottom = getStyle("paddingBottom");
+            
+            // wrap StyleableTextComponent in Group for viewport
+            textDisplayGroup = new Group();
+            textDisplayGroup.clipAndEnableScrolling = true;
+            textDisplayGroup.addElement(textDisplay);
+        }
+        
+        if (!scroller)
+        {
+            scroller = new Scroller();
+            scroller.minViewportInset = 0;
+            scroller.measuredSizeIncludesScrollBars = false;
+            scroller.ensureElementIsVisibleForSoftKeyboard = false;
+            
+            addChild(scroller);
+        }
+        
+        if (!scroller.viewport)
+            scroller.viewport = textDisplayGroup;
+        
+        super.createChildren();
+    }
+    
+    /**
+     *  @private
+     *  TextArea prompt supports wrapping and multiline
+     */
+    override protected function createPromptDisplay():StyleableTextField
+    {
+        var prompt:StyleableTextField = super.createPromptDisplay();
+        prompt.editable = true;
+        prompt.wordWrap = true;
+        
+        return prompt;
+    }
+    
+    /**
+     *  @private
+     */
+    override protected function measure():void
+    {
+        super.measure();
+        
+        var paddingTop:Number = getStyle("paddingTop");
+        var paddingBottom:Number = getStyle("paddingBottom");
+        var paddingLeft:Number = getStyle("paddingLeft");
+        var paddingRight:Number = getStyle("paddingRight");
+        
+        // TextDisplay always defaults to 440 pixels wide (the value is DPI dependent), 
+        // and tall enough to show all text.
+        // 
+        // You can set an explicit width and the height will adjust accordingly. The opposite
+        // is not true: setting an explicit height will not adjust the width accordingly.
+        
+        measuredWidth = measuredDefaultWidth;
+        
+        // now we need to measure textDisplay's height.  Unfortunately, this is tricky and 
+        // is dependent on textDisplay's width.  Let's use the heuristic that our width 
+        // is the same as our last width.
+        // We don't use layoutMeasuredWidth, because that value is just a constant and doesn't
+        // take into account the fact that the TextArea could have an explicitWidth or could 
+        // be constrained by some value.  However, we still default oldTextDisplayWidth to 
+        // be layoutMeasuredWidth the first time through.
+        var textDisplayEstimatedWidth:Number = oldUnscaledWidth - paddingLeft - paddingRight;
+        
+        // now we need to measure textDisplay's height.  Unfortunately, this is tricky and 
+        // is dependent on textDisplay's width.  
+        // Use the old textDisplay width as an estimte for the new one.  
+        // If we are wrong, we'll find out in updateDisplayList()
+        textDisplay.commitStyles();
+        
+        // Clear min sizes first.
+        textDisplay.minWidth = textDisplay.minHeight = NaN;
+        
+        // If lineBreak == explicit, always use NaN for estimated width
+        if (getStyle("lineBreak") == "explicit")
+            textDisplayEstimatedWidth = NaN;
+        
+        setElementSize(textDisplay, textDisplayEstimatedWidth, NaN);
+        
+        measuredHeight = getElementPreferredHeight(textDisplay) + paddingTop + paddingBottom;
+    }
+    
+    /**
+     *  @private
+     */
+    override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+        super.layoutContents(unscaledWidth, unscaledHeight);
+        
+        // position & size border
+        if (border)
+        {
+            setElementSize(border, unscaledWidth, unscaledHeight);
+            setElementPosition(border, 0, 0);
+        }
+        
+        setElementSize(scroller, unscaledWidth, unscaledHeight);
+        setElementPosition(scroller, 0, 0);
+        
+        // position & size the text
+        var explicitLineBreak:Boolean = getStyle("lineBreak") == "explicit";
+        var paddingLeft:Number = getStyle("paddingLeft");
+        var paddingRight:Number = getStyle("paddingRight");
+        var paddingTop:Number = getStyle("paddingTop");
+        var paddingBottom:Number = getStyle("paddingBottom");
+        
+        var unscaledTextWidth:Number = unscaledWidth - paddingLeft - paddingRight;
+        var unscaledTextHeight:Number = unscaledHeight - paddingTop - paddingBottom;
+        var textHeight:Number;
+        var textWidth:Number = explicitLineBreak ? textDisplay.measuredTextSize.x : unscaledTextWidth;
+        
+        var lineIndex:int;
+        var topCharIndex:int;
+        var charBounds:Rectangle;
+        
+        // grab old measured textDisplay height before resizing it
+        var oldPreferredTextHeight:Number = getElementPreferredHeight(textDisplay);
+        
+        // set width first to measure height correctly
+        textDisplay.commitStyles();
+        textDisplay.setLayoutBoundsSize(textWidth, NaN);
+        
+        // In iOS, when we go into editing mode, the runtime overlays a native 
+        // text control over the textDisplay. In order to prevent the text 
+        // from overflowing the component and to get scrolling support, the 
+        // native text control must be the same size as the TextArea
+        if (_isIOS)
+        {
+            if (shrinkTextDisplay)
+            {
+                // Switching to edit mode. Convert from viewport scrolling to 
+                // TextField scrolling
+                var vsp:Number = textDisplayGroup.verticalScrollPosition;
+                            
+                var lineMetrics:TextLineMetrics = textDisplay.getLineMetrics(0);
+                var lineHeight:Number = lineMetrics.ascent + lineMetrics.descent;
+                
+                // TODO Figure out how to get the x offset. Right now is hard coded to 2
+                // At least half the line should be showing before we scroll to that line
+                // This makes the conversion from pixel to line based scrolling a little less jumpy
+                lineIndex = textDisplay.getLineIndexAtPoint(2, vsp + lineHeight / 2) + 1;
+                textDisplayGroup.verticalScrollPosition = 0;
+                isTextDisplayTall = false;
+                //trace("TAS.layoutContents shrinkText vsp",vsp,"lineIndex",lineIndex);
+            }
+            
+            else if (growTextDisplay)
+            {
+                // Leaving edit mode. Convert from TextField scrolling to 
+                // viewport scrolling
+                var scrollV:Number = textDisplay.scrollV;
+                
+                // TODO (jszeto) investigate using lineMetrics.lineHeight * scrollV instead of getCharBoundaries
+                topCharIndex = textDisplay.getLineOffset(scrollV - 1);
+                charBounds = textDisplay.getCharBoundaries(topCharIndex);
+                // If the charBounds is null, just set vsp to 0
+                if (charBounds == null)
+                    charBounds = new Rectangle(0, 0, 0, 0);
+                textDisplay.scrollV = 1;
+                isTextDisplayTall = true;
+                //trace("TAS.layoutContents growText scrollV",scrollV,"topCharIndex",topCharIndex,"charBounds",charBounds);
+            }
+        }
+        
+        // TextField height should match its content or the TextArea bounds at minimum
+        // iOS special case to prevent Flex Scroller scrolling when editable
+        if (isTextDisplayTall)
+            textHeight = Math.max(textDisplay.measuredTextSize.y, unscaledTextHeight);
+        else
+            textHeight = unscaledTextHeight;
+        
+        // FIXME (jasonsj): iOS native scroll bar appears even when explictHeight
+        //                  is not specified. Focus-in is jumpy.
+        
+        if (promptDisplay)
+        {
+            promptDisplay.commitStyles();
+            setElementSize(promptDisplay, unscaledTextWidth, textHeight);
+            setElementPosition(promptDisplay, paddingLeft, paddingTop);
+            
+            // no need to update textDisplay if promptDisplay is present
+            return;
+        }
+        
+        // keep track of oldUnscaledWidth so we have a good guess as to the width 
+        // of the textDisplay on the next measure() pass
+        oldUnscaledWidth = unscaledWidth;
+        
+        // set the width of textDisplay to textWidth.
+        // set the height to oldTextHeight.  If the height's actually wrong, 
+        // we'll invalidateSize() and go through this layout pass again anyways
+        setElementSize(textDisplay, textWidth, textHeight);
+        
+        // Set minWidth/Height on the text so the textDisplayGroup sizes accordingly
+        textDisplay.minWidth = textWidth;
+        textDisplay.minHeight = textHeight;
+        textDisplayGroup.invalidateDisplayList();
+        
+        // grab new measured textDisplay height after the textDisplay has taken its final width
+        var newPreferredTextHeight:Number = getElementPreferredHeight(textDisplay);
+        
+        // if the resize caused the textDisplay's height to change (because of 
+        // text reflow), then we need to remeasure ourselves with our new width
+        if (oldPreferredTextHeight != newPreferredTextHeight)
+            invalidateSize();
+        
+        if (_isIOS)
+        {
+            if (shrinkTextDisplay)
+            {
+                scroller.validateNow();
+                textDisplay.scrollV = lineIndex;
+            }
+            else if (growTextDisplay)
+            {
+                scroller.validateNow();
+                textDisplayGroup.verticalScrollPosition = charBounds.y;
+            }               
+            
+            shrinkTextDisplay = false;
+            growTextDisplay = false;
+        }
+        
+        //trace("TAS.layoutContents tH",textHeight,"tW",textWidth,"invalidateCaret",invalidateCaretPosition);
+        
+        // checking if text fits in TextArea
+        // does not apply to iOS due to native text editing and scrolling
+        // invalidateCaretPosition will never be true for iOS
+        if (invalidateCaretPosition && isTextDisplayTall)
+        {
+            // if the caret is outside the viewport, update the Group verticalScrollPosition
+            var charIndex:int = textDisplay.selectionBeginIndex;
+            var caretBounds:Rectangle = textDisplay.getCharBoundaries(charIndex);
+            lineIndex = textDisplay.getLineIndexOfChar(charIndex);
+            
+            // getCharBoundaries() returns null for new lines
+            if (!caretBounds)
+            {
+                // temporarily insert a character at the caretIndex
+                textDisplay.replaceText(charIndex, charIndex, "W");
+                caretBounds = textDisplay.getCharBoundaries(charIndex);
+                lineIndex = textDisplay.getLineIndexOfChar(charIndex);
+                textDisplay.replaceText(charIndex, charIndex + 1, "");   
+            }
+           
+            if (caretBounds)
+            {
+                // Scroll the internal Scroller to ensure the caret is visible
+                if (textHeight > unscaledTextHeight)
+                {
+                    
+                    if (charIndex == textDisplay.text.length)
+                    {
+                        // Make sure textDisplayGroup is validated, otherwise the 
+                        // verticalScrollPosition may be out of bounds, which will
+                        // cause a bounce effect.
+                        textDisplayGroup.validateNow();
+                        textDisplayGroup.verticalScrollPosition = textHeight;
+                    }
+                    else
+                    {
+                        // caretTopPositon and caretBottomPosition are TextField-relative positions
+                        // the TextField is inset by padding styles of the TextArea (via the VGroup)
+                        
+                        // adjust top position to 0 when on the first line
+                        // caretTopPosition will be negative when off stage
+                        var caretTopPosition:Number = ((caretBounds.y) < 0 || (lineIndex == 0))
+                            ? 0 : caretBounds.y;
+                        
+                        // caretBottomPosition is the y coordinate of the bottom bounds of the caret
+                        var caretBottomPosition:Number = caretBounds.y + caretBounds.height;
+                        
+                        // note that verticalScrollPosition min/max do not account for padding
+                        var vspTop:Number = textDisplayGroup.verticalScrollPosition;
+                        
+                        // vspBottom should be the max visible Y in the TextField
+                        // coordinate space.
+                        // remove paddingBottom for some clearance between caret and border
+                        var vspBottom:Number = vspTop + unscaledHeight - paddingTop - paddingBottom;
+                        
+                        // is the caret in or below the padding and viewport?
+                        if (caretBottomPosition > vspBottom)
+                        {
+                            // adjust caretBottomPosition to max scroll position when on the last line
+                            if (lineIndex + 1 == textDisplay.numLines)
+                            {
+                                // use textHeight+paddings instead of textDisplayGroup.contentHeight
+                                // Group has not been resized by this point
+                                textDisplayGroup.verticalScrollPosition = (textHeight + paddingTop + paddingBottom) - textDisplayGroup.height;
+                            }
+                            else
+                            {
+                                // bottom edge of the caret moves just inside the bottom edge of the scroller
+                                // add delta between caret and vspBottom
+                                textDisplayGroup.verticalScrollPosition = vspTop + (caretBottomPosition - vspBottom);
+                            }
+                        }
+                            // is the caret above the viewport?
+                        else if (caretTopPosition < vspTop)
+                        {
+                            // top edge of the caret moves inside the top edge of the scroller
+                            textDisplayGroup.verticalScrollPosition = caretTopPosition;
+                        }
+                    }
+                    
+                    scroller.validateNow();
+                }
+                
+                // Convert to local coordinates
+                // Dispatch an event for an ancestor Scroller
+                // It will scroll the TextArea so the caret is in view
+                convertBoundsToLocal(caretBounds);
+                if (oldCaretBounds == null || caretBounds.bottom != oldCaretBounds.bottom || caretBounds.top != oldCaretBounds.top)
+                {
+                    //trace("TAS.layoutContents send caret CHANGE");
+                    dispatchEvent(new CaretBoundsChangeEvent(CaretBoundsChangeEvent.CARET_BOUNDS_CHANGE,true,true,oldCaretBounds,caretBounds));
+                }
+                
+                oldCaretBounds = caretBounds;   
+            }
+
+            invalidateCaretPosition = false;
+        }
+        
+        // Make sure final scroll position is valid
+        if (isTextDisplayTall)
+            snapTextScrollPosition();
+    }
+    
+	override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+	{
+		super.drawBackground(unscaledWidth, unscaledHeight);
+		
+		var contentBackgroundColor:uint = getStyle("contentBackgroundColor");
+		var contentBackgroundAlpha:Number = getStyle("contentBackgroundAlpha");	
+		//change border color and thickness when in focus
+		var borderColor:uint = isFocused ? getStyle("focusColor") : getStyle("borderColor");
+		var selectWidth:uint = isFocused ? layoutBorderSize + 1 : layoutBorderSize;
+		if (isNaN(contentBackgroundAlpha))
+		{
+			contentBackgroundAlpha = 1;
+		}        
+		if (getStyle("contentBackgroundBorder") == "flat")
+		{		
+			var halfGap:int = flatheight * 2;
+			//background
+			graphics.beginFill(contentBackgroundColor, contentBackgroundAlpha);
+			graphics.drawRect(0, 0, unscaledWidth, unscaledHeight - flatheight);
+			graphics.endFill();
+			//begin flat border
+			graphics.beginFill(borderColor, 1);
+			//left half border
+			graphics.drawRect(0, unscaledHeight - halfGap, selectWidth, flatheight );
+			//bottom border
+			graphics.drawRect(0, unscaledHeight - flatheight, unscaledWidth, selectWidth);
+			//right border
+			graphics.drawRect(unscaledWidth - selectWidth, unscaledHeight - halfGap, selectWidth, flatheight);
+			graphics.endFill();
+		}
+		else if (getStyle("contentBackgroundBorder") == "rectangle")
+		{
+			var borderWidth:uint = layoutBorderSize * 2;
+			//rectangle border and background
+			graphics.lineStyle(selectWidth, borderColor, 1);
+			graphics.beginFill(contentBackgroundColor, contentBackgroundAlpha);
+			graphics.drawRect(layoutBorderSize, layoutBorderSize, unscaledWidth - borderWidth, unscaledHeight - borderWidth);
+			graphics.endFill();
+		}
+	}
+	
+    /**
+     *  @private
+     *  Make sure the scroll positions are valid, and adjust if needed.
+     */
+    private function snapTextScrollPosition():void
+    {
+        var maxHsp:Number = textDisplayGroup.contentWidth > textDisplayGroup.width ? 
+            textDisplayGroup.contentWidth-textDisplayGroup.width : 0; 
+        textDisplayGroup.horizontalScrollPosition = 
+            Math.min(Math.max(0,textDisplayGroup.horizontalScrollPosition),maxHsp);
+        
+        var maxVsp:Number = textDisplayGroup.contentHeight > textDisplayGroup.height ? 
+            textDisplayGroup.contentHeight-textDisplayGroup.height : 0; 
+        
+        textDisplayGroup.verticalScrollPosition = 
+            Math.min(Math.max(0,textDisplayGroup.verticalScrollPosition),maxVsp);
+    }
+    
+    /**
+     *  @private
+     *  Get the bounds of the caret
+     */    
+    private function getCaretBounds():Rectangle
+    {
+        var charIndex:int = textDisplay.selectionBeginIndex;
+        var caretBounds:Rectangle = textDisplay.getCharBoundaries(charIndex);
+        
+        if (!caretBounds)
+        {
+            textDisplay.replaceText(charIndex, charIndex, "W");
+            caretBounds = textDisplay.getCharBoundaries(charIndex);
+            textDisplay.replaceText(charIndex, charIndex + 1, "");
+        }
+        
+        return caretBounds;
+    }
+    
+    /**
+     *  @private
+     *  Convert bounds from textDisplay to local coordinates
+     */
+    private function convertBoundsToLocal(bounds:Rectangle):void
+    {
+        if (bounds)
+        {
+            var position:Point = new Point(bounds.x, bounds.y);
+            position = textDisplay.localToGlobal(position);
+            position = globalToLocal(position);
+            bounds.x = position.x;
+            bounds.y = position.y;
+        }
+    }
+    
+    /**
+     *  @private
+     */
+    private function scrollToRange(anchorPosition:int, activePosition:int):void
+    {
+        var pos:int = Math.min(anchorPosition, activePosition);
+        var bounds:Rectangle = textDisplay.getCharBoundaries(pos);
+        var vsp:int = textDisplayGroup.verticalScrollPosition;
+        var paddingTop:Number = getStyle("paddingTop");
+        var paddingBottom:Number = getStyle("paddingBottom");
+        
+        if (bounds && (bounds.top < vsp - paddingTop || 
+             bounds.bottom > vsp + unscaledHeight - paddingTop - paddingBottom))
+        {
+            textDisplayGroup.verticalScrollPosition = bounds.top + paddingTop;
+            snapTextScrollPosition();
+        }
+    }
+    
+    /**
+     *  @private
+     *  Handle size and caret position changes that occur when text content
+     *  changes.
+     */
+    private function textDisplay_changeHandler(event:Event):void
+    {
+        var tH:Number = textDisplay.textHeight;
+        var tW:Number = textDisplay.textWidth;
+        var explicitLineBreak:Boolean = getStyle("lineBreak") == "explicit";
+        
+        // Size and caret position have changed if the text height is different or
+        // the text width is different and we aren't word wrapping
+        if (tH != lastTextHeight || ( explicitLineBreak && tW != lastTextWidth))
+        {
+            invalidateSize();
+            invalidateDisplayList();
+            invalidateCaretPosition = true;   
+        }
+        
+        lastTextHeight = tH;
+        lastTextWidth = tW;
+    }
+    
+    /**
+     *  @private
+     *  Cancels any native scroll that the Flash Player attempts to do
+     */
+    private function textDisplay_scrollHandler(event:Event):void
+    {
+        // if iOS, let the OS handle scrolling
+        if (_isIOS)
+            return;
+        
+        // If not IOS, we will handle scrolling, so don't let the native
+        // flash textfield scroll at all.
+        if (textDisplay.scrollV > 1)
+            textDisplay.scrollV = 1;
+        if (textDisplay.scrollH > 0)
+            textDisplay.scrollH = 0;
+    }
+    
+    /**
+     *  @private
+     *  Adjust viewport when using key navigation
+     */
+    private function textDisplay_keyHandler(event:KeyboardEvent):void
+    {
+        // update scroll position when caret changes
+        if ((event.keyCode == Keyboard.UP
+                || event.keyCode == Keyboard.DOWN
+                || event.keyCode == Keyboard.LEFT
+                || event.keyCode == Keyboard.RIGHT))
+        {
+            invalidateDisplayList();
+            invalidateCaretPosition = true;
+        }
+        
+        // Change event is not always sent when delete key is pressed, so
+        // invalidate the size here
+        if (event.keyCode == Keyboard.BACKSPACE)
+        {
+            invalidateSize();
+        }
+    }
+    
+    /**
+     *  @private
+     *  When entering edit mode on iOS, we need to shrink the textDisplay to 
+     *  the size of the TextArea  
+     */ 
+    private function textDisplay_softKeyboardActivatingHandler(event:SoftKeyboardEvent):void
+    {
+        if (event.isDefaultPrevented())
+            return;
+        
+        if (_isIOS && isTextDisplayTall)
+        {
+            //trace("TAS.SK ACTIVATING targ",event.target);
+            shrinkTextDisplay = true;
+            invalidateDisplayList();
+            validateNow();
+        }
+    }  
+    
+    /**
+     *  @private
+     *  Send a caret change event to an ancestor Scroller
+     */
+    private function textDisplay_softKeyboardActivateHandler(event:SoftKeyboardEvent):void
+    {
+        var keyboardRect:Rectangle = stage.softKeyboardRect;
+        
+        if (keyboardRect.width > 0 && keyboardRect.height > 0)
+        {
+            var newCaretBounds:Rectangle = getCaretBounds();
+            convertBoundsToLocal(newCaretBounds);
+            
+            if (oldCaretBounds != newCaretBounds)
+            {
+                //trace("TAS.SK ACTIVATE",keyboardRect,"dispatch caret CHANGE","newCaretBounds",newCaretBounds);
+                dispatchEvent(new CaretBoundsChangeEvent(CaretBoundsChangeEvent.CARET_BOUNDS_CHANGE,true,true,oldCaretBounds,newCaretBounds));
+                oldCaretBounds = newCaretBounds;
+            }
+        }
+    }
+    
+    /**
+     *  @private
+     *  On iOS, when leaving edit mode, we need to restore the textDisplay to the
+     *  height of the text.
+     */  
+    private function textDisplay_softKeyboardDeactivateHandler(event:SoftKeyboardEvent):void
+    {
+        if (_isIOS && !isTextDisplayTall)
+        {
+            growTextDisplay = true;
+            invalidateDisplayList();
+        }
+    }
+    
+    /**
+     *  @private
+     */
+    private function resizeHandler(event:Event):void
+    {
+        // Resizing needs to tickle the TextArea's internal auto-scroll logic
+        invalidateCaretPosition = true;
+        invalidateDisplayList();
+    }
+    
+    /**
+     *  @private
+     */
+    override public function styleChanged(styleProp:String):void
+    {
+        super.styleChanged(styleProp);
+        
+        // propogate styleChanged explicitly to textDisplay
+        if (textDisplay)
+            textDisplay.styleChanged(styleProp);
+        
+        // Check for padding style changes
+        if (!styleProp || styleProp == "styleName" || styleProp.indexOf("padding") >= 0)
+        {
+            if (textDisplay)
+            {
+                textDisplay.left = getStyle("paddingLeft");
+                textDisplay.top = getStyle("paddingTop");
+                textDisplay.right = getStyle("paddingRight");
+                textDisplay.bottom = getStyle("paddingBottom");
+            }
+        }
+    }
+	
+	private function focusChangeHandler(event:FocusEvent):void
+	{
+		isFocused = event.type == FocusEvent.FOCUS_IN;
+		invalidateDisplayList();		
+	}
+	
+}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/75236aa8/frameworks/projects/mobiletheme/src/spark/skins/android4/TextInputSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/android4/TextInputSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/android4/TextInputSkin.as
new file mode 100644
index 0000000..5a7a35e
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/android4/TextInputSkin.as
@@ -0,0 +1,376 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.skins.android4
+{
+	import flash.events.Event;
+	import flash.events.FocusEvent;
+	import flash.events.SoftKeyboardEvent;
+	import flash.system.Capabilities;
+	
+	import mx.core.DPIClassification;
+	import mx.core.EventPriority;
+	import mx.core.mx_internal;
+	import mx.events.FlexEvent;
+	import mx.utils.Platform;
+	
+	import spark.components.TextInput;
+	import spark.components.supportClasses.StyleableTextField;
+	import spark.skins.android4.supportClasses.TextSkinBase;
+	
+	use namespace mx_internal;
+	
+	/**
+	 *  ActionScript-based skin for TextInput controls in mobile applications. 
+	 * 
+	 * @see spark.components.TextInput
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 2.5 
+	 *  @productversion Flex 4.5
+	 */
+	public class TextInputSkin extends TextSkinBase 
+	{
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function TextInputSkin()
+		{
+			super();
+			
+			// on iOS, make adjustments for native text rendering
+			_isIOS = Platform.isIOS;
+			
+			switch (applicationDPI)
+			{
+				case DPIClassification.DPI_640:
+				{
+					measuredDefaultWidth = 1200;
+					measuredDefaultHeight = 132;
+					layoutBorderSize = 4;
+					flatheight = 9;
+					break;
+				}
+				case DPIClassification.DPI_480:
+				{
+
+					measuredDefaultWidth = 880;
+					measuredDefaultHeight = 100;
+					layoutBorderSize = 3;
+					flatheight = 7;				
+					break;
+				}
+				case DPIClassification.DPI_320:
+				{
+					measuredDefaultWidth = 600;
+					measuredDefaultHeight = 66;
+					layoutBorderSize = 2;
+					flatheight = 6;				
+					break;
+				}
+				case DPIClassification.DPI_240:
+				{
+					measuredDefaultWidth = 440;
+					measuredDefaultHeight = 50;
+					layoutBorderSize = 2;
+					flatheight = 5;
+					break;
+				}
+				case DPIClassification.DPI_120:
+				{
+					measuredDefaultWidth = 220;
+					measuredDefaultHeight = 25;
+					layoutBorderSize = 1;
+					flatheight = 2;					
+					break;
+				}
+				default:
+				{
+					measuredDefaultWidth = 300;
+					measuredDefaultHeight = 33;
+					layoutBorderSize = 1;
+					flatheight = 3; 
+					break;
+				}
+			}
+			addEventListener(FocusEvent.FOCUS_IN, focusChangeHandler);
+			addEventListener(FocusEvent.FOCUS_OUT, focusChangeHandler);
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		
+		protected var isFocused:Boolean = false;
+		
+		protected var flatheight:uint;
+		
+		/** 
+		 *  @copy spark.skins.spark.ApplicationSkin#hostComponent
+		 */
+		public var hostComponent:TextInput;  // SkinnableComponent will populate
+			
+		/**
+		 *  @private
+		 */
+		private var _isIOS:Boolean;
+		
+		/**
+		 *  @private
+		 */
+		private var _isEditing:Boolean;
+		
+		/**
+		 *  @private
+		 */
+		override protected function createChildren():void
+		{
+			super.createChildren();
+			
+			textDisplay.addEventListener("editableChanged", editableChangedHandler);
+			textDisplay.addEventListener(FlexEvent.VALUE_COMMIT, valueCommitHandler);
+			
+			// remove hit area improvements on iOS when editing
+			if (_isIOS)
+			{
+				textDisplay.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATING, textDisplay_softKeyboardActivatingHandler, false, EventPriority.DEFAULT_HANDLER);
+				textDisplay.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, textDisplay_softKeyboardDeactivateHandler);
+			}
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function measure():void
+		{
+			super.measure();
+			
+			var paddingLeft:Number = getStyle("paddingLeft");
+			var paddingRight:Number = getStyle("paddingRight");
+			var paddingTop:Number = getStyle("paddingTop");
+			var paddingBottom:Number = getStyle("paddingBottom");
+			var textHeight:Number = getStyle("fontSize") as Number;
+			
+			if (textDisplay)
+			{
+				// temporarily change text for measurement
+				var oldText:String = textDisplay.text;
+				
+				// commit styles so we can get a valid textHeight
+				textDisplay.text = "Wj";
+				textDisplay.commitStyles();
+				
+				textHeight = textDisplay.measuredTextSize.y;
+				textDisplay.text = oldText;
+			}
+			
+			// width is based on maxChars (if set)
+			if (hostComponent && hostComponent.maxChars)
+			{
+				// Grab the fontSize and subtract 2 as the pixel value for each character.
+				// This is just an approximation, but it appears to be a reasonable one
+				// for most input and most font.
+				var characterWidth:int = Math.max(1, (getStyle("fontSize") - 2));
+				measuredWidth =  (characterWidth * hostComponent.maxChars) + 
+					paddingLeft + paddingRight + StyleableTextField.TEXT_WIDTH_PADDING;
+			}
+			
+			measuredHeight = paddingTop + textHeight + paddingBottom;
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.layoutContents(unscaledWidth, unscaledHeight);
+			
+			// position & size border
+			if (border)
+			{
+				setElementSize(border, unscaledWidth, unscaledHeight);
+				setElementPosition(border, 0, 0);
+			}
+			
+			// position & size the text
+			var paddingLeft:Number = getStyle("paddingLeft");
+			var paddingRight:Number = getStyle("paddingRight");
+			var paddingTop:Number = getStyle("paddingTop");
+			var paddingBottom:Number = getStyle("paddingBottom");
+			
+			var unscaledTextWidth:Number = unscaledWidth - paddingLeft - paddingRight;
+			var unscaledTextHeight:Number = unscaledHeight - paddingTop - paddingBottom;
+			
+			// default vertical positioning is centered
+			var textHeight:Number = getElementPreferredHeight(textDisplay);
+			var textY:Number = Math.round(0.5 * (unscaledTextHeight - textHeight)) + paddingTop;
+			
+			// On iOS the TextField top and bottom edges are bounded by the padding.
+			// On all other platforms, the height of the textDisplay is
+			// textHeight + paddingBottom to increase hitArea on bottom.
+			// Note: We don't move the Y position upwards because TextField
+			// has way to set vertical positioning.
+			// Note: iOS is a special case due to the clear button provided by the
+			// native text control used while editing.
+			var adjustedTextHeight:Number = (_isIOS && _isEditing) ? textHeight : textHeight + paddingBottom;
+			
+			if (textDisplay)
+			{
+				// We're going to do a few tricks to try to increase the size of our hitArea to make it 
+				// easier for users to select text or put the caret in a certain spot.  To do that, 
+				// rather than set textDisplay.x=paddingLeft,  we are going to set 
+				// textDisplay.leftMargin = paddingLeft.  In addition, we're going to size the height 
+				// of the textDisplay larger than just the size of the text inside to increase the hitArea
+				// on the bottom.  We'll also assign textDisplay.rightMargin = paddingRight to increase the 
+				// the hitArea on the right.  Unfortunately, there's no way to increase the hitArea on the top
+				// just yet, but these three tricks definitely help out with regards to user experience.  
+				// See http://bugs.adobe.com/jira/browse/SDK-29406 and http://bugs.adobe.com/jira/browse/SDK-29405
+				
+				// set leftMargin, rightMargin to increase the hitArea.  Need to set it before calling commitStyles().
+				var marginChanged:Boolean = ((textDisplay.leftMargin != paddingLeft) || 
+					(textDisplay.rightMargin != paddingRight));
+				
+				textDisplay.leftMargin = paddingLeft;
+				textDisplay.rightMargin = paddingRight;
+				
+				// need to force a styleChanged() after setting leftMargin, rightMargin if they 
+				// changed values.  Then we can validate the styles through commitStyles()
+				if (marginChanged)
+					textDisplay.styleChanged(null);
+				textDisplay.commitStyles();
+				
+				setElementSize(textDisplay, unscaledWidth, adjustedTextHeight);
+				
+				// set x=0 since we're using textDisplay.leftMargin = paddingLeft
+				setElementPosition(textDisplay, 0, textY);
+			}
+			
+			if (promptDisplay)
+			{
+				promptDisplay.commitStyles();
+				setElementSize(promptDisplay, unscaledTextWidth, adjustedTextHeight);
+				setElementPosition(promptDisplay, paddingLeft, textY);
+			}
+		}
+		
+		override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.drawBackground(unscaledWidth, unscaledHeight);
+			
+			var contentBackgroundColor:uint = getStyle("contentBackgroundColor");
+			var contentBackgroundAlpha:Number = getStyle("contentBackgroundAlpha");	
+			//change border color and thickness when in focus
+			var borderColor:uint = isFocused ? getStyle("focusColor") : getStyle("borderColor");
+			var selectWidth:uint = isFocused ? layoutBorderSize + 1 : layoutBorderSize;
+			if (isNaN(contentBackgroundAlpha))
+			{
+				contentBackgroundAlpha = 1;
+			}        
+			if (getStyle("contentBackgroundBorder") == "flat")
+			{		
+				var halfGap:int = flatheight * 2;
+				//background
+				graphics.beginFill(contentBackgroundColor, contentBackgroundAlpha);
+				graphics.drawRect(0, 0, unscaledWidth, unscaledHeight - flatheight);
+				graphics.endFill();
+				//begin flat border
+				graphics.beginFill(borderColor, 1);
+				//left half border
+				graphics.drawRect(0, unscaledHeight - halfGap, selectWidth, flatheight );
+				//bottom border
+				graphics.drawRect(0, unscaledHeight - flatheight, unscaledWidth, selectWidth);
+				//right border
+				graphics.drawRect(unscaledWidth - selectWidth, unscaledHeight - halfGap, selectWidth, flatheight);
+				graphics.endFill();
+			}
+			else if (getStyle("contentBackgroundBorder") == "rectangle")
+			{
+				var borderWidth:uint = layoutBorderSize * 2;
+				//rectangle border and background
+				graphics.lineStyle(selectWidth, borderColor, 1);
+				graphics.beginFill(contentBackgroundColor, contentBackgroundAlpha);
+				graphics.drawRect(layoutBorderSize, layoutBorderSize, unscaledWidth - borderWidth, unscaledHeight - borderWidth);
+				graphics.endFill();
+			}
+		}
+		
+		/**
+		 *  @private
+		 */
+		private function editableChangedHandler(event:Event):void
+		{
+			invalidateDisplayList();
+		}
+		
+		/**
+		 *  @private
+		 *  The text changed in some way.
+		 * 
+		 *  Dynamic fields (ie !editable) with no text measure with width=0 and height=0.
+		 *  If the text changed, need to remeasure the text to get the correct height so it
+		 *  will be laid out correctly.
+		 */
+		private function valueCommitHandler(event:Event):void
+		{
+			if (textDisplay && !textDisplay.editable)
+				invalidateDisplayList();
+		}
+		
+		/**
+		 *  @private
+		 */
+		private function textDisplay_softKeyboardActivatingHandler(event:SoftKeyboardEvent):void
+		{
+			if (event.isDefaultPrevented())
+				return;
+			
+			_isEditing = true;
+			invalidateDisplayList();
+		}
+		
+		/**
+		 *  @private
+		 */
+		private function textDisplay_softKeyboardDeactivateHandler(event:SoftKeyboardEvent):void
+		{
+			_isEditing = false;
+			invalidateDisplayList();
+		}
+		
+		private function focusChangeHandler(event:FocusEvent):void
+		{
+			isFocused = event.type == FocusEvent.FOCUS_IN;
+			invalidateDisplayList();		
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/75236aa8/frameworks/projects/mobiletheme/src/spark/skins/android4/TextSkinBase.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/android4/TextSkinBase.as b/frameworks/projects/mobiletheme/src/spark/skins/android4/TextSkinBase.as
new file mode 100644
index 0000000..79ce852
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/android4/TextSkinBase.as
@@ -0,0 +1,212 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.skins.android4.supportClasses
+{
+	
+	import flash.display.DisplayObject;
+	
+	import mx.core.mx_internal;
+	
+	import spark.components.supportClasses.StyleableTextField;
+	
+	use namespace mx_internal;
+	
+	/**
+	 *  ActionScript-based skin for text input controls in mobile applications that
+	 *  uses a StyleableTextField class for the text display. 
+	 * 
+	 *  @see spark.components.supportClasses.StyleableTextField
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 2.5 
+	 *  @productversion Flex 4.5
+	 */
+	public class TextSkinBase extends MobileSkin 
+	{
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		/**
+		 *  Constructor.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 2.5 
+		 *  @productversion Flex 4.5
+		 * 
+		 */
+		public function TextSkinBase()
+		{
+			super();
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Graphics variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Defines the border.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 2.5 
+		 *  @productversion Flex 4.5
+		 */  
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Layout variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Defines the corner radius.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 2.5 
+		 *  @productversion Flex 4.5
+		 */  
+		
+		protected var layoutBorderSize:uint;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 * 
+		 *  Instance of the border graphics.
+		 */
+		protected var border:DisplayObject;
+		
+		private var borderVisibleChanged:Boolean = false;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Skin parts
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  textDisplay skin part.
+		 */
+		public var textDisplay:StyleableTextField;
+		
+		[Bindable]
+		/**
+		 *  Bindable promptDisplay skin part. Bindings fire when promptDisplay is
+		 *  removed and added for proper updating by the SkinnableTextBase.
+		 */
+		public var promptDisplay:StyleableTextField;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		override protected function createChildren():void
+		{
+			super.createChildren();
+			
+			if (!textDisplay)
+			{
+				textDisplay = StyleableTextField(createInFontContext(StyleableTextField));
+				textDisplay.styleName = this;
+				textDisplay.editable = true;
+				textDisplay.useTightTextBounds = false;
+				addChild(textDisplay);
+			}
+		}
+		
+		/**
+		 *  @private 
+		 */ 
+		protected function createPromptDisplay():StyleableTextField
+		{
+			var prompt:StyleableTextField = StyleableTextField(createInFontContext(StyleableTextField));
+			prompt.styleName = this;
+			prompt.editable = false;
+			prompt.mouseEnabled = false;
+			prompt.useTightTextBounds = false;
+			prompt.focusEnabled = false;
+			return prompt;
+		}
+	
+		/**
+		 *  @private
+		 */
+
+		override public function styleChanged(styleProp:String):void
+		{
+			var allStyles:Boolean = !styleProp || styleProp == "styleName";
+			
+			if (allStyles || styleProp == "borderVisible")
+			{
+				borderVisibleChanged = true;
+				invalidateProperties();
+			}
+			
+			if (allStyles || styleProp.indexOf("padding") == 0)
+			{
+				invalidateDisplayList();
+			}
+			
+			super.styleChanged(styleProp);
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function commitCurrentState():void
+		{
+			super.commitCurrentState();
+			
+			alpha = currentState.indexOf("disabled") == -1 ? 1 : 0.5;
+			
+			var showPrompt:Boolean = currentState.indexOf("WithPrompt") >= 0;
+			
+			if (showPrompt && !promptDisplay)
+			{
+				promptDisplay = createPromptDisplay();
+				addChild(promptDisplay);
+			}
+			else if (!showPrompt && promptDisplay)
+			{
+				removeChild(promptDisplay);
+				promptDisplay = null;
+			}
+			
+			invalidateDisplayList();
+		}   
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/75236aa8/frameworks/projects/mobiletheme/src/spark/skins/android4/supportClasses/StageTextSkinBase.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/android4/supportClasses/StageTextSkinBase.as b/frameworks/projects/mobiletheme/src/spark/skins/android4/supportClasses/StageTextSkinBase.as
new file mode 100644
index 0000000..3dc1966
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/android4/supportClasses/StageTextSkinBase.as
@@ -0,0 +1,402 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.skins.android4.supportClasses
+{
+import flash.display.DisplayObject;
+import flash.events.FocusEvent;
+
+import mx.core.DPIClassification;
+import mx.core.mx_internal;
+
+import spark.components.supportClasses.IStyleableEditableText;
+import spark.components.supportClasses.SkinnableTextBase;
+import spark.components.supportClasses.StyleableStageText;
+import spark.components.supportClasses.StyleableTextField;
+import spark.core.IDisplayText;
+import spark.skins.mobile.supportClasses.MobileSkin;
+
+use namespace mx_internal;
+
+/**
+ *  ActionScript-based skin for text input controls in mobile applications. 
+ * 
+ *  @langversion 3.0
+ *  @playerversion AIR 3.0
+ *  @productversion Flex 4.6
+ */
+public class StageTextSkinBase extends MobileSkin
+{
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  Constructor.
+     * 
+     *  @langversion 3.0
+     *  @playerversion AIR 3.0 
+     *  @productversion Flex 4.6
+     * 
+     */
+    public function StageTextSkinBase()
+    {
+        super();
+		
+        switch (applicationDPI)
+        {
+			case DPIClassification.DPI_640:
+			{	
+				measuredDefaultWidth = 1200;
+				measuredDefaultHeight = 132;
+				layoutBorderSize = 4;
+				flatheight = 9;
+				break;
+			}
+			case DPIClassification.DPI_480:
+			{				
+				measuredDefaultWidth = 880;
+				measuredDefaultHeight = 100;	
+				layoutBorderSize = 3;
+				flatheight = 7;
+				break;
+			}
+            case DPIClassification.DPI_320:
+            {               
+                measuredDefaultWidth = 600;
+                measuredDefaultHeight = 66;   
+				layoutBorderSize = 2;
+				flatheight = 6;
+                break;
+            }
+			case DPIClassification.DPI_240:
+			{				
+				measuredDefaultWidth = 440;
+				measuredDefaultHeight = 50;			
+				layoutBorderSize = 2;
+				flatheight = 5;
+				break;
+			}
+			case DPIClassification.DPI_120:
+			{				
+				measuredDefaultWidth = 220;
+				measuredDefaultHeight = 25;		
+				layoutBorderSize = 1;
+				flatheight = 2;
+				break;
+			}
+            default:
+			{
+                measuredDefaultWidth = 300;
+                measuredDefaultHeight = 33;
+				layoutBorderSize = 1;
+				flatheight = 3; 
+                break;
+            }
+				
+        }
+		addEventListener(FocusEvent.FOCUS_IN, focusChangeHandler);
+		addEventListener(FocusEvent.FOCUS_OUT, focusChangeHandler);
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Graphics variables
+    //
+    //--------------------------------------------------------------------------
+
+
+    //--------------------------------------------------------------------------
+    //
+    //  Layout variables
+    //
+    //-------------------------------------------------------------------------- 
+    
+    /**
+     *  Defines the border's thickness.
+     * 
+     *  @langversion 3.0
+     *  @playerversion AIR 3.0
+     *  @productversion Flex 4.6
+     */
+    protected var layoutBorderSize:uint;
+	
+	protected var flatheight:uint;
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Variables
+    //
+    //--------------------------------------------------------------------------
+	
+	protected var isFocused:Boolean = false;
+	
+    /**
+     *  @private
+     * 
+     *  Instance of the border graphics.
+     */
+    protected var border:DisplayObject;
+    
+    private var borderVisibleChanged:Boolean = false;
+
+    /**
+     *  @private
+     * 
+     *  Multiline flag.
+     */
+    protected var multiline:Boolean = false;
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Skin parts
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  textDisplay skin part.
+     * 
+     *  @langversion 3.0
+     *  @playerversion AIR 3.0
+     *  @productversion Flex 4.6
+     */
+    public var textDisplay:IStyleableEditableText; 
+	
+    [Bindable]
+    /**
+     *  Bindable promptDisplay skin part. Bindings fire when promptDisplay is
+     *  removed and added for proper updating by the SkinnableTextBase.
+     * 
+     *  @langversion 3.0
+     *  @playerversion AIR 3.0
+     *  @productversion Flex 4.6
+     */
+    public var promptDisplay:IDisplayText;
+
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden methods
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+    override protected function createChildren():void
+    {
+        super.createChildren();
+        
+        if (!textDisplay)
+        {
+            textDisplay = createTextDisplay();
+            textDisplay.editable = true;
+            textDisplay.styleName = this;
+            this.addChild(DisplayObject(textDisplay));
+        }
+    }
+
+    /**  Could be overridden by subclasses
+     *
+     * @return   instance of  IStyleableEditableText
+     */
+    protected function createTextDisplay():IStyleableEditableText
+	{
+        return   new StyleableStageText(multiline);
+    }
+
+    /**
+     *  @private
+     */
+    override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+        super.drawBackground(unscaledWidth, unscaledHeight);
+        
+        var contentBackgroundColor:uint = getStyle("contentBackgroundColor");
+        var contentBackgroundAlpha:Number = getStyle("contentBackgroundAlpha");	
+		//change border color and thickness when in focus
+		var borderColor:uint = isFocused ? getStyle("focusColor") : getStyle("borderColor");
+		var selectWidth:uint = isFocused ? layoutBorderSize + 1 : layoutBorderSize;
+        if (isNaN(contentBackgroundAlpha))
+		{
+            contentBackgroundAlpha = 1;
+		}        
+		var halfGap:int = flatheight * 2;
+		// change the border type
+		if (getStyle("contentBackgroundBorder") == "flat")
+		{		
+			//background
+			graphics.beginFill(contentBackgroundColor, contentBackgroundAlpha);
+			graphics.drawRect(0, 0, unscaledWidth, unscaledHeight - flatheight);
+			graphics.endFill();
+			//begin flat border
+			graphics.beginFill(borderColor, 1);
+			//left half border
+			graphics.drawRect(0, unscaledHeight - halfGap, selectWidth, flatheight );
+			//bottom border
+			graphics.drawRect(0, unscaledHeight - flatheight, unscaledWidth, selectWidth);
+			//right border
+			graphics.drawRect(unscaledWidth - selectWidth, unscaledHeight - halfGap, selectWidth, flatheight);
+			graphics.endFill();
+		}
+		else if (getStyle("contentBackgroundBorder") == "rectangle")
+		{
+			var borderWidth:uint = layoutBorderSize * 2;
+			//rectangle border and background
+			graphics.lineStyle(selectWidth, borderColor, 1);
+			graphics.beginFill(contentBackgroundColor, contentBackgroundAlpha);
+			graphics.drawRect(layoutBorderSize, layoutBorderSize, unscaledWidth - borderWidth, unscaledHeight - borderWidth);
+			graphics.endFill();
+		}
+    }
+    
+    /**
+     *  @private
+     */
+    override public function styleChanged(styleProp:String):void
+    {
+        var allStyles:Boolean = !styleProp || styleProp == "styleName";
+        
+        if (allStyles || styleProp == "borderVisible")
+        {
+            borderVisibleChanged = true;
+            invalidateProperties();
+        }
+        
+        if (allStyles || styleProp.indexOf("padding") == 0)
+        {
+            invalidateDisplayList();
+        }       
+        super.styleChanged(styleProp);
+    }
+	
+    /**
+     *  @private
+     */
+    override protected function commitCurrentState():void
+    {
+        super.commitCurrentState();
+        
+        alpha = currentState.indexOf("disabled") == -1 ? 1 : 0.5;
+        
+        var showPrompt:Boolean = currentState.indexOf("WithPrompt") != -1;
+
+        if (showPrompt && !promptDisplay)
+        {
+            promptDisplay = createPromptDisplay();
+            promptDisplay.addEventListener(FocusEvent.FOCUS_IN, promptDisplay_focusInHandler);
+        }
+        else if (!showPrompt && promptDisplay)
+        {
+            promptDisplay.removeEventListener(FocusEvent.FOCUS_IN, promptDisplay_focusInHandler);
+            removeChild(promptDisplay as DisplayObject);
+            promptDisplay = null;
+        }
+		super.commitCurrentState();
+		
+        invalidateDisplayList();
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     *  Create a control appropriate for displaying the prompt text in a mobile
+     *  input field.
+     */
+    protected function createPromptDisplay():IDisplayText
+    {
+        var prompt:StyleableTextField = StyleableTextField(createInFontContext(StyleableTextField));
+        prompt.styleName = this;
+        prompt.editable = false;
+        prompt.mouseEnabled = false;
+        prompt.useTightTextBounds = false;   
+        // StageText objects appear in their own layer on top of the display
+        // list. So, even though this prompt may be created after the StageText
+        // for textDisplay, textDisplay will still be on top.
+        addChild(prompt);
+        
+        return prompt;
+    }
+    
+    /**
+     *  @private
+     *  Utility function used by subclasses' measure functions to measure their
+     *  text host components.
+     */
+    protected function measureTextComponent(hostComponent:SkinnableTextBase):void
+    {
+        var paddingLeft:Number = getStyle("paddingLeft");
+        var paddingRight:Number = getStyle("paddingRight");
+        var paddingTop:Number = getStyle("paddingTop");
+        var paddingBottom:Number = getStyle("paddingBottom");
+        var textHeight:Number = getStyle("fontSize");
+        
+        if (textDisplay)
+		{
+            textHeight = getElementPreferredHeight(textDisplay);
+		}
+        // width is based on maxChars (if set)
+        if (hostComponent && hostComponent.maxChars)
+        {
+            // Grab the fontSize and subtract 2 as the pixel value for each character.
+            // This is just an approximation, but it appears to be a reasonable one
+            // for most input and most font.
+            var characterWidth:int = Math.max(1, (textHeight - 2));
+            measuredWidth =  (characterWidth * hostComponent.maxChars) + paddingLeft + paddingRight;
+        }
+        
+        measuredHeight = paddingTop + textHeight + paddingBottom;
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Event handlers
+    //
+    //--------------------------------------------------------------------------
+	
+	/**
+	 *  Listen to see if the component gains focus then change the style to selected
+	 */	
+	private function focusChangeHandler(event:FocusEvent):void
+	{
+		isFocused = event.type == FocusEvent.FOCUS_IN;
+		invalidateDisplayList();		
+	}
+	
+    /**
+     *  If the prompt is focused, we need to move focus to the textDisplay
+     *  StageText. This needs to happen outside of the process of setting focus
+     *  to the prompt, so we use callLater to do that.
+     */
+    private function focusTextDisplay():void
+    {
+        textDisplay.setFocus();
+    }
+    
+    private function promptDisplay_focusInHandler(event:FocusEvent):void
+    {
+        callLater(focusTextDisplay);
+    }
+}
+}
\ No newline at end of file


Mime
View raw message