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/11/04 20:16:08 UTC

[18/22] git commit: [flex-examples] [refs/heads/develop] - added in Android Skins

added in Android Skins

Signed-off-by: OmPrakash Muppirala <bi...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/flex-examples/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-examples/commit/539852e9
Tree: http://git-wip-us.apache.org/repos/asf/flex-examples/tree/539852e9
Diff: http://git-wip-us.apache.org/repos/asf/flex-examples/diff/539852e9

Branch: refs/heads/develop
Commit: 539852e984111a284dfda239de6f2d26e42b2e5e
Parents: 1f0cce9
Author: nasha001 <na...@DM-DT-NASH.hartford.gov>
Authored: Tue Nov 4 13:00:50 2014 -0500
Committer: OmPrakash Muppirala <bi...@gmail.com>
Committed: Tue Nov 4 11:07:41 2014 -0800

----------------------------------------------------------------------
 tourdeflexmobile/slideoff.png                   | Bin 15894 -> 0 bytes
 .../src/spark/skins/android4/ActionBarSkin.as   | 725 +++++++++++++++
 .../skins/android4/ButtonBarFirstButtonSkin.as  |  93 ++
 .../skins/android4/ButtonBarMiddleButtonSkin.as |  95 ++
 .../src/spark/skins/android4/ButtonBarSkin.as   | 166 ++++
 .../src/spark/skins/android4/ButtonSkin.as      | 397 +++++++++
 .../src/spark/skins/android4/CalloutSkin.as     | 825 +++++++++++++++++
 .../src/spark/skins/android4/CheckBoxSkin.as    | 268 ++++++
 .../src/spark/skins/android4/DateSpinnerSkin.as | 153 ++++
 .../src/spark/skins/android4/HScrollBarSkin.as  | 205 +++++
 .../spark/skins/android4/HScrollBarThumbSkin.as | 169 ++++
 .../src/spark/skins/android4/HSliderSkin.as     | 293 ++++++
 .../spark/skins/android4/HSliderThumbSkin.as    | 333 +++++++
 .../spark/skins/android4/HSliderTrackSkin.as    | 227 +++++
 .../src/spark/skins/android4/ListSkin.as        | 204 +++++
 .../android4/MobileGridHeaderButtonBarSkin.as   |  90 ++
 .../src/spark/skins/android4/MobileGridSkin.as  | 159 ++++
 .../src/spark/skins/android4/RadioButtonSkin.as | 253 ++++++
 .../android4/ScrollingStageTextAreaSkin.as      |  53 ++
 .../android4/ScrollingStageTextInputSkin.as     |  54 ++
 .../skins/android4/SpinnerListContainerSkin.as  | 327 +++++++
 .../skins/android4/SpinnerListScrollerSkin.mxml |  94 ++
 .../src/spark/skins/android4/SpinnerListSkin.as | 293 ++++++
 .../skins/android4/SplitViewNavigatorSkin.as    | 157 ++++
 .../spark/skins/android4/StageTextAreaSkin.as   | 185 ++++
 .../spark/skins/android4/StageTextInputSkin.as  | 130 +++
 .../android4/TabbedViewNavigatorTabBarSkin.as   | 122 +++
 .../skins/android4/TextAreaHScrollBarSkin.as    | 105 +++
 .../android4/TextAreaHScrollBarThumbSkin.as     | 116 +++
 .../src/spark/skins/android4/TextAreaSkin.as    | 892 +++++++++++++++++++
 .../skins/android4/TextAreaVScrollBarSkin.as    | 105 +++
 .../android4/TextAreaVScrollBarThumbSkin.as     | 117 +++
 .../src/spark/skins/android4/TextInputSkin.as   | 375 ++++++++
 .../spark/skins/android4/ToggleSwitchSkin.as    | 506 +++++++++++
 .../android4/TransparentActionButtonSkin.as     | 108 +++
 .../android4/TransparentNavigationButtonSkin.as | 109 +++
 .../src/spark/skins/android4/VScrollBarSkin.as  | 207 +++++
 .../spark/skins/android4/VScrollBarThumbSkin.as | 178 ++++
 .../spark/skins/android4/ViewMenuItemSkin.as    | 238 +++++
 .../src/spark/skins/android4/ViewMenuSkin.mxml  | 184 ++++
 .../android4/assets/ActionBarBackground.fxg     |  55 ++
 .../skins/android4/assets/BusyIndicator.fxg     |  64 ++
 .../assets/ButtonBarFirstButton_down.fxg        |  34 +
 .../ButtonBarFirstButton_selectedDown.fxg       |  39 +
 .../assets/ButtonBarFirstButton_selectedUp.fxg  |  34 +
 .../android4/assets/ButtonBarFirstButton_up.fxg |  29 +
 .../assets/ButtonBarMiddleButton_down.fxg       |  70 ++
 .../ButtonBarMiddleButton_selectedDown.fxg      |  75 ++
 .../assets/ButtonBarMiddleButton_selectedUp.fxg |  70 ++
 .../assets/ButtonBarMiddleButton_up.fxg         |  65 ++
 .../spark/skins/android4/assets/Button_down.fxg |  73 ++
 .../spark/skins/android4/assets/Button_up.fxg   |  60 ++
 .../assets/CalloutContentBackground.fxg         |  51 ++
 .../skins/android4/assets/CheckBox_down.fxg     |  34 +
 .../android4/assets/CheckBox_downSelected.fxg   |  35 +
 .../assets/CheckBox_downSymbolSelected.fxg      |  29 +
 .../spark/skins/android4/assets/CheckBox_up.fxg |  31 +
 .../android4/assets/CheckBox_upSelected.fxg     |  29 +
 .../assets/CheckBox_upSymbolSelected.fxg        |  33 +
 .../android4/assets/HSliderThumb_normal.fxg     |  34 +
 .../android4/assets/HSliderThumb_pressed.fxg    |  39 +
 .../skins/android4/assets/HSliderTrack.fxg      |  29 +
 .../android4/assets/HSliderTrack_filled.fxg     |  29 +
 .../skins/android4/assets/RadioButton_down.fxg  |  34 +
 .../assets/RadioButton_downSymbolSelected.fxg   |  29 +
 .../skins/android4/assets/RadioButton_up.fxg    |  29 +
 .../assets/RadioButton_upSymbolSelected.fxg     |  36 +
 .../assets/SpinnerListContainerBackground.fxg   |  48 +
 .../SpinnerListContainerSelectionIndicator.fxg  |  45 +
 .../assets/SpinnerListContainerShadow.fxg       |  40 +
 .../skins/android4/assets/TextInput_border.fxg  |  34 +
 .../assets/TextInput_border_Rectangle.fxg       |  28 +
 .../assets/TextInput_border_Rectangle_focus.fxg |  28 +
 .../android4/assets/TextInput_border_focus.fxg  |  34 +
 .../android4/assets/ToggleSwitchBackground.fxg  |  29 +
 .../android4/assets/ToggleSwitchThumb_off.fxg   |  40 +
 .../android4/assets/ToggleSwitchThumb_on.fxg    |  40 +
 .../assets/TransparentActionButton_down.fxg     |  69 ++
 .../assets/TransparentActionButton_up.fxg       |  59 ++
 .../assets/TransparentNavigationButton_down.fxg |  69 ++
 .../assets/TransparentNavigationButton_up.fxg   |  59 ++
 .../skins/android4/assets/ViewMenuItem_down.fxg |  36 +
 .../android4/assets/ViewMenuItem_showsCaret.fxg |  36 +
 .../skins/android4/assets/ViewMenuItem_up.fxg   |  35 +
 .../skins/android4/assets/fonts/Roboto-Bold.ttf | Bin 0 -> 84924 bytes
 .../android4/assets/fonts/Roboto-Regular.ttf    | Bin 0 -> 84564 bytes
 .../android4/supportClasses/CalloutArrow.as     | 457 ++++++++++
 .../supportClasses/StageTextSkinBase.as         | 402 +++++++++
 .../android4/supportClasses/TextSkinBase.as     | 213 +++++
 89 files changed, 12280 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/slideoff.png
