System

2 位贡献者:

System app 是在 Firefox OS 启动过程 中由Gecko装载的第一个 web 应用,  它会处理许多运行系统所需要的任务,因此不会局限于某一个单独的 web 应用。 这篇文档主要是讲解 Sytem如何工作。

任何一个可以用 JavaScript 编写的应用, 会最终使用 JavaScript 构建的。 -- Atwood's Law

注意: 您可以在 Gaia Github 仓库中获取到 source code for the System app

system app 是如何启动的

当 Gecko 试图启动System应用时, 它会解析System's manifest.webapp 文件,并根据 launch_path 参数(该参数在Gaia应用中一般是 /index.html) 装载 index.html 文件。 要管理整个的移动系统,Sytem app需要装载很多资源文件。  

整个启动过程是从  bootstrap.js 中的下面代码开始的: 

window.addEventListener('load', function startup() {
// define safelyLaunchFTU
function safelyLaunchFTU() {
  ...
}

if (Applications.ready) {
  safelyLaunchFTU();
} else {
  ...
}

window.addEventListener('ftudone', function doneWithFTU() {
  window.removeEventListener('ftudone', doneWithFTU);

  var lock = window.navigator.mozSettings.createLock();
  lock.set({
    'gaia.system.checkForUpdates': true
  });
}

  ...

// With all important event handlers in place, we can now notify
// Gecko that we're ready for certain system services to send us
// messages (e.g. the radio).
var evt = new CustomEvent('mozContentEvent',
{ bubbles: true, cancelable: false,
  detail: { type: 'system-message-listener-ready' } });
  window.dispatchEvent(evt);
}

这段代码是这样工作的:

  1. System 是运行在浏览器引擎中真正的web应用, 并需要所有它依赖的资源都装载进去 — 包括 图片(images)和样式(styles)。 因此一旦 window.onload 事件触发, 我们就要开始这些工作。
  2. 首先,我们要使用 safelyLaunchFTU() 函数准备启动首次启动体验(FTU)  。顾名思义, 只有当用户首次启动 Firefox OS 时, FTU才会出现。
  3. 当用户在 FTU中点击 “完成” 时, 会启动 ftudone 自定义事件,  bootstrap.js 会监听和处理这个事件。
  4. 下一步, 我们会使用 Settings API (navigator.mozSettings)  将  gaia.system.checkForUpdates 设置成 true,  表示系统会检查更新。
  5. 最后,我们会通过 CustomEvent 运行自定义的 window.dispatchEvent。这是Gaia 使用的一个非常重要的设计模式, 用于系统消息的处理以及与Gecko层的通信。上面方法是指 Gaia System app 通知 Gecko层, 它已经准备好监听和处理事件了。 

实现模块化

为了实现更好的模块化和灵活性,system 应用本身也在不断的改进。 从1.4 版本开始, 专门发起了一个关于 refactor the system module as instantiable object 的倡议来讨论该问题。

在所有上述代码运行后,每个对 bootstrap.js  中的系统组件的引用都是是如下的形式:

window.telephonySettings = new TelephonySettings();
window.telephonySettings.start();

 TelephonySettings() 的源代码框架如下:

(function(exports) {
  'use strict';
  function TelephonySettings() {
    this.init_param = false;
  }

  TelephonySettings.prototype = {
    // Initialzes all settings.
    start: function() {
      ...
    },

    // Clean all settings.
    stop: function() {
      ...
    },

    1st_method: function ts_1st_method() {
      ...
    },

    2nd_method: function ts_2nd_method() {
      ...
    }
  };

  exports.TelephonySettings = TelephonySettings;

}(window));

这种模式可以帮助每个系统组件实现模块化,并使它们的可测性更强。

开机和关机动画

本部分会讲解 System app是如何控制开机动画和关机动画的。 init_logo_handler.js 和 sleep_menu.js 文件会对 system 开机动画和关机动画进行处理。

开机动画

开机动画当前并没有包含在主引导程序中,而是要借助于检查 EventListeners。

在 init_logo_handler.js 文件中的开机启动代码如下所示:

一旦Gecko准备将一些东西画在屏幕上时, 会选择 logo或者是动画。当DOM装载完成时, 我们会运行合适的系统处理程序来完成log或动画。当 ftudone 或者 ftuskip 运行时会将logo隐藏。 包含在  init_logo_handler.js 中的 _appendCarrierPowerOn 方法表示了如何通过监听DOMContentLoaded事件来启动动画或启动logo。logoLoader 方法则在 logo_loader.js 中定义。

var self = this;
document.addEventListener('DOMContentLoaded', function() {
  self.carrierLogo.appendChild(self.logoLoader.element);
  self._setReady();
});

一旦准备好 logo, 系统会调用 _setReady() 方法,  在方法中会建立一个监听器来监听特殊的 mozChromeEvent事件,这个事件会带有 system-first-paint 类型,表示系统系统已经准备好向屏幕绘图。

var elem = this.logoLoader.element;
  ...
window.addEventListener('mozChromeEvent', function startVideo(e) {
  if (e.detail.type == 'system-first-paint') {
    window.removeEventListener('mozChromeEvent', startVideo);
    if (elem && elem.ended === false) {
      elem.play();
    }
  }
});

此时图形元素开始运行。一旦启动 ftuopen 或 ftuskip 事件,  init_logo_handler.js 会调用默认的 handleEvent() 方法反过来触发 animate() 方法来以淡出的效果隐藏动画。

init: function ilh_init(logoLoader) {
  window.addEventListener('ftuopen', this);
  window.addEventListener('ftuskip', this);
    ...
},

handleEvent: function ilh_handleEvent() {
  this.animate();
},

关机动画

当系统准备就绪时,长按电源(power)按键,会触发定义在 hardware_button.js 文件中的 holdsleep 事件。 hardware_button.js 文件会处理所有“物理按键点击“的事件,包括电源(休眠)键,home键,音量增/减键等。

HardwareButtonsSleepState.prototype.enter = function() {
  this.timer = setTimeout(function() {
    / * When the user holds Sleep button more than HOLD_INTERVAL. */
    this.hardwareButtons.publish('holdsleep');
    this.hardwareButtons.setState('base');
  }.bind(this), this.hardwareButtons.HOLD_INTERVAL);
};

关机动画是由 sleep_menu.js 处理的;这个脚本文件会监听 holdsleep 事件,并且当它触发时会显示菜单对话框。

init: function sm_init() {
    ...
  window.addEventListener('holdsleep', this.show.bind(this));
    ...
}

如果用户通过重启和关机菜单选项选择关机,会触发 startPowerOff() 方法, 它反过来会触发 LogoLoader() 函数来对关机动画进行处理。

handleEvent: function sm_handleEvent(evt) {
  switch (evt.type) {
    case 'click':
      ...
    this.handler(action);
    break;
    ...
  }
}

handler: function sm_handler(action) {
  switch (action) {
    ...
    case 'restart':
      this.startPowerOff(true);
      break;

    case 'power':
      this.startPowerOff(false);
      break;
    ...
  }
}

System 的功能

 System app 会负责许多功能和任务, 你可能还会对能在其职权范围内找到而惊讶。系统应用负责的范围包括:状态栏( statusbar)和 实用工具盘管理(utility tray management), SIM卡锁(SIM lock), 更新管理(update manager), 主屏幕启动(homescreen launcher),webapp 窗口管理(webapp window) 等。 本节会对System 提供的一些最重要的功能进行探究。

状态栏(Statusbar)和实用工具盘(utility tray)

系统状态栏和下拉菜单 (Gaia 通常称之为 utility tray; Android 称之为 notification bar) 是由 statusbar.js 和 utility_tray.js 来处理的。 在应用的 index.html 中,状态栏条目是在 <div id="statusbar" data-z-index-level="statusbar">  中定义的,而实用工具盘条目在下面的结构中定义:

<div id="utility-tray" data-z-index-level="utility-tray">
  <div id="notifications-container">
    ...
  </div>
</div>

实用工具盘(utility tray)中会有一些特殊的面板,如更新管理器,紧急回调管理器,存储监视通知,媒体播放通知和控制,蓝牙传输状态,按键输入法(IME)切换。与之相关联的处理程序和样式放置在  js/ 和style/ 文件夹中。

特殊的应用launcher

System app 有三个特殊的launchers,  在需要时会调用单独的web应用程序。

  • 主屏幕启动器 : Homescreen 应用在运行时,当用户按下 Home 按钮,webapp 崩溃或者使用其他方式退出webapp时,都会显示主屏幕。
  • 锁屏启动器: 运行 lockscreen 应用时, 每次当用户打开屏幕时都会显示锁屏界面。
  •  FTU 启动器:  运行FTU 体验应用。这个应用只会在用户使用一个全新的 FirefoxOS设备(或者将设备恢复到出厂模式)时运行一次。而且 FTU webapp不会允许用户点击Home按键退出这个应用。

锁屏

Lockscreen app 的主要入口文件是 system/js/lockscreen.js。用户可以在这个界面解锁,启动相机以及音乐播放器。

紧急拨号器

紧急拨号器的代码是在 gaia/apps/system/emergency-call/ 文件夹下的。 它是拨号应用的简化版本,允许用户可以访问 SIM PIN unlock dialog 实现紧急拨号服务。

全系统(System-wide)UI

System应用会处理绝大多数的全系统(system-wide) UI, 其中大部分包括的是一些对话框,如音量警告对话框,SIM PIN解锁对话框,小区广播(cell broadcast)对话框,还包括一些影响窗口行为的UI元素,如 software home按键。

z-index level

在System 应用的 index.html 文件中,许多组件都带有 data-z-index-level 属性,例如

<div id="sleep-menu" data-z-index-level="sleep-menu">
  ...
</div>

对应 z-index-levels 定义在 system/style/zindex.css 文件中,如

#screen > [data-z-index-level="sleep-menu"] {
  z-index: 65536;
}

...

#screen > [data-z-index-level="app"] > .appWindow {
  z-index: 3;
}

