//////////////////////////////////////////////////////////////////////////////// // // 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.components { import flash.display.DisplayObject; import flash.display.StageDisplayState; import flash.events.Event; import flash.events.FullScreenEvent; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.events.TimerEvent; import flash.geom.Rectangle; import flash.media.Video; import flash.system.ApplicationDomain; import flash.utils.Timer; import mx.core.FlexGlobals; import mx.core.IVisualElementContainer; import mx.core.mx_internal; import mx.events.FlexEvent; import mx.managers.PopUpManager; import mx.utils.BitFlagUtil; import org.osmf.events.LoadEvent; import org.osmf.events.MediaPlayerStateChangeEvent; import org.osmf.events.TimeEvent; import org.osmf.media.MediaPlayerState; import spark.components.mediaClasses.MuteButton; import spark.components.mediaClasses.ScrubBar; import spark.components.mediaClasses.VolumeBar; import spark.components.supportClasses.ButtonBase; import spark.components.supportClasses.SkinnableComponent; import spark.components.supportClasses.ToggleButtonBase; import spark.core.IDisplayText; import spark.events.TrackBaseEvent; use namespace mx_internal; //-------------------------------------- // Events //-------------------------------------- /** * Dispatched when the data is received as a download operation progresses. * This event is only dispatched when playing a video by downloading it * directly from a server, typically by issuing an HTTP request. * It is not displatched when playing a video from a special media server, * such as Flash Media Server. * *
This event may not be dispatched when the source is set to null or a playback * error occurs.
* * @eventType org.osmf.events.LoadEvent.BYTES_LOADED_CHANGE * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.0 * @productversion Flex 4 */ [Event(name="bytesLoadedChange",type="org.osmf.events.LoadEvent")] /** * Dispatched when the playhead reaches the duration for playable media. * * @eventType org.osmf.events.TimeEvent.COMPLETE * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.0 * @productversion Flex 4 */ [Event(name="complete", type="org.osmf.events.TimeEvent")] /** * Dispatched when thecurrentTime
property of the MediaPlayer has changed.
*
* This event may not be dispatched when the source is set to null or a playback * error occurs.
* * @eventType org.osmf.events.TimeEvent.CURRENT_TIME_CHANGE * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.0 * @productversion Flex 4 */ [Event(name="currentTimeChange",type="org.osmf.events.TimeEvent")] /** * Dispatched when theduration
property of the media has changed.
*
* This event may not be dispatched when the source is set to null or a playback * error occurs.
* * @eventType org.osmf.events.TimeEvent.DURATION_CHANGE * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.0 * @productversion Flex 4 */ [Event(name="durationChange", type="org.osmf.events.TimeEvent")] /** * Dispatched when the MediaPlayer's state has changed. * * @eventType org.osmf.events.MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.0 * @productversion Flex 4 */ [Event(name="mediaPlayerStateChange", type="org.osmf.events.MediaPlayerStateChangeEvent")] //-------------------------------------- // Styles //-------------------------------------- include "../styles/metadata/BasicInheritingTextStyles.as"; /** * Controls the visibility of the drop shadow for this component. * * @default true * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [Style(name="dropShadowVisible", type="Boolean", inherit="no", theme="spark")] /** * The time, in milli-seconds, to wait in fullscreen mode with no user-interaction * before hiding the video playback controls. * *If set to Infinity
, then the playback controls will not
* be hidden in fullscreen mode. Changing this value while already in
* fullscreen mode has no effect.
VideoDisplay
is the chromeless version that does not support skinning.
* It is useful when you do not want the user to interact with the control.
The VideoPlayer control has the following default characteristics:
*Characteristic | *Description | *
---|---|
Default size | *263 pixels wide by 184 pixels high | *
Minimum size | *0 | *
Maximum size | *10000 pixels wide and 10000 pixels high | *
Default skin class | *spark.skins.spark.VideoPlayerSkin | *
The <s:VideoPlayer>
tag inherits all of the tag
* attributes of its superclass and adds the following tag attributes:
* <s:VideoPlayer * Properties * autoDisplayFirstFrame="true" * autoPlay="true" * autoRewind="true" * loop="false" * muted="false" * pauseWhenHidden="true" * scaleMode="letterbox" * source="" * volume="1" * * Events * bytesLoadedChange="No default" * complete="No default" * currentTimeChange="No default" * durationChange="No default" * mediaPlayerStateChange="No default" * * * Styles * alignmentBaseline="baseline" * baselineShift="0" * cffHinting="0.0" * color="0x000000" * digitCase="default" * digitWidth="default" * direction="ltr" * dominantBaseline="auto" * dropShadowVisible="true" * fontFamily="Arial" * fontLookup="device" * fontSize="12" * fontStyle="normal" * fontWeight="normal" * justificationRule="auto" * justificationStyle="auto" * kerning="false" * ligatureLevel="common" * lineHeight="120%" * lineThrough="false%" * locale="en" * renderingMode="cff" * textAlign="start" * textAlignLast="start" * textAlpha="1" * textDecoration="start" * textJustify="interWord" * trackingLeft="0" * trackingRight="00" * typographicCase="default" * /> ** * @includeExample examples/VideoPlayerExample.mxml * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public class VideoPlayer extends SkinnableComponent { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Class constants // //-------------------------------------------------------------------------- /** * @private */ private static const AUTO_DISPLAY_FIRST_FRAME_PROPERTY_FLAG:uint = 1 << 0; /** * @private */ private static const AUTO_PLAY_PROPERTY_FLAG:uint = 1 << 1; /** * @private */ private static const AUTO_REWIND_PROPERTY_FLAG:uint = 1 << 2; /** * @private */ private static const LOOP_PROPERTY_FLAG:uint = 1 << 3; /** * @private */ private static const SCALE_MODE_PROPERTY_FLAG:uint = 1 << 4; /** * @private */ private static const MUTED_PROPERTY_FLAG:uint = 1 << 5; /** * @private */ private static const SOURCE_PROPERTY_FLAG:uint = 1 << 6; /** * @private */ private static const VOLUME_PROPERTY_FLAG:uint = 1 << 7; /** * @private */ private static const PAUSE_WHEN_HIDDEN_PROPERTY_FLAG:uint = 1 << 8; /** * @private */ private static const THUMBNAIL_SOURCE_PROPERTY_FLAG:uint = 1 << 9; //-------------------------------------------------------------------------- // // Class properties // //-------------------------------------------------------------------------- /** * @private */ private static var _screenClass:Class; /** * @private */ private static var checkedForScreenClass:Boolean; /** * @private */ private static function get screenClass():Class { if (!checkedForScreenClass) { checkedForScreenClass = true; if (ApplicationDomain.currentDomain. hasDefinition("flash.display::Screen")) { _screenClass = Class(ApplicationDomain.currentDomain. getDefinition("flash.display::Screen")); } } return _screenClass; } //-------------------------------------------------------------------------- // // Class mixins // //-------------------------------------------------------------------------- /** * @private * Placeholder for mixin by VideoPlayerAccImpl. */ mx_internal static var createAccessibilityImplementation:Function; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function VideoPlayer() { super(); } //-------------------------------------------------------------------------- // // Skin Parts // //-------------------------------------------------------------------------- [SkinPart(required="true")] /** * A required skin part that defines the VideoDisplay. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var videoDisplay:VideoDisplay; [SkinPart(required="false")] /** * An optional skin part to display the current value of
codecurrentTime
.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var currentTimeDisplay:IDisplayText;
[SkinPart(required="false")]
/**
* An optional skin part for a button to toggle fullscreen mode.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var fullScreenButton:ButtonBase;
[SkinPart(required="false")]
/**
* An optional skin part for the mute button. The mute
* button has both a muted
property and a
* volume
property.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var muteButton:MuteButton;
[SkinPart(required="false")]
/**
* An optional skin part for the pause button.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var pauseButton:ButtonBase;
[SkinPart(required="false")]
/**
* An optional skin part for the play button.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var playButton:ButtonBase;
[SkinPart(required="false")]
/**
* An optional skin part for all of the player controls.
* This skin is used to determine what to hide when the player is in full screen
* mode and there has been no user interaction.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var playerControls:DisplayObject;
[SkinPart(required="false")]
/**
* An optional skin part for a play/pause button. When the
* video is playing, the selected
property is set to
* true
. When the video is paused or stopped,
* the selected
property is set to false
.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var playPauseButton:ToggleButtonBase;
[SkinPart(required="false")]
/**
* An optional skin part for the scrub bar (the
* timeline).
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var scrubBar:ScrubBar;
[SkinPart(required="false")]
/**
* An optional skin part for the stop button.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var stopButton:ButtonBase;
[SkinPart(required="false")]
/**
* An optional skin part to display the duration.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var durationDisplay:IDisplayText;
[SkinPart(required="false")]
/**
* An optional skin part for the volume control.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var volumeBar:VolumeBar;
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
* Several properties are proxied to videoDisplay. However, when videoDisplay
* is not around, we need to store values set on VideoPlayer. This object
* stores those values. If videoDisplay is around, the values are stored
* on the videoDisplay directly. However, we need to know what values
* have been set by the developer on the VideoPlayer (versus set on
* the videoDisplay or defaults of the videoDisplay) as those are values
* we want to carry around if the videoDisplay changes (via a new skin).
* In order to store this info effeciently, videoDisplayProperties becomes
* a uint to store a series of BitFlags. These bits represent whether a
* property has been explicitely set on this VideoPlayer. When the
* contentGroup is not around, videoDisplayProperties is a typeless
* object to store these proxied properties. When videoDisplay is around,
* videoDisplayProperties stores booleans as to whether these properties
* have been explicitely set or not.
*/
private var videoDisplayProperties:Object = {};
/**
* @private
* The value of the pauseWhenHidden property before exiting
* fullScreen. We need to store it away here so we can
* restore it at commitProperties() time because of an AIR
* Mac bug.
*/
private var exitingFullScreenPauseWhenHidden:Boolean;
/**
* @private
* Whether the pauseWhenHidden property needs to be updated.
*/
private var needsToUpdatePauseWhenHidden:Boolean = false;
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// autoDisplayFirstFrame
//----------------------------------
[Inspectable(category="General", defaultValue="true")]
/**
* @copy spark.components.VideoDisplay#autoDisplayFirstFrame
*
* @default true
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get autoDisplayFirstFrame():Boolean
{
if (videoDisplay)
{
return videoDisplay.autoDisplayFirstFrame;
}
else
{
var v:* = videoDisplayProperties.autoDisplayFirstFrame;
return (v === undefined) ? true : v;
}
}
/**
* @private
*/
public function set autoDisplayFirstFrame(value:Boolean):void
{
if (videoDisplay)
{
videoDisplay.autoDisplayFirstFrame = value;
videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint,
AUTO_DISPLAY_FIRST_FRAME_PROPERTY_FLAG, true);
}
else
{
videoDisplayProperties.autoDisplayFirstFrame = value;
}
}
//----------------------------------
// autoPlay
//----------------------------------
[Inspectable(category="General", defaultValue="true")]
/**
* @copy spark.components.VideoDisplay#autoPlay
*
* @default true
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get autoPlay():Boolean
{
if (videoDisplay)
{
return videoDisplay.autoPlay;
}
else
{
var v:* = videoDisplayProperties.autoPlay;
return (v === undefined) ? true : v;
}
}
/**
* @private
*/
public function set autoPlay(value:Boolean):void
{
if (videoDisplay)
{
videoDisplay.autoPlay = value;
videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint,
AUTO_PLAY_PROPERTY_FLAG, true);
}
else
{
videoDisplayProperties.autoPlay = value;
}
}
//----------------------------------
// autoRewind
//----------------------------------
[Inspectable(category="General", defaultValue="true")]
/**
* @copy spark.components.VideoDisplay#autoRewind
*
* @default true
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get autoRewind():Boolean
{
if (videoDisplay)
{
return videoDisplay.autoRewind;
}
else
{
var v:* = videoDisplayProperties.autoRewind;
return (v === undefined) ? true : v;
}
}
/**
* @private
*/
public function set autoRewind(value:Boolean):void
{
if (videoDisplay)
{
videoDisplay.autoRewind = value;
videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint,
AUTO_REWIND_PROPERTY_FLAG, true);
}
else
{
videoDisplayProperties.autoRewind = value;
}
}
//----------------------------------
// bytesLoaded
//----------------------------------
[Inspectable(Category="General", defaultValue="0")]
[Bindable("bytesLoadedChange")]
[Bindable("mediaPlayerStateChange")]
/**
* @copy spark.components.VideoDisplay#bytesLoaded
*
* @default 0
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get bytesLoaded():Number
{
if (videoDisplay)
return videoDisplay.bytesLoaded;
else
return 0;
}
//----------------------------------
// bytesTotal
//----------------------------------
[Inspectable(Category="General", defaultValue="0")]
[Bindable("mediaPlayerStateChange")]
/**
* @copy spark.components.VideoDisplay#bytesTotal
*
* @default 0
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get bytesTotal():Number
{
if (videoDisplay)
return videoDisplay.bytesTotal;
else
return 0;
}
//----------------------------------
// currentTime
//----------------------------------
[Inspectable(Category="General", defaultValue="0")]
[Bindable("currentTimeChange")]
[Bindable("mediaPlayerStateChange")]
/**
* @copy spark.components.VideoDisplay#currentTime
*
* @default 0
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get currentTime():Number
{
if (videoDisplay)
return videoDisplay.currentTime;
else
return 0;
}
//----------------------------------
// duration
//----------------------------------
[Inspectable(Category="General", defaultValue="0")]
[Bindable("durationChange")]
[Bindable("mediaPlayerStateChange")]
/**
* @copy spark.components.VideoDisplay#duration
*
* @default 0
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get duration():Number
{
if (videoDisplay)
return videoDisplay.duration;
else
return 0;
}
//----------------------------------
// loop
//----------------------------------
[Inspectable(Category="General", defaultValue="false")]
/**
* @copy spark.components.VideoDisplay#loop
*
* @default false
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get loop():Boolean
{
if (videoDisplay)
{
return videoDisplay.loop;
}
else
{
var v:* = videoDisplayProperties.loop;
return (v === undefined) ? false : v;
}
}
/**
* @private
*/
public function set loop(value:Boolean):void
{
if (videoDisplay)
{
videoDisplay.loop = value;
videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint,
LOOP_PROPERTY_FLAG, true);
}
else
{
videoDisplayProperties.loop = value;
}
}
//----------------------------------
// mediaPlayerState
//----------------------------------
[Inspectable(category="General", defaultValue="uninitialized")]
[Bindable("mediaPlayerStateChange")]
/**
* @copy spark.components.VideoDisplay#mediaPlayerState
*
* @default uninitialized
*
* @see org.osmf.media.MediaPlayerState
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get mediaPlayerState():String
{
if (videoDisplay)
return videoDisplay.mediaPlayerState;
else
return MediaPlayerState.UNINITIALIZED;
}
//----------------------------------
// muted
//----------------------------------
[Inspectable(category="General", defaultValue="false")]
[Bindable("volumeChanged")]
/**
* @copy spark.components.VideoDisplay#muted
*
* @default false
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get muted():Boolean
{
if (videoDisplay)
{
return videoDisplay.muted;
}
else
{
var v:* = videoDisplayProperties.muted;
return (v === undefined) ? false : v;
}
}
/**
* @private
*/
public function set muted(value:Boolean):void
{
if (videoDisplay)
{
videoDisplay.muted = value;
videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint,
MUTED_PROPERTY_FLAG, true);
}
else
{
videoDisplayProperties.muted = value;
}
if (volumeBar)
volumeBar.muted = value;
if (muteButton)
muteButton.muted = value;
}
//----------------------------------
// pauseWhenHidden
//----------------------------------
[Inspectable(category="General", defaultValue="true")]
/**
* @copy spark.components.VideoDisplay#pauseWhenHidden
*
* @default true
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get pauseWhenHidden():Boolean
{
if (needsToUpdatePauseWhenHidden)
{
return exitingFullScreenPauseWhenHidden;
}
else if (videoDisplay)
{
return videoDisplay.pauseWhenHidden;
}
else
{
var v:* = videoDisplayProperties.pauseWhenHidden;
return (v === undefined) ? false : v;
}
}
/**
* @private
*/
public function set pauseWhenHidden(value:Boolean):void
{
if (needsToUpdatePauseWhenHidden)
{
exitingFullScreenPauseWhenHidden = value;
}
else if (videoDisplay)
{
videoDisplay.pauseWhenHidden = value;
videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint,
PAUSE_WHEN_HIDDEN_PROPERTY_FLAG, true);
}
else
{
videoDisplayProperties.pauseWhenHidden = value;
}
}
//----------------------------------
// playing
//----------------------------------
[Inspectable(category="General")]
[Bindable("mediaPlayerStateChange")]
/**
* @copy spark.components.VideoDisplay#playing
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get playing():Boolean
{
if (videoDisplay)
return videoDisplay.playing;
else
return false;
}
//----------------------------------
// scaleMode
//----------------------------------
[Inspectable(Category="General", enumeration="none,stretch,letterbox,zoom", defaultValue="letterbox")]
/**
* @copy spark.components.VideoDisplay#scaleMode
*
* @default "letterbox"
*
* @see org.osmf.display.ScaleMode
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get scaleMode():String
{
if (videoDisplay)
{
return videoDisplay.scaleMode;
}
else
{
var v:* = videoDisplayProperties.scaleMode;
return (v === undefined) ? "letterbox" : v;
}
}
/**
* @private
*/
public function set scaleMode(value:String):void
{
if (videoDisplay)
{
videoDisplay.scaleMode = value;
videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint,
SCALE_MODE_PROPERTY_FLAG, true);
}
else
{
videoDisplayProperties.scaleMode = value;
}
}
//----------------------------------
// source
//----------------------------------
[Inspectable(category="General", defaultValue="null")]
[Bindable("sourceChanged")]
/**
* @copy spark.components.VideoDisplay#source
*
* @default null
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get source():Object
{
if (videoDisplay)
{
return videoDisplay.source;
}
else
{
var v:* = videoDisplayProperties.source;
return (v === undefined) ? null : v;
}
}
/**
* @private
*/
public function set source(value:Object):void
{
if (videoDisplay)
{
videoDisplay.source = value;
videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint,
SOURCE_PROPERTY_FLAG, true);
}
else
{
videoDisplayProperties.source = value;
}
}
//----------------------------------
// thumbnailSource
//----------------------------------
[Inspectable(category="General")]
/**
* @private
* @copy spark.components.VideoDisplay#thumbnailSource
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
mx_internal function get thumbnailSource():Object
{
if (videoDisplay)
{
return videoDisplay.thumbnailSource;
}
else
{
var v:* = videoDisplayProperties.thumbnailSource;
return (v === undefined) ? null : v;
}
}
/**
* @private
*/
mx_internal function set thumbnailSource(value:Object):void
{
if (videoDisplay)
{
videoDisplay.thumbnailSource = value;
videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint,
THUMBNAIL_SOURCE_PROPERTY_FLAG, true);
}
else
{
videoDisplayProperties.thumbnailSource = value;
}
}
//----------------------------------
// videoObject
//----------------------------------
[Inspectable(category="General", defaultValue="null")]
/**
* @copy spark.components.VideoDisplay#videoObject
*
* @default null
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get videoObject():Video
{
if (videoDisplay)
return videoDisplay.videoObject;
else
return null;
}
//----------------------------------
// volume
//----------------------------------
[Inspectable(category="General", defaultValue="1.0", minValue="0.0", maxValue="1.0")]
[Bindable("volumeChanged")]
/**
* @copy spark.components.VideoDisplay#volume
*
* @default 1
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get volume():Number
{
if (videoDisplay)
{
return videoDisplay.volume;
}
else
{
var v:* = videoDisplayProperties.volume;
return (v === undefined) ? 1 : v;
}
}
/**
* @private
*/
public function set volume(value:Number):void
{
if (videoDisplay)
{
videoDisplay.volume = value;
videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint,
VOLUME_PROPERTY_FLAG, true);
}
else
{
videoDisplayProperties.volume = value;
}
if (volumeBar)
volumeBar.value = value;
}
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
/**
* @private
*/
override protected function initializeAccessibility():void
{
if (VideoPlayer.createAccessibilityImplementation != null)
VideoPlayer.createAccessibilityImplementation(this);
}
/**
* @private
*/
override protected function getCurrentSkinState():String
{
if (!videoDisplay || !videoDisplay.videoPlayer)
return null;
var state:String = videoDisplay.videoPlayer.state;
// now that we have our video player's current state (atleast the one we care about)
// and that we've set the previous state to something we care about, let's figure
// out our skin's state
if (!enabled)
state="disabled"
if (fullScreen)
return state + "AndFullScreen";
return state;
}
/**
* @private
*/
override protected function partAdded(partName:String, instance:Object):void
{
super.partAdded(partName, instance);
if (instance == videoDisplay)
{
videoDisplay.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, videoDisplay_currentTimeChangeHandler);
videoDisplay.addEventListener(LoadEvent.BYTES_LOADED_CHANGE, videoDisplay_bytesLoadedChangeHandler);
videoDisplay.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, videoDisplay_mediaPlayerStateChangeHandler);
videoDisplay.addEventListener(TimeEvent.DURATION_CHANGE, videoDisplay_durationChangeHandler);
videoDisplay.addEventListener(TimeEvent.COMPLETE, dispatchEvent);
// just strictly for binding purposes
videoDisplay.addEventListener("sourceChanged", dispatchEvent);
videoDisplay.addEventListener("volumeChanged", videoDisplay_volumeChangedHandler);
// copy proxied values from videoProperties (if set) to video
var newVideoProperties:uint = 0;
if (videoDisplayProperties.source !== undefined)
{
videoDisplay.source = videoDisplayProperties.source;
newVideoProperties = BitFlagUtil.update(newVideoProperties as uint,
SOURCE_PROPERTY_FLAG, true);
}
if (videoDisplayProperties.autoPlay !== undefined)
{
videoDisplay.autoPlay = videoDisplayProperties.autoPlay;
newVideoProperties = BitFlagUtil.update(newVideoProperties as uint,
AUTO_PLAY_PROPERTY_FLAG, true);
}
if (videoDisplayProperties.volume !== undefined)
{
videoDisplay.volume = videoDisplayProperties.volume;
newVideoProperties = BitFlagUtil.update(newVideoProperties as uint,
VOLUME_PROPERTY_FLAG, true);
}
if (videoDisplayProperties.autoRewind !== undefined)
{
videoDisplay.autoRewind = videoDisplayProperties.autoRewind;
newVideoProperties = BitFlagUtil.update(newVideoProperties as uint,
AUTO_REWIND_PROPERTY_FLAG, true);
}
if (videoDisplayProperties.loop !== undefined)
{
videoDisplay.loop = videoDisplayProperties.loop;
newVideoProperties = BitFlagUtil.update(newVideoProperties as uint,
LOOP_PROPERTY_FLAG, true);
}
if (videoDisplayProperties.scaleMode !== undefined)
{
videoDisplay.scaleMode = videoDisplayProperties.scaleMode;
newVideoProperties = BitFlagUtil.update(newVideoProperties as uint,
SCALE_MODE_PROPERTY_FLAG, true);
}
if (videoDisplayProperties.muted !== undefined)
{
videoDisplay.muted = videoDisplayProperties.muted;
newVideoProperties = BitFlagUtil.update(newVideoProperties as uint,
MUTED_PROPERTY_FLAG, true);
}
if (videoDisplayProperties.pauseWhenHidden !== undefined)
{
videoDisplay.pauseWhenHidden = videoDisplayProperties.pauseWhenHidden;
newVideoProperties = BitFlagUtil.update(newVideoProperties as uint,
PAUSE_WHEN_HIDDEN_PROPERTY_FLAG, true);
}
if (videoDisplayProperties.autoDisplayFirstFrame !== undefined)
{
videoDisplay.autoDisplayFirstFrame = videoDisplayProperties.autoDisplayFirstFrame;
newVideoProperties = BitFlagUtil.update(newVideoProperties as uint,
AUTO_DISPLAY_FIRST_FRAME_PROPERTY_FLAG, true);
}
if (videoDisplayProperties.thumbnailSource !== undefined)
{
videoDisplay.thumbnailSource = videoDisplayProperties.thumbnailSource;
newVideoProperties = BitFlagUtil.update(newVideoProperties as uint,
THUMBNAIL_SOURCE_PROPERTY_FLAG, true);
}
// these are state properties just carried over from an old video element
if (videoDisplayProperties.currentTime !== undefined ||
videoDisplayProperties.playing !== undefined)
{
videoDisplay_updateCompleteHandlerProperties = {
autoPlay: videoDisplay.autoPlay,
playing: videoDisplayProperties.playing,
currentTime: videoDisplayProperties.currentTime};
// so the videoDisplay doesn't start playing...we'll handle it instead in
// videoDisplay_updateCompleteHandler
videoDisplay.autoPlay = false;
videoDisplay.addEventListener(FlexEvent.UPDATE_COMPLETE, videoDisplay_updateCompleteHandler);
}
videoDisplayProperties = newVideoProperties;
if (volumeBar)
{
volumeBar.value = videoDisplay.volume;
volumeBar.muted = videoDisplay.muted;
}
if (muteButton)
{
muteButton.volume = videoDisplay.volume;
muteButton.muted = videoDisplay.muted;
}
if (scrubBar)
updateScrubBar();
if (currentTimeDisplay)
updateCurrentTime();
if (durationDisplay)
updateDuration();
}
else if (instance == playButton)
{
playButton.addEventListener(MouseEvent.CLICK, playButton_clickHandler);
}
else if (instance == pauseButton)
{
pauseButton.addEventListener(MouseEvent.CLICK, pauseButton_clickHandler);
}
else if (instance == playPauseButton)
{
playPauseButton.addEventListener(MouseEvent.CLICK, playPauseButton_clickHandler);
}
else if (instance == stopButton)
{
stopButton.addEventListener(MouseEvent.CLICK, stopButton_clickHandler);
}
else if (instance == muteButton)
{
if (videoDisplay)
{
muteButton.muted = muted;
muteButton.volume = volume;
}
muteButton.addEventListener(FlexEvent.MUTED_CHANGE, muteButton_mutedChangeHandler);
}
else if (instance == volumeBar)
{
volumeBar.minimum = 0;
volumeBar.maximum = 1;
if (videoDisplay)
{
volumeBar.value = volume;
volumeBar.muted = muted;
}
volumeBar.addEventListener(Event.CHANGE, volumeBar_changeHandler);
volumeBar.addEventListener(FlexEvent.MUTED_CHANGE, volumeBar_mutedChangeHandler);
}
else if (instance == scrubBar)
{
if (videoDisplay)
updateScrubBar();
// add thumbPress and thumbRelease so we pause the video while dragging
scrubBar.addEventListener(TrackBaseEvent.THUMB_PRESS, scrubBar_thumbPressHandler);
scrubBar.addEventListener(TrackBaseEvent.THUMB_RELEASE, scrubBar_thumbReleaseHandler);
// add change to actually seek() when the change is complete
scrubBar.addEventListener(Event.CHANGE, scrubBar_changeHandler);
// add changeEnd and changeStart so we don't update the scrubbar's value
// while the scrubbar is moving around due to an animation
scrubBar.addEventListener(FlexEvent.CHANGE_END, scrubBar_changeEndHandler);
scrubBar.addEventListener(FlexEvent.CHANGE_START, scrubBar_changeStartHandler);
}
else if (instance == fullScreenButton)
{
fullScreenButton.addEventListener(MouseEvent.CLICK, fullScreenButton_clickHandler);
}
else if (instance == currentTimeDisplay)
{
if (videoDisplay)
updateCurrentTime();
}
else if (instance == durationDisplay)
{
if (videoDisplay)
updateDuration();
}
}
/**
* @private
* Holds the state of the video element when the skin is being swapped out.
* This is so the new videoDisplay can load up and start playing
* where it left off.
*/
private var videoDisplay_updateCompleteHandlerProperties:Object;
/**
* @private
* We only listen for the updateComplete event on the videoDisplay when
* a skin has been swapped. This is so we can push the old videoDisplay's
* state in to the new object, and we can start playing the video
* where it left off.
*/
private function videoDisplay_updateCompleteHandler(event:FlexEvent):void
{
if (videoDisplay_updateCompleteHandlerProperties.autoPlay)
videoDisplay.autoPlay = true;
if (videoDisplay_updateCompleteHandlerProperties.currentTime !== undefined)
videoDisplay.seek(videoDisplay_updateCompleteHandlerProperties.currentTime);
if (videoDisplay_updateCompleteHandlerProperties.playing)
videoDisplay.play();
videoDisplay_updateCompleteHandlerProperties = null;
videoDisplay.removeEventListener(FlexEvent.UPDATE_COMPLETE, videoDisplay_updateCompleteHandler);
}
/**
* @private
*/
override protected function partRemoved(partName:String, instance:Object):void
{
super.partRemoved(partName, instance);
if (instance == videoDisplay)
{
// validate before doing anything with the videoDisplay.
// This is so if the video element hasn't been validated, it won't start playing.
// plus this way we'll get a valid currentTime and all those other properties
// we are interested in.
videoDisplay.validateNow();
// copy proxied values from video (if explicitely set) to videoProperties
var newVideoProperties:Object = {};
if (BitFlagUtil.isSet(videoDisplayProperties as uint, SOURCE_PROPERTY_FLAG))
newVideoProperties.source = videoDisplay.source;
if (BitFlagUtil.isSet(videoDisplayProperties as uint, AUTO_PLAY_PROPERTY_FLAG))
newVideoProperties.autoPlay = videoDisplay.autoPlay;
if (BitFlagUtil.isSet(videoDisplayProperties as uint, VOLUME_PROPERTY_FLAG))
newVideoProperties.volume = videoDisplay.volume;
if (BitFlagUtil.isSet(videoDisplayProperties as uint, AUTO_REWIND_PROPERTY_FLAG))
newVideoProperties.autoRewind = videoDisplay.autoRewind;
if (BitFlagUtil.isSet(videoDisplayProperties as uint, LOOP_PROPERTY_FLAG))
newVideoProperties.loop = videoDisplay.loop;
if (BitFlagUtil.isSet(videoDisplayProperties as uint, SCALE_MODE_PROPERTY_FLAG))
newVideoProperties.scaleMode = videoDisplay.scaleMode;
if (BitFlagUtil.isSet(videoDisplayProperties as uint, MUTED_PROPERTY_FLAG))
newVideoProperties.muted = videoDisplay.muted;
if (BitFlagUtil.isSet(videoDisplayProperties as uint, PAUSE_WHEN_HIDDEN_PROPERTY_FLAG))
newVideoProperties.pauseWhenHidden = videoDisplay.pauseWhenHidden;
if (BitFlagUtil.isSet(videoDisplayProperties as uint, AUTO_DISPLAY_FIRST_FRAME_PROPERTY_FLAG))
newVideoProperties.autoDisplayFirstFrame = videoDisplay.autoDisplayFirstFrame;
if (BitFlagUtil.isSet(videoDisplayProperties as uint, THUMBNAIL_SOURCE_PROPERTY_FLAG))
newVideoProperties.thumbnailSource = videoDisplay.thumbnailSource;
// push our current state (where we were in the video and whether we were playing)
// so that the new skin gets these as well
newVideoProperties.currentTime = videoDisplay.currentTime;
newVideoProperties.playing = videoDisplay.playing;
videoDisplay.stop();
videoDisplayProperties = newVideoProperties;
videoDisplay.removeEventListener(TimeEvent.CURRENT_TIME_CHANGE, videoDisplay_currentTimeChangeHandler);
videoDisplay.removeEventListener(LoadEvent.BYTES_LOADED_CHANGE, videoDisplay_bytesLoadedChangeHandler);
videoDisplay.removeEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, videoDisplay_mediaPlayerStateChangeHandler);
videoDisplay.removeEventListener(TimeEvent.DURATION_CHANGE, videoDisplay_durationChangeHandler);
videoDisplay.removeEventListener(TimeEvent.COMPLETE, dispatchEvent);
// just strictly for binding purposes
videoDisplay.removeEventListener("sourceChanged", dispatchEvent);
videoDisplay.removeEventListener("volumeChanged", videoDisplay_volumeChangedHandler);
}
else if (instance == playButton)
{
playButton.removeEventListener(MouseEvent.CLICK, playButton_clickHandler);
}
else if (instance == pauseButton)
{
pauseButton.removeEventListener(MouseEvent.CLICK, pauseButton_clickHandler);
}
else if (instance == playPauseButton)
{
playPauseButton.removeEventListener(MouseEvent.CLICK, playPauseButton_clickHandler);
}
else if (instance == stopButton)
{
stopButton.removeEventListener(MouseEvent.CLICK, stopButton_clickHandler);
}
else if (instance == muteButton)
{
playButton.removeEventListener(FlexEvent.MUTED_CHANGE, muteButton_mutedChangeHandler);
}
else if (instance == volumeBar)
{
volumeBar.removeEventListener(Event.CHANGE, volumeBar_changeHandler);
volumeBar.removeEventListener(FlexEvent.MUTED_CHANGE, volumeBar_mutedChangeHandler);
}
else if (instance == scrubBar)
{
scrubBar.removeEventListener(TrackBaseEvent.THUMB_PRESS, scrubBar_thumbPressHandler);
scrubBar.removeEventListener(TrackBaseEvent.THUMB_RELEASE, scrubBar_thumbReleaseHandler);
scrubBar.removeEventListener(Event.CHANGE, scrubBar_changeHandler);
scrubBar.removeEventListener(FlexEvent.CHANGE_END, scrubBar_changeEndHandler);
scrubBar.removeEventListener(FlexEvent.CHANGE_START, scrubBar_changeStartHandler);
}
else if (instance == fullScreenButton)
{
fullScreenButton.removeEventListener(MouseEvent.CLICK, fullScreenButton_clickHandler);
}
}
/**
* @private
*/
override protected function commitProperties():void
{
super.commitProperties();
// if coming from full screen mode, we reset the
// pauseWhenHidden property here because of an AIR bug
// that requires us to defer it.
if (needsToUpdatePauseWhenHidden)
{
needsToUpdatePauseWhenHidden = false;
pauseWhenHidden = exitingFullScreenPauseWhenHidden;
}
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @throws TypeError If the skin hasn't been loaded and there is no videoDisplay.
*
* @copy spark.components.VideoDisplay#pause()
*
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function pause():void
{
videoDisplay.pause();
}
/**
* @copy spark.components.VideoDisplay#play()
*
* @throws TypeError if the skin hasn't been loaded up yet
* and there's no videoDisplay.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function play():void
{
//trace("play");
videoDisplay.play();
}
/**
* @copy spark.components.VideoDisplay#seek()
*
* @throws TypeError if the skin hasn't been loaded up yet
* and there's no videoDisplay.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function seek(time:Number):void
{
videoDisplay.seek(time);
}
/**
* @copy spark.components.VideoDisplay#stop()
*
* @throws TypeError if the skin hasn't been loaded up yet
* and there's no videoDisplay.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function stop():void
{
videoDisplay.stop();
}
/**
* @private
*/
private function updateScrubBar():void
{
if (!videoDisplay)
return;
if (!scrubBarMouseCaptured && !scrubBarChanging)
{
scrubBar.minimum = 0;
scrubBar.maximum = videoDisplay.duration;
scrubBar.value = videoDisplay.currentTime;
}
// if streaming, then we pretend to have everything in view
// if progressive, then look at the bytesLoaded and bytesTotal
if (!videoDisplay.videoPlayer.canLoad)
scrubBar.loadedRangeEnd = videoDisplay.duration;
else if (videoDisplay.bytesTotal == 0)
scrubBar.loadedRangeEnd = 0;
else
scrubBar.loadedRangeEnd = (videoDisplay.bytesLoaded/videoDisplay.bytesTotal)*videoDisplay.duration;
}
/**
* @private
*/
private function updateDuration():void
{
durationDisplay.text = formatTimeValue(duration);
}
/**
* Formats a time value, specified in seconds, into a String that
* gets used for currentTime
and the duration
.
*
* @param value Value in seconds of the time to format.
*
* @return Formatted time value.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
protected function formatTimeValue(value:Number):String
{
// default format: hours:minutes:seconds
value = Math.round(value);
var hours:uint = Math.floor(value/3600) % 24;
var minutes:uint = Math.floor(value/60) % 60;
var seconds:uint = value % 60;
var result:String = "";
if (hours != 0)
result = hours + ":";
if (result && minutes < 10)
result += "0" + minutes + ":";
else
result += minutes + ":";
if (seconds < 10)
result += "0" + seconds;
else
result += seconds;
return result;
}
/**
* @private
*/
private function updateCurrentTime():void
{
currentTimeDisplay.text = formatTimeValue(currentTime);
}
/**
* @private
* Returns the screen bounds.
* If we are on the AIR Player, we need to work around AIR Player bug #2503351
* We check if the flash.display.Screen class is defined. If so, then
* we are running on the AIR Player and can access this API.
*/
mx_internal function getScreenBounds():Rectangle
{
var resultRect:Rectangle = new Rectangle(0, 0, stage.fullScreenWidth, stage.fullScreenHeight);
if (screenClass)
{
// Get the screen where the application resides
try
{
var nativeWindowBounds:Rectangle = stage["nativeWindow"]["bounds"];
var currentScreen:Object = screenClass["getScreensForRectangle"](nativeWindowBounds)[0];
// Return the bounds of that screen
resultRect = currentScreen["bounds"];
}
catch (e:Error)
{
}
}
return resultRect;
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* @private
*/
private function videoDisplay_currentTimeChangeHandler(event:TimeEvent):void
{
if (scrubBar)
updateScrubBar();
if (currentTimeDisplay)
updateCurrentTime();
dispatchEvent(event);
}
/**
* @private
*/
private function videoDisplay_bytesLoadedChangeHandler(event:LoadEvent):void
{
if (scrubBar)
updateScrubBar();
dispatchEvent(event);
}
/**
* @private
*/
private function videoDisplay_mediaPlayerStateChangeHandler(event:MediaPlayerStateChangeEvent):void
{
invalidateSkinState();
if (scrubBar)
updateScrubBar();
if (durationDisplay)
updateDuration();
if (currentTimeDisplay)
updateCurrentTime();
if (playPauseButton)
playPauseButton.selected = playing;
//trace("mediaPlayerStateChangeHandler " + event + " state = " + event.state + " playing = " + playing);
dispatchEvent(event);
}
/**
* @private
*/
private function videoDisplay_durationChangeHandler(event:TimeEvent):void
{
if (scrubBar)
updateScrubBar();
if (durationDisplay)
updateDuration();
dispatchEvent(event);
}
/**
* @private
*/
private function videoDisplay_volumeChangedHandler(event:Event):void
{
if (volumeBar)
{
volumeBar.value = volume;
volumeBar.muted = muted;
}
if (muteButton)
{
muteButton.muted = muted;
muteButton.volume = volume;
}
dispatchEvent(event);
}
/**
* @private
* Indicates whether we are in the full screen state or not.
* We use this when determining our current skin state.
*/
private var fullScreen:Boolean = false;
/**
* @private
* Holds a list of properties for the "video player state" that will
* be restored when going out of fullScreen mode.
*/
private var beforeFullScreenInfo:Object;
/**
* @private
* Timer, which waits for 3 seconds by default to hide the
* playback controls. If there's interaction by the user, then
* these playback controls are show again, and the timer will reset
* and start the countdown.
*/
private var fullScreenHideControlTimer:Timer;
/**
* @private
*/
private function fullScreenButton_clickHandler(event:MouseEvent):void
{
if (!fullScreen)
{
// check to make sure we can go into fullscreen mode
if (!systemManager.getTopLevelRoot())
return;
var screenBounds:Rectangle = getScreenBounds();
fullScreen = true;
// need it to go into full screen state for the skin
invalidateSkinState();
// keep track of pauseWhenHidden b/c we will set it to false temporarily
// so that the video does not pause when we reparent it to the top
// level application
var oldPauseWhenHidden:Boolean = pauseWhenHidden;
// let's get it off of our layout system so it doesn't interfere with
// the sizing and positioning. Then let's resize it to be
// the full size of our screen. Then let's position it off-screen so
// there are no other elements in the way.
beforeFullScreenInfo = {parent: this.parent,
x: this.x,
y: this.y,
explicitWidth: this.explicitWidth,
explicitHeight: this.explicitHeight,
percentWidth: this.percentWidth,
percentHeight: this.percentHeight,
isPopUp: this.isPopUp};
pauseWhenHidden = false;
if (!isPopUp)
{
// remove from old parent
if (parent is IVisualElementContainer)
{
var ivec:IVisualElementContainer = IVisualElementContainer(parent);
beforeFullScreenInfo.childIndex = ivec.getElementIndex(this);
ivec.removeElement(this);
}
else
{
beforeFullScreenInfo.childIndex = parent.getChildIndex(this);
parent.removeChild(this);
}
// add as a popup
PopUpManager.addPopUp(this, FlexGlobals.topLevelApplication as DisplayObject, false, null, moduleFactory);
}
// Resize the component to be the full screen of the stage.
// Push the component at (0,0). It should be on top of everything
// at this point because it was added as a popup
setLayoutBoundsSize(screenBounds.width, screenBounds.height, true);
// set the explicit width/height to make sure this value sticks regardless
// of any other code or layout passes. Calling setLayoutBoundsSize() before hand
// allows us to use postLayout width/height.
// Setting explictWidth/Height sets percentWidth/Height to NaN.
this.explicitWidth = width;
this.explicitHeight = height;
setLayoutBoundsPosition(0, 0, true);
// this is for video performance reasons, but sometimes the videoObject isn't there
// if the source is null
if (videoDisplay.videoObject)
{
beforeFullScreenInfo.smoothing = videoDisplay.videoObject.smoothing;
beforeFullScreenInfo.deblocking = videoDisplay.videoObject.deblocking;
videoDisplay.videoObject.smoothing = false;
videoDisplay.videoObject.deblocking = 0;
}
this.validateNow();
systemManager.stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenEventHandler);
// TODO (rfrishbe): Should we make this FULL_SCREEN_INTERACTIVE if in AIR?
systemManager.stage.displayState = StageDisplayState.FULL_SCREEN;
pauseWhenHidden = oldPauseWhenHidden;
var fullScreenHideControlsDelay:Number = getStyle("fullScreenHideControlsDelay");
if (fullScreenHideControlsDelay == 0)
{
playerControls.visible = false;
if (volumeBar)
volumeBar.closeDropDown(true);
}
else if (fullScreenHideControlsDelay < Infinity)
{
// start timer for detecting for mouse movements/clicks to hide the controls
fullScreenHideControlTimer = new Timer(fullScreenHideControlsDelay, 1);
fullScreenHideControlTimer.addEventListener(TimerEvent.TIMER_COMPLETE,
fullScreenHideControlTimer_timerCompleteHandler, false, 0, true);
// use stage or systemManager?
systemManager.getSandboxRoot().addEventListener(MouseEvent.MOUSE_DOWN, resetFullScreenHideControlTimer);
systemManager.getSandboxRoot().addEventListener(MouseEvent.MOUSE_MOVE, resetFullScreenHideControlTimer);
systemManager.getSandboxRoot().addEventListener(MouseEvent.MOUSE_WHEEL, resetFullScreenHideControlTimer);
// keyboard events don't happen when in fullScreen mode, but could be in fullScreen and interactive mode
systemManager.getSandboxRoot().addEventListener(KeyboardEvent.KEY_DOWN, resetFullScreenHideControlTimer);
fullScreenHideControlTimer.start();
}
}
else
{
systemManager.stage.displayState = StageDisplayState.NORMAL;
}
}
/**
* @private
* After waiting a certain time perdiod, we hide the controls if no
* user-interaction has occurred on-screen.
*/
private function fullScreenHideControlTimer_timerCompleteHandler(event:TimerEvent):void
{
playerControls.visible = false;
if (volumeBar)
volumeBar.closeDropDown(true);
}
/**
* @private
* Handles when mouse interaction happens, and we are in the fullscreen mode. This
* resets the fullScreenHideControlTimer.
*/
private function resetFullScreenHideControlTimer(event:Event):void
{
playerControls.visible = true;
if (fullScreenHideControlTimer)
{
fullScreenHideControlTimer.reset();
fullScreenHideControlTimer.start();
}
else
{
fullScreenHideControlTimer = new Timer(getStyle("fullScreenHideControlsDelay"), 1);
fullScreenHideControlTimer.addEventListener(TimerEvent.TIMER_COMPLETE,
fullScreenHideControlTimer_timerCompleteHandler, false, 0, true);
}
}
/**
* @private
* Handles when coming out the full screen mode
*/
private function fullScreenEventHandler(event:FullScreenEvent):void
{
// going in to full screen is handled by the
// fullScreenButton_clickHandler
if (event.fullScreen)
return;
// keep track of pauseWhenHidden b/c we will set it to false temporarily
// so that the video does not pause when we reparent it to the top
// level application
exitingFullScreenPauseWhenHidden = pauseWhenHidden;
pauseWhenHidden = false;
// set the fullScreen variable back to false and remove this event listener
fullScreen = false;
systemManager.stage.removeEventListener(FullScreenEvent.FULL_SCREEN, fullScreenEventHandler);
// remove the event listeners to hide the controls
systemManager.getSandboxRoot().removeEventListener(MouseEvent.MOUSE_DOWN, resetFullScreenHideControlTimer);
systemManager.getSandboxRoot().removeEventListener(MouseEvent.MOUSE_MOVE, resetFullScreenHideControlTimer);
systemManager.getSandboxRoot().removeEventListener(MouseEvent.MOUSE_WHEEL, resetFullScreenHideControlTimer);
systemManager.getSandboxRoot().removeEventListener(KeyboardEvent.KEY_DOWN, resetFullScreenHideControlTimer);
if (fullScreenHideControlTimer)
{
fullScreenHideControlTimer.stop();
fullScreenHideControlTimer = null;
}
// make the controls visible no matter what
playerControls.visible = true;
// reset it so we're re-included in the layout
this.x = beforeFullScreenInfo.x;
this.y = beforeFullScreenInfo.y;
this.explicitWidth = beforeFullScreenInfo.explicitWidth;
this.explicitHeight = beforeFullScreenInfo.explicitHeight;
this.percentWidth = beforeFullScreenInfo.percentWidth;
this.percentHeight = beforeFullScreenInfo.percentHeight;
// sometimes there's no video object currently or there might not've been a
// video object when we went in to fullScreen mode. There may be no videoObject
// if the source hasn't been set.
if (videoDisplay.videoObject && beforeFullScreenInfo.smoothing !== undefined)
{
videoDisplay.videoObject.smoothing = beforeFullScreenInfo.smoothing;
videoDisplay.videoObject.deblocking = beforeFullScreenInfo.deblocking;
}
if (!beforeFullScreenInfo.isPopUp)
{
// remove from top level application:
PopUpManager.removePopUp(this);
// add back to original parent
if (beforeFullScreenInfo.parent is IVisualElementContainer)
beforeFullScreenInfo.parent.addElementAt(this, beforeFullScreenInfo.childIndex);
else
beforeFullScreenInfo.parent.addChildAt(this, beforeFullScreenInfo.childIndex);
}
// want to update pauseWhenHidden, but can't do it here
// b/c the AIR window thinks it's invisible at this point
// if we're on a Mac (a bug), so let's just defer this check
// to commitProperties().
if (exitingFullScreenPauseWhenHidden)
{
// if we need to set it back to true
needsToUpdatePauseWhenHidden = true;
invalidateProperties();
}
beforeFullScreenInfo = null;
invalidateSkinState();
invalidateSize();
invalidateDisplayList();
}
/**
* @private
*/
private function playButton_clickHandler(event:MouseEvent):void
{
if (!playing)
play();
}
/**
* @private
*/
private function pauseButton_clickHandler(event:MouseEvent):void
{
pause();
}
/**
* @private
*/
private function stopButton_clickHandler(event:MouseEvent):void
{
stop();
}
/**
* @private
*/
private function playPauseButton_clickHandler(event:MouseEvent):void
{
if (playing)
pause();
else
play();
// need to synch up to what we've actually got because sometimes
// the play() didn't actually play() because there's no source
// or we're in an error state
playPauseButton.selected = playing;
}
/**
* @private
*/
private function muteButton_mutedChangeHandler(event:FlexEvent):void
{
muted = muteButton.muted;
}
/**
* @private
*/
private function volumeBar_changeHandler(event:Event):void
{
if (volume != volumeBar.value)
volume = volumeBar.value;
}
/**
* @private
*/
private function volumeBar_mutedChangeHandler(event:FlexEvent):void
{
if (muted != volumeBar.muted)
muted = volumeBar.muted;
}
/**
* @private
* When someone is holding the scrubBar, we don't want to update the
* range's value--for this time period, we'll let the user completely
* control the range.
*/
private var scrubBarMouseCaptured:Boolean;
/**
* @private
* We pause the video when dragging the thumb for the scrub bar. This
* stores whether we were paused or not.
*/
private var wasPlayingBeforeSeeking:Boolean;
/**
* @private
* We are in the process of changing the timestamp
*/
private var scrubBarChanging:Boolean;
/**
* @private
*/
private function scrubBar_changeStartHandler(event:Event):void
{
scrubBarChanging = true;
}
/**
* @private
*/
private function scrubBar_thumbPressHandler(event:TrackBaseEvent):void
{
scrubBarMouseCaptured = true;
if (playing)
{
pause();
wasPlayingBeforeSeeking = true;
}
}
/**
* @private
*/
private function scrubBar_thumbReleaseHandler(event:TrackBaseEvent):void
{
scrubBarMouseCaptured = false;
if (wasPlayingBeforeSeeking)
{
play();
wasPlayingBeforeSeeking = false;
}
}
/**
* @private
*/
private function scrubBar_changeHandler(event:Event):void
{
seek(scrubBar.value);
}
/**
* @private
*/
private function scrubBar_changeEndHandler(event:Event):void
{
scrubBarChanging = false;
}
}
}