----------------------------------------------------------------------
diff --git a/tourdeflexmobile/slideoff.png b/tourdeflexmobile/slideoff.png
deleted file mode 100644
index 538d0f8..0000000
Binary files a/tourdeflexmobile/slideoff.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/ActionBarSkin.as
----------------------------------------------------------------------
diff --git a/tourdeflexmobile/src/spark/skins/android4/ActionBarSkin.as b/tourdeflexmobile/src/spark/skins/android4/ActionBarSkin.as
new file mode 100644
index 0000000..f1ef220
--- /dev/null
+++ b/tourdeflexmobile/src/spark/skins/android4/ActionBarSkin.as
@@ -0,0 +1,725 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.GradientType;
+	import flash.events.Event;
+	import flash.text.TextFormatAlign;
+	
+	import mx.core.DPIClassification;
+	import mx.core.mx_internal;
+	import mx.utils.ColorUtil;
+	
+	import spark.components.ActionBar;
+	import spark.components.Group;
+	import spark.components.supportClasses.StyleableTextField;
+	import spark.core.SpriteVisualElement;
+	import spark.layouts.HorizontalAlign;
+	import spark.layouts.HorizontalLayout;
+	import spark.layouts.VerticalAlign;
+	import spark.skins.android4.assets.ActionBarBackground;
+	import spark.skins.mobile.supportClasses.MobileSkin;
+	
+	use namespace mx_internal;
+	
+	/**
+	 *  The default skin class for the Spark ActionBar component in mobile
+	 *  applications.
+	 *  
+	 *  @see spark.components.ActionBar
+	 *  @see spark.skins.mobile.TransparentNavigationButtonSkin
+	 *  @see spark.skins.mobile.BeveledBackButtonSkin
+	 *  @see spark.skins.mobile.TransparentActionButtonSkin
+	 *  @see spark.skins.mobile.BeveledActionButtonSkin
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion AIR 2.5
+	 *  @productversion Flex 4.5
+	 */
+	public class ActionBarSkin extends MobileSkin
+	{
+		//--------------------------------------------------------------------------
+		//
+		//  Class constants
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		mx_internal static const ACTIONBAR_CHROME_COLOR_RATIOS:Array = [0, 80];
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function ActionBarSkin()
+		{
+			super();
+			
+			borderClass = spark.skins.android4.assets.ActionBarBackground;
+			
+			switch (applicationDPI)
+			{
+				
+				case DPIClassification.DPI_640:
+				{
+					borderSize = 2;
+					layoutContentGroupHeight = 172;
+					layoutTitleGroupHorizontalPadding = 52;
+					
+					break;
+				}
+				case DPIClassification.DPI_480:
+				{
+					borderSize = 2;
+					layoutContentGroupHeight = 130;
+					layoutTitleGroupHorizontalPadding = 40;
+					
+					
+					break;
+				}
+				case DPIClassification.DPI_320:
+				{
+					borderSize = 2;
+					layoutContentGroupHeight = 86;
+					layoutTitleGroupHorizontalPadding = 26;
+					
+					break;
+				}
+				case DPIClassification.DPI_240:
+				{
+					borderSize = 1;
+					layoutContentGroupHeight = 65;
+					layoutTitleGroupHorizontalPadding = 20;
+					
+					break;
+				}
+				case DPIClassification.DPI_120:
+				{
+					borderSize = 1;
+					layoutContentGroupHeight = 32;
+					layoutTitleGroupHorizontalPadding = 10;
+					
+					break;
+				}	
+				default:
+				{
+					// default DPI_160
+					borderSize = 1;
+					layoutContentGroupHeight = 43;
+					layoutTitleGroupHorizontalPadding = 13;
+					
+					break;
+				}
+			}
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Graphics variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  FXG Class reference for the ActionBar background border graphic.
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		protected var borderClass:Class;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Layout variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		private var borderSize:uint;
+		
+		/**
+		 *  Default height for navigationGroup, titleGroup and actionGroup.
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		protected var layoutContentGroupHeight:uint;
+		
+		/**
+		 *  Default horizontal padding for the titleGroup and titleDisplay.
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		protected var layoutTitleGroupHorizontalPadding:uint;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/** 
+		 *  @copy spark.skins.spark.ApplicationSkin#hostComponent
+		 */
+		public var hostComponent:ActionBar;
+		
+		/**
+		 *  @private
+		 */
+		private var _navigationVisible:Boolean = false;
+		
+		/**
+		 *  @private
+		 */
+		private var _titleContentVisible:Boolean = false;
+		
+		/**
+		 *  @private
+		 */
+		private var _actionVisible:Boolean = false;
+		
+		/**
+		 *  @private
+		 */
+		private var border:SpriteVisualElement;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Skin parts
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @copy spark.components.ActionBar#navigationGroup
+		 */
+		public var navigationGroup:Group;
+		
+		/**
+		 *  @copy spark.components.ActionBar#titleGroup
+		 */
+		public var titleGroup:Group;
+		
+		/**
+		 *  @copy spark.components.ActionBar#actionGroup
+		 */
+		public var actionGroup:Group;
+		
+		/**
+		 *  @copy spark.components.ActionBar#titleDisplay
+		 * 
+		 *  @private
+		 *  Wraps a StyleableTextField in a UIComponent to be compatible with
+		 *  ViewTransition effects.
+		 */
+		public var titleDisplay:TitleDisplayComponent;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		override protected function createChildren():void
+		{
+			if (borderClass)
+			{
+				border = new borderClass();
+				addChild(border);
+			}
+			
+			navigationGroup = new Group();
+			var hLayout:HorizontalLayout = new HorizontalLayout();
+			hLayout.horizontalAlign = HorizontalAlign.LEFT;
+			hLayout.verticalAlign = VerticalAlign.MIDDLE;
+			hLayout.gap = 0;
+			hLayout.paddingLeft = hLayout.paddingTop = hLayout.paddingRight =  hLayout.paddingBottom = 0;
+			navigationGroup.layout = hLayout;
+			navigationGroup.id = "navigationGroup";
+			
+			titleGroup = new Group();
+			hLayout = new HorizontalLayout();
+			hLayout.horizontalAlign = HorizontalAlign.LEFT;
+			hLayout.verticalAlign = VerticalAlign.MIDDLE;
+			hLayout.gap = 0;
+			hLayout.paddingLeft = hLayout.paddingRight = layoutTitleGroupHorizontalPadding; 
+			hLayout.paddingTop = hLayout.paddingBottom = 0;
+			titleGroup.layout = hLayout;
+			titleGroup.id = "titleGroup";
+			
+			actionGroup = new Group();
+			hLayout = new HorizontalLayout();
+			hLayout.horizontalAlign = HorizontalAlign.RIGHT;
+			hLayout.verticalAlign = VerticalAlign.MIDDLE;
+			hLayout.gap = 0;
+			hLayout.paddingLeft = hLayout.paddingTop = hLayout.paddingRight =  hLayout.paddingBottom = 0;
+			actionGroup.layout = hLayout;
+			actionGroup.id = "actionGroup";
+			
+			titleDisplay = new TitleDisplayComponent();
+			titleDisplay.id = "titleDisplay";
+			
+			// initialize titleAlign style (center is managed explicitly in layoutContents)
+			var titleAlign:String = getStyle("titleAlign");
+			titleAlign = (titleAlign == "center") ? TextFormatAlign.LEFT : titleAlign;
+			titleDisplay.setStyle("textAlign", titleAlign);
+			
+			addChild(navigationGroup);
+			addChild(titleGroup);
+			addChild(actionGroup);
+			addChild(titleDisplay);
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function measure():void
+		{
+			var titleWidth:Number = 0;
+			var titleHeight:Number = 0;
+			
+			if (_titleContentVisible)
+			{
+				titleWidth = titleGroup.getPreferredBoundsWidth();
+				titleHeight = titleGroup.getPreferredBoundsHeight();
+			}
+			else
+			{
+				// use titleLayout for paddingLeft and paddingRight
+				var layoutObject:Object = hostComponent.titleLayout;
+				titleWidth = ((layoutObject.paddingLeft) ? Number(layoutObject.paddingLeft) : 0)
+					+ ((layoutObject.paddingRight) ? Number(layoutObject.paddingRight) : 0)
+					+ titleDisplay.getPreferredBoundsWidth();
+				
+				titleHeight = titleDisplay.getPreferredBoundsHeight();
+			}
+			
+			measuredWidth =
+				getStyle("paddingLeft")
+				+ navigationGroup.getPreferredBoundsWidth()
+				+ titleWidth
+				+ actionGroup.getPreferredBoundsWidth()
+				+ getStyle("paddingRight");
+			
+			// measuredHeight is contentGroupHeight, 2x border on top and bottom
+			measuredHeight =
+				getStyle("paddingTop")
+				+ Math.max(layoutContentGroupHeight,
+					navigationGroup.getPreferredBoundsHeight(), 
+					actionGroup.getPreferredBoundsHeight(),
+					titleHeight)
+				+ getStyle("paddingBottom");
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function commitCurrentState():void
+		{
+			super.commitCurrentState();
+			
+			_titleContentVisible = currentState.indexOf("titleContent") >= 0;
+			_navigationVisible = currentState.indexOf("Navigation") >= 0;
+			_actionVisible = currentState.indexOf("Action") >= 0;
+			
+			invalidateSize();
+			invalidateDisplayList();
+		}
+		
+		/**
+		 *  @private
+		 */
+		override public function styleChanged(styleProp:String):void
+		{
+			if (titleDisplay)
+			{
+				var allStyles:Boolean = !styleProp || styleProp == "styleName";
+				
+				if (allStyles || (styleProp == "titleAlign"))
+				{
+					var titleAlign:String = getStyle("titleAlign");
+					
+					if (titleAlign == "center")
+					{ 
+						// If the title align is set to center, the alignment is set to LEFT
+						// so that the skin can manually center the component in layoutContents
+						titleDisplay.setStyle("textAlign", TextFormatAlign.LEFT);
+					}
+					else
+					{
+						titleDisplay.setStyle("textAlign", titleAlign);
+					}
+				}
+			}
+			
+			super.styleChanged(styleProp);
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.layoutContents(unscaledWidth, unscaledHeight);
+			
+			var navigationGroupWidth:Number = 0;
+			
+			var paddingLeft:Number   = getStyle("paddingLeft"); 
+			var paddingRight:Number  = getStyle("paddingRight");
+			var paddingTop:Number    = getStyle("paddingTop");
+			var paddingBottom:Number = getStyle("paddingBottom");
+			
+			var titleCompX:Number = paddingLeft;
+			var titleCompWidth:Number = 0;
+			
+			var actionGroupX:Number = unscaledWidth;
+			var actionGroupWidth:Number = 0;
+			
+			// remove top and bottom padding from content group height
+			var contentGroupsHeight:Number = Math.max(0, unscaledHeight - paddingTop - paddingBottom);
+			
+			if (border)
+			{
+				// FXG uses scale-9, drop shadow is drawn outside the bounds
+				setElementSize(border, unscaledWidth, unscaledHeight);
+			}
+			
+			// position groups, overlap of navigation and action groups is allowed
+			// when overlap occurs, titleDisplay/titleGroup is not visible
+			if (_navigationVisible)
+			{
+				navigationGroupWidth = navigationGroup.getPreferredBoundsWidth();
+				titleCompX += navigationGroupWidth;
+				
+				setElementSize(navigationGroup, navigationGroupWidth, contentGroupsHeight);
+				setElementPosition(navigationGroup, paddingLeft, paddingTop);
+			}
+			
+			if (_actionVisible)
+			{
+				// actionGroup x position can be negative
+				actionGroupWidth = actionGroup.getPreferredBoundsWidth();
+				actionGroupX = unscaledWidth - actionGroupWidth - paddingRight;
+				
+				setElementSize(actionGroup, actionGroupWidth, contentGroupsHeight);
+				setElementPosition(actionGroup, actionGroupX, paddingTop);
+			}
+			
+			// titleGroup or titleDisplay is given remaining width after navigation
+			// and action groups preferred widths
+			titleCompWidth = unscaledWidth - navigationGroupWidth - actionGroupWidth
+				- paddingLeft - paddingRight;
+			
+			if (titleCompWidth <= 0)
+			{
+				titleDisplay.visible = false;
+				titleGroup.visible = false;
+			}
+			else if (_titleContentVisible)
+			{
+				titleDisplay.visible = false;
+				titleGroup.visible = true;
+				
+				// use titleGroup for titleContent
+				setElementSize(titleGroup, titleCompWidth, contentGroupsHeight);
+				setElementPosition(titleGroup, titleCompX, paddingTop);
+			}
+			else
+			{
+				// use titleDisplay for title text label
+				titleGroup.visible = false;
+				
+				// use titleLayout for paddingLeft and paddingRight
+				var layoutObject:Object = hostComponent.titleLayout;
+				var titlePaddingLeft:Number = (layoutObject.paddingLeft) ? Number(layoutObject.paddingLeft) : 0;
+				var titlePaddingRight:Number = (layoutObject.paddingRight) ? Number(layoutObject.paddingRight) : 0;
+				
+				// align titleDisplay to the absolute center
+				var titleAlign:String = getStyle("titleAlign");
+				
+				// check for available width after padding
+				if ((titleCompWidth - titlePaddingLeft - titlePaddingRight) <= 0)
+				{
+					titleCompX = 0;
+					titleCompWidth = 0;
+				}
+				else if (titleAlign == "center")
+				{ 
+					// use LEFT instead of CENTER
+					titleCompWidth = titleDisplay.getExplicitOrMeasuredWidth();
+					
+					// use x position of titleDisplay to implement CENTER
+					titleCompX = Math.round((unscaledWidth - titleCompWidth) / 2); 
+					
+					var navigationOverlap:Number = navigationGroupWidth + titlePaddingLeft - titleCompX;
+					var actionOverlap:Number = (titleCompX + titleCompWidth + titlePaddingRight) - actionGroupX;
+					
+					// shrink and/or move titleDisplay width if there is any
+					// overlap after centering
+					if ((navigationOverlap > 0) && (actionOverlap > 0))
+					{
+						// remaining width
+						titleCompX = navigationGroupWidth + titlePaddingLeft;
+						titleCompWidth = unscaledWidth - navigationGroupWidth - actionGroupWidth - titlePaddingLeft - titlePaddingRight;
+					}
+					else if ((navigationOverlap > 0) || (actionOverlap > 0))
+					{
+						if (navigationOverlap > 0)
+						{
+							// nudge to the right
+							titleCompX += navigationOverlap;
+						}
+						else if (actionOverlap > 0)
+						{
+							// nudge to the left
+							titleCompX -= actionOverlap;
+							
+							// force left padding
+							if (titleCompX < (navigationGroupWidth + titlePaddingLeft))
+								titleCompX = navigationGroupWidth + titlePaddingLeft;
+						}
+						
+						// recompute action overlap and force right padding
+						actionOverlap = (titleCompX + titleCompWidth + titlePaddingRight) - actionGroupX;
+						
+						if (actionOverlap > 0)
+							titleCompWidth -= actionOverlap;
+					}
+				}
+				else
+				{
+					// implement padding by adjusting width and position
+					titleCompX += titlePaddingLeft;
+					titleCompWidth = titleCompWidth - titlePaddingLeft - titlePaddingRight;
+				}
+				
+				// check for negative width
+				titleCompWidth = (titleCompWidth < 0) ? 0 : titleCompWidth;
+				
+				setElementSize(titleDisplay, titleCompWidth, contentGroupsHeight);
+				setElementPosition(titleDisplay, titleCompX, paddingTop);
+				
+				titleDisplay.visible = true;
+			}
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.drawBackground(unscaledWidth, unscaledHeight);
+			
+			var chromeColor:uint = getStyle("chromeColor");
+			var backgroundAlphaValue:Number = getStyle("backgroundAlpha");
+			var colors:Array = [];
+			
+			// apply alpha to chromeColor fill only
+			var backgroundAlphas:Array = [backgroundAlphaValue, backgroundAlphaValue];
+			
+			// exclude top and bottom 1px borders
+			colorMatrix.createGradientBox(unscaledWidth, unscaledHeight - (borderSize * 2), Math.PI / 2, 0, 0);
+			
+			colors[0] = ColorUtil.adjustBrightness2(chromeColor, 20);
+			colors[1] = chromeColor;
+			
+			graphics.beginGradientFill(GradientType.LINEAR, colors, backgroundAlphas, ACTIONBAR_CHROME_COLOR_RATIOS, colorMatrix);
+			graphics.drawRect(0, borderSize, unscaledWidth, unscaledHeight - (borderSize * 2));
+			graphics.endFill();
+		}
+		
+	}
+}
+import flash.events.Event;
+
+import mx.core.UIComponent;
+import mx.core.mx_internal;
+import mx.events.FlexEvent;
+
+import spark.components.supportClasses.StyleableTextField;
+import spark.core.IDisplayText;
+
+use namespace mx_internal;
+
+/**
+ *  @private
+ *  Component that holds StyleableTextFields to produce a drop shadow effect.
+ *  Combines label and shadow into a single component to allow transitions to
+ *  target them both.
+ */
+class TitleDisplayComponent extends UIComponent implements IDisplayText
+{
+	private var titleDisplay:StyleableTextField;
+	private var titleDisplayShadow:StyleableTextField;
+	private var title:String;
+	private var titleChanged:Boolean;
+	
+	public function TitleDisplayComponent()
+	{
+		super();
+		title = "";
+	}
+	
+	override public function get baselinePosition():Number
+	{
+		return titleDisplay.baselinePosition;
+	}
+	
+	/**
+	 *  @private
+	 */
+	override protected function createChildren():void
+	{
+		super.createChildren();
+		
+		titleDisplay = StyleableTextField(createInFontContext(StyleableTextField));
+		titleDisplay.styleName = this;
+		titleDisplay.editable = false;
+		titleDisplay.selectable = false;
+		titleDisplay.multiline = false;
+		titleDisplay.wordWrap = false;
+		titleDisplay.addEventListener(FlexEvent.VALUE_COMMIT,
+			titleDisplay_valueCommitHandler);
+		
+		titleDisplayShadow =
+			StyleableTextField(createInFontContext(StyleableTextField));
+		titleDisplayShadow.styleName = this;
+		titleDisplayShadow.colorName = "textShadowColor";
+		titleDisplayShadow.editable = false;
+		titleDisplayShadow.selectable = false;
+		titleDisplayShadow.multiline = false;
+		titleDisplayShadow.wordWrap = false;
+		
+		addChild(titleDisplayShadow);
+		addChild(titleDisplay);
+	}
+	
+	/**
+	 *  @private
+	 */
+	override protected function commitProperties():void
+	{
+		super.commitProperties();
+		
+		if (titleChanged)
+		{
+			titleDisplay.text = title;
+			
+			invalidateSize();
+			invalidateDisplayList();
+			
+			titleChanged = false;
+		}
+	}
+	
+	/**
+	 *  @private
+	 */
+	override protected function measure():void
+	{
+		// reset text if it was truncated before.
+		if (titleDisplay.isTruncated)
+			titleDisplay.text = title;
+		
+		measuredWidth = titleDisplay.getPreferredBoundsWidth();
+		
+		// tightTextHeight
+		measuredHeight = titleDisplay.getPreferredBoundsHeight();
+	}
+	
+	/**
+	 *  @private
+	 */
+	override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+	{
+		super.updateDisplayList(unscaledWidth, unscaledHeight);
+		
+		// reset text if it was truncated before.
+		if (titleDisplay.isTruncated)
+			titleDisplay.text = title;
+		titleDisplay.commitStyles();
+		
+		// use preferred height, setLayoutBoundsSize will accommodate for tight
+		// text adjustment
+		var tightHeight:Number = titleDisplay.getPreferredBoundsHeight();
+		var tightY:Number = (unscaledHeight - tightHeight) / 2;
+		
+		titleDisplay.setLayoutBoundsSize(unscaledWidth, tightHeight);
+		titleDisplay.setLayoutBoundsPosition(0, (unscaledHeight - tightHeight) / 2);
+		
+		// now truncate the text
+		titleDisplay.truncateToFit();
+		
+		titleDisplayShadow.commitStyles();
+		titleDisplayShadow.setLayoutBoundsSize(unscaledWidth, tightHeight);
+		titleDisplayShadow.setLayoutBoundsPosition(0, tightY + 1);
+		
+		titleDisplayShadow.alpha = getStyle("textShadowAlpha");
+		
+		// if labelDisplay is truncated, then push it down here as well.
+		// otherwise, it would have gotten pushed in the labelDisplay_valueCommitHandler()
+		if (titleDisplay.isTruncated)
+			titleDisplayShadow.text = titleDisplay.text;
+	}
+	
+	/**
+	 *  @private 
+	 */ 
+	private function titleDisplay_valueCommitHandler(event:Event):void 
+	{
+		titleDisplayShadow.text = titleDisplay.text;
+	}
+	
+	public function get text():String
+	{
+		return title;
+	}
+	
+	public function set text(value:String):void
+	{
+		title = value;
+		titleChanged = true;
+		
+		invalidateProperties();
+	}
+	
+	public function get isTruncated():Boolean
+	{
+		return titleDisplay.isTruncated;
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/ButtonBarFirstButtonSkin.as
----------------------------------------------------------------------
diff --git a/tourdeflexmobile/src/spark/skins/android4/ButtonBarFirstButtonSkin.as b/tourdeflexmobile/src/spark/skins/android4/ButtonBarFirstButtonSkin.as
new file mode 100644
index 0000000..4b8cbba
--- /dev/null
+++ b/tourdeflexmobile/src/spark/skins/android4/ButtonBarFirstButtonSkin.as
@@ -0,0 +1,93 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.skins.android4.assets.ButtonBarFirstButton_selectedDown;
+	import spark.skins.android4.assets.ButtonBarFirstButton_selectedUp;
+	import spark.skins.mobile.supportClasses.ButtonBarButtonSkinBase;
+	
+	/**
+	 *  Android 4.x specific Button skin for the first Button in a ButtonBar.
+	 * 
+	 *  @see spark.components.ButtonBar#firstButton
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 2.5 
+	 *  @productversion Flex 4.5
+	 */
+	public class ButtonBarFirstButtonSkin extends ButtonBarButtonSkinBase
+	{
+		
+		/**
+		 *  Class to use for the border in the selected and down state.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 2.5 
+		 *  @productversion Flex 4.5
+		 */  
+		protected var selectedDownBorderSkin:Class;
+		
+		/**
+		 *  Constructor.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 2.5 
+		 *  @productversion Flex 4.5
+		 */
+		public function ButtonBarFirstButtonSkin()
+		{
+			super();
+			
+			upBorderSkin = spark.skins.android4.assets.ButtonBarFirstButton_up;
+			downBorderSkin = spark.skins.android4.assets.ButtonBarFirstButton_down;
+			selectedBorderSkin = spark.skins.android4.assets.ButtonBarFirstButton_selectedUp;
+			selectedDownBorderSkin = spark.skins.android4.assets.ButtonBarFirstButton_selectedDown;
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden methods
+		//
+		//--------------------------------------------------------------------------
+		
+		override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			//Dont draw background
+		}
+		
+		override protected function getBorderClassForCurrentState():Class
+		{
+			var isSelected:Boolean = currentState.indexOf("Selected") >= 0;
+			var isDown:Boolean = currentState.indexOf("down") >= 0;
+			
+			if (isSelected && !isDown )
+				return selectedBorderSkin;
+			else if (isSelected && isDown)
+				return selectedDownBorderSkin;
+			else if (!isSelected && !isDown)
+				return upBorderSkin;
+			else 
+				return downBorderSkin;
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/ButtonBarMiddleButtonSkin.as
----------------------------------------------------------------------
diff --git a/tourdeflexmobile/src/spark/skins/android4/ButtonBarMiddleButtonSkin.as b/tourdeflexmobile/src/spark/skins/android4/ButtonBarMiddleButtonSkin.as
new file mode 100644
index 0000000..c6206d0
--- /dev/null
+++ b/tourdeflexmobile/src/spark/skins/android4/ButtonBarMiddleButtonSkin.as
@@ -0,0 +1,95 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.skins.android4.assets.ButtonBarMiddleButton_selectedDown;
+	import spark.skins.android4.assets.ButtonBarMiddleButton_selectedUp;
+	import spark.skins.android4.assets.ButtonBarMiddleButton_up;
+	import spark.skins.mobile.supportClasses.ButtonBarButtonSkinBase;
+	
+	/**
+	 *  Android 4.x specific Button skin for middle Buttons in a ButtonBar.
+	 * 
+	 *  @see spark.components.ButtonBar#middleButton
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 2.5 
+	 *  @productversion Flex 4.5
+	 */
+	public class ButtonBarMiddleButtonSkin extends ButtonBarButtonSkinBase
+	{
+		
+		/**
+		 *  Class to use for the border in the selected and down state.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 2.5 
+		 *  @productversion Flex 4.5
+		 */  
+		protected var selectedDownBorderSkin:Class;
+		
+		/**
+		 *  Constructor.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 2.5 
+		 *  @productversion Flex 4.5
+		 */
+		public function ButtonBarMiddleButtonSkin()
+		{
+			super();
+			
+			upBorderSkin = spark.skins.android4.assets.ButtonBarMiddleButton_up;
+			downBorderSkin = spark.skins.android4.assets.ButtonBarMiddleButton_down;
+			selectedBorderSkin = spark.skins.android4.assets.ButtonBarMiddleButton_selectedUp;
+			selectedDownBorderSkin = spark.skins.android4.assets.ButtonBarMiddleButton_selectedDown;
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden methods
+		//
+		//--------------------------------------------------------------------------
+		
+		override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			//Dont draw background
+		}
+		
+		override protected function getBorderClassForCurrentState():Class
+		{
+			var isSelected:Boolean = currentState.indexOf("Selected") >= 0;
+			var isDown:Boolean = currentState.indexOf("down") >= 0;
+			
+			if (isSelected && !isDown )
+				return selectedBorderSkin;
+			else if (isSelected && isDown)
+				return selectedDownBorderSkin;
+			else if (!isSelected && !isDown)
+				return upBorderSkin;
+			else 
+				return downBorderSkin;
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/ButtonBarSkin.as
----------------------------------------------------------------------
diff --git a/tourdeflexmobile/src/spark/skins/android4/ButtonBarSkin.as b/tourdeflexmobile/src/spark/skins/android4/ButtonBarSkin.as
new file mode 100644
index 0000000..4b194fd
--- /dev/null
+++ b/tourdeflexmobile/src/spark/skins/android4/ButtonBarSkin.as
@@ -0,0 +1,166 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.ButtonBar;
+import spark.components.ButtonBarButton;
+import spark.components.DataGroup;
+import spark.components.supportClasses.ButtonBarHorizontalLayout;
+import spark.skins.android4.ButtonBarFirstButtonSkin;
+import spark.skins.mobile.ButtonBarLastButtonSkin;
+import spark.skins.mobile.supportClasses.ButtonBarButtonClassFactory;
+import spark.skins.mobile.supportClasses.MobileSkin;
+
+/**
+ *  The Android 4.x specific skin class for the Spark ButtonBar component.
+ *
+ *  @see spark.components.ButtonBar
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.5
+ *  @productversion Flex 4.5
+ */
+public class ButtonBarSkin extends MobileSkin
+{
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     * Constructor.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5
+     *  @productversion Flex 4.5
+     *
+     */
+    public function ButtonBarSkin()
+    {
+        super();
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Skin parts
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @copy spark.skins.spark.ApplicationSkin#hostComponent
+     */
+    public var hostComponent:ButtonBar;
+    
+    /**
+     *  @copy spark.components.ButtonBar#firstButton
+     */
+    public var firstButton:ButtonBarButtonClassFactory;
+    
+    /**
+     *  @copy spark.components.ButtonBar#lastButton
+     */
+    public var lastButton:ButtonBarButtonClassFactory;
+    
+    /**
+     *  @copy spark.components.ButtonBar#middleButton
+     */
+    public var middleButton:ButtonBarButtonClassFactory;
+    
+    /**
+     *  @copy spark.components.SkinnableDataContainer#dataGroup
+     */
+    public var dataGroup:DataGroup;
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden methods
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+    override protected function createChildren():void
+    {
+        // Set up the class factories for the buttons
+        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;
+        }
+        
+        // create the data group to house the buttons
+        if (!dataGroup)
+        {
+            dataGroup = new DataGroup();
+            var hLayout:ButtonBarHorizontalLayout = new ButtonBarHorizontalLayout();
+            hLayout.gap = 0;
+            dataGroup.layout = hLayout;
+            addChild(dataGroup);
+        }
+    }
+    
+    /**
+     *  @private
+     */
+    override protected function commitCurrentState():void
+    {
+        alpha = (currentState == "disabled") ? 0.5 : 1;
+    }
+    
+    /**
+     *  @private
+     */
+    override protected function measure():void
+    {
+        measuredWidth = dataGroup.measuredWidth;
+        measuredHeight = dataGroup.measuredHeight;
+        
+        measuredMinWidth = dataGroup.measuredMinWidth;
+        measuredMinHeight = dataGroup.measuredMinHeight;
+    }
+    
+    /**
+     *  @private
+     */
+    override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+        super.layoutContents(unscaledWidth, unscaledHeight);
+        
+        setElementPosition(dataGroup, 0, 0);
+        setElementSize(dataGroup, unscaledWidth, unscaledHeight);
+    }
+}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/ButtonSkin.as
----------------------------------------------------------------------
diff --git a/tourdeflexmobile/src/spark/skins/android4/ButtonSkin.as b/tourdeflexmobile/src/spark/skins/android4/ButtonSkin.as
new file mode 100644
index 0000000..43fb108
--- /dev/null
+++ b/tourdeflexmobile/src/spark/skins/android4/ButtonSkin.as
@@ -0,0 +1,397 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.DisplayObject;
+
+import mx.core.DPIClassification;
+import mx.core.mx_internal;
+import mx.events.FlexEvent;
+
+import spark.components.supportClasses.StyleableTextField;
+import spark.skins.android4.assets.Button_down;
+import spark.skins.android4.assets.Button_up;
+import spark.skins.mobile.supportClasses.ButtonSkinBase;
+
+
+use namespace mx_internal;
+
+/**
+ *  ActionScript-based skin for Button controls in mobile applications. The skin supports 
+ *  iconClass and labelPlacement. It uses FXG classes to 
+ *  implement the vector drawing.  
+ * 
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.5 
+ *  @productversion Flex 4.5
+ */
+public class ButtonSkin extends ButtonSkinBase
+{
+    //--------------------------------------------------------------------------
+    //
+    //  Class constants
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     * An array of color distribution ratios.
+     * This is used in the chrome color fill.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5
+     *  @productversion Flex 4.5
+     */
+    mx_internal static const CHROME_COLOR_RATIOS:Array = [0, 127.5];
+    
+    /**
+     * An array of alpha values for the corresponding colors in the colors array. 
+     * This is used in the chrome color fill.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5
+     *  @productversion Flex 4.5
+     */
+    mx_internal static const CHROME_COLOR_ALPHAS:Array = [1, 1];
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+    /**
+     *  Constructor.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5
+     *  @productversion Flex 4.5
+     */
+    public function ButtonSkin()
+    {
+        super();
+		upBorderSkin = spark.skins.android4.assets.Button_up;
+		downBorderSkin = spark.skins.android4.assets.Button_down;
+		layoutCornerEllipseSize = 0;
+        
+        switch (applicationDPI)
+        {
+			case DPIClassification.DPI_640:
+			{
+				
+				layoutGap = 20;
+				layoutPaddingLeft = 40;
+				layoutPaddingRight = 40;
+				layoutPaddingTop = 40;
+				layoutPaddingBottom = 40;
+				layoutBorderSize = 2;
+				measuredDefaultWidth = 128;
+				measuredDefaultHeight = 172;
+				
+				break;
+			}
+			case DPIClassification.DPI_480:
+			{
+				
+				layoutGap = 14;
+				layoutPaddingLeft = 30;
+				layoutPaddingRight = 30;
+				layoutPaddingTop = 30;
+				layoutPaddingBottom = 30;
+				layoutBorderSize = 2;
+				measuredDefaultWidth = 96;
+				measuredDefaultHeight = 130;
+				
+				break;
+			}
+            case DPIClassification.DPI_320:
+            {
+                
+                layoutGap = 10;
+                layoutPaddingLeft = 20;
+                layoutPaddingRight = 20;
+                layoutPaddingTop = 20;
+                layoutPaddingBottom = 20;
+                layoutBorderSize = 2;
+                measuredDefaultWidth = 64;
+                measuredDefaultHeight = 86;
+                
+                break;
+            }
+			case DPIClassification.DPI_240:
+			{
+				
+				layoutGap = 7;
+				layoutPaddingLeft = 15;
+				layoutPaddingRight = 15;
+				layoutPaddingTop = 15;
+				layoutPaddingBottom = 15;
+				layoutBorderSize = 1;
+				measuredDefaultWidth = 48;
+				measuredDefaultHeight = 65;
+				
+				break;
+			}
+			case DPIClassification.DPI_120:
+			{
+				
+				layoutGap = 4;
+				layoutPaddingLeft = 8;
+				layoutPaddingRight = 8;
+				layoutPaddingTop = 8;
+				layoutPaddingBottom = 8;
+				layoutBorderSize = 1;
+				measuredDefaultWidth = 24;
+				measuredDefaultHeight = 33;
+				
+				break;
+			}
+            default:
+            {
+                
+                layoutGap = 5;
+                layoutPaddingLeft = 10;
+                layoutPaddingRight = 10;
+                layoutPaddingTop = 10;
+                layoutPaddingBottom = 10;
+                layoutBorderSize = 1;
+                measuredDefaultWidth = 32;
+                measuredDefaultHeight = 43;
+                
+                break;
+            }
+        }
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Layout variables
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  Defines the corner radius.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5 
+     *  @productversion Flex 4.5
+     */  
+    protected var layoutCornerEllipseSize:uint;
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Variables
+    //
+    //--------------------------------------------------------------------------
+    private var _border:DisplayObject;
+    
+    private var changeFXGSkin:Boolean = false;
+    
+    private var borderClass:Class;
+    
+    mx_internal var fillColorStyleName:String = "chromeColor";
+    
+    /**
+     *  Defines the shadow for the Button control's label.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5 
+     *  @productversion Flex 4.5
+     */  
+    public var labelDisplayShadow:StyleableTextField;
+    
+    /**
+     *  Read-only button border graphic. Use getBorderClassForCurrentState()
+     *  to specify a graphic per-state.
+     * 
+     *  @see #getBorderClassForCurrentState()
+     */
+    protected function get border():DisplayObject
+    {
+        return _border;
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  Class to use for the border in the up state.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5 
+     *  @productversion Flex 4.5
+     * 
+     *  @default Button_up
+     */  
+    protected var upBorderSkin:Class;
+    
+    /**
+     *  Class to use for the border in the down state.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5 
+     *  @productversion Flex 4.5
+     *       
+     *  @default Button_down
+     */ 
+    protected var downBorderSkin:Class;
+    
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden methods
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+    override protected function createChildren():void
+    {
+        super.createChildren();
+        
+        if (!labelDisplayShadow && labelDisplay)
+        {
+            labelDisplayShadow = StyleableTextField(createInFontContext(StyleableTextField));
+            labelDisplayShadow.styleName = this;
+            labelDisplayShadow.colorName = "textShadowColor";
+            labelDisplayShadow.useTightTextBounds = false;
+            
+            // add shadow before display
+            addChildAt(labelDisplayShadow, getChildIndex(labelDisplay));
+        }
+        
+        setStyle("textAlign", "center");
+    }
+    
+    /**
+     *  @private 
+     */
+    override protected function commitCurrentState():void
+    {   
+        super.commitCurrentState();
+        
+        borderClass = getBorderClassForCurrentState();
+        
+        if (!(_border is borderClass))
+            changeFXGSkin = true;
+        
+        // update borderClass and background
+        invalidateDisplayList();
+    }
+    
+    /**
+     *  @private
+     */
+    override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+        super.layoutContents(unscaledWidth, unscaledHeight);
+        
+        // size the FXG background
+        if (changeFXGSkin)
+        {
+            changeFXGSkin = false;
+            
+            if (_border)
+            {
+                removeChild(_border);
+                _border = null;
+            }
+            
+            if (borderClass)
+            {
+                _border = new borderClass();
+                addChildAt(_border, 0);
+            }
+        }
+        
+        layoutBorder(unscaledWidth, unscaledHeight);
+        
+        // update label shadow
+        labelDisplayShadow.alpha = getStyle("textShadowAlpha");
+        labelDisplayShadow.commitStyles();
+        
+        // don't use tightText positioning on shadow
+        setElementPosition(labelDisplayShadow, labelDisplay.x, labelDisplay.y + 1);
+        setElementSize(labelDisplayShadow, labelDisplay.width, labelDisplay.height);
+        
+        // if labelDisplay is truncated, then push it down here as well.
+        // otherwise, it would have gotten pushed in the labelDisplay_valueCommitHandler()
+        if (labelDisplay.isTruncated)
+            labelDisplayShadow.text = labelDisplay.text;
+    }
+    
+    /**
+     *  Position the background of the skin. Override this function to re-position the background. 
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5 
+     *  @productversion Flex 4.5
+     */ 
+    mx_internal function layoutBorder(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+        setElementSize(border, unscaledWidth, unscaledHeight);
+        setElementPosition(border, 0, 0);
+    }
+    
+    /**
+     *  Returns the borderClass to use based on the currentState.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5 
+     *  @productversion Flex 4.5
+     */
+    protected function getBorderClassForCurrentState():Class
+    {
+        if (currentState == "down") 
+            return downBorderSkin;
+        else
+            return upBorderSkin;
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Event Handlers
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private 
+     */
+    override protected function labelDisplay_valueCommitHandler(event:FlexEvent):void 
+    {
+        super.labelDisplay_valueCommitHandler(event);
+        labelDisplayShadow.text = labelDisplay.text;
+    }
+    
+}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/CalloutSkin.as
----------------------------------------------------------------------
diff --git a/tourdeflexmobile/src/spark/skins/android4/CalloutSkin.as b/tourdeflexmobile/src/spark/skins/android4/CalloutSkin.as
new file mode 100644
index 0000000..22f04f5
--- /dev/null
+++ b/tourdeflexmobile/src/spark/skins/android4/CalloutSkin.as
@@ -0,0 +1,825 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.BlendMode;
+	import flash.display.GradientType;
+	import flash.display.Graphics;
+	import flash.display.Sprite;
+	import flash.events.Event;
+	
+	import mx.core.DPIClassification;
+	import mx.core.UIComponent;
+	import mx.core.mx_internal;
+	import mx.events.EffectEvent;
+	import mx.events.FlexEvent;
+	import mx.utils.ColorUtil;
+	
+	import spark.components.ArrowDirection;
+	import spark.components.Callout;
+	import spark.components.ContentBackgroundAppearance;
+	import spark.components.Group;
+	import spark.core.SpriteVisualElement;
+	import spark.effects.Fade;
+	import spark.primitives.RectangularDropShadow;
+	import spark.skins.android4.assets.CalloutContentBackground;
+	import spark.skins.android4.supportClasses.CalloutArrow;
+	import spark.skins.mobile.supportClasses.MobileSkin;
+	
+	use namespace mx_internal;
+	
+	/**
+	 *  The default skin class for the Spark Callout component in mobile
+	 *  applications.
+	 * 
+	 *  <p>The <code>contentGroup</code> lies above a <code>backgroundColor</code> fill
+	 *  which frames the <code>contentGroup</code>. The position and size of the frame 
+	 *  adjust based on the host component <code>arrowDirection</code>, leaving
+	 *  space for the <code>arrow</code> to appear on the outside edge of the
+	 *  frame.</p>
+	 * 
+	 *  <p>The <code>arrow</code> skin part is not positioned by the skin. Instead,
+	 *  the Callout component positions the arrow relative to the owner in
+	 *  <code>updateSkinDisplayList()</code>. This method assumes that Callout skin
+	 *  and the <code>arrow</code> use the same coordinate space.</p>
+	 *  
+	 *  @see spark.components.Callout
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion AIR 3
+	 *  @productversion Flex 4.6
+	 */ 
+	public class CalloutSkin extends MobileSkin
+	{
+		mx_internal static const BACKGROUND_GRADIENT_BRIGHTNESS_TOP:int = 15;
+		
+		mx_internal static const BACKGROUND_GRADIENT_BRIGHTNESS_BOTTOM:int = -15;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor. 
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		public function CalloutSkin()
+		{
+			super();
+			
+			dropShadowAlpha = 0.7;
+			contentBackgroundInsetClass = spark.skins.android4.assets.CalloutContentBackground;
+			
+			switch (applicationDPI)
+			{
+				case DPIClassification.DPI_640:
+				{
+					
+					backgroundCornerRadius = 24;
+					backgroundGradientHeight = 440;
+					frameThickness = 12;
+					arrowWidth = 160;
+					arrowHeight = 80;
+					contentCornerRadius = 40;
+					dropShadowBlurX = 64;
+					dropShadowBlurY = 64;
+					dropShadowDistance = 12;
+					highlightWeight = 4;
+					
+					break;
+				}
+				case DPIClassification.DPI_480:
+				{
+					backgroundCornerRadius = 16;
+					backgroundGradientHeight = 330;
+					frameThickness = 8;
+					arrowWidth = 120;
+					arrowHeight = 60;
+					contentCornerRadius = 28;
+					dropShadowBlurX = 48;
+					dropShadowBlurY = 48;
+					dropShadowDistance = 8;
+					highlightWeight = 2;
+					
+					break;
+				}
+				case DPIClassification.DPI_320:
+				{
+					
+					backgroundCornerRadius = 12;
+					backgroundGradientHeight = 220;
+					frameThickness = 6;
+					arrowWidth = 80;
+					arrowHeight = 40;
+					contentCornerRadius = 20;
+					dropShadowBlurX = 32;
+					dropShadowBlurY = 32;
+					dropShadowDistance = 6;
+					highlightWeight = 2;
+					
+					break;
+				}
+				case DPIClassification.DPI_240:
+				{
+					backgroundCornerRadius = 8;
+					backgroundGradientHeight = 165;
+					frameThickness = 4;
+					arrowWidth = 60;
+					arrowHeight = 30;
+					contentCornerRadius = 14;
+					dropShadowBlurX = 24;
+					dropShadowBlurY = 24;
+					dropShadowDistance = 4;
+					highlightWeight = 1;
+					
+					break;
+				}
+				case DPIClassification.DPI_120:
+				{
+					backgroundCornerRadius = 4;
+					backgroundGradientHeight = 83;
+					frameThickness = 2;
+					arrowWidth = 30;
+					arrowHeight = 15;
+					contentCornerRadius = 7;
+					dropShadowBlurX = 12;
+					dropShadowBlurY = 12;
+					dropShadowDistance = 2;
+					highlightWeight = 0.5;
+					
+					break;
+				}
+				default:
+				{
+					// default DPI_160
+					backgroundCornerRadius = 6;
+					backgroundGradientHeight = 110;
+					frameThickness = 3;
+					arrowWidth = 40;
+					arrowHeight = 20;
+					contentCornerRadius = 10;
+					dropShadowBlurX = 16;
+					dropShadowBlurY = 16;
+					dropShadowDistance = 3;
+					highlightWeight = 1;
+					
+					break;
+				}
+			}
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/** 
+		 *  @copy spark.skins.spark.ApplicationSkin#hostComponent
+		 */
+		public var hostComponent:Callout;
+		
+		/**
+		 *  Enables a RectangularDropShadow behind the <code>backgroundColor</code> frame.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var dropShadowVisible:Boolean = true;
+		
+		/**
+		 *  Enables a vertical linear gradient in the <code>backgroundColor</code> frame. This
+		 *  gradient fill is drawn across both the arrow and the frame. By default,
+		 *  the gradient brightens the background color by 15% and darkens it by 60%.
+		 * 
+		 *  @default true
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var useBackgroundGradient:Boolean = true;
+		
+		/**
+		 *  Corner radius used for the <code>contentBackgroundColor</code> fill.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var contentCornerRadius:uint;
+		
+		/**
+		 *  A class reference to an FXG class that is layered underneath the
+		 *  <code>contentGroup</code>. The instance of this class is sized to match the
+		 *  <code>contentGroup</code>.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var contentBackgroundInsetClass:Class;
+		
+		/**
+		 *  Corner radius of the <code>backgroundColor</code> "frame".
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var backgroundCornerRadius:Number;
+		
+		/**
+		 *  The thickness of the <code>backgroundColor</code> "frame" that surrounds the
+		 *  <code>contentGroup</code>.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var frameThickness:Number;
+		
+		/**
+		 *  Color of the border stroke around the <code>backgroundColor</code> "frame".
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var borderColor:Number = -1; // not set
+		
+		/**
+		 *  Thickness of the border stroke around the <code>backgroundColor</code>
+		 *  "frame".
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var borderThickness:Number = -1 ;      // marker that borderThickness was not set  directly
+		
+		/**
+		 *  Width of the arrow in vertical directions. This property also controls
+		 *  the height of the arrow in horizontal directions.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var arrowWidth:Number;
+		
+		/**
+		 *  Height of the arrow in vertical directions. This property also controls
+		 *  the width of the arrow in horizontal directions.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion AIR 3
+		 *  @productversion Flex 4.6
+		 */
+		protected var arrowHeight:Number;
+		
+		/**
+		 *  @private
+		 *  Instance of the contentBackgroundClass
+		 */
+		mx_internal var contentBackgroundGraphic:SpriteVisualElement;
+		
+		/**
+		 *  @private
+		 *  Tracks changes to the skin state to support the fade out tranisition 
+		 *  when closed;
+		 */
+		mx_internal var isOpen:Boolean;
+		
+		private var backgroundGradientHeight:Number;
+		
+		private var contentMask:Sprite;
+		
+		private var backgroundFill:SpriteVisualElement;
+		
+		private var dropShadow:RectangularDropShadow;
+		
+		private var dropShadowBlurX:Number;
+		
+		private var dropShadowBlurY:Number;
+		
+		private var dropShadowDistance:Number;
+		
+		private var dropShadowAlpha:Number;
+		
+		private var fade:Fade;
+		
+		private var highlightWeight:Number;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Skin parts
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @copy spark.components.SkinnableContainer#contentGroup
+		 */
+		public var contentGroup:Group;
+		
+		/**
+		 * @copy spark.components.Callout#arrow
+		 */
+		public var arrow:UIComponent;
+		
+		/* helper private accessors */
+		
+		/* returns borderThickness from style if member is -1, or borderThickness.  Returns 0 if NaN */
+		mx_internal function get actualBorderThickness():Number
+		{
+			var border: Number =  borderThickness != -1 ? borderThickness : getStyle('borderThickness');
+			return isNaN(border)? 0: border;
+		}
+		
+		mx_internal function get actualBorderColor():uint
+		{
+			return borderColor != -1 ? borderColor: getStyle('borderColor');
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 * @private
+		 */
+		override protected function createChildren():void
+		{
+			super.createChildren();
+			
+			if (dropShadowVisible)
+			{
+				dropShadow = new RectangularDropShadow();
+				dropShadow.angle = 90;
+				dropShadow.distance = dropShadowDistance;
+				dropShadow.blurX = dropShadowBlurX;
+				dropShadow.blurY = dropShadowBlurY;
+				dropShadow.tlRadius = dropShadow.trRadius = dropShadow.blRadius = 
+					dropShadow.brRadius = backgroundCornerRadius ;
+				dropShadow.mouseEnabled = false;
+				dropShadow.alpha = dropShadowAlpha;
+				addChild(dropShadow);
+			}
+			
+			// background fill placed above the drop shadow
+			backgroundFill = new SpriteVisualElement();
+			addChild(backgroundFill);
+			
+			// arrow
+			if (!arrow)
+			{
+				arrow = new CalloutArrow();
+				arrow.id = "arrow";
+				arrow.styleName = this;
+				addChild(arrow);
+			}
+			
+			// contentGroup
+			if (!contentGroup)
+			{
+				contentGroup = new Group();
+				contentGroup.id = "contentGroup";
+				addChild(contentGroup);
+			}
+			
+			
+		}
+		
+		/**
+		 * @private
+		 */
+		override protected function commitProperties():void
+		{
+			super.commitProperties();
+			
+			// add or remove the contentBackgroundGraphic
+			var contentBackgroundAppearance:String = getStyle("contentBackgroundAppearance");
+			
+			if (contentBackgroundAppearance == ContentBackgroundAppearance.INSET)
+			{
+				// create the contentBackgroundGraphic
+				if (!contentBackgroundGraphic && contentBackgroundInsetClass)
+				{
+					contentBackgroundGraphic = new contentBackgroundInsetClass() as SpriteVisualElement;
+					
+					// with the current skin structure, contentBackgroundGraphic is
+					// always the last child
+					addChild(contentBackgroundGraphic);
+				}
+			}
+			else if (contentBackgroundGraphic)
+			{
+				// if already created, remove the graphic for "flat" and "none"
+				removeChild(contentBackgroundGraphic);
+				contentBackgroundGraphic = null;
+			}
+			
+			// always invalidate to accomodate arrow direction changes
+			invalidateSize();
+			invalidateDisplayList();
+		}
+		
+		
+		/**
+		 * @private
+		 */
+		override protected function measure():void
+		{
+			super.measure();
+			
+			var borderWeight:Number =actualBorderThickness;
+			var frameAdjustment:Number = (frameThickness + borderWeight) * 2;
+			
+			var arrowMeasuredWidth:Number;
+			var arrowMeasuredHeight:Number;
+			
+			// pad the arrow so that the edges are within the background corner radius
+			if (isArrowHorizontal)
+			{
+				arrowMeasuredWidth = arrowHeight;
+				arrowMeasuredHeight = arrowWidth + (backgroundCornerRadius * 2);
+			}
+			else if (isArrowVertical)
+			{
+				arrowMeasuredWidth = arrowWidth + (backgroundCornerRadius * 2);
+				arrowMeasuredHeight = arrowHeight;
+			}
+			
+			// count the contentGroup size and frame size
+			measuredMinWidth = contentGroup.measuredMinWidth + frameAdjustment;
+			measuredMinHeight = contentGroup.measuredMinHeight + frameAdjustment;
+			
+			measuredWidth = contentGroup.getPreferredBoundsWidth() + frameAdjustment;
+			measuredHeight = contentGroup.getPreferredBoundsHeight() + frameAdjustment;
+			
+			// add the arrow size based on the arrowDirection
+			if (isArrowHorizontal)
+			{
+				measuredMinWidth += arrowMeasuredWidth;
+				measuredMinHeight = Math.max(measuredMinHeight, arrowMeasuredHeight);
+				
+				measuredWidth += arrowMeasuredWidth;
+				measuredHeight = Math.max(measuredHeight, arrowMeasuredHeight);
+			}
+			else if (isArrowVertical)
+			{
+				measuredMinWidth += Math.max(measuredMinWidth, arrowMeasuredWidth);
+				measuredMinHeight += arrowMeasuredHeight;
+				
+				measuredWidth = Math.max(measuredWidth, arrowMeasuredWidth);
+				measuredHeight += arrowMeasuredHeight;
+			}
+		}
+		
+		/**
+		 *  @private
+		 *  SkinnaablePopUpContainer skins must dispatch a 
+		 *  FlexEvent.STATE_CHANGE_COMPLETE event for the component to properly
+		 *  update the skin state.
+		 */
+		override protected function commitCurrentState():void
+		{
+			super.commitCurrentState();
+			
+			var isNormal:Boolean = (currentState == "normal");
+			var isDisabled:Boolean = (currentState == "disabled")
+			
+			// play a fade out if the callout was previously open
+			if (!(isNormal || isDisabled) && isOpen)
+			{
+				if (!fade)
+				{
+					fade = new Fade();
+					fade.target = this;
+					fade.duration = 200;
+					fade.alphaTo = 0;
+				}
+				
+				// BlendMode.LAYER while fading out
+				blendMode = BlendMode.LAYER;
+				
+				// play a short fade effect
+				fade.addEventListener(EffectEvent.EFFECT_END, stateChangeComplete);
+				fade.play();
+				
+				isOpen = false;
+			}
+			else
+			{
+				isOpen = isNormal || isDisabled;
+				
+				// handle re-opening the Callout while fading out
+				if (fade && fade.isPlaying)
+				{
+					// Do not dispatch a state change complete.
+					// SkinnablePopUpContainer handles state interruptions.
+					fade.removeEventListener(EffectEvent.EFFECT_END, stateChangeComplete);
+					fade.stop();
+				}
+				
+				if (isDisabled)
+				{
+					// BlendMode.LAYER to allow CalloutArrow BlendMode.ERASE
+					blendMode = BlendMode.LAYER;
+					
+					alpha = 0.5;
+				}
+				else
+				{
+					// BlendMode.NORMAL for non-animated state transitions
+					blendMode = BlendMode.NORMAL;
+					
+					if (isNormal)
+						alpha = 1;
+					else
+						alpha = 0;
+				}
+				
+				stateChangeComplete();
+			}
+		}
+		
+		/**
+		 * @private
+		 */
+		override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.drawBackground(unscaledWidth, unscaledHeight);
+			
+			var frameEllipseSize:Number = backgroundCornerRadius * 2;
+			
+			// account for borderThickness center stroke alignment
+			var borderWeight:Number =actualBorderThickness;
+			var showBorder:Boolean = borderWeight > 0 ;
+			
+			
+			// contentBackgroundGraphic already accounts for the arrow position
+			// use it's positioning instead of recalculating based on unscaledWidth
+			// and unscaledHeight
+			var frameX:Number = Math.floor(contentGroup.getLayoutBoundsX() - frameThickness) - (borderWeight / 2);
+			var frameY:Number = Math.floor(contentGroup.getLayoutBoundsY() - frameThickness) - (borderWeight / 2);
+			var frameWidth:Number = contentGroup.getLayoutBoundsWidth() + (frameThickness * 2) + borderWeight;
+			var frameHeight:Number = contentGroup.getLayoutBoundsHeight() + (frameThickness * 2) + borderWeight;
+			
+			var backgroundColor:Number = getStyle("primaryAccentColor");
+			var backgroundAlpha:Number = getStyle("backgroundAlpha");
+			
+			var bgFill:Graphics = backgroundFill.graphics;
+			bgFill.clear();
+			
+			if (showBorder)
+				bgFill.lineStyle(borderWeight, actualBorderColor, 1, true);
+			
+			if (useBackgroundGradient)
+			{
+				// top color is brighter if arrowDirection == ArrowDirection.UP
+				var backgroundColorTop:Number = ColorUtil.adjustBrightness2(backgroundColor, 
+					BACKGROUND_GRADIENT_BRIGHTNESS_TOP);
+				var backgroundColorBottom:Number = ColorUtil.adjustBrightness2(backgroundColor, 
+					BACKGROUND_GRADIENT_BRIGHTNESS_BOTTOM);
+				
+				// max gradient height = backgroundGradientHeight
+				colorMatrix.createGradientBox(unscaledWidth, backgroundGradientHeight,
+					Math.PI / 2, 0, 0);
+				
+				bgFill.beginGradientFill(GradientType.LINEAR,
+					[backgroundColorTop, backgroundColorBottom],
+					[backgroundAlpha, backgroundAlpha],
+					[0, 255],
+					colorMatrix);
+			}
+			else
+			{
+				bgFill.beginFill(backgroundColor, backgroundAlpha);
+			}
+			
+			bgFill.drawRoundRect(frameX, frameY, frameWidth,
+				frameHeight, frameEllipseSize, frameEllipseSize);
+			bgFill.endFill();
+			
+			// draw content background styles
+			var contentBackgroundAppearance:String = getStyle("contentBackgroundAppearance");
+			
+			if (contentBackgroundAppearance != ContentBackgroundAppearance.NONE)
+			{
+				var contentEllipseSize:Number = contentCornerRadius * 2;
+				var contentBackgroundAlpha:Number = getStyle("contentBackgroundAlpha");
+				var contentWidth:Number = contentGroup.getLayoutBoundsWidth();
+				var contentHeight:Number = contentGroup.getLayoutBoundsHeight();
+				
+				// all appearance values except for "none" use a mask
+				if (!contentMask)
+					contentMask = new SpriteVisualElement();
+				
+				contentGroup.mask = contentMask;
+				
+				// draw contentMask in contentGroup coordinate space
+				var maskGraphics:Graphics = contentMask.graphics;
+				maskGraphics.clear();
+				maskGraphics.beginFill(0, 1);
+				maskGraphics.drawRoundRect(0, 0, contentWidth, contentHeight,
+					contentEllipseSize, contentEllipseSize);
+				maskGraphics.endFill();
+				
+				// reset line style to none
+				if (showBorder)
+					bgFill.lineStyle(NaN);
+				
+				// draw the contentBackgroundColor
+				bgFill.beginFill(getStyle("contentBackgroundColor"),
+					contentBackgroundAlpha);
+				bgFill.drawRoundRect(contentGroup.getLayoutBoundsX(),
+					contentGroup.getLayoutBoundsY(),
+					contentWidth, contentHeight, contentEllipseSize, contentEllipseSize);
+				bgFill.endFill();
+				
+				if (contentBackgroundGraphic)
+					contentBackgroundGraphic.alpha = contentBackgroundAlpha;
+			}
+			else // if (contentBackgroundAppearance == CalloutContentBackgroundAppearance.NONE))
+			{
+				// remove the mask
+				if (contentMask)
+				{
+					contentGroup.mask = null;
+					contentMask = null;
+				}
+			}
+			
+			// draw highlight in the callout when the arrow is hidden
+			if (useBackgroundGradient && !isArrowHorizontal && !isArrowVertical)
+			{
+				// highlight width spans the callout width minus the corner radius
+				var highlightWidth:Number = frameWidth - frameEllipseSize;
+				var highlightX:Number = frameX + backgroundCornerRadius;
+				var highlightOffset:Number = (highlightWeight * 1.5);
+				
+				// straight line across the top
+				bgFill.lineStyle(highlightWeight, 0xFFFFFF, 0.2 * backgroundAlpha);
+				bgFill.moveTo(highlightX, highlightOffset);
+				bgFill.lineTo(highlightX + highlightWidth, highlightOffset);
+			}
+		}
+		
+		/**
+		 * @private
+		 */
+		override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.layoutContents(unscaledWidth, unscaledHeight);
+			
+			// pad the arrow so that the edges are within the background corner radius
+			if (isArrowHorizontal)
+			{
+				arrow.width = arrowHeight;
+				arrow.height = arrowWidth + (backgroundCornerRadius * 2);
+			}
+			else if (isArrowVertical)
+			{
+				arrow.width = arrowWidth + (backgroundCornerRadius * 2);
+				arrow.height = arrowHeight;
+			}
+			
+			setElementSize(backgroundFill, unscaledWidth, unscaledHeight);
+			setElementPosition(backgroundFill, 0, 0);
+			
+			var frameX:Number = 0;
+			var frameY:Number = 0;
+			var frameWidth:Number = unscaledWidth;
+			var frameHeight:Number = unscaledHeight;
+			
+			switch (hostComponent.arrowDirection)
+			{
+				case ArrowDirection.UP:
+					frameY = arrow.height;
+					frameHeight -= arrow.height;
+					break;
+				case ArrowDirection.DOWN:
+					frameHeight -= arrow.height;
+					break;
+				case ArrowDirection.LEFT:
+					frameX = arrow.width;
+					frameWidth -= arrow.width;
+					break;
+				case ArrowDirection.RIGHT:
+					frameWidth -= arrow.width;
+					break;
+				default:
+					// no arrow, content takes all available space
+					break;
+			}
+			
+			if (dropShadow)
+			{
+				setElementSize(dropShadow, frameWidth, frameHeight);
+				setElementPosition(dropShadow, frameX, frameY);
+			}
+			
+			// Show frameThickness by inset of contentGroup
+			var borderWeight:Number = actualBorderThickness;
+			var contentBackgroundAdjustment:Number = frameThickness + borderWeight;
+			
+			var contentBackgroundX:Number = frameX + contentBackgroundAdjustment;
+			var contentBackgroundY:Number = frameY + contentBackgroundAdjustment;
+			
+			contentBackgroundAdjustment = contentBackgroundAdjustment * 2;
+			var contentBackgroundWidth:Number = frameWidth - contentBackgroundAdjustment;
+			var contentBackgroundHeight:Number = frameHeight - contentBackgroundAdjustment;
+			
+			if (contentBackgroundGraphic)
+			{
+				setElementSize(contentBackgroundGraphic, contentBackgroundWidth, contentBackgroundHeight);
+				setElementPosition(contentBackgroundGraphic, contentBackgroundX, contentBackgroundY);
+			}
+			
+			setElementSize(contentGroup, contentBackgroundWidth, contentBackgroundHeight);
+			setElementPosition(contentGroup, contentBackgroundX, contentBackgroundY);
+			
+			// mask position is in the contentGroup coordinate space
+			if (contentMask)
+				setElementSize(contentMask, contentBackgroundWidth, contentBackgroundHeight);
+		}
+		
+		override public function styleChanged(styleProp:String):void
+		{
+			super.styleChanged(styleProp);
+			
+			var allStyles:Boolean = !styleProp || styleProp == "styleName";
+			
+			if (allStyles || (styleProp == "contentBackgroundAppearance"))
+				invalidateProperties();
+			
+			if (allStyles || (styleProp == "backgroundAlpha"))
+			{
+				var backgroundAlpha:Number = getStyle("backgroundAlpha");
+				
+				// Use BlendMode.LAYER to allow CalloutArrow to erase the dropShadow
+				// when the Callout background is transparent
+				blendMode = (backgroundAlpha < 1) ? BlendMode.LAYER : BlendMode.NORMAL;
+			}
+		}
+		
+		/**
+		 * @private
+		 */
+		mx_internal function get isArrowHorizontal():Boolean
+		{
+			return (hostComponent.arrowDirection == ArrowDirection.LEFT
+				|| hostComponent.arrowDirection == ArrowDirection.RIGHT);
+		}
+		
+		/**
+		 * @private
+		 */
+		mx_internal function get isArrowVertical():Boolean
+		{
+			return (hostComponent.arrowDirection == ArrowDirection.UP
+				|| hostComponent.arrowDirection == ArrowDirection.DOWN);
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Event handlers
+		//
+		//--------------------------------------------------------------------------
+		
+		private function stateChangeComplete(event:Event=null):void
+		{
+			if (fade && event)
+				fade.removeEventListener(EffectEvent.EFFECT_END, stateChangeComplete);
+			
+			// SkinnablePopUpContainer relies on state changes for open and close
+			dispatchEvent(new FlexEvent(FlexEvent.STATE_CHANGE_COMPLETE));
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/539852e9/tourdeflexmobile/src/spark/skins/android4/CheckBoxSkin.as
----------------------------------------------------------------------
diff --git a/tourdeflexmobile/src/spark/skins/android4/CheckBoxSkin.as b/tourdeflexmobile/src/spark/skins/android4/CheckBoxSkin.as
new file mode 100644
index 0000000..f091205
--- /dev/null
+++ b/tourdeflexmobile/src/spark/skins/android4/CheckBoxSkin.as
@@ -0,0 +1,268 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.DisplayObject;
+	
+	import mx.core.DPIClassification;
+	
+	import spark.skins.android4.assets.CheckBox_up;
+	import spark.skins.mobile.supportClasses.SelectableButtonSkinBase;
+	
+	/**
+	 *  ActionScript-based skin for CheckBox components in mobile applications. 
+	 * 
+	 *  @see spark.components.CheckBox
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 2.5 
+	 *  @productversion Flex 4.5
+	 */
+	public class CheckBoxSkin extends SelectableButtonSkinBase
+	{
+		//--------------------------------------------------------------------------
+		//
+		//  Class constants
+		//
+		//--------------------------------------------------------------------------
+		
+		private static const exclusions:Array = ["labelDisplay", "labelDisplayShadow"];
+
+		//--------------------------------------------------------------------------
+		//
+		//  Member variables
+		//
+		//--------------------------------------------------------------------------
+
+		protected var symbolOffsetX:Number;
+		protected var symbolOffsetY:Number;
+		protected var iconWidth:Number;
+		protected var iconHeight:Number;
+		protected var symbolWidth:Number;
+		protected var symbolHeight:Number;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		public function CheckBoxSkin()
+		{
+			super();
+			
+			layoutPaddingLeft = 0;
+			layoutPaddingRight = 0;
+			layoutPaddingTop = 0;
+			layoutPaddingBottom = 0;
+			
+			upIconClass = spark.skins.android4.assets.CheckBox_up;
+			upSelectedIconClass = spark.skins.android4.assets.CheckBox_upSelected;
+			downIconClass = spark.skins.android4.assets.CheckBox_down;
+			downSelectedIconClass = spark.skins.android4.assets.CheckBox_downSelected;
+			upSymbolIconClass = null;
+			upSymbolIconSelectedClass = spark.skins.android4.assets.CheckBox_upSymbolSelected;
+			downSymbolIconSelectedClass = spark.skins.android4.assets.CheckBox_downSymbolSelected;
+			downSymbolIconClass = null;
+					
+			switch (applicationDPI)
+			{
+				case DPIClassification.DPI_640:
+				{
+					
+					layoutGap = 16;
+					minWidth = 128;
+					minHeight = 128;
+					layoutBorderSize = 6;
+					iconWidth = 128;
+					iconHeight = 128;
+					symbolWidth = 64;
+					symbolHeight = 64;
+					symbolOffsetX = 32;
+					symbolOffsetY = 32;
+					
+					break;
+				}
+				case DPIClassification.DPI_480:
+				{
+					
+					layoutGap = 12;
+					minWidth = 96;
+					minHeight = 96;
+					layoutBorderSize = 4;
+					iconWidth = 96;
+					iconHeight = 96;
+					symbolWidth = 48;
+					symbolHeight = 48;
+					symbolOffsetX = 24;
+					symbolOffsetY = 24;
+					
+					break;
+				}
+				case DPIClassification.DPI_320:
+				{
+					
+					layoutGap = 8;
+					minWidth = 64;
+					minHeight = 64;
+					layoutBorderSize = 3;
+					iconWidth = 64;
+					iconHeight = 64;
+					symbolWidth = 32;
+					symbolHeight = 32;
+					symbolOffsetX = 16;
+					symbolOffsetY = 16;
+					
+					break;
+				}
+				case DPIClassification.DPI_240:
+				{
+					
+					layoutGap = 6;
+					minWidth = 48;
+					minHeight = 48;
+					layoutBorderSize = 2;
+					iconWidth = 48;
+					iconHeight = 48;
+					symbolWidth = 24;
+					symbolHeight = 24;
+					symbolOffsetX = 12;
+					symbolOffsetY = 12;
+					
+					break;
+				}
+				case DPIClassification.DPI_120:
+				{
+					
+					layoutGap = 3;
+					minWidth = 24;
+					minHeight = 24;
+					layoutBorderSize = 1;
+					iconWidth = 24;
+					iconHeight = 24;
+					symbolWidth = 12;
+					symbolHeight = 12;
+					symbolOffsetX = 6;
+					symbolOffsetY = 6;
+					
+					break;
+				}
+				default:
+				{
+					// default DPI_160
+					
+					layoutGap = 4;
+					minWidth = 32;
+					minHeight = 32;
+					layoutBorderSize = 2;
+					iconWidth = 32;
+					iconHeight = 32;
+					symbolWidth = 16;
+					symbolHeight = 16;
+					symbolOffsetX = 8;
+					symbolOffsetY = 8;
+					
+					
+					break;
+				}
+			}
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 *  CheckBox <code>chromeColor</code> is drawn to match the FXG rectangle
+		 *  shape and position.
+		 */
+		override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			// super draws a transparent hit zone
+			super.drawBackground(unscaledWidth, unscaledHeight);
+			
+			// get the size and position of iconDisplay
+			var currentIcon:DisplayObject = getIconDisplay();
+			var widthAdjustment:Number = layoutBorderSize * 2;
+			
+			graphics.beginFill(getStyle("chromeColor"));
+			graphics.drawRoundRect(currentIcon.x + layoutBorderSize,
+				currentIcon.y + layoutBorderSize,
+				currentIcon.width - widthAdjustment,
+				currentIcon.height - widthAdjustment, layoutBorderSize, layoutBorderSize);
+			graphics.endFill();
+		}
+		
+		/**
+		 *  List of IDs of items that should be excluded when rendering the focus ring.
+		 *  Only items of type DisplayObject or GraphicElement should be excluded. Items
+		 *  of other types are ignored.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 2.5
+		 *  @productversion Flex 4.5
+		 */
+		override protected function get focusSkinExclusions():Array 
+		{
+			return exclusions;
+		}
+		
+		override protected function commitCurrentState():void
+		{
+			super.commitCurrentState();
+			if(symbolIcon != null)
+			{
+				symbolIcon.width = symbolWidth;
+				symbolIcon.height = symbolHeight;
+			}
+			var iconDisplay:DisplayObject = getIconDisplay(); 
+			if(iconDisplay != null)
+			{
+				iconDisplay.width = iconWidth;
+				iconDisplay.height = iconHeight;
+			}
+		}
+		
+		override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.layoutContents(unscaledWidth, unscaledHeight);
+			// position the symbols to align with the background "icon"
+			if (symbolIcon)
+			{
+				var currentIcon:DisplayObject = getIconDisplay();
+				setElementPosition(symbolIcon, symbolOffsetX, symbolOffsetY);
+			}
+		}
+		
+	}
+}
\ No newline at end of file