PageRenderTime 54ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/flowplayer/trunk/src/actionscript/org/flowplayer/view/Launcher.as

http://flowplayer-core.googlecode.com/
ActionScript | 955 lines | 722 code | 131 blank | 102 comment | 141 complexity | 32e90e1e5f7836d4d6b478da8c8bae55 MD5 | raw file
Possible License(s): GPL-3.0, AGPL-1.0
  1. /*
  2. * Copyright (c) 2008-2011 Flowplayer Oy *
  3. * This file is part of Flowplayer.
  4. *
  5. * Flowplayer is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * Flowplayer is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with Flowplayer. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. package org.flowplayer.view {
  19. import flash.external.ExternalInterface;
  20. import org.flowplayer.config.Config;
  21. import org.flowplayer.config.ConfigParser;
  22. import org.flowplayer.config.ExternalInterfaceHelper;
  23. import org.flowplayer.config.VersionInfo;
  24. import org.flowplayer.controller.PlayListController;
  25. import org.flowplayer.controller.ResourceLoader;
  26. import org.flowplayer.controller.ResourceLoaderImpl;
  27. import org.flowplayer.flow_internal;
  28. import org.flowplayer.model.Callable;
  29. import org.flowplayer.model.Clip;
  30. import org.flowplayer.model.ClipEvent;
  31. import org.flowplayer.model.ClipEventType;
  32. import org.flowplayer.model.DisplayPluginModel;
  33. import org.flowplayer.model.DisplayProperties;
  34. import org.flowplayer.model.DisplayPropertiesImpl;
  35. import org.flowplayer.model.ErrorCode;
  36. import org.flowplayer.model.EventDispatcher;
  37. import org.flowplayer.model.Loadable;
  38. import org.flowplayer.model.Logo;
  39. import org.flowplayer.model.PlayButtonOverlay;
  40. import org.flowplayer.model.PlayerError;
  41. import org.flowplayer.model.PlayerEvent;
  42. import org.flowplayer.model.Playlist;
  43. import org.flowplayer.model.Plugin;
  44. import org.flowplayer.model.PluginError;
  45. import org.flowplayer.model.PluginEvent;
  46. import org.flowplayer.model.PluginModel;
  47. import org.flowplayer.model.ProviderModel;
  48. import org.flowplayer.model.State;
  49. import org.flowplayer.util.Arrange;
  50. import org.flowplayer.util.Log;
  51. import org.flowplayer.util.TextUtil;
  52. import org.flowplayer.util.URLUtil;
  53. import org.flowplayer.view.Panel;
  54. import org.flowplayer.view.PluginLoader;
  55. import org.flowplayer.view.Screen;
  56. import org.flowplayer.view.KeyboardHandler;
  57. import org.osflash.thunderbolt.Logger;
  58. import flash.display.DisplayObject;
  59. import flash.display.DisplayObjectContainer;
  60. import flash.display.Sprite;
  61. import flash.display.BlendMode;
  62. import flash.events.Event;
  63. import flash.events.MouseEvent;
  64. import flash.events.TimerEvent;
  65. import flash.net.URLRequest;
  66. import flash.net.navigateToURL;
  67. import flash.system.Capabilities;
  68. import flash.system.Security;
  69. import flash.text.TextField;
  70. import flash.text.TextFieldAutoSize;
  71. import flash.utils.*;
  72. CONFIG::FLASH_10_1 {
  73. import flash.media.StageVideo;
  74. }
  75. use namespace flow_internal;
  76. public class Launcher extends StyleableSprite implements ErrorHandler {
  77. private var _panel:Panel;
  78. private var _screen:Screen;
  79. private var _config:Config;
  80. private var _flowplayer:Flowplayer;
  81. private var _pluginRegistry:PluginRegistry;
  82. private var _animationEngine:AnimationEngine;
  83. private var _playButtonOverlay:PlayButtonOverlay;
  84. private var _controlsModel:DisplayPluginModel;
  85. private var _providers:Dictionary = new Dictionary();
  86. private var _canvasLogo:Sprite;
  87. private var _pluginLoader:PluginLoader;
  88. private var _error:TextField;
  89. private var _pluginsInitialized:Number = 0;
  90. private var _enteringFullscreen:Boolean;
  91. private var _copyrightNotice:TextField;
  92. private var _playlistLoader:ResourceLoader;
  93. private var _fullscreenManager:FullscreenManager;
  94. private var _screenArrangeCount:int = 0;
  95. private var _clickCount:int;
  96. private var _clickTimer:Timer = new Timer(200, 1);
  97. private var _clickEvent:MouseEvent;
  98. //private var _screenMask:Sprite;
  99. [Frame(factoryClass="org.flowplayer.view.Preloader")]
  100. public function Launcher() {
  101. addEventListener(Event.ADDED_TO_STAGE, function(e:Event):void {
  102. URLUtil.loaderInfo = loaderInfo;
  103. trace("Launcher added to stage");
  104. callAndHandleError(createFlashVarsConfig, PlayerError.INIT_FAILED);
  105. });
  106. super("#canvas", this);
  107. }
  108. private function initPhase1():void {
  109. if (_flowplayer) {
  110. log.debug("already initialized, returning");
  111. return;
  112. }
  113. Log.configure(_config.getLogConfiguration());
  114. trace("created log configuration, tracing enabled? " + Log.traceEnabled)
  115. initCustomClipEvents();
  116. if (_config.playerId) {
  117. Security.allowDomain(URLUtil.pageLocation);
  118. }
  119. loader = createNewLoader();
  120. rootStyle = _config.canvas.style;
  121. stage.addEventListener(Event.RESIZE, onStageResize);
  122. stage.addEventListener(Event.RESIZE, arrangeScreen);
  123. setSize(Arrange.parentWidth, Arrange.parentHeight);
  124. if (! VersionInfo.commercial) {
  125. log.debug("Adding logo to canvas");
  126. createLogoForCanvas();
  127. }
  128. log = new Log(this);
  129. EventDispatcher.playerId = _config.playerId;
  130. log.debug("security sandbox type: " + Security.sandboxType);
  131. log.info(VersionInfo.versionInfo());
  132. trace(VersionInfo.versionInfo());
  133. log.debug("creating Panel");
  134. createPanel();
  135. _pluginRegistry = new PluginRegistry(_panel);
  136. log.debug("Creating animation engine");
  137. createAnimationEngine(_pluginRegistry);
  138. log.debug("creating play button overlay");
  139. createPlayButtonOverlay();
  140. log.debug("creating Flowplayer API");
  141. createFlowplayer();
  142. // keyboard handler must be present for plugins.
  143. //
  144. loadPlaylistFeed();
  145. }
  146. private function initPhase2(event:Event = null):void {
  147. log.info("initPhase2");
  148. _flowplayer.keyboardHandler = new KeyboardHandler(stage, function():Boolean { return enteringFullscreen });
  149. loadPlugins();
  150. }
  151. private function initPhase3(event:Event = null):void {
  152. log.debug("initPhase3, all plugins loaded");
  153. createScreen();
  154. _config.getPlaylist().onBeforeBegin(function(event:ClipEvent):void { hideErrorMessage(); });
  155. if (_playButtonOverlay) {
  156. PlayButtonOverlayView(_playButtonOverlay.getDisplayObject()).playlist = _config.getPlaylist();
  157. }
  158. log.debug("creating PlayListController");
  159. _providers = _pluginLoader.providers;
  160. var playListController:PlayListController = createPlayListController();
  161. addPlayListListeners();
  162. createFullscreenManager(playListController.playlist);
  163. addScreenToPanel();
  164. if (!validateLicenseKey()) {
  165. createLogoForCanvas();
  166. resizeCanvasLogo();
  167. }
  168. log.debug("creating logo");
  169. createLogo();
  170. contextMenu = new ContextMenuBuilder(_config.playerId, _config.contextMenu).build();
  171. log.debug("initializing ExternalInterface");
  172. if (useExternalInterface()) {
  173. _flowplayer.initExternalInterface();
  174. }
  175. log.debug("calling onLoad to plugins");
  176. _pluginRegistry.onLoad(_flowplayer);
  177. if (countPlugins() == 0) {
  178. log.debug("no loadable plugins, calling initPhase4");
  179. initPhase4();
  180. }
  181. }
  182. private function initPhase4(event:Event = null):void {
  183. log.info("initPhase4, all plugins initialized");
  184. log.debug("Adding visible plugins to panel");
  185. addPluginsToPanel(_pluginRegistry);
  186. log.debug("dispatching onLoad");
  187. _flowplayer.dispatchEvent(PlayerEvent.load("player"));
  188. log.debug("starting configured streams");
  189. startStreams();
  190. //#508 disabling the stagevideo screen mask, canvas is visible without it.
  191. //createScreenMask();
  192. arrangeScreen();
  193. addListeners();
  194. // _controlsModel.onPluginEvent(function(event:PluginEvent):void {
  195. // log.debug("received plugin event " + event.id);
  196. // var model:DisplayPluginModel = event.target as DisplayPluginModel;
  197. // log.debug("controls y-pos now is " + model.getDisplayObject().y);
  198. // });
  199. //
  200. // _controlsModel.onBeforePluginEvent(function(event:PluginEvent):void {
  201. // log.debug("received before plugin event " + event.id);
  202. // var model:DisplayPluginModel = event.target as DisplayPluginModel;
  203. // log.debug("controls y-pos now is " + model.getDisplayObject().y);
  204. // event.preventDefault();
  205. // });
  206. // lookupSlowMotionPlugin(_flowplayer);
  207. }
  208. //#508 disabling the stagevideo screen mask, canvas is visible without it.
  209. /*private function createScreenMask():void {
  210. blendMode = BlendMode.LAYER;
  211. _screenMask = new Sprite();
  212. _screenMask.graphics.beginFill(0xff0000);
  213. _screenMask.graphics.drawRect(0, 0, 1, 1);
  214. _screenMask.blendMode = BlendMode.ERASE;
  215. _screenMask.x = 0;
  216. _screenMask.y = 0;
  217. _screenMask.width = 100;
  218. _screenMask.height = 100;
  219. } */
  220. private function resizeCanvasLogo():void {
  221. _canvasLogo.alpha = 1;
  222. _canvasLogo.width = 150;
  223. _canvasLogo.scaleY = _canvasLogo.scaleX;
  224. arrangeCanvasLogo();
  225. }
  226. private function useExternalInterface():Boolean {
  227. log.debug("useExternalInteface: " + (_config.playerId != null));
  228. return _config.playerId != null;
  229. }
  230. private function onStageResize(event:Event = null):void {
  231. setSize(Arrange.parentWidth, Arrange.parentHeight);
  232. arrangeCanvasLogo();
  233. }
  234. private function arrangeCanvasLogo():void {
  235. if (!_canvasLogo) return;
  236. _canvasLogo.x = 15;
  237. _canvasLogo.y = Arrange.parentHeight - (_controlsModel ? _controlsModel.dimensions.height.toPx(Arrange.parentHeight) + 10 : 10) - _canvasLogo.height - _copyrightNotice.height;
  238. _copyrightNotice.x = 12;
  239. _copyrightNotice.y = _canvasLogo.y + _canvasLogo.height;
  240. }
  241. private function loadPlugins():void {
  242. var plugins:Array = _config.getLoadables();
  243. log.debug("will load following plugins: ");
  244. logPluginInfo(plugins);
  245. _pluginLoader = new PluginLoader(URLUtil.playerBaseUrl, _pluginRegistry, this, useExternalInterface());
  246. _pluginLoader.addEventListener(Event.COMPLETE, pluginLoadListener);
  247. _flowplayer.pluginLoader = _pluginLoader;
  248. if (plugins.length == 0) {
  249. log.debug("configuration has no plugins");
  250. initPhase3();
  251. } else {
  252. // _builtInPlugins = _config.createLoadables(BuiltInConfig.config.plugins);
  253. // log.debug("following built-in plugins will be instantiated");
  254. // trace("builtIn plugins: ");
  255. // logPluginInfo(_builtInPlugins, true);
  256. _pluginLoader.load(plugins, onPluginLoad, onPluginLoadError);
  257. }
  258. }
  259. private function logPluginInfo(plugins:Array, doTrace:Boolean = false):void {
  260. for (var i:Number = 0; i < plugins.length; i++) {
  261. log.info("" + plugins[i]);
  262. if (doTrace) {
  263. trace("" + plugins[i]);
  264. }
  265. }
  266. }
  267. private function pluginLoadListener(event:Event = null):void {
  268. _pluginLoader.removeEventListener(Event.COMPLETE, pluginLoadListener);
  269. callAndHandleError(initPhase3, PlayerError.INIT_FAILED);
  270. }
  271. private function loadPlaylistFeed():void {
  272. var playlistFeed:String = _config.playlistFeed;
  273. if (! playlistFeed) {
  274. callAndHandleError(initPhase2, PlayerError.INIT_FAILED);
  275. return;
  276. }
  277. log.info("loading playlist from " + playlistFeed);
  278. _playlistLoader = _flowplayer.createLoader();
  279. _playlistLoader.addTextResourceUrl(playlistFeed);
  280. _playlistLoader.load(null,
  281. function(loader:ResourceLoader):void {
  282. log.info("received playlist feed");
  283. _config.playlistDocument = loader.getContent() as String;
  284. _config.getPlaylist().dispatchPlaylistReplace();
  285. callAndHandleError(initPhase2, PlayerError.INIT_FAILED);
  286. });
  287. }
  288. private function onPluginLoad(event:PluginEvent):void {
  289. var plugin:PluginModel = event.target as PluginModel;
  290. log.info("plugin " + plugin + " initialized");
  291. checkPluginsInitialized();
  292. }
  293. private function onPluginLoadError(event:PluginEvent):void {
  294. if (event.target is Loadable) {
  295. handleError(PlayerError.PLUGIN_LOAD_FAILED, "unable to load plugin '" + Loadable(event.target).name + "', url: '" + Loadable(event.target).url + "'");
  296. // throw new Error("unable to load plugin '" + Loadable(event.target).name + "', url: '" + Loadable(event.target).url + "'");
  297. } else {
  298. var plugin:PluginModel = event.target as PluginModel;
  299. _pluginRegistry.removePlugin(plugin);
  300. handleError(PlayerError.PLUGIN_LOAD_FAILED, "load/init error on " + plugin);
  301. }
  302. }
  303. private function checkPluginsInitialized():void {
  304. var numPlugins:int = countPlugins();
  305. if (++_pluginsInitialized == numPlugins) {
  306. log.info("all plugins initialized");
  307. callAndHandleError(initPhase4, PlayerError.INIT_FAILED);
  308. }
  309. log.info(_pluginsInitialized + " out of " + numPlugins + " plugins initialized");
  310. }
  311. private function countPlugins():int {
  312. var count:Number = 0;
  313. var loadables:Array = _config.getLoadables();
  314. for (var i:Number = 0; i < loadables.length; i++) {
  315. var plugin:PluginModel = Loadable(loadables[i]).plugin;
  316. if (! plugin) {
  317. handleError(PlayerError.PLUGIN_LOAD_FAILED, "Unable to load plugin, url " + Loadable(loadables[i]).url + ", name " + Loadable(loadables[i]).name);
  318. // throw new Error("Plugin " + loadables[i] + " not available");
  319. }
  320. else
  321. {
  322. var isNonAdHocPlugin:Boolean = plugin.pluginObject is Plugin;
  323. // var isNonAdHocPlugin:Boolean = (plugin is DisplayPluginModel && DisplayPluginModel(plugin).getDisplayObject() is Plugin) ||
  324. // plugin is ProviderModel && ProviderModel(plugin).pluginObject is Plugin;
  325. if (Loadable(loadables[i]).loadFailed) {
  326. log.debug("load failed for " + loadables[i]);
  327. count++;
  328. } else if (! plugin) {
  329. log.debug("this plugin is not loaded yet");
  330. count++;
  331. } else if (isNonAdHocPlugin) {
  332. log.debug("will wait for onLoad from plugin " + plugin);
  333. count++;
  334. } else {
  335. log.debug("will NOT wait for onLoad from plugin " + Loadable(loadables[i]).plugin);
  336. }
  337. }
  338. }
  339. // +1 comes from the playbuttonoverlay
  340. return count + (_playButtonOverlay ? 1 : 0);
  341. }
  342. private function validateLicenseKey():Boolean {
  343. try {
  344. return LicenseKey.validate(root.loaderInfo.url, _flowplayer.version, _config.licenseKey, useExternalInterface());
  345. } catch (e:Error) {
  346. log.warn("License key not accepted, will show flowplayer logo");
  347. }
  348. return false;
  349. }
  350. private function createFullscreenManager(playlist:Playlist):void {
  351. _fullscreenManager = new FullscreenManager(stage, playlist, _panel, _pluginRegistry, _animationEngine);
  352. _flowplayer.fullscreenManager = _fullscreenManager;
  353. }
  354. public function showError(message:String):void {
  355. if (! _panel) return;
  356. if (! _config.showErrors) return;
  357. if (_error && _error.parent == this) {
  358. removeChild(_error);
  359. }
  360. _error = TextUtil.createTextField(false);
  361. _error.background = true;
  362. _error.backgroundColor = 0;
  363. _error.textColor = 0xffffff;
  364. _error.autoSize = TextFieldAutoSize.CENTER;
  365. _error.multiline = true;
  366. _error.wordWrap = true;
  367. _error.text = message;
  368. _error.selectable = true;
  369. _error.width = Arrange.parentWidth - 40;
  370. Arrange.center(_error, Arrange.parentWidth, Arrange.parentHeight);
  371. addChild(_error);
  372. createErrorMessageHideTimer();
  373. }
  374. private function createErrorMessageHideTimer():void {
  375. var errorHideTimer:Timer = new Timer(10000, 1);
  376. errorHideTimer.addEventListener(TimerEvent.TIMER_COMPLETE, hideErrorMessage);
  377. errorHideTimer.start();
  378. }
  379. private function hideErrorMessage(event:TimerEvent = null):void {
  380. if (_error && _error.parent == this) {
  381. if (_animationEngine) {
  382. _animationEngine.fadeOut(_error, 1000, function():void { removeChild(_error); });
  383. } else {
  384. removeChild(_error);
  385. }
  386. }
  387. }
  388. public function handleError(error:ErrorCode, info:Object = null, throwError:Boolean = true):void {
  389. if (_flowplayer) {
  390. _flowplayer.dispatchError(error, info);
  391. } else {
  392. // initialization is not complete, create a dispatcher just to dispatch this error
  393. new PlayerEventDispatcher().dispatchError(error, info);
  394. }
  395. var stack:String = "";
  396. if ( CONFIG::debug && info is Error && info.getStackTrace() )
  397. stack = info.getStackTrace();
  398. doHandleError(error.code + ": " + error.message + ( info ? ": " + info + (stack ? " - Stack: "+ stack : "") : ""), throwError);
  399. }
  400. private function doHandleError(message:String, throwError:Boolean = true):void {
  401. if (_config && _config.playerId) {
  402. Logger.error(message);
  403. }
  404. showError(message);
  405. if (throwError && Capabilities.isDebugger && _config.showErrors) {
  406. throw new Error(message);
  407. }
  408. }
  409. private function createAnimationEngine(pluginRegistry:PluginRegistry):void {
  410. _animationEngine = new AnimationEngine(_panel, pluginRegistry);
  411. }
  412. private function addPluginsToPanel(_pluginRegistry:PluginRegistry):void {
  413. for each (var pluginObj:Object in _pluginRegistry.plugins) {
  414. if (pluginObj is DisplayPluginModel) {
  415. var model:DisplayPluginModel = pluginObj as DisplayPluginModel;
  416. log.debug("adding plugin '"+ model.name +"' to panel: " + model.visible + ", plugin object is " + model.getDisplayObject());
  417. if (model.visible) {
  418. if (model.zIndex == -1) {
  419. model.zIndex = 100;
  420. }
  421. _panel.addView(model.getDisplayObject(), undefined, model);
  422. }
  423. if (model.name == "controls") {
  424. _controlsModel = model;
  425. }
  426. }
  427. }
  428. if (_controlsModel) {
  429. arrangeCanvasLogo();
  430. }
  431. }
  432. private function addScreenToPanel():void {
  433. // if controls visible and screen was not explicitly configured --> place screen on top of controls
  434. var screen:DisplayProperties = _pluginRegistry.getPlugin("screen") as DisplayProperties;
  435. screen.display = "none";
  436. screen.getDisplayObject().visible = false;
  437. _panel.addView(screen.getDisplayObject(), null, screen);
  438. }
  439. private function arrangeScreen(event:Event = null):void {
  440. log.debug("arrangeScreen(), already arranged " + _screenArrangeCount);
  441. if (_screenArrangeCount > 1) return;
  442. if (! _pluginRegistry) return;
  443. var screen:DisplayProperties = _pluginRegistry.getPlugin("screen") as DisplayProperties;
  444. if (! screen) return;
  445. if (_controlsModel && _controlsModel.visible) {
  446. if (isControlsAlwaysAutoHide() || (_controlsModel.position.bottom.px > 0)) {
  447. log.debug("controls is autoHide or it's in a non-default vertical position, configuring screen to take all available space");
  448. setScreenBottomAndHeight(screen, 100, 0);
  449. } else {
  450. var controlsHeight:Number = _controlsModel.getDisplayObject().height;
  451. var occupiedHeight:Number = screenTopOrBottomConfigured() ? getScreenTopOrBottomPx(screen) : controlsHeight;
  452. log.debug("occupied by controls or screen's configured bottom/top is " + occupiedHeight);
  453. var heightPct:Number = 0;
  454. if (screenTopOrBottomConfigured() && (screen.position.top.pct >= 0 || screen.position.bottom.pct >= 0)) {
  455. heightPct = 100 - Math.abs(50 - (screen.position.top.pct >= 0 ? screen.position.top.pct : screen.position.bottom.pct))*2;
  456. setScreenBottomAndHeight(screen, heightPct, controlsHeight);
  457. } else {
  458. heightPct = ((Arrange.parentHeight - occupiedHeight) / Arrange.parentHeight) * 100;
  459. setScreenBottomAndHeight(screen, heightPct, controlsHeight);
  460. }
  461. }
  462. }
  463. log.debug("arrangeScreen(): arranging screen to pos " + screen.position);
  464. screen.display = "block";
  465. screen.alpha = 1;
  466. screen.getDisplayObject().visible = true;
  467. _pluginRegistry.updateDisplayProperties(screen, true);
  468. _panel.update(screen.getDisplayObject(), screen);
  469. _panel.draw(screen.getDisplayObject());
  470. _screenArrangeCount++;
  471. }
  472. private function getScreenTopOrBottomPx(screen:DisplayProperties):Number {
  473. var screenConf:Object = _config.getObject("screen");
  474. if (screenConf.hasOwnProperty("top")) return screen.position.top.toPx(Arrange.parentHeight);
  475. if (screenConf.hasOwnProperty("bottom")) return screen.position.bottom.toPx(Arrange.parentHeight);
  476. return 0;
  477. }
  478. private function setScreenBottomAndHeight(screen:DisplayProperties, heightPct:Number, bottom:Number = 0):void {
  479. if (! screenTopOrBottomConfigured()) {
  480. log.debug("screen vertical pos not configured, setting bottom to value " + bottom);
  481. screen.bottom = bottom;
  482. } else {
  483. log.debug("using configured top/bottom for screen");
  484. }
  485. var heightConfigured:Boolean = _config.getObject("screen") && _config.getObject("screen").hasOwnProperty("height");
  486. if (! heightConfigured) {
  487. log.debug("screen height not configured, setting it to value " + heightPct + "%");
  488. screen.height = heightPct + "%";
  489. } else {
  490. log.debug("using configured height for screen");
  491. }
  492. }
  493. private function screenTopOrBottomConfigured():Boolean {
  494. var screen:Object = _config.getObject("screen");
  495. if (! screen) return false;
  496. if (screen.hasOwnProperty("top")) return true;
  497. if (screen.hasOwnProperty("bottom")) return true;
  498. return false;
  499. }
  500. private function isControlsAlwaysAutoHide():Boolean {
  501. if (!_controlsModel) return false;
  502. var controls:Object = _controlsModel.getDisplayObject();
  503. log.debug("controls.auotoHide " + controls.getAutoHide());
  504. //#583 this seems to handle the fullscreenOnly property better
  505. return !controls.getAutoHide().fullscreenOnly;
  506. }
  507. private function createFlowplayer():void {
  508. _flowplayer = new Flowplayer(stage, _pluginRegistry, _panel,
  509. _animationEngine, this, this, _config, URLUtil.playerBaseUrl);
  510. _flowplayer.onBeforeFullscreen(onFullscreen);
  511. // _flowplayer.onFullscreenExit(onFullscreen);
  512. }
  513. private function onFullscreen(event:PlayerEvent):void {
  514. log.debug("entering fullscreen, disabling display clicks");
  515. _screenArrangeCount = 100;
  516. stage.removeEventListener(Event.RESIZE, arrangeScreen);
  517. _enteringFullscreen = true;
  518. var delay:Timer = new Timer(1000, 1);
  519. delay.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete);
  520. delay.start();
  521. }
  522. private function onTimerComplete(event:TimerEvent):void {
  523. log.debug("fullscreen wait delay complete, display clicks are enabled again");
  524. _enteringFullscreen = false;
  525. }
  526. private function createFlashVarsConfig():void {
  527. log.debug("createFlashVarsConfig()");
  528. if (! root.loaderInfo.parameters) {
  529. return;
  530. }
  531. var configStr:String = Preloader(root).injectedConfig || root.loaderInfo.parameters["config"];
  532. var configObj:Object = configStr && configStr.indexOf("{") == 0 ? ConfigParser.parse(configStr) : {};
  533. if (! configStr || (configStr && configStr.indexOf("{") == 0 && ! configObj.hasOwnProperty("url"))) {
  534. _config = ConfigParser.parseConfig(configObj, BuiltInConfig.config, loaderInfo.url, VersionInfo.controlsVersion, VersionInfo.audioVersion);
  535. callAndHandleError(initPhase1, PlayerError.INIT_FAILED);
  536. } else {
  537. ConfigParser.loadConfig(configObj.hasOwnProperty("url") ? String(configObj["url"]) : configStr, BuiltInConfig.config, function(config:Config):void {
  538. _config = config;
  539. callAndHandleError(initPhase1, PlayerError.INIT_FAILED);
  540. }, new ResourceLoaderImpl(null, this), loaderInfo.url, VersionInfo.controlsVersion, VersionInfo.audioVersion);
  541. }
  542. }
  543. private function createPlayListController():PlayListController {
  544. createHttpProviders();
  545. var playListController:PlayListController = new PlayListController(_config.getPlaylist(), _providers, _config, createNewLoader());
  546. playListController.playerEventDispatcher = _flowplayer;
  547. _flowplayer.playlistController = playListController;
  548. return playListController;
  549. }
  550. private function createHttpProviders():void {
  551. if (! _providers) {
  552. _providers = new Dictionary();
  553. }
  554. _providers["http"] = createProvider("http");
  555. _providers["httpInstream"] = createProvider("httpInstream");
  556. }
  557. private function createProvider(name:String):Object {
  558. log.debug("creating provider with name " + name);
  559. var httpProvider:ProviderModel = _config.createHttpProvider(name);
  560. _pluginRegistry.registerProvider(httpProvider);
  561. return httpProvider.pluginObject;
  562. }
  563. private function get hasHttpChildClip():Boolean {
  564. var children:Array = _config.getPlaylist().childClips;
  565. // log.debug("configuration has child clips", children);
  566. for (var i:int = 0; i < children.length; i++) {
  567. if (Clip(children[i]).provider == "httpInstream") {
  568. log.info("child clip with http provider found");
  569. return true;
  570. }
  571. }
  572. return false;
  573. }
  574. private function createScreen():void {
  575. _screen = new Screen(_config.getPlaylist(), _animationEngine, _playButtonOverlay, _pluginRegistry);
  576. var screenModel:DisplayProperties = _config.getScreenProperties();
  577. initView(_screen, screenModel, null, false);
  578. if (_playButtonOverlay) {
  579. PlayButtonOverlayView(_playButtonOverlay.getDisplayObject()).setScreen(_screen, hasClip && _config.useBufferingAnimation);
  580. }
  581. // addViewLiteners(_screen);
  582. }
  583. private function createPlayButtonOverlay():void {
  584. _playButtonOverlay = _config.getPlayButtonOverlay();
  585. if (! _playButtonOverlay) return;
  586. _playButtonOverlay.onLoad(onPluginLoad);
  587. _playButtonOverlay.onError(onPluginLoadError);
  588. var overlay:PlayButtonOverlayView = new PlayButtonOverlayView(! playButtonOverlayWidthDefined(), _playButtonOverlay, _pluginRegistry);
  589. initView(overlay, _playButtonOverlay, null, false);
  590. }
  591. private function playButtonOverlayWidthDefined():Boolean {
  592. if (! _config.getObject("play")) return false;
  593. return _config.getObject("play").hasOwnProperty("width");
  594. }
  595. private function get hasClip():Boolean {
  596. var firstClip:Clip = _config.getPlaylist().current;
  597. var hasClip:Boolean = ! firstClip.isNullClip && (firstClip.url || firstClip.provider != 'http');
  598. return hasClip;
  599. }
  600. private function createLogo():void {
  601. var logoView:LogoView = new LogoView(_panel, _flowplayer);
  602. var logo:Logo = _config.getLogo(logoView) || new Logo(logoView, "logo");
  603. // do not show it initially
  604. logo.visible = false;
  605. logoView.model = logo;
  606. initView(logoView, logo, logoView.draw, false);
  607. }
  608. private function initView(view:DisplayObject, props:DisplayProperties, resizeListener:Function = null, addToPanel:Boolean = true):void {
  609. if (props.name != "logo" || VersionInfo.commercial) {
  610. _pluginRegistry.registerDisplayPlugin(props, view);
  611. }
  612. if (addToPanel) {
  613. _panel.addView(view, resizeListener, props);
  614. }
  615. if (props is Callable) {
  616. ExternalInterfaceHelper.initializeInterface(props as Callable, view);
  617. }
  618. }
  619. private function addListeners():void {
  620. _clickTimer.addEventListener(TimerEvent.TIMER, onClickTimer);
  621. doubleClickEnabled = true;
  622. addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
  623. _screen.addEventListener(MouseEvent.CLICK, onClickEvent);
  624. if (_playButtonOverlay) {
  625. _playButtonOverlay.getDisplayObject().addEventListener(MouseEvent.CLICK, onClickEvent);
  626. }
  627. addEventListener(MouseEvent.ROLL_OVER, onMouseOver);
  628. addEventListener(MouseEvent.ROLL_OUT, onMouseOut);
  629. // add some color so that the ROLL_OVER/ROLL_OUT events are always triggered
  630. graphics.beginFill(0, 0);
  631. graphics.drawRect(0, 0, Arrange.parentWidth, Arrange.parentHeight);
  632. graphics.endFill();
  633. //#508 disabling the stagevideo screen mask, canvas is visible without it.
  634. /*CONFIG::FLASH_10_1 {
  635. _flowplayer.playlist.onStageVideoStateChange(onStageVideoStateChange);
  636. } */
  637. }
  638. private function onMouseOut(event:MouseEvent):void {
  639. _flowplayer.dispatchEvent(PlayerEvent.mouseOut());
  640. }
  641. private function onMouseOver(event:MouseEvent):void {
  642. _flowplayer.dispatchEvent(PlayerEvent.mouseOver());
  643. }
  644. //#508 disabling the stagevideo screen mask, canvas is visible without it.
  645. /*CONFIG::FLASH_10_1 {
  646. private function onStageVideoStateChange(event:ClipEvent):void {
  647. var stageVideo:StageVideo = event.info as StageVideo;
  648. log.info("stage video state changed " + stageVideo);
  649. if ( stageVideo ) {
  650. _screenMask.width = stageVideo.viewPort.width;
  651. _screenMask.height = stageVideo.viewPort.height;
  652. _screenMask.x = stageVideo.viewPort.x;
  653. _screenMask.y = stageVideo.viewPort.y;
  654. log.debug("mask dimensions " + _screenMask.width + " x " + _screenMask.height);
  655. log.debug("mask pos " + _screenMask.x + ", " + _screenMask.y);
  656. if ( ! contains(_screenMask) ) {
  657. //#508 stage video mask was being added to the top layer and hiding all children.
  658. addChildAt(_screenMask, 1);
  659. //addChildAt(_screenMask, _canvasLogo ? getChildIndex(_canvasLogo) + 1 : 1);
  660. log.debug("adding mask");
  661. }
  662. } else {
  663. if ( contains(_screenMask) ) {
  664. log.debug("removing mask")
  665. removeChild(_screenMask);
  666. }
  667. }
  668. }
  669. } */
  670. private function createPanel():void {
  671. _panel = new Panel();
  672. addChild(_panel);
  673. }
  674. private function startStreams():void {
  675. var canStart:Boolean = true;
  676. if (_flowplayer.state != State.WAITING) {
  677. log.debug("streams have been started in player.onLoad(), will not start streams here.");
  678. canStart = false;
  679. }
  680. if (! hasClip) {
  681. log.info("Configuration has no clips to play.");
  682. canStart = false;
  683. }
  684. var playButton:PlayButtonOverlayView = _playButtonOverlay ? PlayButtonOverlayView(_playButtonOverlay.getDisplayObject()) : null;
  685. if (canStart) {
  686. if (_flowplayer.currentClip.autoPlay) {
  687. log.debug("clip is autoPlay");
  688. _flowplayer.play();
  689. } else if (_flowplayer.currentClip.autoBuffering) {
  690. log.debug("clip is autoBuffering");
  691. _flowplayer.startBuffering();
  692. } else {
  693. if (playButton) {
  694. playButton.stopBuffering();
  695. playButton.showButton();
  696. }
  697. }
  698. } else {
  699. // cannot start playing here, stop buffering indicator, don't show the button
  700. if (playButton) {
  701. playButton.stopBuffering();
  702. }
  703. }
  704. }
  705. private function addPlayListListeners():void {
  706. var playlist:Playlist = _config.getPlaylist();
  707. playlist.onError(onClipError);
  708. playlist.onBegin(onBegin);
  709. }
  710. private function onBegin(event:ClipEvent):void {
  711. this.buttonMode = Boolean(Clip(event.target).linkUrl);
  712. }
  713. private function onClipError(event:ClipEvent):void {
  714. if (event.isDefaultPrevented()) return;
  715. doHandleError(event.error.code + ", " + event.error.message + ", " + event.info2 + ", clip: '" + Clip(event.target) + "'");
  716. }
  717. private function onClickTimer(event:TimerEvent):void {
  718. if (_clickCount == 1) {
  719. onSingleClick(_clickEvent);
  720. }
  721. _clickCount = 0;
  722. }
  723. private function onDoubleClick(event:MouseEvent = null):void {
  724. log.debug("onDoubleClick");
  725. _flowplayer.toggleFullscreen();
  726. }
  727. private function onSingleClick(event:MouseEvent):void {
  728. if (isParent(DisplayObject(event.target), _screen)) {
  729. log.debug("screen clicked");
  730. _flowplayer.toggle();
  731. }
  732. }
  733. private function onClickEvent(event:MouseEvent):void {
  734. if (_enteringFullscreen) return;
  735. log.debug("onViewClicked, target " + event.target + ", current target " + event.currentTarget);
  736. event.stopPropagation();
  737. if (_playButtonOverlay && isParent(DisplayObject(event.target), _playButtonOverlay.getDisplayObject())) {
  738. _flowplayer.toggle();
  739. return;
  740. } else {
  741. // if using linkUrl, no doubleclick to fullscreen
  742. var clip:Clip = _flowplayer.playlist.current;
  743. if (clip.linkUrl) {
  744. log.debug("opening linked page " + clip.linkUrl);
  745. _flowplayer.pause();
  746. URLUtil.openPage(clip.linkUrl, clip.linkWindow);
  747. return;
  748. }
  749. }
  750. if (++_clickCount == 2) {
  751. onDoubleClick(event);
  752. } else {
  753. _clickEvent = event;
  754. _clickTimer.start();
  755. }
  756. }
  757. private function isParent(child:DisplayObject, parent:DisplayObject):Boolean {
  758. try {
  759. if (DisplayObject(child).parent == parent) return true;
  760. if (! (parent is DisplayObjectContainer)) return false;
  761. for (var i:Number = 0;i < DisplayObjectContainer(parent).numChildren; i++) {
  762. var curChild:DisplayObject = DisplayObjectContainer(parent).getChildAt(i);
  763. if (isParent(child, curChild)) {
  764. return true;
  765. }
  766. }
  767. } catch (e:SecurityError) {
  768. return true;
  769. }
  770. return false;
  771. }
  772. override protected function onRedraw():void {
  773. if (bgImageHolder && getChildIndex(bgImageHolder) > getChildIndex(_panel)) {
  774. swapChildren(bgImageHolder, _panel);
  775. }
  776. }
  777. private function createLogoForCanvas():void {
  778. if (_canvasLogo) return;
  779. _copyrightNotice = LogoUtil.createCopyrightNotice(8);
  780. addChild(_copyrightNotice);
  781. _canvasLogo = new CanvasLogo();
  782. _canvasLogo.width = 85;
  783. _canvasLogo.scaleY = _canvasLogo.scaleX;
  784. _canvasLogo.alpha = .4;
  785. _canvasLogo.addEventListener(MouseEvent.CLICK,
  786. function(event:MouseEvent):void { navigateToURL(new URLRequest("http://flowplayer.org"), "_self"); });
  787. _canvasLogo.buttonMode = true;
  788. log.debug("adding logo to display list");
  789. addChild(_canvasLogo);
  790. onStageResize();
  791. }
  792. private function createNewLoader():ResourceLoader {
  793. return new ResourceLoaderImpl(_config.playerId ? null : URLUtil.playerBaseUrl, this);
  794. }
  795. private function initCustomClipEvents():void {
  796. createCustomClipEvents(_config.connectionCallbacks);
  797. createCustomClipEvents(_config.streamCallbacks);
  798. }
  799. private function createCustomClipEvents(callbacks:Array):void {
  800. if (! callbacks) return;
  801. for (var i:int = 0; i < callbacks.length; i++) {
  802. log.debug("creating custom event type " + callbacks[i]);
  803. new ClipEventType(callbacks[i], true);
  804. }
  805. }
  806. private function callAndHandleError(func:Function, error:PlayerError):void {
  807. try {
  808. func();
  809. } catch (e:Error) {
  810. handleError(error, e, false);
  811. throw e;
  812. }
  813. }
  814. internal function get enteringFullscreen():Boolean {
  815. return _enteringFullscreen;
  816. }
  817. }
  818. }