z-index 设置是根据元素在屏幕上显示的顺序进行排列的 — 如果元素需要在视觉层次中比较高的元素数值也会较高。这就是System app在基本水平上窗口管理的方式。 

software home 按键

 software home 按键是 home按键的一种替代,会在缺少物理 home按键的情况下自动启动。例如在 Nexus 4 中。 要控制它的外观,Gecko提供了一个专有的媒体功能称为  -moz-physical-home-button, 它能够在媒体查询时使用基于硬件Home按键的外观。 如果需要,窗口管理会为 software home按键分配一些屏幕的空间。

在 system/style/window.css (以及许多其他的系统样式文件中), 可以看到

@media not all and (-moz-physical-home-button) {
  #screen:not(.software-button-disabled) > #windows > .appWindow {
    bottom: 5rem;
  }
 }

Home 手势 (从屏幕底部向上滑动)

home 手势是另外一个硬件home按键的替代;它可以在 开发者设置  中使能,而控制代码在 system/js/home_gesture.js 文件中。例如,这个手势涉及到从屏幕底部清扫,可以用来关闭应用。

这个手势能够在 Firefox OS 平板设备中自动使能。 而 gaia/shared/js/screen_layout.js 是专门用于检测设备是否是平板的。

音量警告对话框

在 system/js/sound_manager.js. 中包含控制音量警告对话框的代码。如果下面所有条件都满足,则会弹出音量警告对话框:

  • 耳机已插入设备
  • 已超过最大音量限值  85dB 
  • 声道音频中有内容播放

SIM PIN 解锁对话框

控制SIM PIN 解锁对话框的代码在 system/js/simcard_dialog.js 中 — 当Passcode lock选项使能时,对话框会在锁屏界面显示。开放的应用必须要在  manifest.webapp 中包含 telephony 权限中(System app中含有该权限)。

注意:  当手机在飞行模式时,不会显示SIM PIN 解锁对话框

 

文档标签和贡献者

向此页面作出贡献: ReyCG_sub, ReyCG
最后编辑者: ReyCG_sub,
隐藏侧边栏