You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by bi...@apache.org on 2014/10/02 00:54:13 UTC

[3/5] Adding new branch for working on ios7 skins.

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListContainerSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListContainerSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListContainerSkin.as
new file mode 100644
index 0000000..e076a6b
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListContainerSkin.as
@@ -0,0 +1,326 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.display.Graphics;
+	import flash.display.InteractiveObject;
+	import flash.display.Sprite;
+	
+	import mx.core.DPIClassification;
+	import mx.core.mx_internal;
+	
+	import spark.components.Group;
+	import spark.components.SpinnerListContainer;
+	import spark.layouts.HorizontalLayout;
+	import spark.skins.android4.assets.SpinnerListContainerBackground;
+	import spark.skins.android4.assets.SpinnerListContainerSelectionIndicator;
+	import spark.skins.android4.assets.SpinnerListContainerShadow;
+	import spark.skins.mobile.supportClasses.MobileSkin;
+
+	use namespace mx_internal;
+	/**
+	 *  ActionScript-based skin for the SpinnerListContainer in mobile applications. 
+	 * 
+	 *  @see spark.components.SpinnerListContainer
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion AIR 3
+	 *  @productversion Flex 4.6
+	 */
+	public class SpinnerListContainerSkin extends MobileSkin
+	{
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		/**
+		 *  Constructor.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 * 
+		 */
+		public function SpinnerListContainerSkin()
+		{
+			super();
+			
+			borderClass = spark.skins.android4.assets.SpinnerListContainerBackground;
+			selectionIndicatorClass = spark.skins.android4.assets.SpinnerListContainerSelectionIndicator;
+			shadowClass = spark.skins.android4.assets.SpinnerListContainerShadow;
+			cornerRadius = 0;
+			borderThickness = 0;
+			switch (applicationDPI)
+			{
+				case DPIClassification.DPI_640:
+				{
+					selectionIndicatorHeight = 182;
+					break;
+				}
+				case DPIClassification.DPI_480:
+				{
+					selectionIndicatorHeight = 144;
+					break;
+				}
+				case DPIClassification.DPI_320:
+				{					
+					selectionIndicatorHeight = 96;
+					break;
+				}
+				case DPIClassification.DPI_240:
+				{
+					selectionIndicatorHeight = 72;
+					break;
+				}
+				case DPIClassification.DPI_120:
+				{
+					selectionIndicatorHeight = 36;
+					break;
+				}
+				default: // default DPI_160
+				{
+					selectionIndicatorHeight = 48;
+					
+					break;
+				}
+			}
+			
+			minWidth = 30;
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		/**
+		 *  Pixel thickness of the border. 
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var borderThickness:Number;
+		
+		/**
+		 *  Radius of the border corners.
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var cornerRadius:Number;
+		
+		/**
+		 *  Height of the selection indicator.  
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var selectionIndicatorHeight:Number;
+		
+		/**
+		 *  Class for the border part. 
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var borderClass:Class;
+		
+		/**
+		 *  Class for the selection indicator skin part. 
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var selectionIndicatorClass:Class;
+		
+		/**
+		 *  Class for the shadow skin part.  
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var shadowClass:Class;
+		
+		/**
+		 *  Border skin part which includes the background. 
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var border:InteractiveObject;
+		
+		/**
+		 *  Selection indicator skin part. 
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var selectionIndicator:InteractiveObject;
+		
+		/**
+		 *  Shadow skin part. 
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var shadow:InteractiveObject;
+		
+		/**
+		 *  Mask for the content group. 
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var contentGroupMask:Sprite;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Skin parts 
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  An optional skin part that defines the Group where the content 
+		 *  children are pushed into and laid out.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		public var contentGroup:Group;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties 
+		//
+		//--------------------------------------------------------------------------
+		/** 
+		 *  @copy spark.skins.spark.ApplicationSkin#hostComponent
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		public var hostComponent:SpinnerListContainer;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Methods 
+		//
+		//--------------------------------------------------------------------------
+		/**
+		 *  @private
+		 */
+		override protected function createChildren():void
+		{
+			super.createChildren();
+			
+			if (!border)
+			{
+				// Border and background
+				border = new borderClass();
+				border.mouseEnabled = false;
+				addChild(border);
+			}
+			
+			if (!contentGroup)
+			{
+				// Contains the child elements
+				contentGroup = new Group();
+				var hLayout:HorizontalLayout = new HorizontalLayout();
+				hLayout.gap = 0;
+				hLayout.verticalAlign = "middle";
+				contentGroup.layout = hLayout;
+				contentGroup.id = "contentGroup";
+				addChild(contentGroup);
+			}
+			
+			if (!shadow)
+			{
+				// Shadowing sits on top of the content
+				shadow = new shadowClass();
+				shadow.mouseEnabled = false;
+				addChild(shadow);
+			}
+			
+
+			if (!contentGroupMask)
+			{
+				// Create a mask for the content
+				contentGroupMask = new Sprite();
+				addChild(contentGroupMask);
+			}
+		}   
+		
+		/**
+		 *  @private
+		 */
+		override protected function measure():void
+		{
+			super.measure();
+			
+			var contentW:Number = contentGroup.getPreferredBoundsWidth();
+			var contentH:Number = contentGroup.getPreferredBoundsHeight();
+			
+			measuredWidth = measuredMinWidth = contentW + borderThickness * 2;
+			measuredHeight = contentH + borderThickness * 2;
+
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.layoutContents(unscaledWidth, unscaledHeight);
+	
+			setElementSize(contentGroup, unscaledWidth - borderThickness * 2, unscaledHeight - borderThickness * 2);
+			setElementPosition(contentGroup, borderThickness, borderThickness);
+			
+			// Inset by the borderThickness horizontally because the selectionIndicator starts at 0
+			setElementSize(border, unscaledWidth - borderThickness * 2, unscaledHeight);
+			setElementPosition(border, borderThickness, 0);			
+			
+			setElementSize(shadow, unscaledWidth - borderThickness * 4, measuredHeight - borderThickness * 2);
+			setElementPosition(shadow, borderThickness * 2, unscaledHeight/2 - measuredHeight/2);
+		
+			// The SpinnerLists contain a left and right border. We don't want to show the leftmost 
+			// SpinnerLists's left border nor the rightmost one's right border. 
+			// We inset the mask on the left and right sides to accomplish this. 
+			var g:Graphics = contentGroupMask.graphics;
+			g.clear();
+			g.beginFill(0x00FF00);
+			g.drawRoundRect(borderThickness * 2, borderThickness, unscaledWidth - borderThickness * 4, unscaledHeight - borderThickness * 2, cornerRadius, cornerRadius);
+			g.endFill();
+			
+			contentGroup.mask = contentGroupMask;       
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListScrollerSkin.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListScrollerSkin.mxml b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListScrollerSkin.mxml
new file mode 100644
index 0000000..270818e
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListScrollerSkin.mxml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+
+
+<!--
+
+Scroller unconditionally sets its skin's layout to private layout
+implementation that handles the scroll policies.  Scroller skins can
+only provide replacement scrollbars.  The skin's layout and
+constraints or dimensions set on skin parts will not be honored.  To
+gain more control over the layout of a viewport and its scrollbars,
+instead of using Scroller, add them to a Group and use the ScrollBar component's
+viewport property to link them together.
+
+-->
+
+<!--- The default skin class for the Spark Scroller that is used by the SpinnerList component. 
+
+@see spark.components.SpinnerList
+@see spark.components.Scroller
+
+@langversion 3.0
+@playerversion AIR 3
+@productversion Flex 4.6
+-->
+<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark">
+	
+	<fx:Metadata>
+		<![CDATA[ 
+		/** 
+		* @copy spark.skins.spark.ApplicationSkin#hostComponent
+		* 
+		*  @langversion 3.0
+		*  @playerversion AIR 3
+		*  @productversion Flex 4.6
+		*/
+		[HostComponent("spark.components.Scroller")]
+		]]>
+	</fx:Metadata> 
+	
+	<fx:Script>
+		<![CDATA[    
+			/**
+			 *  @private
+			 */
+			override public function beginHighlightBitmapCapture() : Boolean
+			{
+				var needUpdate:Boolean = super.beginHighlightBitmapCapture();
+				
+				// Draw an opaque rect that fill our entire skin. Our background
+				// is transparent, but we don't want focus/error skins to
+				// poke through.  This is safe to do since we don't have any 
+				// graphic elements as direct children.
+				graphics.beginFill(0);
+				graphics.drawRect(0, 0, width, height);
+				graphics.endFill();
+				
+				return needUpdate;
+			}
+			
+			/**
+			 *  @private
+			 */
+			override public function endHighlightBitmapCapture() : Boolean
+			{
+				var needUpdate:Boolean = super.endHighlightBitmapCapture();
+				
+				// Clear the rect we drew in beginBitmapCapture();
+				graphics.clear();
+				
+				return needUpdate;
+			}
+		]]>
+	</fx:Script>
+	
+</s:SparkSkin>
+

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListSkin.as
new file mode 100644
index 0000000..b86553f
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/SpinnerListSkin.as
@@ -0,0 +1,294 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.display.InteractiveObject;
+	
+	import mx.core.ClassFactory;
+	import mx.core.DPIClassification;
+	import mx.core.mx_internal;
+	
+	import spark.components.DataGroup;
+	import spark.components.Scroller;
+	import spark.components.SpinnerList;
+	import spark.components.SpinnerListItemRenderer;
+	import spark.layouts.VerticalSpinnerLayout;
+	import spark.skins.android4.assets.SpinnerListContainerSelectionIndicator;
+	import spark.skins.mobile.supportClasses.MobileSkin;	
+
+	
+	use namespace mx_internal;
+	/**
+	 *  ActionScript-based skin for the SpinnerList in mobile applications. 
+	 * 
+	 *  @see spark.components.SpinnerList
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion AIR 3
+	 *  @productversion Flex 4.6
+	 */
+	public class SpinnerListSkin extends MobileSkin
+	{
+		/**
+		 *  Constructor.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		public function SpinnerListSkin()
+		{
+			super();
+			
+			selectionIndicatorClass = spark.skins.android4.assets.SpinnerListContainerSelectionIndicator;
+			borderThickness = 1;
+			switch (applicationDPI)
+			{
+				case DPIClassification.DPI_640:
+				{
+					selectionIndicatorHeight = 182;
+					minWidth = 64;
+					borderThickness = 3;
+					break;
+				}
+				case DPIClassification.DPI_480:
+				{
+					selectionIndicatorHeight = 144;
+					minWidth = 48;
+					borderThickness = 2;
+					break;
+				}
+				case DPIClassification.DPI_320:
+				{
+					selectionIndicatorHeight = 96;
+					minWidth = 32;
+					borderThickness = 2;
+					break;
+				}
+				case DPIClassification.DPI_240:
+				{
+					selectionIndicatorHeight = 72;
+					minWidth = 24;
+					borderThickness = 1;
+					break;
+				}
+				case DPIClassification.DPI_120:
+				{
+					selectionIndicatorHeight = 36;
+					minWidth = 12;
+					borderThickness = 0;
+					break;
+				}
+				default:
+				{
+					selectionIndicatorHeight = 48;
+					minWidth = 16;
+					borderThickness = 1;
+				}   
+			}
+			
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Skin parts 
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Scroller skin part.
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */ 
+		public var scroller:Scroller;
+		
+		/**
+		 *  DataGroup skin part.
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */ 
+		public var dataGroup:DataGroup;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties 
+		//
+		//--------------------------------------------------------------------------
+		/** 
+		 *  @copy spark.skins.spark.ApplicationSkin#hostComponent
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		public var hostComponent:SpinnerList;
+		
+		/**
+		 *  Pixel size of the border.
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */ 
+		protected var borderThickness:int;
+		
+		/**
+		 *  Class for the selection indicator skin part. 
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var selectionIndicatorClass:Class;
+		
+		/**
+		 *  Selection indicator skin part. 
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var selectionIndicator:InteractiveObject;
+		
+		/**
+		 *  Height of the selection indicator.  
+		 *       
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var selectionIndicatorHeight:Number;
+
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Methods 
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		override protected function commitCurrentState():void
+		{
+			super.commitCurrentState();
+			
+			alpha = currentState.indexOf("disabled") == -1 ? 1 : 0.5;
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function createChildren():void
+		{           
+			super.createChildren();
+			
+			if (!dataGroup)
+			{
+				// Create data group layout
+				var layout:VerticalSpinnerLayout = new VerticalSpinnerLayout();
+				layout.requestedRowCount = 5;
+				
+				// Create data group
+				dataGroup = new DataGroup();
+				dataGroup.id = "dataGroup";
+				dataGroup.layout = layout;
+
+				dataGroup.itemRenderer = new ClassFactory(spark.components.SpinnerListItemRenderer);
+			}
+
+			if (!scroller)
+			{
+				// Create scroller
+				scroller = new Scroller();
+				scroller.id = "scroller";
+				scroller.hasFocusableChildren = false;
+				scroller.ensureElementIsVisibleForSoftKeyboard = false;
+				
+				// Only support vertical scrolling
+				scroller.setStyle("verticalScrollPolicy","on");
+				scroller.setStyle("horizontalScrollPolicy", "off");
+				scroller.setStyle("skinClass", spark.skins.android4.SpinnerListScrollerSkin);
+				
+				addChild(scroller);
+			}
+			
+			if (!selectionIndicator)
+			{
+				// Selection indicator is on top
+				selectionIndicator = new selectionIndicatorClass();
+				selectionIndicator.mouseEnabled = false;
+				addChild(selectionIndicator);
+			}
+			
+			// Associate scroller with data group
+			if (!scroller.viewport)
+				scroller.viewport = dataGroup;
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function measure():void
+		{
+			measuredWidth = scroller.getPreferredBoundsWidth() + borderThickness * 2;
+			measuredHeight = scroller.getPreferredBoundsHeight();
+			//add in for selection indicator
+			measuredMinHeight = selectionIndicatorHeight + borderThickness * 4;
+			minHeight = measuredMinHeight;			
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+		{   
+			super.layoutContents(unscaledWidth, unscaledHeight);			
+			
+			// Scroller
+			setElementSize(scroller, unscaledWidth - borderThickness * 2, unscaledHeight);
+			setElementPosition(scroller, borderThickness, 0);
+			//selection indicator
+			unscaledHeight = Math.max(unscaledHeight, selectionIndicatorHeight + borderThickness * 4);
+			
+			setElementSize(selectionIndicator, unscaledWidth, selectionIndicatorHeight);
+			setElementPosition(selectionIndicator, 0, Math.floor((unscaledHeight - selectionIndicatorHeight) / 2));
+		}
+		
+		/**
+		 *  @private
+		 */
+		override public function styleChanged(styleProp:String):void
+		{
+			// Reinitialize the typical element so it picks up the latest styles
+			// Font styles might impact the size of the SpinnerList
+			if (styleProp != "color" && styleProp != "accentColor")
+			{
+				if (dataGroup)
+					dataGroup.invalidateTypicalItemRenderer();
+			}
+			
+			super.styleChanged(styleProp);
+		}
+		
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextAreaSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextAreaSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextAreaSkin.as
new file mode 100644
index 0000000..d48377d
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/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/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextInputSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextInputSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/StageTextInputSkin.as
new file mode 100644
index 0000000..7f92647
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/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/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/TabbedViewNavigatorTabBarSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/TabbedViewNavigatorTabBarSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TabbedViewNavigatorTabBarSkin.as
new file mode 100644
index 0000000..eea5948
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TabbedViewNavigatorTabBarSkin.as
@@ -0,0 +1,122 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.ButtonBarButton;
+import spark.components.DataGroup;
+import spark.skins.mobile.supportClasses.ButtonBarButtonClassFactory;
+import spark.skins.mobile.supportClasses.TabbedViewNavigatorTabBarHorizontalLayout;
+
+/**
+ *  The Android 4.x specific skin class for the Spark TabbedViewNavigator tabBar skin part.
+ *  It uses the ButtonBarFirstButtonSkin and ButtonBarMiddleButtonSkin as skins for first
+ *  middle buttons
+ *  
+ *  @see spark.components.TabbedViewNavigator#tabBar
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.5
+ *  @productversion Flex 4.5
+ */
+public class TabbedViewNavigatorTabBarSkin extends ButtonBarSkin
+{
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  Constructor.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5 
+     *  @productversion Flex 4.5
+     * 
+     */
+    public function TabbedViewNavigatorTabBarSkin()
+    {
+        super();
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden methods
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+    override protected function createChildren():void
+    {
+        if (!firstButton)
+        {
+            firstButton = new ButtonBarButtonClassFactory(ButtonBarButton);
+            firstButton.skinClass = spark.skins.android4.ButtonBarFirstButtonSkin;
+        }
+        
+        if (!lastButton)
+        {
+            lastButton = new ButtonBarButtonClassFactory(ButtonBarButton);
+            lastButton.skinClass = spark.skins.android4.ButtonBarFirstButtonSkin;
+        }
+        
+        if (!middleButton)
+        {
+            middleButton = new ButtonBarButtonClassFactory(ButtonBarButton);
+            middleButton.skinClass = spark.skins.android4.ButtonBarMiddleButtonSkin;
+        }
+        
+        if (!dataGroup)
+        {
+            // TabbedViewNavigatorButtonBarHorizontalLayout for even percent layout
+            var tabLayout:TabbedViewNavigatorTabBarHorizontalLayout = 
+                new TabbedViewNavigatorTabBarHorizontalLayout();
+            tabLayout.useVirtualLayout = false;
+            
+            dataGroup = new DataGroup();
+            dataGroup.layout = tabLayout;
+            addChild(dataGroup);
+        }
+    }
+    
+    /**
+     *  @private
+     */
+    override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+        super.drawBackground(unscaledWidth, unscaledHeight);
+
+        // backgroundAlpha style is not supported by ButtonBar
+        // TabbedViewNavigatorSkin sets a hard-coded value to support
+        // overlayControls
+        var backgroundAlphaValue:* = getStyle("backgroundAlpha");
+        var backgroundAlpha:Number = (backgroundAlphaValue === undefined)
+            ? 1 : getStyle("backgroundAlpha");
+        
+        graphics.beginFill(getStyle("chromeColor"), backgroundAlpha);
+        graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
+        graphics.endFill();
+    }
+}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextAreaSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextAreaSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextAreaSkin.as
new file mode 100644
index 0000000..0c231a6
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/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/3fd6027d/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextInputSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextInputSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextInputSkin.as
new file mode 100644
index 0000000..7488e1f
--- /dev/null
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/TextInputSkin.as
@@ -0,0 +1,375 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 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