From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- b2g/LICENSE | 373 ++++++ b2g/Makefile.in | 6 + b2g/app.mozbuild | 15 + b2g/app/Makefile.in | 66 + b2g/app/b2g.js | 1018 +++++++++++++++ b2g/app/macbuild/Contents/Info.plist.in | 67 + b2g/app/macbuild/Contents/MacOS-files.in | 9 + .../Resources/English.lproj/InfoPlist.strings.in | 5 + b2g/app/moz.build | 76 ++ b2g/app/nsBrowserApp.cpp | 239 ++++ b2g/app/ua-update.json.in | 51 + b2g/branding/branding-common.mozbuild | 23 + b2g/branding/browserhtml/app.icns | Bin 0 -> 256255 bytes b2g/branding/browserhtml/app.ico | Bin 0 -> 370070 bytes b2g/branding/browserhtml/background.png | Bin 0 -> 129900 bytes b2g/branding/browserhtml/configure.sh | 5 + b2g/branding/browserhtml/content/about.png | Bin 0 -> 25842 bytes b2g/branding/browserhtml/content/favicon32.png | Bin 0 -> 2670 bytes b2g/branding/browserhtml/content/icon48.png | Bin 0 -> 5302 bytes b2g/branding/browserhtml/content/icon64.png | Bin 0 -> 8267 bytes b2g/branding/browserhtml/content/jar.mn | 10 + b2g/branding/browserhtml/content/logo.png | Bin 0 -> 19488 bytes b2g/branding/browserhtml/content/logoWordmark.png | Bin 0 -> 14021 bytes b2g/branding/browserhtml/content/moz.build | 7 + b2g/branding/browserhtml/content/splash.png | Bin 0 -> 19610 bytes b2g/branding/browserhtml/default.png | Bin 0 -> 36395 bytes b2g/branding/browserhtml/disk.icns | Bin 0 -> 891873 bytes b2g/branding/browserhtml/dsstore | Bin 0 -> 12292 bytes b2g/branding/browserhtml/locales/en-US/brand.dtd | 7 + .../browserhtml/locales/en-US/brand.properties | 6 + b2g/branding/browserhtml/locales/jar.mn | 11 + b2g/branding/browserhtml/locales/moz.build | 7 + b2g/branding/browserhtml/moz.build | 10 + b2g/branding/horizon/app.icns | Bin 0 -> 53371 bytes b2g/branding/horizon/app.ico | Bin 0 -> 15086 bytes b2g/branding/horizon/background.png | Bin 0 -> 129900 bytes b2g/branding/horizon/configure.sh | 5 + b2g/branding/horizon/content/about.png | Bin 0 -> 25842 bytes b2g/branding/horizon/content/favicon32.png | Bin 0 -> 2670 bytes b2g/branding/horizon/content/icon48.png | Bin 0 -> 5302 bytes b2g/branding/horizon/content/icon64.png | Bin 0 -> 8267 bytes b2g/branding/horizon/content/jar.mn | 10 + b2g/branding/horizon/content/logo.png | Bin 0 -> 19488 bytes b2g/branding/horizon/content/logoWordmark.png | Bin 0 -> 14021 bytes b2g/branding/horizon/content/moz.build | 7 + b2g/branding/horizon/content/splash.png | Bin 0 -> 19610 bytes b2g/branding/horizon/default.png | Bin 0 -> 51360 bytes b2g/branding/horizon/disk.icns | Bin 0 -> 891873 bytes b2g/branding/horizon/dsstore | Bin 0 -> 12292 bytes b2g/branding/horizon/locales/en-US/brand.dtd | 8 + .../horizon/locales/en-US/brand.properties | 6 + b2g/branding/horizon/locales/jar.mn | 11 + b2g/branding/horizon/locales/moz.build | 7 + b2g/branding/horizon/moz.build | 10 + b2g/branding/official/app.icns | Bin 0 -> 11953 bytes b2g/branding/official/app.ico | Bin 0 -> 4286 bytes b2g/branding/official/background.png | Bin 0 -> 129900 bytes b2g/branding/official/configure.sh | 6 + b2g/branding/official/content/about.png | Bin 0 -> 25842 bytes b2g/branding/official/content/favicon32.png | Bin 0 -> 2670 bytes b2g/branding/official/content/icon48.png | Bin 0 -> 5302 bytes b2g/branding/official/content/icon64.png | Bin 0 -> 8267 bytes b2g/branding/official/content/jar.mn | 10 + b2g/branding/official/content/logo.png | Bin 0 -> 19488 bytes b2g/branding/official/content/logoWordmark.png | Bin 0 -> 14021 bytes b2g/branding/official/content/moz.build | 7 + b2g/branding/official/content/splash.png | Bin 0 -> 19610 bytes b2g/branding/official/default.png | Bin 0 -> 4762 bytes b2g/branding/official/disk.icns | Bin 0 -> 891873 bytes b2g/branding/official/dsstore | Bin 0 -> 12292 bytes b2g/branding/official/locales/en-US/brand.dtd | 8 + .../official/locales/en-US/brand.properties | 6 + b2g/branding/official/locales/jar.mn | 11 + b2g/branding/official/locales/moz.build | 7 + b2g/branding/official/moz.build | 10 + b2g/branding/unofficial/app.icns | Bin 0 -> 11953 bytes b2g/branding/unofficial/app.ico | Bin 0 -> 4286 bytes b2g/branding/unofficial/background.png | Bin 0 -> 129900 bytes b2g/branding/unofficial/configure.sh | 6 + b2g/branding/unofficial/content/about.png | Bin 0 -> 16858 bytes b2g/branding/unofficial/content/favicon32.png | Bin 0 -> 1761 bytes b2g/branding/unofficial/content/icon48.png | Bin 0 -> 4053 bytes b2g/branding/unofficial/content/icon64.png | Bin 0 -> 5897 bytes b2g/branding/unofficial/content/jar.mn | 10 + b2g/branding/unofficial/content/logo.png | Bin 0 -> 19844 bytes b2g/branding/unofficial/content/logoWordmark.png | Bin 0 -> 15088 bytes b2g/branding/unofficial/content/moz.build | 7 + b2g/branding/unofficial/content/splash.png | Bin 0 -> 19766 bytes b2g/branding/unofficial/default.png | Bin 0 -> 4762 bytes b2g/branding/unofficial/disk.icns | Bin 0 -> 891873 bytes b2g/branding/unofficial/dsstore | Bin 0 -> 12292 bytes b2g/branding/unofficial/locales/en-US/brand.dtd | 8 + .../unofficial/locales/en-US/brand.properties | 6 + b2g/branding/unofficial/locales/jar.mn | 11 + b2g/branding/unofficial/locales/moz.build | 7 + b2g/branding/unofficial/moz.build | 10 + b2g/build.mk | 31 + b2g/chrome/content/ErrorPage.js | 73 ++ b2g/chrome/content/aboutCertError.xhtml | 233 ++++ b2g/chrome/content/arrow.svg | 5 + b2g/chrome/content/blank.css | 7 + b2g/chrome/content/blank.html | 10 + b2g/chrome/content/content.css | 321 +++++ b2g/chrome/content/desktop.css | 59 + b2g/chrome/content/desktop.js | 179 +++ b2g/chrome/content/devtools/adb.js | 233 ++++ b2g/chrome/content/devtools/debugger.js | 397 ++++++ b2g/chrome/content/devtools/hud.js | 1017 +++++++++++++++ b2g/chrome/content/identity.js | 166 +++ b2g/chrome/content/images/arrowdown-16.png | Bin 0 -> 246 bytes b2g/chrome/content/images/arrowright-16.png | Bin 0 -> 235 bytes b2g/chrome/content/images/desktop/home-black.png | Bin 0 -> 331 bytes b2g/chrome/content/images/desktop/home-white.png | Bin 0 -> 276 bytes b2g/chrome/content/images/desktop/rotate.png | Bin 0 -> 657 bytes b2g/chrome/content/images/error.png | Bin 0 -> 433 bytes .../content/images/errorpage-larry-black.png | Bin 0 -> 850 bytes .../content/images/errorpage-larry-white.png | Bin 0 -> 886 bytes b2g/chrome/content/images/errorpage-warning.png | Bin 0 -> 631 bytes b2g/chrome/content/images/exitfullscreen-hdpi.png | Bin 0 -> 3409 bytes b2g/chrome/content/images/fullscreen-hdpi.png | Bin 0 -> 3382 bytes b2g/chrome/content/images/mute-hdpi.png | Bin 0 -> 3217 bytes b2g/chrome/content/images/pause-hdpi.png | Bin 0 -> 3042 bytes b2g/chrome/content/images/play-hdpi.png | Bin 0 -> 3318 bytes b2g/chrome/content/images/scrubber-hdpi.png | Bin 0 -> 3967 bytes b2g/chrome/content/images/throbber.png | Bin 0 -> 11862 bytes b2g/chrome/content/images/unmute-hdpi.png | Bin 0 -> 3259 bytes b2g/chrome/content/netError.css | 131 ++ b2g/chrome/content/screen.js | 276 +++++ b2g/chrome/content/settings.js | 698 +++++++++++ b2g/chrome/content/shell.css | 81 ++ b2g/chrome/content/shell.html | 66 + b2g/chrome/content/shell.js | 1308 ++++++++++++++++++++ b2g/chrome/content/shell_remote.html | 19 + b2g/chrome/content/shell_remote.js | 139 +++ .../test/mochitest/RecordingStatusChromeScript.js | 40 + .../test/mochitest/RecordingStatusHelper.js | 82 ++ .../test/mochitest/file_getusermedia_iframe.html | 36 + b2g/chrome/content/test/mochitest/mochitest.ini | 11 + b2g/chrome/content/test/mochitest/moz.build | 7 + .../test/mochitest/test_recordingStatus_basic.html | 119 ++ .../mochitest/test_recordingStatus_iframe.html | 71 ++ .../test_recordingStatus_kill_content_process.html | 72 ++ .../test_recordingStatus_multiple_requests.html | 108 ++ b2g/chrome/content/touchcontrols.css | 233 ++++ b2g/chrome/jar.mn | 60 + b2g/chrome/moz.build | 13 + b2g/common.configure | 32 + b2g/components/AboutServiceWorkers.jsm | 183 +++ b2g/components/ActivityChannel.jsm | 64 + b2g/components/AlertsHelper.jsm | 279 +++++ b2g/components/AlertsService.js | 153 +++ b2g/components/B2GAboutRedirector.js | 78 ++ b2g/components/B2GAppMigrator.js | 152 +++ b2g/components/B2GComponents.manifest | 108 ++ b2g/components/B2GPresentationDevicePrompt.js | 87 ++ b2g/components/BootstrapCommandLine.js | 52 + b2g/components/Bootstraper.jsm | 156 +++ b2g/components/CommandLine.js | 29 + b2g/components/ContentPermissionPrompt.js | 461 +++++++ b2g/components/ContentRequestHelper.jsm | 68 + b2g/components/DebuggerActors.js | 83 ++ b2g/components/DirectoryProvider.js | 295 +++++ b2g/components/ErrorPage.jsm | 187 +++ b2g/components/FilePicker.js | 223 ++++ b2g/components/Frames.jsm | 146 +++ b2g/components/FxAccountsMgmtService.jsm | 173 +++ b2g/components/FxAccountsUIGlue.js | 39 + b2g/components/GaiaChrome.cpp | 188 +++ b2g/components/GaiaChrome.h | 44 + b2g/components/GlobalSimulatorScreen.jsm | 90 ++ b2g/components/HelperAppDialog.js | 115 ++ b2g/components/LogCapture.jsm | 221 ++++ b2g/components/LogParser.jsm | 257 ++++ b2g/components/LogShake.jsm | 588 +++++++++ b2g/components/MailtoProtocolHandler.js | 46 + b2g/components/OMAContentHandler.js | 57 + b2g/components/OopCommandLine.js | 46 + b2g/components/OrientationChangeHandler.jsm | 70 ++ b2g/components/PresentationRequestUIGlue.js | 116 ++ b2g/components/ProcessGlobal.js | 202 +++ b2g/components/RecoveryService.js | 160 +++ b2g/components/SafeMode.jsm | 150 +++ b2g/components/Screenshot.jsm | 43 + b2g/components/SignInToWebsite.jsm | 444 +++++++ b2g/components/SimulatorScreen.js | 117 ++ b2g/components/SmsProtocolHandler.js | 74 ++ b2g/components/SystemAppProxy.jsm | 377 ++++++ b2g/components/SystemMessageInternal.js | 64 + b2g/components/TelProtocolHandler.js | 60 + b2g/components/TelURIParser.jsm | 120 ++ b2g/components/UpdatePrompt.js | 783 ++++++++++++ b2g/components/moz.build | 91 ++ b2g/components/nsIGaiaChrome.idl | 15 + b2g/components/nsISystemMessagesInternal.idl | 51 + .../test/mochitest/SandboxPromptTest.html | 57 + .../mochitest/filepicker_path_handler_chrome.js | 31 + b2g/components/test/mochitest/mochitest.ini | 28 + .../test/mochitest/permission_handler_chrome.js | 36 + .../presentation_prompt_handler_chrome.js | 94 ++ .../presentation_ui_glue_handler_chrome.js | 32 + b2g/components/test/mochitest/screenshot_helper.js | 40 + b2g/components/test/mochitest/systemapp_helper.js | 173 +++ .../test/mochitest/test_filepicker_path.html | 130 ++ .../test/mochitest/test_permission_deny.html | 83 ++ .../mochitest/test_permission_gum_remember.html | 170 +++ .../test_permission_visibilitychange.html | 57 + .../mochitest/test_presentation_device_prompt.html | 145 +++ .../test_presentation_request_ui_glue.html | 105 ++ .../test/mochitest/test_sandbox_permission.html | 104 ++ b2g/components/test/mochitest/test_screenshot.html | 31 + b2g/components/test/mochitest/test_systemapp.html | 31 + b2g/components/test/moz.build | 8 + b2g/components/test/unit/data/test_logger_file | Bin 0 -> 4037 bytes b2g/components/test/unit/head_identity.js | 159 +++ b2g/components/test/unit/head_logshake_gonk.js | 58 + .../test/unit/test_aboutserviceworkers.js | 142 +++ b2g/components/test/unit/test_bug793310.js | 39 + b2g/components/test/unit/test_bug832946.js | 18 + b2g/components/test/unit/test_fxaccounts.js | 212 ++++ b2g/components/test/unit/test_logcapture.js | 13 + b2g/components/test/unit/test_logcapture_gonk.js | 70 ++ b2g/components/test/unit/test_logparser.js | 75 ++ b2g/components/test/unit/test_logshake.js | 218 ++++ b2g/components/test/unit/test_logshake_gonk.js | 61 + .../test/unit/test_logshake_gonk_compression.js | 76 ++ .../test/unit/test_logshake_readLog_gonk.js | 65 + b2g/components/test/unit/test_signintowebsite.js | 322 +++++ b2g/components/test/unit/xpcshell.ini | 49 + b2g/config/aries/config.json | 52 + b2g/config/aries/releng-aries.manifest | 27 + b2g/config/aries/sources.xml | 162 +++ b2g/config/desktop/config.json | 8 + b2g/config/gaia.json | 7 + b2g/config/mozconfigs/common | 24 + b2g/config/mozconfigs/common.override | 8 + b2g/config/mozconfigs/ics_armv7a_gecko/debug | 20 + b2g/config/mozconfigs/ics_armv7a_gecko/nightly | 21 + b2g/config/mozconfigs/linux32_gecko/debug | 34 + b2g/config/mozconfigs/linux32_gecko/nightly | 36 + b2g/config/mozconfigs/linux64_gecko/nightly | 36 + b2g/config/mozconfigs/macosx64_gecko/debug | 33 + b2g/config/mozconfigs/macosx64_gecko/nightly | 34 + b2g/config/mozconfigs/win32_gecko/debug | 29 + b2g/config/mozconfigs/win32_gecko/nightly | 30 + b2g/config/nexus-5-l/config.json | 55 + b2g/config/nexus-5-l/releng-nexus5.manifest | 19 + b2g/config/nexus-5-l/sources.xml | 162 +++ .../tooltool-manifests/linux32/releng.manifest | 32 + .../tooltool-manifests/macosx64/releng.manifest | 24 + .../tooltool-manifests/win32/releng.manifest | 22 + b2g/confvars.sh | 45 + b2g/dev/app.mozbuild | 21 + b2g/dev/app/moz.build | 15 + b2g/dev/app/mulet.js | 20 + b2g/dev/build.mk | 6 + b2g/dev/config/mozconfigs/linux64/mulet | 10 + b2g/dev/config/mozconfigs/linux64/mulet-hazards | 13 + b2g/dev/config/mozconfigs/linux64/mulet_dbg | 14 + b2g/dev/config/mozconfigs/macosx64/mulet | 27 + b2g/dev/config/mozconfigs/win32/mulet | 13 + .../tooltool-manifests/linux64/hazard.manifest | 48 + .../tooltool-manifests/linux64/releng.manifest | 48 + .../tooltool-manifests/macosx64/releng.manifest | 24 + .../tooltool-manifests/win32/releng.manifest | 22 + b2g/dev/confvars.sh | 12 + b2g/dev/moz.configure | 9 + b2g/gaia/Makefile.in | 14 + b2g/gaia/moz.build | 20 + b2g/gaia/run-b2g.c | 50 + b2g/gaia/run-b2g.cpp | 102 ++ b2g/graphene/app.mozbuild | 17 + b2g/graphene/build.mk | 5 + b2g/graphene/config/horizon-mozconfigs/common | 24 + .../config/horizon-mozconfigs/common.override | 5 + .../config/horizon-mozconfigs/linux32/debug | 25 + .../config/horizon-mozconfigs/linux32/nightly | 25 + .../config/horizon-mozconfigs/linux64/debug | 25 + .../config/horizon-mozconfigs/linux64/nightly | 25 + .../config/horizon-mozconfigs/macosx64/debug | 23 + .../config/horizon-mozconfigs/macosx64/nightly | 23 + b2g/graphene/config/horizon-mozconfigs/win32/debug | 19 + .../config/horizon-mozconfigs/win32/nightly | 18 + b2g/graphene/config/horizon-mozconfigs/win64/debug | 23 + .../config/horizon-mozconfigs/win64/nightly | 26 + b2g/graphene/config/mozconfigs/common | 24 + b2g/graphene/config/mozconfigs/common.override | 5 + b2g/graphene/config/mozconfigs/linux32/debug | 25 + b2g/graphene/config/mozconfigs/linux32/nightly | 25 + b2g/graphene/config/mozconfigs/linux64/debug | 25 + b2g/graphene/config/mozconfigs/linux64/nightly | 25 + b2g/graphene/config/mozconfigs/macosx64/debug | 23 + b2g/graphene/config/mozconfigs/macosx64/nightly | 23 + b2g/graphene/config/mozconfigs/win32/debug | 19 + b2g/graphene/config/mozconfigs/win32/nightly | 18 + b2g/graphene/config/mozconfigs/win64/debug | 23 + b2g/graphene/config/mozconfigs/win64/nightly | 26 + b2g/graphene/confvars.sh | 53 + b2g/graphene/graphene.js | 59 + b2g/graphene/moz.configure | 7 + b2g/graphene/settings.json | 3 + b2g/installer/Makefile.in | 135 ++ b2g/installer/flash.bat | 73 ++ b2g/installer/moz.build | 6 + b2g/installer/package-manifest.in | 845 +++++++++++++ b2g/installer/removed-files.in | 45 + b2g/locales/Makefile.in | 149 +++ b2g/locales/all-locales | 3 + b2g/locales/en-US/b2g-l10n.js | 12 + b2g/locales/en-US/chrome/graphene.properties | 5 + .../en-US/chrome/overrides/aboutCertError.dtd | 38 + .../en-US/chrome/overrides/appstrings.properties | 39 + b2g/locales/en-US/defines.inc | 9 + b2g/locales/filter.py | 15 + b2g/locales/jar.mn | 75 ++ b2g/locales/l10n.ini | 13 + b2g/locales/moz.build | 7 + b2g/moz.build | 14 + b2g/moz.configure | 32 + b2g/simulator/bootstrap.js | 4 + b2g/simulator/build_xpi.py | 148 +++ b2g/simulator/custom-prefs.js | 8 + b2g/simulator/custom-settings.json | 6 + b2g/simulator/icon.png | Bin 0 -> 4762 bytes b2g/simulator/icon64.png | Bin 0 -> 7858 bytes b2g/simulator/install.rdf.in | 52 + b2g/test/b2g-unittest-requirements.txt | 8 + b2g/test/emulator.manifest | 6 + 327 files changed, 22896 insertions(+) create mode 100644 b2g/LICENSE create mode 100644 b2g/Makefile.in create mode 100644 b2g/app.mozbuild create mode 100644 b2g/app/Makefile.in create mode 100644 b2g/app/b2g.js create mode 100644 b2g/app/macbuild/Contents/Info.plist.in create mode 100644 b2g/app/macbuild/Contents/MacOS-files.in create mode 100644 b2g/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in create mode 100644 b2g/app/moz.build create mode 100644 b2g/app/nsBrowserApp.cpp create mode 100644 b2g/app/ua-update.json.in create mode 100644 b2g/branding/branding-common.mozbuild create mode 100644 b2g/branding/browserhtml/app.icns create mode 100644 b2g/branding/browserhtml/app.ico create mode 100644 b2g/branding/browserhtml/background.png create mode 100644 b2g/branding/browserhtml/configure.sh create mode 100644 b2g/branding/browserhtml/content/about.png create mode 100644 b2g/branding/browserhtml/content/favicon32.png create mode 100644 b2g/branding/browserhtml/content/icon48.png create mode 100644 b2g/branding/browserhtml/content/icon64.png create mode 100644 b2g/branding/browserhtml/content/jar.mn create mode 100644 b2g/branding/browserhtml/content/logo.png create mode 100644 b2g/branding/browserhtml/content/logoWordmark.png create mode 100644 b2g/branding/browserhtml/content/moz.build create mode 100644 b2g/branding/browserhtml/content/splash.png create mode 100644 b2g/branding/browserhtml/default.png create mode 100644 b2g/branding/browserhtml/disk.icns create mode 100644 b2g/branding/browserhtml/dsstore create mode 100644 b2g/branding/browserhtml/locales/en-US/brand.dtd create mode 100644 b2g/branding/browserhtml/locales/en-US/brand.properties create mode 100644 b2g/branding/browserhtml/locales/jar.mn create mode 100644 b2g/branding/browserhtml/locales/moz.build create mode 100644 b2g/branding/browserhtml/moz.build create mode 100644 b2g/branding/horizon/app.icns create mode 100644 b2g/branding/horizon/app.ico create mode 100644 b2g/branding/horizon/background.png create mode 100644 b2g/branding/horizon/configure.sh create mode 100644 b2g/branding/horizon/content/about.png create mode 100644 b2g/branding/horizon/content/favicon32.png create mode 100644 b2g/branding/horizon/content/icon48.png create mode 100644 b2g/branding/horizon/content/icon64.png create mode 100644 b2g/branding/horizon/content/jar.mn create mode 100644 b2g/branding/horizon/content/logo.png create mode 100644 b2g/branding/horizon/content/logoWordmark.png create mode 100644 b2g/branding/horizon/content/moz.build create mode 100644 b2g/branding/horizon/content/splash.png create mode 100644 b2g/branding/horizon/default.png create mode 100644 b2g/branding/horizon/disk.icns create mode 100644 b2g/branding/horizon/dsstore create mode 100644 b2g/branding/horizon/locales/en-US/brand.dtd create mode 100644 b2g/branding/horizon/locales/en-US/brand.properties create mode 100644 b2g/branding/horizon/locales/jar.mn create mode 100644 b2g/branding/horizon/locales/moz.build create mode 100644 b2g/branding/horizon/moz.build create mode 100644 b2g/branding/official/app.icns create mode 100644 b2g/branding/official/app.ico create mode 100644 b2g/branding/official/background.png create mode 100644 b2g/branding/official/configure.sh create mode 100644 b2g/branding/official/content/about.png create mode 100644 b2g/branding/official/content/favicon32.png create mode 100644 b2g/branding/official/content/icon48.png create mode 100644 b2g/branding/official/content/icon64.png create mode 100644 b2g/branding/official/content/jar.mn create mode 100644 b2g/branding/official/content/logo.png create mode 100644 b2g/branding/official/content/logoWordmark.png create mode 100644 b2g/branding/official/content/moz.build create mode 100644 b2g/branding/official/content/splash.png create mode 100644 b2g/branding/official/default.png create mode 100644 b2g/branding/official/disk.icns create mode 100644 b2g/branding/official/dsstore create mode 100644 b2g/branding/official/locales/en-US/brand.dtd create mode 100644 b2g/branding/official/locales/en-US/brand.properties create mode 100644 b2g/branding/official/locales/jar.mn create mode 100644 b2g/branding/official/locales/moz.build create mode 100644 b2g/branding/official/moz.build create mode 100644 b2g/branding/unofficial/app.icns create mode 100644 b2g/branding/unofficial/app.ico create mode 100644 b2g/branding/unofficial/background.png create mode 100644 b2g/branding/unofficial/configure.sh create mode 100644 b2g/branding/unofficial/content/about.png create mode 100644 b2g/branding/unofficial/content/favicon32.png create mode 100644 b2g/branding/unofficial/content/icon48.png create mode 100644 b2g/branding/unofficial/content/icon64.png create mode 100644 b2g/branding/unofficial/content/jar.mn create mode 100644 b2g/branding/unofficial/content/logo.png create mode 100644 b2g/branding/unofficial/content/logoWordmark.png create mode 100644 b2g/branding/unofficial/content/moz.build create mode 100644 b2g/branding/unofficial/content/splash.png create mode 100644 b2g/branding/unofficial/default.png create mode 100644 b2g/branding/unofficial/disk.icns create mode 100644 b2g/branding/unofficial/dsstore create mode 100644 b2g/branding/unofficial/locales/en-US/brand.dtd create mode 100644 b2g/branding/unofficial/locales/en-US/brand.properties create mode 100644 b2g/branding/unofficial/locales/jar.mn create mode 100644 b2g/branding/unofficial/locales/moz.build create mode 100644 b2g/branding/unofficial/moz.build create mode 100644 b2g/build.mk create mode 100644 b2g/chrome/content/ErrorPage.js create mode 100644 b2g/chrome/content/aboutCertError.xhtml create mode 100644 b2g/chrome/content/arrow.svg create mode 100644 b2g/chrome/content/blank.css create mode 100644 b2g/chrome/content/blank.html create mode 100644 b2g/chrome/content/content.css create mode 100644 b2g/chrome/content/desktop.css create mode 100644 b2g/chrome/content/desktop.js create mode 100644 b2g/chrome/content/devtools/adb.js create mode 100644 b2g/chrome/content/devtools/debugger.js create mode 100644 b2g/chrome/content/devtools/hud.js create mode 100644 b2g/chrome/content/identity.js create mode 100644 b2g/chrome/content/images/arrowdown-16.png create mode 100644 b2g/chrome/content/images/arrowright-16.png create mode 100644 b2g/chrome/content/images/desktop/home-black.png create mode 100644 b2g/chrome/content/images/desktop/home-white.png create mode 100644 b2g/chrome/content/images/desktop/rotate.png create mode 100644 b2g/chrome/content/images/error.png create mode 100644 b2g/chrome/content/images/errorpage-larry-black.png create mode 100644 b2g/chrome/content/images/errorpage-larry-white.png create mode 100644 b2g/chrome/content/images/errorpage-warning.png create mode 100644 b2g/chrome/content/images/exitfullscreen-hdpi.png create mode 100644 b2g/chrome/content/images/fullscreen-hdpi.png create mode 100644 b2g/chrome/content/images/mute-hdpi.png create mode 100644 b2g/chrome/content/images/pause-hdpi.png create mode 100644 b2g/chrome/content/images/play-hdpi.png create mode 100644 b2g/chrome/content/images/scrubber-hdpi.png create mode 100644 b2g/chrome/content/images/throbber.png create mode 100644 b2g/chrome/content/images/unmute-hdpi.png create mode 100644 b2g/chrome/content/netError.css create mode 100644 b2g/chrome/content/screen.js create mode 100644 b2g/chrome/content/settings.js create mode 100644 b2g/chrome/content/shell.css create mode 100644 b2g/chrome/content/shell.html create mode 100644 b2g/chrome/content/shell.js create mode 100644 b2g/chrome/content/shell_remote.html create mode 100644 b2g/chrome/content/shell_remote.js create mode 100644 b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js create mode 100644 b2g/chrome/content/test/mochitest/RecordingStatusHelper.js create mode 100644 b2g/chrome/content/test/mochitest/file_getusermedia_iframe.html create mode 100644 b2g/chrome/content/test/mochitest/mochitest.ini create mode 100644 b2g/chrome/content/test/mochitest/moz.build create mode 100644 b2g/chrome/content/test/mochitest/test_recordingStatus_basic.html create mode 100644 b2g/chrome/content/test/mochitest/test_recordingStatus_iframe.html create mode 100644 b2g/chrome/content/test/mochitest/test_recordingStatus_kill_content_process.html create mode 100644 b2g/chrome/content/test/mochitest/test_recordingStatus_multiple_requests.html create mode 100644 b2g/chrome/content/touchcontrols.css create mode 100644 b2g/chrome/jar.mn create mode 100644 b2g/chrome/moz.build create mode 100644 b2g/common.configure create mode 100644 b2g/components/AboutServiceWorkers.jsm create mode 100644 b2g/components/ActivityChannel.jsm create mode 100644 b2g/components/AlertsHelper.jsm create mode 100644 b2g/components/AlertsService.js create mode 100644 b2g/components/B2GAboutRedirector.js create mode 100644 b2g/components/B2GAppMigrator.js create mode 100644 b2g/components/B2GComponents.manifest create mode 100644 b2g/components/B2GPresentationDevicePrompt.js create mode 100644 b2g/components/BootstrapCommandLine.js create mode 100644 b2g/components/Bootstraper.jsm create mode 100644 b2g/components/CommandLine.js create mode 100644 b2g/components/ContentPermissionPrompt.js create mode 100644 b2g/components/ContentRequestHelper.jsm create mode 100644 b2g/components/DebuggerActors.js create mode 100644 b2g/components/DirectoryProvider.js create mode 100644 b2g/components/ErrorPage.jsm create mode 100644 b2g/components/FilePicker.js create mode 100644 b2g/components/Frames.jsm create mode 100644 b2g/components/FxAccountsMgmtService.jsm create mode 100644 b2g/components/FxAccountsUIGlue.js create mode 100644 b2g/components/GaiaChrome.cpp create mode 100644 b2g/components/GaiaChrome.h create mode 100644 b2g/components/GlobalSimulatorScreen.jsm create mode 100644 b2g/components/HelperAppDialog.js create mode 100644 b2g/components/LogCapture.jsm create mode 100644 b2g/components/LogParser.jsm create mode 100644 b2g/components/LogShake.jsm create mode 100644 b2g/components/MailtoProtocolHandler.js create mode 100644 b2g/components/OMAContentHandler.js create mode 100644 b2g/components/OopCommandLine.js create mode 100644 b2g/components/OrientationChangeHandler.jsm create mode 100644 b2g/components/PresentationRequestUIGlue.js create mode 100644 b2g/components/ProcessGlobal.js create mode 100644 b2g/components/RecoveryService.js create mode 100644 b2g/components/SafeMode.jsm create mode 100644 b2g/components/Screenshot.jsm create mode 100644 b2g/components/SignInToWebsite.jsm create mode 100644 b2g/components/SimulatorScreen.js create mode 100644 b2g/components/SmsProtocolHandler.js create mode 100644 b2g/components/SystemAppProxy.jsm create mode 100644 b2g/components/SystemMessageInternal.js create mode 100644 b2g/components/TelProtocolHandler.js create mode 100644 b2g/components/TelURIParser.jsm create mode 100644 b2g/components/UpdatePrompt.js create mode 100644 b2g/components/moz.build create mode 100644 b2g/components/nsIGaiaChrome.idl create mode 100644 b2g/components/nsISystemMessagesInternal.idl create mode 100644 b2g/components/test/mochitest/SandboxPromptTest.html create mode 100644 b2g/components/test/mochitest/filepicker_path_handler_chrome.js create mode 100644 b2g/components/test/mochitest/mochitest.ini create mode 100644 b2g/components/test/mochitest/permission_handler_chrome.js create mode 100644 b2g/components/test/mochitest/presentation_prompt_handler_chrome.js create mode 100644 b2g/components/test/mochitest/presentation_ui_glue_handler_chrome.js create mode 100644 b2g/components/test/mochitest/screenshot_helper.js create mode 100644 b2g/components/test/mochitest/systemapp_helper.js create mode 100644 b2g/components/test/mochitest/test_filepicker_path.html create mode 100644 b2g/components/test/mochitest/test_permission_deny.html create mode 100644 b2g/components/test/mochitest/test_permission_gum_remember.html create mode 100644 b2g/components/test/mochitest/test_permission_visibilitychange.html create mode 100644 b2g/components/test/mochitest/test_presentation_device_prompt.html create mode 100644 b2g/components/test/mochitest/test_presentation_request_ui_glue.html create mode 100644 b2g/components/test/mochitest/test_sandbox_permission.html create mode 100644 b2g/components/test/mochitest/test_screenshot.html create mode 100644 b2g/components/test/mochitest/test_systemapp.html create mode 100644 b2g/components/test/moz.build create mode 100644 b2g/components/test/unit/data/test_logger_file create mode 100644 b2g/components/test/unit/head_identity.js create mode 100644 b2g/components/test/unit/head_logshake_gonk.js create mode 100644 b2g/components/test/unit/test_aboutserviceworkers.js create mode 100644 b2g/components/test/unit/test_bug793310.js create mode 100644 b2g/components/test/unit/test_bug832946.js create mode 100644 b2g/components/test/unit/test_fxaccounts.js create mode 100644 b2g/components/test/unit/test_logcapture.js create mode 100644 b2g/components/test/unit/test_logcapture_gonk.js create mode 100644 b2g/components/test/unit/test_logparser.js create mode 100644 b2g/components/test/unit/test_logshake.js create mode 100644 b2g/components/test/unit/test_logshake_gonk.js create mode 100644 b2g/components/test/unit/test_logshake_gonk_compression.js create mode 100644 b2g/components/test/unit/test_logshake_readLog_gonk.js create mode 100644 b2g/components/test/unit/test_signintowebsite.js create mode 100644 b2g/components/test/unit/xpcshell.ini create mode 100644 b2g/config/aries/config.json create mode 100644 b2g/config/aries/releng-aries.manifest create mode 100644 b2g/config/aries/sources.xml create mode 100644 b2g/config/desktop/config.json create mode 100644 b2g/config/gaia.json create mode 100644 b2g/config/mozconfigs/common create mode 100644 b2g/config/mozconfigs/common.override create mode 100644 b2g/config/mozconfigs/ics_armv7a_gecko/debug create mode 100644 b2g/config/mozconfigs/ics_armv7a_gecko/nightly create mode 100644 b2g/config/mozconfigs/linux32_gecko/debug create mode 100644 b2g/config/mozconfigs/linux32_gecko/nightly create mode 100644 b2g/config/mozconfigs/linux64_gecko/nightly create mode 100644 b2g/config/mozconfigs/macosx64_gecko/debug create mode 100644 b2g/config/mozconfigs/macosx64_gecko/nightly create mode 100644 b2g/config/mozconfigs/win32_gecko/debug create mode 100644 b2g/config/mozconfigs/win32_gecko/nightly create mode 100644 b2g/config/nexus-5-l/config.json create mode 100644 b2g/config/nexus-5-l/releng-nexus5.manifest create mode 100644 b2g/config/nexus-5-l/sources.xml create mode 100644 b2g/config/tooltool-manifests/linux32/releng.manifest create mode 100644 b2g/config/tooltool-manifests/macosx64/releng.manifest create mode 100644 b2g/config/tooltool-manifests/win32/releng.manifest create mode 100644 b2g/confvars.sh create mode 100644 b2g/dev/app.mozbuild create mode 100644 b2g/dev/app/moz.build create mode 100644 b2g/dev/app/mulet.js create mode 100644 b2g/dev/build.mk create mode 100644 b2g/dev/config/mozconfigs/linux64/mulet create mode 100644 b2g/dev/config/mozconfigs/linux64/mulet-hazards create mode 100644 b2g/dev/config/mozconfigs/linux64/mulet_dbg create mode 100644 b2g/dev/config/mozconfigs/macosx64/mulet create mode 100644 b2g/dev/config/mozconfigs/win32/mulet create mode 100644 b2g/dev/config/tooltool-manifests/linux64/hazard.manifest create mode 100644 b2g/dev/config/tooltool-manifests/linux64/releng.manifest create mode 100644 b2g/dev/config/tooltool-manifests/macosx64/releng.manifest create mode 100644 b2g/dev/config/tooltool-manifests/win32/releng.manifest create mode 100644 b2g/dev/confvars.sh create mode 100644 b2g/dev/moz.configure create mode 100644 b2g/gaia/Makefile.in create mode 100644 b2g/gaia/moz.build create mode 100644 b2g/gaia/run-b2g.c create mode 100644 b2g/gaia/run-b2g.cpp create mode 100644 b2g/graphene/app.mozbuild create mode 100644 b2g/graphene/build.mk create mode 100644 b2g/graphene/config/horizon-mozconfigs/common create mode 100644 b2g/graphene/config/horizon-mozconfigs/common.override create mode 100644 b2g/graphene/config/horizon-mozconfigs/linux32/debug create mode 100644 b2g/graphene/config/horizon-mozconfigs/linux32/nightly create mode 100644 b2g/graphene/config/horizon-mozconfigs/linux64/debug create mode 100644 b2g/graphene/config/horizon-mozconfigs/linux64/nightly create mode 100644 b2g/graphene/config/horizon-mozconfigs/macosx64/debug create mode 100644 b2g/graphene/config/horizon-mozconfigs/macosx64/nightly create mode 100644 b2g/graphene/config/horizon-mozconfigs/win32/debug create mode 100644 b2g/graphene/config/horizon-mozconfigs/win32/nightly create mode 100644 b2g/graphene/config/horizon-mozconfigs/win64/debug create mode 100644 b2g/graphene/config/horizon-mozconfigs/win64/nightly create mode 100644 b2g/graphene/config/mozconfigs/common create mode 100644 b2g/graphene/config/mozconfigs/common.override create mode 100644 b2g/graphene/config/mozconfigs/linux32/debug create mode 100644 b2g/graphene/config/mozconfigs/linux32/nightly create mode 100644 b2g/graphene/config/mozconfigs/linux64/debug create mode 100644 b2g/graphene/config/mozconfigs/linux64/nightly create mode 100644 b2g/graphene/config/mozconfigs/macosx64/debug create mode 100644 b2g/graphene/config/mozconfigs/macosx64/nightly create mode 100644 b2g/graphene/config/mozconfigs/win32/debug create mode 100644 b2g/graphene/config/mozconfigs/win32/nightly create mode 100644 b2g/graphene/config/mozconfigs/win64/debug create mode 100644 b2g/graphene/config/mozconfigs/win64/nightly create mode 100644 b2g/graphene/confvars.sh create mode 100644 b2g/graphene/graphene.js create mode 100644 b2g/graphene/moz.configure create mode 100644 b2g/graphene/settings.json create mode 100644 b2g/installer/Makefile.in create mode 100755 b2g/installer/flash.bat create mode 100644 b2g/installer/moz.build create mode 100644 b2g/installer/package-manifest.in create mode 100644 b2g/installer/removed-files.in create mode 100644 b2g/locales/Makefile.in create mode 100644 b2g/locales/all-locales create mode 100644 b2g/locales/en-US/b2g-l10n.js create mode 100644 b2g/locales/en-US/chrome/graphene.properties create mode 100644 b2g/locales/en-US/chrome/overrides/aboutCertError.dtd create mode 100644 b2g/locales/en-US/chrome/overrides/appstrings.properties create mode 100644 b2g/locales/en-US/defines.inc create mode 100644 b2g/locales/filter.py create mode 100644 b2g/locales/jar.mn create mode 100644 b2g/locales/l10n.ini create mode 100644 b2g/locales/moz.build create mode 100644 b2g/moz.build create mode 100644 b2g/moz.configure create mode 100644 b2g/simulator/bootstrap.js create mode 100644 b2g/simulator/build_xpi.py create mode 100644 b2g/simulator/custom-prefs.js create mode 100644 b2g/simulator/custom-settings.json create mode 100644 b2g/simulator/icon.png create mode 100644 b2g/simulator/icon64.png create mode 100644 b2g/simulator/install.rdf.in create mode 100644 b2g/test/b2g-unittest-requirements.txt create mode 100644 b2g/test/emulator.manifest (limited to 'b2g') diff --git a/b2g/LICENSE b/b2g/LICENSE new file mode 100644 index 000000000..14e2f777f --- /dev/null +++ b/b2g/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/b2g/Makefile.in b/b2g/Makefile.in new file mode 100644 index 000000000..9b3e1e08a --- /dev/null +++ b/b2g/Makefile.in @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include $(topsrcdir)/config/rules.mk +include $(topsrcdir)/testing/testsuite-targets.mk diff --git a/b2g/app.mozbuild b/b2g/app.mozbuild new file mode 100644 index 000000000..4587438d5 --- /dev/null +++ b/b2g/app.mozbuild @@ -0,0 +1,15 @@ +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +include('/toolkit/toolkit.mozbuild') + +if CONFIG['MOZ_EXTENSIONS']: + DIRS += ['/extensions'] + +DIRS += [ + '/%s' % CONFIG['MOZ_BRANDING_DIRECTORY'], + '/b2g', +] diff --git a/b2g/app/Makefile.in b/b2g/app/Makefile.in new file mode 100644 index 000000000..6b50b87f7 --- /dev/null +++ b/b2g/app/Makefile.in @@ -0,0 +1,66 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Make sure the standalone glue doesn't try to get libxpcom.so from b2g/app. +NSDISTMODE = copy + +include $(topsrcdir)/config/rules.mk + +APP_ICON = app + +APP_BINARY = $(MOZ_APP_NAME)$(BIN_SUFFIX) + +ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) + +APP_NAME = $(MOZ_APP_DISPLAYNAME) +APP_VERSION = $(MOZ_APP_VERSION) + +ifdef MOZ_DEBUG +APP_NAME := $(APP_NAME)Debug +endif + +AB_CD = $(MOZ_UI_LOCALE) + +ifeq (zh-TW,$(AB_CD)) +LPROJ_ROOT := $(subst -,_,$(AB_CD)) +else +LPROJ_ROOT := $(firstword $(subst -, ,$(AB_CD))) +endif +LPROJ := Contents/Resources/$(LPROJ_ROOT).lproj + +clean clobber repackage:: + rm -rf $(DIST)/$(APP_NAME).app + +libs-preqs = \ + $(call mkdir_deps,$(DIST)/$(APP_NAME).app/Contents/MacOS) \ + $(call mkdir_deps,$(DIST)/$(APP_NAME).app/$(LPROJ)) \ + $(NULL) + +.PHONY: repackage +tools repackage:: $(libs-preqs) + rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents $(DIST)/$(APP_NAME).app --exclude English.lproj + rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(DIST)/$(APP_NAME).app/$(LPROJ) + sed -e 's/%MOZ_APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MOZ_APP_NAME%/$(MOZ_APP_NAME)/' -e 's/%APP_VERSION%/$(APP_VERSION)/' -e 's/%APP_NAME%/$(APP_NAME)/' -e 's/%APP_BINARY%/$(APP_BINARY)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(DIST)/$(APP_NAME).app/Contents/Info.plist + sed -e 's/%APP_VERSION%/$(APP_VERSION)/' -e 's/%APP_NAME%/$(APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(DIST)/$(APP_NAME).app/$(LPROJ)/InfoPlist.strings + rsync -a --exclude 'mangle' --exclude 'shlibsign' --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/Resources + rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/MacOS + $(RM) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM) + rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS + cp -RL $(DIST)/branding/app.icns $(DIST)/$(APP_NAME).app/Contents/Resources/$(MOZ_APP_NAME).icns + printf APPLMOZB > $(DIST)/$(APP_NAME).app/Contents/PkgInfo + +else # MOZ_WIDGET_TOOLKIT != cocoa + +libs:: + $(NSINSTALL) -D $(DIST)/bin/chrome/icons/default + +# Copy the app icon for b2g-desktop +ifeq ($(OS_ARCH),WINNT) + cp $(DIST)/branding/$(APP_ICON).ico $(DIST)/bin/chrome/icons/default/$(APP_ICON).ico + cp $(DIST)/branding/$(APP_ICON).ico $(DIST)/bin/chrome/icons/default/default.ico +else ifneq (gonk,$(MOZ_WIDGET_TOOLKIT)) + cp $(DIST)/branding/default.png $(DIST)/bin/chrome/icons/default/default.png +endif + +endif diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js new file mode 100644 index 000000000..ec2f2a0f1 --- /dev/null +++ b/b2g/app/b2g.js @@ -0,0 +1,1018 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#filter substitution + +// For the all MOZ_MULET ifdef conditions in this file: see bug 1174234 + +#ifndef MOZ_MULET +pref("toolkit.defaultChromeURI", "chrome://b2g/content/shell.html"); +pref("browser.chromeURL", "chrome://b2g/content/"); +#endif + +#ifdef MOZ_MULET +// Set FxOS as the default homepage +// bug 1000122: this pref is fetched as a complex value, +// so that it can't be set a just a string. +// data: url is a workaround this. +pref("browser.startup.homepage", "data:text/plain,browser.startup.homepage=chrome://b2g/content/shell.html"); +pref("b2g.is_mulet", true); +// Prevent having the firstrun page +pref("startup.homepage_welcome_url", ""); +pref("browser.shell.checkDefaultBrowser", false); +// Automatically open devtools on the firefox os panel +pref("devtools.toolbox.host", "side"); +pref("devtools.toolbox.sidebar.width", 800); +// Disable session store to ensure having only one tab opened +pref("browser.sessionstore.max_tabs_undo", 0); +pref("browser.sessionstore.max_windows_undo", 0); +pref("browser.sessionstore.restore_on_demand", false); +pref("browser.sessionstore.resume_from_crash", false); +// No e10s on mulet +pref("browser.tabs.remote.autostart.1", false); +pref("browser.tabs.remote.autostart.2", false); +#endif + +// Bug 945235: Prevent all bars to be considered visible: +pref("toolkit.defaultChromeFeatures", "chrome,dialog=no,close,resizable,scrollbars,extrachrome"); + +// Disable focus rings +pref("browser.display.focus_ring_width", 0); + +// Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density. +pref("browser.viewport.scaleRatio", -1); + +/* disable text selection */ +pref("browser.ignoreNativeFrameTextSelection", true); + +/* cache prefs */ +#ifdef MOZ_WIDGET_GONK +pref("browser.cache.disk.enable", true); +pref("browser.cache.disk.capacity", 55000); // kilobytes +pref("browser.cache.disk.parent_directory", "/cache"); +#endif +pref("browser.cache.disk.smart_size.enabled", false); +pref("browser.cache.disk.smart_size.first_run", false); + +pref("browser.cache.memory.enable", true); +pref("browser.cache.memory.capacity", 1024); // kilobytes + +pref("browser.cache.memory_limit", 2048); // 2 MB + +/* image cache prefs */ +pref("image.cache.size", 1048576); // bytes +pref("canvas.image.cache.limit", 20971520); // 20 MB + +/* offline cache prefs */ +pref("browser.offline-apps.notify", false); +pref("browser.cache.offline.enable", true); +pref("offline-apps.allow_by_default", true); + +/* protocol warning prefs */ +pref("network.protocol-handler.warn-external.tel", false); +pref("network.protocol-handler.warn-external.mailto", false); +pref("network.protocol-handler.warn-external.vnd.youtube", false); + +/* http prefs */ +pref("network.http.pipelining", true); +pref("network.http.pipelining.ssl", true); +pref("network.http.proxy.pipelining", true); +pref("network.http.pipelining.maxrequests" , 6); +pref("network.http.keep-alive.timeout", 109); +pref("network.http.max-connections", 20); +pref("network.http.max-persistent-connections-per-server", 6); +pref("network.http.max-persistent-connections-per-proxy", 20); + +// Keep the old default of accepting all cookies, +// no matter if you already visited the website or not +pref("network.cookie.cookieBehavior", 0); + +// spdy +pref("network.http.spdy.push-allowance", 32768); +pref("network.http.spdy.default-hpack-buffer", 4096); // 4k + +// See bug 545869 for details on why these are set the way they are +pref("network.buffer.cache.count", 24); +pref("network.buffer.cache.size", 16384); + +// predictive actions +pref("network.predictor.enabled", false); // disabled on b2g +pref("network.predictor.max-db-size", 2097152); // bytes +pref("network.predictor.preserve", 50); // percentage of predictor data to keep when cleaning up + +/* session history */ +pref("browser.sessionhistory.max_entries", 50); +pref("browser.sessionhistory.contentViewerTimeout", 360); + +/* session store */ +pref("browser.sessionstore.resume_session_once", false); +pref("browser.sessionstore.resume_from_crash", true); +pref("browser.sessionstore.resume_from_crash_timeout", 60); // minutes +pref("browser.sessionstore.interval", 10000); // milliseconds +pref("browser.sessionstore.max_tabs_undo", 1); + +/* these should help performance */ +pref("mozilla.widget.force-24bpp", true); +pref("mozilla.widget.use-buffer-pixmap", true); +pref("mozilla.widget.disable-native-theme", true); +pref("layout.reflow.synthMouseMove", false); +#ifndef MOZ_X11 +pref("layers.enable-tiles", true); +#endif +pref("layers.low-precision-buffer", true); +pref("layers.low-precision-opacity", "0.5"); +pref("layers.progressive-paint", true); + +/* download manager (don't show the window or alert) */ +pref("browser.download.useDownloadDir", true); +pref("browser.download.folderList", 1); // Default to ~/Downloads +pref("browser.download.manager.showAlertOnComplete", false); +pref("browser.download.manager.showAlertInterval", 2000); +pref("browser.download.manager.retention", 2); +pref("browser.download.manager.showWhenStarting", false); +pref("browser.download.manager.closeWhenDone", true); +pref("browser.download.manager.openDelay", 0); +pref("browser.download.manager.focusWhenStarting", false); +pref("browser.download.manager.flashCount", 2); +pref("browser.download.manager.displayedHistoryDays", 7); + +/* download helper */ +pref("browser.helperApps.deleteTempFileOnExit", false); + +/* password manager */ +pref("signon.rememberSignons", true); +pref("signon.expireMasterPassword", false); + +/* autocomplete */ +pref("browser.formfill.enable", true); + +/* spellcheck */ +pref("layout.spellcheckDefault", 0); + +/* block popups by default, and notify the user about blocked popups */ +pref("dom.disable_open_during_load", true); +pref("privacy.popups.showBrowserMessage", true); + +pref("keyword.enabled", true); +pref("browser.fixup.domainwhitelist.localhost", true); + +pref("accessibility.typeaheadfind", false); +pref("accessibility.typeaheadfind.timeout", 5000); +pref("accessibility.typeaheadfind.flashBar", 1); +pref("accessibility.typeaheadfind.linksonly", false); +pref("accessibility.typeaheadfind.casesensitive", 0); + +// SSL error page behaviour +pref("browser.ssl_override_behavior", 2); +pref("browser.xul.error_pages.expert_bad_cert", false); + +// disable updating +pref("browser.search.update", false); + +// tell the search service that we don't really expose the "current engine" +pref("browser.search.noCurrentEngine", true); + +// enable xul error pages +pref("browser.xul.error_pages.enabled", true); + +// disable color management +pref("gfx.color_management.mode", 0); + +// don't allow JS to move and resize existing windows +pref("dom.disable_window_move_resize", true); + +// prevent click image resizing for nsImageDocument +pref("browser.enable_click_image_resizing", false); + +// controls which bits of private data to clear. by default we clear them all. +pref("privacy.item.cache", true); +pref("privacy.item.cookies", true); +pref("privacy.item.offlineApps", true); +pref("privacy.item.history", true); +pref("privacy.item.formdata", true); +pref("privacy.item.downloads", true); +pref("privacy.item.passwords", true); +pref("privacy.item.sessions", true); +pref("privacy.item.geolocation", true); +pref("privacy.item.siteSettings", true); +pref("privacy.item.syncAccount", true); + +// base url for the wifi geolocation network provider +pref("geo.provider.use_mls", false); +pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%"); + +// base url for the stumbler +pref("geo.stumbler.url", "https://location.services.mozilla.com/v1/geosubmit?key=%MOZILLA_API_KEY%"); + +// enable geo +pref("geo.enabled", true); + +// content sink control -- controls responsiveness during page load +// see https://bugzilla.mozilla.org/show_bug.cgi?id=481566#c9 +pref("content.sink.enable_perf_mode", 2); // 0 - switch, 1 - interactive, 2 - perf +pref("content.sink.pending_event_mode", 0); +pref("content.sink.perf_deflect_count", 1000000); +pref("content.sink.perf_parse_time", 50000000); + +// Maximum scripts runtime before showing an alert +// Disable the watchdog thread for B2G. See bug 870043 comment 31. +pref("dom.use_watchdog", false); + +// The slow script dialog can be triggered from inside the JS engine as well, +// ensure that those calls don't accidentally trigger the dialog. +pref("dom.max_script_run_time", 0); +pref("dom.max_chrome_script_run_time", 0); + +// plugins +pref("plugin.disable", true); +pref("dom.ipc.plugins.enabled", true); + +// product URLs +// The breakpad report server to link to in about:crashes +pref("breakpad.reportURL", "https://crash-stats.mozilla.com/report/index/"); +pref("app.releaseNotesURL", "https://www.mozilla.com/%LOCALE%/b2g/%VERSION%/releasenotes/"); +pref("app.support.baseURL", "https://support.mozilla.com/b2g"); +pref("app.privacyURL", "https://www.mozilla.com/%LOCALE%/m/privacy.html"); +pref("app.creditsURL", "https://www.mozilla.org/credits/"); +pref("app.featuresURL", "https://www.mozilla.com/%LOCALE%/b2g/features/"); +pref("app.faqURL", "https://www.mozilla.com/%LOCALE%/b2g/faq/"); + +// Name of alternate about: page for certificate errors (when undefined, defaults to about:neterror) +pref("security.alternate_certificate_error_page", "certerror"); + +pref("security.warn_viewing_mixed", false); // Warning is disabled. See Bug 616712. + +// Block insecure active content on https pages +pref("security.mixed_content.block_active_content", true); + +// 2 = strict certificate pinning checks. +// This default preference is more strict than Firefox because B2G +// currently does not have a way to install local root certificates. +// Strict checking is effectively equivalent to non-strict checking as +// long as that is true. If an ability to add local certificates is +// added, there may be a need to change this pref. +pref("security.cert_pinning.enforcement_level", 2); + + +// Override some named colors to avoid inverse OS themes +pref("ui.-moz-dialog", "#efebe7"); +pref("ui.-moz-dialogtext", "#101010"); +pref("ui.-moz-field", "#fff"); +pref("ui.-moz-fieldtext", "#1a1a1a"); +pref("ui.-moz-buttonhoverface", "#f3f0ed"); +pref("ui.-moz-buttonhovertext", "#101010"); +pref("ui.-moz-combobox", "#fff"); +pref("ui.-moz-comboboxtext", "#101010"); +pref("ui.buttonface", "#ece7e2"); +pref("ui.buttonhighlight", "#fff"); +pref("ui.buttonshadow", "#aea194"); +pref("ui.buttontext", "#101010"); +pref("ui.captiontext", "#101010"); +pref("ui.graytext", "#b1a598"); +pref("ui.highlighttext", "#1a1a1a"); +pref("ui.threeddarkshadow", "#000"); +pref("ui.threedface", "#ece7e2"); +pref("ui.threedhighlight", "#fff"); +pref("ui.threedlightshadow", "#ece7e2"); +pref("ui.threedshadow", "#aea194"); +pref("ui.windowframe", "#efebe7"); + +// Themable via mozSettings +pref("ui.menu", "#f97c17"); +pref("ui.menutext", "#ffffff"); +pref("ui.infobackground", "#343e40"); +pref("ui.infotext", "#686868"); +pref("ui.window", "#ffffff"); +pref("ui.windowtext", "#000000"); +pref("ui.highlight", "#b2f2ff"); + +// replace newlines with spaces on paste into single-line text boxes +pref("editor.singleLine.pasteNewlines", 2); + +// threshold where a tap becomes a drag, in 1/240" reference pixels +// The names of the preferences are to be in sync with EventStateManager.cpp +pref("ui.dragThresholdX", 25); +pref("ui.dragThresholdY", 25); + +// Layers Acceleration. We can only have nice things on gonk, because +// they're not maintained anywhere else. +#ifndef MOZ_WIDGET_GONK +pref("dom.ipc.tabs.disabled", true); +pref("layers.async-pan-zoom.enabled", false); +#else +pref("dom.ipc.tabs.disabled", false); +pref("layers.acceleration.disabled", false); +pref("gfx.content.azure.backends", "cairo"); +#endif + +// Web Notifications +pref("notification.feature.enabled", true); + +// prevent video elements from preloading too much data +pref("media.preload.default", 1); // default to preload none +pref("media.preload.auto", 2); // preload metadata if preload=auto +pref("media.cache_size", 4096); // 4MB media cache +// Try to save battery by not resuming reading from a connection until we fall +// below 10s of buffered data. +pref("media.cache_resume_threshold", 10); +pref("media.cache_readahead_limit", 30); + +#ifdef MOZ_FMP4 +// Enable/Disable Gonk Decoder Module +pref("media.gonk.enabled", true); +#endif + +//Encrypted media extensions. +pref("media.eme.enabled", true); +pref("media.eme.apiVisible", true); +// The default number of decoded video frames that are enqueued in +// MediaDecoderReader's mVideoQueue. +pref("media.video-queue.default-size", 3); + +// optimize images' memory usage +pref("image.downscale-during-decode.enabled", true); +pref("image.mem.allow_locking_in_content_processes", true); +// Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller. +// Almost everything that was factored into 'max_decoded_image_kb' is now stored +// in the surface cache. 1/8 of main memory is 32MB on a 256MB device, which is +// about the same as the old 'max_decoded_image_kb'. +pref("image.mem.surfacecache.max_size_kb", 131072); // 128MB +pref("image.mem.surfacecache.size_factor", 8); // 1/8 of main memory +pref("image.mem.surfacecache.discard_factor", 2); // Discard 1/2 of the surface cache at a time. +pref("image.mem.surfacecache.min_expiration_ms", 86400000); // 24h, we rely on the out of memory hook + +pref("dom.w3c_touch_events.safetyX", 0); // escape borders in units of 1/240" +pref("dom.w3c_touch_events.safetyY", 120); // escape borders in units of 1/240" + +// True if this is the first time we are showing about:firstrun +pref("browser.firstrun.show.uidiscovery", true); +pref("browser.firstrun.show.localepicker", true); + +// initiated by a user +pref("content.ime.strict_policy", true); + +// True if you always want dump() to work +// +// On Android, you also need to do the following for the output +// to show up in logcat: +// +// $ adb shell stop +// $ adb shell setprop log.redirect-stdio true +// $ adb shell start +pref("browser.dom.window.dump.enabled", false); + +// Default Content Security Policy to apply to certified apps. +// If you change this CSP, make sure to update the fast path in nsCSPService.cpp +pref("security.apps.certified.CSP.default", "default-src * data: blob:; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline' app://theme.gaiamobile.org"); + +// handle links targeting new windows +// 1=current window/tab, 2=new window, 3=new tab in most recent window +pref("browser.link.open_newwindow", 3); + +// 0: no restrictions - divert everything +// 1: don't divert window.open at all +// 2: don't divert window.open with features +pref("browser.link.open_newwindow.restriction", 0); + +// Enable browser frames (including OOP, except on Windows, where it doesn't +// work), but make in-process browser frames the default. +pref("dom.mozBrowserFramesEnabled", true); + +// Enable a (virtually) unlimited number of mozbrowser processes. +// We'll run out of PIDs on UNIX-y systems before we hit this limit. +pref("dom.ipc.processCount", 100000); + +pref("dom.ipc.browser_frames.oop_by_default", false); + +#if !defined(MOZ_MULET) && !defined(MOZ_GRAPHENE) +pref("dom.meta-viewport.enabled", true); +#endif + +//The waiting time in network manager. +pref("network.gonk.ms-release-mms-connection", 30000); + +// Shortnumber matching needed for e.g. Brazil: +// 03187654321 can be found with 87654321 +pref("dom.phonenumber.substringmatching.BR", 8); +pref("dom.phonenumber.substringmatching.CO", 10); +pref("dom.phonenumber.substringmatching.VE", 7); +pref("dom.phonenumber.substringmatching.CL", 8); +pref("dom.phonenumber.substringmatching.PE", 7); + +// NetworkStats +#ifdef MOZ_WIDGET_GONK +pref("dom.mozNetworkStats.enabled", true); +pref("dom.webapps.firstRunWithSIM", true); +#endif + +#ifdef MOZ_B2G_RIL +// SingleVariant +pref("dom.mozApps.single_variant_sourcedir", "/persist/svoperapps"); +#endif + +// WebSettings +pref("dom.mozSettings.enabled", true); +pref("dom.mozPermissionSettings.enabled", true); + +// controls if we want camera support +pref("device.camera.enabled", true); +pref("media.realtime_decoder.enabled", true); + +// TCPSocket +pref("dom.mozTCPSocket.enabled", true); + +// "Preview" landing of bug 710563, which is bogged down in analysis +// of talos regression. This is a needed change for higher-framerate +// CSS animations, and incidentally works around an apparent bug in +// our handling of requestAnimationFrame() listeners, which are +// supposed to enable this REPEATING_PRECISE_CAN_SKIP behavior. The +// secondary bug isn't really worth investigating since it's obseleted +// by bug 710563. +pref("layout.frame_rate.precise", true); + +// Handle hardware buttons in the b2g chrome package +pref("b2g.keys.menu.enabled", true); + +// Display simulator software buttons +pref("b2g.software-buttons", false); + +// Screen timeout in seconds +pref("power.screen.timeout", 60); + +pref("full-screen-api.enabled", true); + +#ifndef MOZ_WIDGET_GONK +// If we're not actually on physical hardware, don't make the top level widget +// fullscreen when transitioning to fullscreen. This means in emulated +// environments (like the b2g desktop client) we won't make the client window +// fill the whole screen, we'll just make the content fill the client window, +// i.e. it won't give the impression to content that the number of device +// screen pixels changes! +pref("full-screen-api.ignore-widgets", true); +#endif + +pref("media.volume.steps", 10); + +#ifdef ENABLE_MARIONETTE +//Enable/disable marionette server, set listening port +pref("marionette.defaultPrefs.enabled", true); +pref("marionette.defaultPrefs.port", 2828); +#ifndef MOZ_WIDGET_GONK +// On desktop builds, we need to force the socket to listen on localhost only +pref("marionette.force-local", true); +#endif +#endif + +#ifdef MOZ_UPDATER +// When we're applying updates, we can't let anything hang us on +// quit+restart. The user has no recourse. +pref("shutdown.watchdog.timeoutSecs", 10); +// Timeout before the update prompt automatically installs the update +pref("b2g.update.apply-prompt-timeout", 60000); // milliseconds +// Amount of time to wait after the user is idle before prompting to apply an update +pref("b2g.update.apply-idle-timeout", 600000); // milliseconds +// Amount of time after which connection will be restarted if no progress +pref("b2g.update.download-watchdog-timeout", 120000); // milliseconds +pref("b2g.update.download-watchdog-max-retries", 5); + +pref("app.update.enabled", true); +pref("app.update.auto", false); +pref("app.update.silent", false); +pref("app.update.staging.enabled", true); +pref("app.update.service.enabled", true); + +pref("app.update.url", "https://aus5.mozilla.org/update/5/%PRODUCT%/%VERSION%/%BUILD_ID%/%PRODUCT_DEVICE%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%IMEI%/update.xml"); +pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@"); + +// Interval at which update manifest is fetched. In units of seconds. +pref("app.update.interval", 86400); // 1 day +// Don't throttle background updates. +pref("app.update.download.backgroundInterval", 0); + +// Retry update socket connections every 30 seconds in the cases of certain kinds of errors +pref("app.update.socket.retryTimeout", 30000); + +// Max of 20 consecutive retries (total 10 minutes) before giving up and marking +// the update download as failed. +// Note: Offline errors will always retry when the network comes online. +pref("app.update.socket.maxErrors", 20); + +// Enable update logging for now, to diagnose growing pains in the +// field. +pref("app.update.log", true); + +// SystemUpdate API +pref("dom.system_update.active", "@mozilla.org/updates/update-prompt;1"); +#else +// Explicitly disable the shutdown watchdog. It's enabled by default. +// When the updater is disabled, we want to know about shutdown hangs. +pref("shutdown.watchdog.timeoutSecs", -1); +#endif + +// Allow webapps update checking +pref("webapps.update.enabled", true); + +// Check daily for apps updates. +pref("webapps.update.interval", 86400); + +// Extensions preferences +pref("extensions.update.enabled", false); +pref("extensions.getAddons.cache.enabled", false); + +// Context Menu +pref("ui.click_hold_context_menus", true); +pref("ui.click_hold_context_menus.delay", 400); + +// Enable device storage +pref("device.storage.enabled", true); + +// Enable pre-installed applications +pref("dom.webapps.useCurrentProfile", true); + +// Enable system message +pref("dom.sysmsg.enabled", true); +pref("media.plugins.enabled", false); +pref("media.rtsp.enabled", true); +pref("media.rtsp.video.enabled", true); + +// Disable printing (particularly, window.print()) +pref("dom.disable_window_print", true); + +// Disable window.showModalDialog +pref("dom.disable_window_showModalDialog", true); + +// Enable new experimental html forms +pref("dom.experimental_forms", true); +pref("dom.forms.number", true); + +// Don't enable yet as we don't have a color picker +// implemented for b2g (bug 875751) +pref("dom.forms.color", false); + +// This preference instructs the JS engine to discard the +// source of any privileged JS after compilation. This saves +// memory, but makes things like Function.prototype.toSource() +// fail. +pref("javascript.options.discardSystemSource", true); + +// XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging +pref("javascript.options.mem.log", false); + +// Increase mark slice time from 10ms to 30ms +pref("javascript.options.mem.gc_incremental_slice_ms", 30); + +// Increase time to get more high frequency GC on benchmarks from 1000ms to 1500ms +pref("javascript.options.mem.gc_high_frequency_time_limit_ms", 1500); + +pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 300); +pref("javascript.options.mem.gc_high_frequency_heap_growth_min", 120); +pref("javascript.options.mem.gc_high_frequency_high_limit_mb", 40); +pref("javascript.options.mem.gc_high_frequency_low_limit_mb", 0); +pref("javascript.options.mem.gc_low_frequency_heap_growth", 120); +pref("javascript.options.mem.high_water_mark", 6); +pref("javascript.options.mem.gc_allocation_threshold_mb", 1); +pref("javascript.options.mem.gc_min_empty_chunk_count", 1); +pref("javascript.options.mem.gc_max_empty_chunk_count", 2); + +// Show/Hide scrollbars when active/inactive +pref("ui.showHideScrollbars", 1); +pref("ui.useOverlayScrollbars", 1); +pref("ui.scrollbarFadeBeginDelay", 450); +pref("ui.scrollbarFadeDuration", 0); + +// Scrollbar position follows the document `dir` attribute +pref("layout.scrollbar.side", 1); + +// CSS Scroll Snapping +pref("layout.css.scroll-snap.enabled", true); + +// Enable the ProcessPriorityManager, and give processes with no visible +// documents a 1s grace period before they're eligible to be marked as +// background. Background processes that are perceivable due to playing +// media are given a longer grace period to accomodate changing tracks, etc. +pref("dom.ipc.processPriorityManager.enabled", true); +pref("dom.ipc.processPriorityManager.backgroundGracePeriodMS", 1000); +pref("dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS", 5000); +pref("dom.ipc.processPriorityManager.temporaryPriorityLockMS", 5000); + +// Number of different background/foreground levels for background/foreground +// processes. We use these different levels to force the low-memory killer to +// kill processes in a LRU order. +pref("dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels", 5); +pref("dom.ipc.processPriorityManager.BACKGROUND_PERCEIVABLE.LRUPoolLevels", 4); + +// Kernel parameters for process priorities. These affect how processes are +// killed on low-memory and their relative CPU priorities. +// +// The kernel can only accept 6 (OomScoreAdjust, KillUnderKB) pairs. But it is +// okay, kernel will still kill processes with larger OomScoreAdjust first even +// its OomScoreAdjust don't have a corresponding KillUnderKB. + +pref("hal.processPriorityManager.gonk.MASTER.OomScoreAdjust", 0); +pref("hal.processPriorityManager.gonk.MASTER.KillUnderKB", 4096); +pref("hal.processPriorityManager.gonk.MASTER.cgroup", ""); + +pref("hal.processPriorityManager.gonk.PREALLOC.OomScoreAdjust", 67); +pref("hal.processPriorityManager.gonk.PREALLOC.cgroup", "apps/bg_non_interactive"); + +pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.OomScoreAdjust", 67); +pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.KillUnderKB", 5120); +pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.cgroup", "apps/critical"); + +pref("hal.processPriorityManager.gonk.FOREGROUND.OomScoreAdjust", 134); +pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderKB", 6144); +pref("hal.processPriorityManager.gonk.FOREGROUND.cgroup", "apps"); + +pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.OomScoreAdjust", 200); +pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.cgroup", "apps"); + +pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.OomScoreAdjust", 400); +pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.KillUnderKB", 8192); +pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.cgroup", "apps/bg_perceivable"); + +pref("hal.processPriorityManager.gonk.BACKGROUND.OomScoreAdjust", 667); +pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480); +pref("hal.processPriorityManager.gonk.BACKGROUND.cgroup", "apps/bg_non_interactive"); + +// Control group definitions (i.e., CPU priority groups) for B2G processes. +// +// memory_swappiness - 0 - The kernel will swap only to avoid an out of memory condition +// memory_swappiness - 60 - The default value. +// memory_swappiness - 100 - The kernel will swap aggressively. + +// Foreground apps +pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_shares", 1024); +pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_notify_on_migrate", 0); +pref("hal.processPriorityManager.gonk.cgroups.apps.memory_swappiness", 10); + +// Foreground apps with high priority, 16x more CPU than foreground ones +pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_shares", 16384); +pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_notify_on_migrate", 0); +pref("hal.processPriorityManager.gonk.cgroups.apps/critical.memory_swappiness", 0); + +// Background perceivable apps, ~10x less CPU than foreground ones +pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_shares", 103); +pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_notify_on_migrate", 0); +pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.memory_swappiness", 60); + +// Background apps, ~20x less CPU than foreground ones and ~2x less than perceivable ones +pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_shares", 52); +pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_notify_on_migrate", 0); +pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.memory_swappiness", 100); + +// By default the compositor thread on gonk runs without real-time priority. RT +// priority can be enabled by setting this pref to a value between 1 and 99. +// Note that audio processing currently runs at RT priority 2 or 3 at most. +// +// If RT priority is disabled, then the compositor nice value is used. We prefer +// to use a nice value of -4, which matches Android's preferences. Setting a preference +// of RT priority 1 would mean it is higher than audio, which is -16. The compositor +// priority must be below the audio thread. +// +// Do not change these values without gfx team review. +pref("hal.gonk.COMPOSITOR.rt_priority", 0); +pref("hal.gonk.COMPOSITOR.nice", -4); + +// Fire a memory pressure event when the system has less than Xmb of memory +// remaining. You should probably set this just above Y.KillUnderKB for +// the highest priority class Y that you want to make an effort to keep alive. +// (For example, we want BACKGROUND_PERCEIVABLE to stay alive.) If you set +// this too high, then we'll send out a memory pressure event every Z seconds +// (see below), even while we have processes that we would happily kill in +// order to free up memory. +pref("gonk.notifyHardLowMemUnderKB", 14336); + +// Fire a memory pressure event when the system has less than Xmb of memory +// remaining and then switch to the hard trigger, see above. This should be +// placed above the BACKGROUND priority class. +pref("gonk.notifySoftLowMemUnderKB", 43008); + +// We wait this long before polling the memory-pressure fd after seeing one +// memory pressure event. (When we're not under memory pressure, we sit +// blocked on a poll(), and this pref has no effect.) +pref("gonk.systemMemoryPressureRecoveryPollMS", 5000); + +// Enable pre-launching content processes for improved startup time +// (hiding latency). +pref("dom.ipc.processPrelaunch.enabled", true); +// Wait this long before pre-launching a new subprocess. +pref("dom.ipc.processPrelaunch.delayMs", 5000); + +pref("dom.ipc.reuse_parent_app", false); + +// When a process receives a system message, we hold a CPU wake lock on its +// behalf for this many seconds, or until it handles the system message, +// whichever comes first. +pref("dom.ipc.systemMessageCPULockTimeoutSec", 30); + +// Ignore the "dialog=1" feature in window.open. +pref("dom.disable_window_open_dialog_feature", true); + +// Enable before keyboard events and after keyboard events. +pref("dom.beforeAfterKeyboardEvent.enabled", true); + +// Screen reader support +pref("accessibility.accessfu.activate", 2); +pref("accessibility.accessfu.quicknav_modes", "Link,Heading,FormElement,Landmark,ListItem"); +// Active quicknav mode, index value of list from quicknav_modes +pref("accessibility.accessfu.quicknav_index", 0); +// Setting for an utterance order (0 - description first, 1 - description last). +pref("accessibility.accessfu.utterance", 1); +// Whether to skip images with empty alt text +pref("accessibility.accessfu.skip_empty_images", true); +// Setting to change the verbosity of entered text (0 - none, 1 - characters, +// 2 - words, 3 - both) +pref("accessibility.accessfu.keyboard_echo", 3); + +// Enable hit-target fluffing +pref("ui.touch.radius.enabled", true); +pref("ui.touch.radius.leftmm", 3); +pref("ui.touch.radius.topmm", 5); +pref("ui.touch.radius.rightmm", 3); +pref("ui.touch.radius.bottommm", 2); + +pref("ui.mouse.radius.enabled", true); +pref("ui.mouse.radius.leftmm", 3); +pref("ui.mouse.radius.topmm", 5); +pref("ui.mouse.radius.rightmm", 3); +pref("ui.mouse.radius.bottommm", 2); + +// Disable native prompt +pref("browser.prompt.allowNative", false); + +// Minimum delay in milliseconds between network activity notifications (0 means +// no notifications). The delay is the same for both download and upload, though +// they are handled separately. This pref is only read once at startup: +// a restart is required to enable a new value. +pref("network.activity.blipIntervalMilliseconds", 250); + +// By default we want the NetworkManager service to manage Gecko's offline +// status for us according to the state of Wifi/cellular data connections. +// In some environments, such as the emulator or hardware with other network +// connectivity, this is not desireable, however, in which case this pref +// can be flipped to false. +pref("network.gonk.manage-offline-status", true); + +// On Firefox Mulet, we can't enable shared JSM scope +// as it breaks most Firefox JSMs (see bug 961777) +#ifndef MOZ_MULET +// Break any JSMs or JS components that rely on shared scope +#ifndef DEBUG +pref("jsloader.reuseGlobal", true); +#endif +#endif + +// Enable font inflation for browser tab content. +pref("font.size.inflation.minTwips", 120); +// And disable it for lingering master-process UI. +pref("font.size.inflation.disabledInMasterProcess", true); + +// Enable freeing dirty pages when minimizing memory; this reduces memory +// consumption when applications are sent to the background. +pref("memory.free_dirty_pages", true); + +// Enable the Linux-specific, system-wide memory reporter. +pref("memory.system_memory_reporter", true); + +// Don't dump memory reports on OOM, by default. +pref("memory.dump_reports_on_oom", false); + +pref("layout.framevisibility.numscrollportwidths", 1); +pref("layout.framevisibility.numscrollportheights", 1); + +// Wait up to this much milliseconds when orientation changed +pref("layers.orientation.sync.timeout", 1000); + +// Animate the orientation change +pref("b2g.orientation.animate", true); + +// Don't discard WebGL contexts for foreground apps on memory +// pressure. +pref("webgl.can-lose-context-in-foreground", false); + +// Allow nsMemoryInfoDumper to create a fifo in the temp directory. We use +// this fifo to trigger about:memory dumps, among other things. +pref("memory_info_dumper.watch_fifo.enabled", true); +pref("memory_info_dumper.watch_fifo.directory", "/data/local"); + +// See ua-update.json.in for the packaged UA override list +pref("general.useragent.updates.enabled", true); +pref("general.useragent.updates.url", "https://dynamicua.cdn.mozilla.net/0/%APP_ID%"); +pref("general.useragent.updates.interval", 604800); // 1 week +pref("general.useragent.updates.retry", 86400); // 1 day +// Device ID can be composed of letter, numbers, hyphen ("-") and dot (".") +pref("general.useragent.device_id", ""); + +// Add Mozilla AudioChannel APIs. +pref("media.useAudioChannelAPI", true); + +pref("b2g.version", @MOZ_B2G_VERSION@); +pref("b2g.osName", @MOZ_B2G_OS_NAME@); + +// Disable console buffering to save memory. +pref("consoleservice.buffered", false); + +#ifdef MOZ_WIDGET_GONK +// Performance testing suggests 2k is a better page size for SQLite. +pref("toolkit.storage.pageSize", 2048); +#endif + +// The url of the manifest we use for ADU pings. +pref("ping.manifestURL", "https://marketplace.firefox.com/packaged.webapp"); + +// Enable the disk space watcher +pref("disk_space_watcher.enabled", true); + +// SNTP preferences. +pref("network.sntp.maxRetryCount", 10); +pref("network.sntp.refreshPeriod", 86400); // In seconds. +pref("network.sntp.pools", // Servers separated by ';'. + "0.pool.ntp.org;1.pool.ntp.org;2.pool.ntp.org;3.pool.ntp.org"); +pref("network.sntp.port", 123); +pref("network.sntp.timeout", 30); // In seconds. + +// Allow ADB to run for this many hours before disabling +// (only applies when marionette is disabled) +// 0 disables the timer. +pref("b2g.adb.timeout-hours", 12); + +// InputMethod so we can do soft keyboards +pref("dom.mozInputMethod.enabled", true); + +// Absolute path to the devtool unix domain socket file used +// to communicate with a usb cable via adb forward +pref("devtools.debugger.unix-domain-socket", "/data/local/debugger-socket"); + +// enable Skia/GL (OpenGL-accelerated 2D drawing) for large enough 2d canvases, +// falling back to Skia/software for smaller canvases +#ifdef MOZ_WIDGET_GONK +pref("gfx.canvas.azure.backends", "skia"); +pref("gfx.canvas.azure.accelerated", true); +#endif + +// Turn on dynamic cache size for Skia +pref("gfx.canvas.skiagl.dynamic-cache", true); + +// Limit skia to canvases the size of the device screen or smaller +pref("gfx.canvas.max-size-for-skia-gl", -1); + +// enable fence with readpixels for SurfaceStream +pref("gfx.gralloc.fence-with-readpixels", true); + +// enable screen mirroring to external display +pref("gfx.screen-mirroring.enabled", true); + +// The url of the page used to display network error details. +pref("b2g.neterror.url", "net_error.html"); + +// Enable Web Speech synthesis API +pref("media.webspeech.synth.enabled", true); + +// Enable Web Speech recognition API +pref("media.webspeech.recognition.enable", true); + +// Downloads API +pref("dom.mozDownloads.enabled", true); +pref("dom.downloads.max_retention_days", 7); + +// External Helper Application Handling +// +// All external helper application handling can require the docshell to be +// active before allowing the external helper app service to handle content. +// +// To prevent SD card DoS attacks via downloads we disable background handling. +// +pref("security.exthelperapp.disable_background_handling", true); + +// Inactivity time in milliseconds after which we shut down the OS.File worker. +pref("osfile.reset_worker_delay", 5000); + +// APZ physics settings, tuned by UX designers +pref("apz.axis_lock.mode", 2); // Use "sticky" axis locking +pref("apz.fling_curve_function_x1", "0.41"); +pref("apz.fling_curve_function_y1", "0.0"); +pref("apz.fling_curve_function_x2", "0.80"); +pref("apz.fling_curve_function_y2", "1.0"); +pref("apz.fling_curve_threshold_inches_per_ms", "0.01"); +pref("apz.fling_friction", "0.0019"); +pref("apz.max_velocity_inches_per_ms", "0.07"); +pref("apz.overscroll.enabled", true); +pref("apz.displayport_expiry_ms", 0); // causes issues on B2G, see bug 1250924 + +// For event-regions based hit-testing +pref("layout.event-regions.enabled", true); + +// This preference allows FirefoxOS apps (and content, I think) to force +// the use of software (instead of hardware accelerated) 2D canvases by +// creating a context like this: +// +// canvas.getContext('2d', { willReadFrequently: true }) +// +// Using a software canvas can save memory when JS calls getImageData() +// on the canvas frequently. See bug 884226. +pref("gfx.canvas.willReadFrequently.enable", true); + +// Disable autofocus until we can have it not bring up the keyboard. +// https://bugzilla.mozilla.org/show_bug.cgi?id=965763 +pref("browser.autofocus", false); + +// Enable wakelock +pref("dom.wakelock.enabled", true); + +// Enable webapps add-ons +pref("dom.apps.reviewer_paths", "/reviewers/,/extension/reviewers/"); + +// New implementation to unify touch-caret and selection-carets. +pref("layout.accessiblecaret.enabled", true); + +// Show the selection bars at the two ends of the selection highlight. Required +// by the spec in bug 921965. +pref("layout.accessiblecaret.bar.enabled", true); + +// Hide the caret in cursor mode after 3 seconds. +pref("layout.accessiblecaret.timeout_ms", 3000); + +// Hide carets and text selection dialog during scrolling. +pref("layout.accessiblecaret.always_show_when_scrolling", false); + +// Enable sync with Firefox Accounts. +pref("services.sync.fxaccounts.enabled", true); +pref("identity.fxaccounts.enabled", true); + +pref("identity.fxaccounts.remote.oauth.uri", "https://oauth.accounts.firefox.com/v1"); +pref("identity.fxaccounts.remote.profile.uri", "https://profile.accounts.firefox.com/v1"); + +// Disable Firefox Accounts device registration until bug 1238895 is fixed. +pref("identity.fxaccounts.skipDeviceRegistration", true); + +// Enable mapped array buffer. +pref("dom.mapped_arraybuffer.enabled", true); + +// SystemUpdate API +pref("dom.system_update.enabled", true); + +// UDPSocket API +pref("dom.udpsocket.enabled", true); + +// Enable TV Manager API +pref("dom.tv.enabled", true); + +// Enable Inputport Manager API +pref("dom.inputport.enabled", true); + +pref("dom.mozSettings.SettingsDB.debug.enabled", true); +pref("dom.mozSettings.SettingsManager.debug.enabled", true); +pref("dom.mozSettings.SettingsRequestManager.debug.enabled", true); +pref("dom.mozSettings.SettingsService.debug.enabled", true); + +pref("dom.mozSettings.SettingsDB.verbose.enabled", false); +pref("dom.mozSettings.SettingsManager.verbose.enabled", false); +pref("dom.mozSettings.SettingsRequestManager.verbose.enabled", false); +pref("dom.mozSettings.SettingsService.verbose.enabled", false); + +// Controlling whether we want to allow forcing some Settings +// IndexedDB transactions to be opened as readonly or keep everything as +// readwrite. +pref("dom.mozSettings.allowForceReadOnly", false); + +// Comma separated list of activity names that can only be provided by +// the system app in dev mode. +pref("dom.activities.developer_mode_only", "import-app"); + +// mulet apparently loads firefox.js as well as b2g.js, so we have to explicitly +// disable serviceworkers and push here to get them disabled in mulet. +pref("dom.serviceWorkers.enabled", false); +pref("dom.push.enabled", false); + +#if defined(RELEASE_OR_BETA) +// Bug 1278848: Enable service worker notifications on release B2G once +// they're ready. +pref("dom.webnotifications.serviceworker.enabled", false); +#else +pref("dom.webnotifications.serviceworker.enabled", true); +#endif + +// Retain at most 10 processes' layers buffers +pref("layers.compositor-lru-size", 10); + +// In B2G by deafult any AudioChannelAgent is muted when created. +pref("dom.audiochannel.mutedByDefault", true); + +// Default device name for Presentation API +pref("dom.presentation.device.name", "Firefox OS"); + +// Enable notification of performance timing +pref("dom.performance.enable_notify_performance_timing", true); + +// Multi-screen +pref("b2g.multiscreen.chrome_remote_url", "chrome://b2g/content/shell_remote.html"); +pref("b2g.multiscreen.system_remote_url", "index_remote.html"); + +// Audio competing between tabs +pref("dom.audiochannel.audioCompeting", false); + +// Because we can't have nice things. +#ifdef MOZ_GRAPHENE +#include ../graphene/graphene.js +#endif diff --git a/b2g/app/macbuild/Contents/Info.plist.in b/b2g/app/macbuild/Contents/Info.plist.in new file mode 100644 index 000000000..d5ea85f4d --- /dev/null +++ b/b2g/app/macbuild/Contents/Info.plist.in @@ -0,0 +1,67 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + %APP_BINARY% + CFBundleGetInfoString + %APP_NAME% %APP_VERSION% + CFBundleIconFile + %MOZ_APP_NAME%.icns + CFBundleIdentifier + org.mozilla.b2g + CFBundleInfoDictionaryVersion + %MOZ_APP_VERSION% + CFBundleName + %APP_NAME% + CFBundlePackageType + APPL + CFBundleShortVersionString + %APP_VERSION% + CFBundleSignature + MOZB + CFBundleVersion + %APP_VERSION% + NSAppleScriptEnabled + + CGDisableCoalescedUpdates + + NSHighResolutionCapable + + NSPrincipalClass + GeckoNSApplication + CFBundleURLTypes + + + CFBundleURLIconFile + document.icns + CFBundleURLName + http URL + CFBundleURLSchemes + + http + + + + CFBundleURLIconFile + document.icns + CFBundleURLName + https URL + CFBundleURLSchemes + + https + + + + CFBundleURLName + ftp URL + CFBundleURLSchemes + + ftp + + + + + diff --git a/b2g/app/macbuild/Contents/MacOS-files.in b/b2g/app/macbuild/Contents/MacOS-files.in new file mode 100644 index 000000000..4cefd2ff9 --- /dev/null +++ b/b2g/app/macbuild/Contents/MacOS-files.in @@ -0,0 +1,9 @@ +/*.app/*** +/*.dylib +/b2g +/certutil +/gtest/*** +/pk12util +/ssltunnel +/xpcshell +/XUL diff --git a/b2g/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in b/b2g/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in new file mode 100644 index 000000000..ddd3e0afa --- /dev/null +++ b/b2g/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +CFBundleName = "%APP_NAME%"; diff --git a/b2g/app/moz.build b/b2g/app/moz.build new file mode 100644 index 000000000..b28889065 --- /dev/null +++ b/b2g/app/moz.build @@ -0,0 +1,76 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if CONFIG['GAIADIR']: + GeckoProgram(CONFIG['MOZ_APP_NAME'] + "-bin") +else: + GeckoProgram(CONFIG['MOZ_APP_NAME']) + +SOURCES += [ + 'nsBrowserApp.cpp', +] +if CONFIG['_MSC_VER']: + # Always enter a Windows program through wmain, whether or not we're + # a console application. + WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup'] + +USE_LIBS += [ + 'zlib', +] + +for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION', 'MOZ_UPDATER'): + DEFINES[var] = CONFIG[var] + +LOCAL_INCLUDES += [ + '!/build', + '/toolkit/xre', + '/xpcom/base', + '/xpcom/build', +] + +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': + LOCAL_INCLUDES += [ + '/widget/gonk/libdisplay', + ] + + LDFLAGS += ['-Wl,--export-dynamic'] + + USE_LIBS += [ + 'display', + 'mozpng', + ] + OS_LIBS += [ + 'ui', + 'EGL', + 'hardware_legacy', + 'hardware', + 'cutils', + ] + OS_LIBS += CONFIG['MOZ_ZLIB_LIBS'] + if CONFIG['ANDROID_VERSION'] in ('17', '18', '19', '21', '22'): + OS_LIBS += [ + 'gui', + 'suspend', + ] + OS_LIBS += [ + 'binder', + 'utils', + ] + +DISABLE_STL_WRAPPING = True + +if CONFIG['OS_ARCH'] == 'WINNT': + OS_LIBS += [ + 'version', + ] + +JS_PREFERENCE_PP_FILES += [ + 'b2g.js', +] + +FINAL_TARGET_PP_FILES += [ + 'ua-update.json.in', +] diff --git a/b2g/app/nsBrowserApp.cpp b/b2g/app/nsBrowserApp.cpp new file mode 100644 index 000000000..967b54b76 --- /dev/null +++ b/b2g/app/nsBrowserApp.cpp @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsXULAppAPI.h" +#include "application.ini.h" +#include "nsXPCOMGlue.h" +#if defined(XP_WIN) +#include +#include +#elif defined(XP_UNIX) +#include +#include +#include +#endif + +#include +#include +#include + +#include "nsCOMPtr.h" +#include "nsIFile.h" +#include "nsStringGlue.h" + +#ifdef XP_WIN +// we want a wmain entry point +#include "nsWindowsWMain.cpp" +#define strcasecmp _stricmp +#endif + +#ifdef MOZ_WIDGET_GONK +#include "BootAnimation.h" +#endif + +#include "BinaryPath.h" + +#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL + +#ifdef MOZ_WIDGET_GONK +# include +#endif + +#include "mozilla/Sprintf.h" +#include "mozilla/Telemetry.h" +#include "mozilla/WindowsDllBlocklist.h" + +static void Output(const char *fmt, ... ) +{ + va_list ap; + va_start(ap, fmt); + +#if defined(XP_WIN) && !MOZ_WINCONSOLE + wchar_t msg[2048]; + _vsnwprintf(msg, sizeof(msg)/sizeof(msg[0]), NS_ConvertUTF8toUTF16(fmt).get(), ap); + MessageBoxW(nullptr, msg, L"XULRunner", MB_OK | MB_ICONERROR); +#else + vfprintf(stderr, fmt, ap); +#endif + + va_end(ap); +} + +/** + * Return true if |arg| matches the given argument name. + */ +static bool IsArg(const char* arg, const char* s) +{ + if (*arg == '-') + { + if (*++arg == '-') + ++arg; + return !strcasecmp(arg, s); + } + +#if defined(XP_WIN) + if (*arg == '/') + return !strcasecmp(++arg, s); +#endif + + return false; +} + +XRE_GetFileFromPathType XRE_GetFileFromPath; +XRE_CreateAppDataType XRE_CreateAppData; +XRE_FreeAppDataType XRE_FreeAppData; +XRE_TelemetryAccumulateType XRE_TelemetryAccumulate; +XRE_mainType XRE_main; + +static const nsDynamicFunctionLoad kXULFuncs[] = { + { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, + { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, + { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, + { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate }, + { "XRE_main", (NSFuncPtr*) &XRE_main }, + { nullptr, nullptr } +}; + +static int do_main(int argc, char* argv[]) +{ + nsCOMPtr appini; + nsresult rv; + + // Allow firefox.exe to launch XULRunner apps via -app + // Note that -app must be the *first* argument. + const char *appDataFile = getenv("XUL_APP_FILE"); + if (appDataFile && *appDataFile) { + rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini)); + if (NS_FAILED(rv)) { + Output("Invalid path found: '%s'", appDataFile); + return 255; + } + } + else if (argc > 1 && IsArg(argv[1], "app")) { + if (argc == 2) { + Output("Incorrect number of arguments passed to -app"); + return 255; + } + + rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini)); + if (NS_FAILED(rv)) { + Output("application.ini path not recognized: '%s'", argv[2]); + return 255; + } + + char appEnv[MAXPATHLEN]; + SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]); + if (putenv(strdup(appEnv))) { + Output("Couldn't set %s.\n", appEnv); + return 255; + } + argv[2] = argv[0]; + argv += 2; + argc -= 2; + } + +#ifdef MOZ_WIDGET_GONK + /* Start boot animation */ + mozilla::StartBootAnimation(); +#endif + + if (appini) { + nsXREAppData *appData; + rv = XRE_CreateAppData(appini, &appData); + if (NS_FAILED(rv)) { + Output("Couldn't read application.ini"); + return 255; + } + int result = XRE_main(argc, argv, appData, 0); + XRE_FreeAppData(appData); + return result; + } + + return XRE_main(argc, argv, &sAppData, 0); +} + +int main(int argc, char* argv[]) +{ + char exePath[MAXPATHLEN]; + +#ifdef MOZ_WIDGET_GONK + // This creates a ThreadPool for binder ipc. A ThreadPool is necessary to + // receive binder calls, though not necessary to send binder calls. + // ProcessState::Self() also needs to be called once on the main thread to + // register the main thread with the binder driver. + android::ProcessState::self()->startThreadPool(); +#endif + + nsresult rv; + rv = mozilla::BinaryPath::Get(argv[0], exePath); + if (NS_FAILED(rv)) { + Output("Couldn't calculate the application directory.\n"); + return 255; + } + + char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); + if (!lastSlash || ((lastSlash - exePath) + sizeof(XPCOM_DLL) + 1 > MAXPATHLEN)) + return 255; + + strcpy(++lastSlash, XPCOM_DLL); + +#if defined(XP_UNIX) + // If the b2g app is launched from adb shell, then the shell will wind + // up being the process group controller. This means that we can't send + // signals to the process group (useful for profiling). + // We ignore the return value since setsid() fails if we're already the + // process group controller (the normal situation). + (void)setsid(); +#endif + +#ifdef HAS_DLL_BLOCKLIST + DllBlocklist_Initialize(); +#endif + + // We do this because of data in bug 771745 + XPCOMGlueEnablePreload(); + + rv = XPCOMGlueStartup(exePath); + if (NS_FAILED(rv)) { + Output("Couldn't load XPCOM.\n"); + return 255; + } + // Reset exePath so that it is the directory name and not the xpcom dll name + *lastSlash = 0; + + rv = XPCOMGlueLoadXULFunctions(kXULFuncs); + if (NS_FAILED(rv)) { + Output("Couldn't load XRE functions.\n"); + return 255; + } + + int result; + { + ScopedLogging log; + char **_argv; + + /* + * Duplicate argument vector to conform non-const argv of + * do_main() since XRE_main() is very stupid with non-const argv. + */ + _argv = new char *[argc + 1]; + for (int i = 0; i < argc; i++) { + size_t len = strlen(argv[i]) + 1; + _argv[i] = new char[len]; + MOZ_ASSERT(_argv[i] != nullptr); + memcpy(_argv[i], argv[i], len); + } + _argv[argc] = nullptr; + + result = do_main(argc, _argv); + + for (int i = 0; i < argc; i++) { + delete[] _argv[i]; + } + delete[] _argv; + } + + return result; +} diff --git a/b2g/app/ua-update.json.in b/b2g/app/ua-update.json.in new file mode 100644 index 000000000..cb4c66d12 --- /dev/null +++ b/b2g/app/ua-update.json.in @@ -0,0 +1,51 @@ +#filter slashslash +// Everything after the first // on a line will be removed by the preproccesor. +// Send these sites a custom user-agent. Bugs should be included with an entry. +{ + // bug 826347, msn.com + "msn.com": "\\(Mobile#(Android 4.4.4; Mobile", + // bug 826353, itau.com.br + "itau.com.br": "\\(Mobile#(Android; Mobile", + // bug 826510, r7.com + "r7.com": "\\(Mobile#(Android; Mobile", + // bug 827622, bing.com + "bing.com": "\\(Mobile#(Android; Mobile", + // bug 827626, magazineluiza.com.br + "magazineluiza.com.br": "\\(Mobile#(Android; Mobile", + // bug 827670, elpais.com.co + "elpais.com.co": "\\(Mobile#(Android 4.4.4; Mobile", + // bug 828416, loteriasyapuestas.es + "loteriasyapuestas.es": "\\(Mobile#(Android; Mobile", + // bug 828418, bbva.es + "bbva.es": "\\(Mobile#(Android; Mobile", + // bug 828439, movistar.com.ve + "movistar.com.ve": "\\(Mobile#(Android; Mobile", + // bug 843132, comunio.es + "comunio.es": "\\(Mobile#(Android; Mobile", + // bug 843151, citibank.com + "citibank.com": "\\(Mobile#(Android; Mobile", + // bug 843153, games.com + "games.com": "\\(Mobile#(Android; Mobile", + // bug 843160, ehow.com + "ehow.com": "\\(Mobile#(Android; Mobile", + // bug 878228, blikk.hu + "blikk.hu": "\\(Mobile#(Android; Mobile", + // bug 878238, koponyeg.hu + "koponyeg.hu": "\\(Mobile#(Android; Mobile", + // bug 878240, kuruc.info + "kuruc.info": "\\(Mobile#(Android; Mobile", + // bug 878242, nemzetisport.hu + "nemzetisport.hu": "\\(Mobile#(Android; Mobile", + // bug 878246, port.hu + "port.hu": "\\(Mobile#(Android; Mobile", + // bug 878249, portfolio.hu + "portfolio.hu": "\\(Mobile#(Android; Mobile", + // bug 878260, cdm.me + "cdm.me": "\\(Mobile#(Android; Mobile", + // bug 878262, download.com + "download.com": "\\(Mobile#(Android; Mobile", + // bug 878273, livescore.com + "livescore.com": "\\(Mobile#(Android; Mobile", + // bug 878653, redstarbelgrade.info + "redstarbelgrade.info": "\\(Mobile#(Android; Mobile" +} diff --git a/b2g/branding/branding-common.mozbuild b/b2g/branding/branding-common.mozbuild new file mode 100644 index 000000000..ae4aeb285 --- /dev/null +++ b/b2g/branding/branding-common.mozbuild @@ -0,0 +1,23 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@template +def B2GBranding(): + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': + BRANDING_FILES += [ + 'app.ico', + ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + BRANDING_FILES += [ + 'app.icns', + 'background.png', + 'disk.icns', + 'dsstore', + ] + elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: + BRANDING_FILES += [ + 'default.png', + ] diff --git a/b2g/branding/browserhtml/app.icns b/b2g/branding/browserhtml/app.icns new file mode 100644 index 000000000..3d680134e Binary files /dev/null and b/b2g/branding/browserhtml/app.icns differ diff --git a/b2g/branding/browserhtml/app.ico b/b2g/branding/browserhtml/app.ico new file mode 100644 index 000000000..04596e4d0 Binary files /dev/null and b/b2g/branding/browserhtml/app.ico differ diff --git a/b2g/branding/browserhtml/background.png b/b2g/branding/browserhtml/background.png new file mode 100644 index 000000000..db5576a33 Binary files /dev/null and b/b2g/branding/browserhtml/background.png differ diff --git a/b2g/branding/browserhtml/configure.sh b/b2g/branding/browserhtml/configure.sh new file mode 100644 index 000000000..71c6129d2 --- /dev/null +++ b/b2g/branding/browserhtml/configure.sh @@ -0,0 +1,5 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +MOZ_APP_DISPLAYNAME=Browser.html diff --git a/b2g/branding/browserhtml/content/about.png b/b2g/branding/browserhtml/content/about.png new file mode 100644 index 000000000..3cc1444f6 Binary files /dev/null and b/b2g/branding/browserhtml/content/about.png differ diff --git a/b2g/branding/browserhtml/content/favicon32.png b/b2g/branding/browserhtml/content/favicon32.png new file mode 100644 index 000000000..ac4a6968b Binary files /dev/null and b/b2g/branding/browserhtml/content/favicon32.png differ diff --git a/b2g/branding/browserhtml/content/icon48.png b/b2g/branding/browserhtml/content/icon48.png new file mode 100644 index 000000000..b7513c2e4 Binary files /dev/null and b/b2g/branding/browserhtml/content/icon48.png differ diff --git a/b2g/branding/browserhtml/content/icon64.png b/b2g/branding/browserhtml/content/icon64.png new file mode 100644 index 000000000..c8bee8fca Binary files /dev/null and b/b2g/branding/browserhtml/content/icon64.png differ diff --git a/b2g/branding/browserhtml/content/jar.mn b/b2g/branding/browserhtml/content/jar.mn new file mode 100644 index 000000000..8a2c16964 --- /dev/null +++ b/b2g/branding/browserhtml/content/jar.mn @@ -0,0 +1,10 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +chrome.jar: +% content branding %content/branding/ contentaccessible=yes + content/branding/about.png (about.png) + content/branding/logoWordmark.png (logoWordmark.png) + content/branding/logo.png (logo.png) + content/branding/favicon32.png (favicon32.png) diff --git a/b2g/branding/browserhtml/content/logo.png b/b2g/branding/browserhtml/content/logo.png new file mode 100644 index 000000000..9d9d0c57e Binary files /dev/null and b/b2g/branding/browserhtml/content/logo.png differ diff --git a/b2g/branding/browserhtml/content/logoWordmark.png b/b2g/branding/browserhtml/content/logoWordmark.png new file mode 100644 index 000000000..878363181 Binary files /dev/null and b/b2g/branding/browserhtml/content/logoWordmark.png differ diff --git a/b2g/branding/browserhtml/content/moz.build b/b2g/branding/browserhtml/content/moz.build new file mode 100644 index 000000000..eb4454d28 --- /dev/null +++ b/b2g/branding/browserhtml/content/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/browserhtml/content/splash.png b/b2g/branding/browserhtml/content/splash.png new file mode 100644 index 000000000..84ab581d2 Binary files /dev/null and b/b2g/branding/browserhtml/content/splash.png differ diff --git a/b2g/branding/browserhtml/default.png b/b2g/branding/browserhtml/default.png new file mode 100644 index 000000000..ae4736223 Binary files /dev/null and b/b2g/branding/browserhtml/default.png differ diff --git a/b2g/branding/browserhtml/disk.icns b/b2g/branding/browserhtml/disk.icns new file mode 100644 index 000000000..c49b7b878 Binary files /dev/null and b/b2g/branding/browserhtml/disk.icns differ diff --git a/b2g/branding/browserhtml/dsstore b/b2g/branding/browserhtml/dsstore new file mode 100644 index 000000000..657101d6e Binary files /dev/null and b/b2g/branding/browserhtml/dsstore differ diff --git a/b2g/branding/browserhtml/locales/en-US/brand.dtd b/b2g/branding/browserhtml/locales/en-US/brand.dtd new file mode 100644 index 000000000..6c3088d70 --- /dev/null +++ b/b2g/branding/browserhtml/locales/en-US/brand.dtd @@ -0,0 +1,7 @@ + + + + + diff --git a/b2g/branding/browserhtml/locales/en-US/brand.properties b/b2g/branding/browserhtml/locales/en-US/brand.properties new file mode 100644 index 000000000..897d1a800 --- /dev/null +++ b/b2g/branding/browserhtml/locales/en-US/brand.properties @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +brandShortName=Browser.html +brandFullName=Mozilla Browser.html diff --git a/b2g/branding/browserhtml/locales/jar.mn b/b2g/branding/browserhtml/locales/jar.mn new file mode 100644 index 000000000..2ea47e168 --- /dev/null +++ b/b2g/branding/browserhtml/locales/jar.mn @@ -0,0 +1,11 @@ +#filter substitution +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +@AB_CD@.jar: +% locale branding @AB_CD@ %locale/branding/ +# Branding only exists in en-US + locale/branding/brand.dtd (en-US/brand.dtd) + locale/branding/brand.properties (en-US/brand.properties) diff --git a/b2g/branding/browserhtml/locales/moz.build b/b2g/branding/browserhtml/locales/moz.build new file mode 100644 index 000000000..eb4454d28 --- /dev/null +++ b/b2g/branding/browserhtml/locales/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/browserhtml/moz.build b/b2g/branding/browserhtml/moz.build new file mode 100644 index 000000000..bf7aff4c0 --- /dev/null +++ b/b2g/branding/browserhtml/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['content', 'locales'] + +include('../branding-common.mozbuild') +B2GBranding() diff --git a/b2g/branding/horizon/app.icns b/b2g/branding/horizon/app.icns new file mode 100644 index 000000000..6c7b9f5b5 Binary files /dev/null and b/b2g/branding/horizon/app.icns differ diff --git a/b2g/branding/horizon/app.ico b/b2g/branding/horizon/app.ico new file mode 100644 index 000000000..49eb90419 Binary files /dev/null and b/b2g/branding/horizon/app.ico differ diff --git a/b2g/branding/horizon/background.png b/b2g/branding/horizon/background.png new file mode 100644 index 000000000..db5576a33 Binary files /dev/null and b/b2g/branding/horizon/background.png differ diff --git a/b2g/branding/horizon/configure.sh b/b2g/branding/horizon/configure.sh new file mode 100644 index 000000000..65774e384 --- /dev/null +++ b/b2g/branding/horizon/configure.sh @@ -0,0 +1,5 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +MOZ_APP_DISPLAYNAME=Horizon diff --git a/b2g/branding/horizon/content/about.png b/b2g/branding/horizon/content/about.png new file mode 100644 index 000000000..3cc1444f6 Binary files /dev/null and b/b2g/branding/horizon/content/about.png differ diff --git a/b2g/branding/horizon/content/favicon32.png b/b2g/branding/horizon/content/favicon32.png new file mode 100644 index 000000000..ac4a6968b Binary files /dev/null and b/b2g/branding/horizon/content/favicon32.png differ diff --git a/b2g/branding/horizon/content/icon48.png b/b2g/branding/horizon/content/icon48.png new file mode 100644 index 000000000..b7513c2e4 Binary files /dev/null and b/b2g/branding/horizon/content/icon48.png differ diff --git a/b2g/branding/horizon/content/icon64.png b/b2g/branding/horizon/content/icon64.png new file mode 100644 index 000000000..c8bee8fca Binary files /dev/null and b/b2g/branding/horizon/content/icon64.png differ diff --git a/b2g/branding/horizon/content/jar.mn b/b2g/branding/horizon/content/jar.mn new file mode 100644 index 000000000..8a2c16964 --- /dev/null +++ b/b2g/branding/horizon/content/jar.mn @@ -0,0 +1,10 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +chrome.jar: +% content branding %content/branding/ contentaccessible=yes + content/branding/about.png (about.png) + content/branding/logoWordmark.png (logoWordmark.png) + content/branding/logo.png (logo.png) + content/branding/favicon32.png (favicon32.png) diff --git a/b2g/branding/horizon/content/logo.png b/b2g/branding/horizon/content/logo.png new file mode 100644 index 000000000..9d9d0c57e Binary files /dev/null and b/b2g/branding/horizon/content/logo.png differ diff --git a/b2g/branding/horizon/content/logoWordmark.png b/b2g/branding/horizon/content/logoWordmark.png new file mode 100644 index 000000000..878363181 Binary files /dev/null and b/b2g/branding/horizon/content/logoWordmark.png differ diff --git a/b2g/branding/horizon/content/moz.build b/b2g/branding/horizon/content/moz.build new file mode 100644 index 000000000..eb4454d28 --- /dev/null +++ b/b2g/branding/horizon/content/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/horizon/content/splash.png b/b2g/branding/horizon/content/splash.png new file mode 100644 index 000000000..84ab581d2 Binary files /dev/null and b/b2g/branding/horizon/content/splash.png differ diff --git a/b2g/branding/horizon/default.png b/b2g/branding/horizon/default.png new file mode 100644 index 000000000..0e6a4016c Binary files /dev/null and b/b2g/branding/horizon/default.png differ diff --git a/b2g/branding/horizon/disk.icns b/b2g/branding/horizon/disk.icns new file mode 100644 index 000000000..c49b7b878 Binary files /dev/null and b/b2g/branding/horizon/disk.icns differ diff --git a/b2g/branding/horizon/dsstore b/b2g/branding/horizon/dsstore new file mode 100644 index 000000000..657101d6e Binary files /dev/null and b/b2g/branding/horizon/dsstore differ diff --git a/b2g/branding/horizon/locales/en-US/brand.dtd b/b2g/branding/horizon/locales/en-US/brand.dtd new file mode 100644 index 000000000..ad7a938b5 --- /dev/null +++ b/b2g/branding/horizon/locales/en-US/brand.dtd @@ -0,0 +1,8 @@ + + + + + + diff --git a/b2g/branding/horizon/locales/en-US/brand.properties b/b2g/branding/horizon/locales/en-US/brand.properties new file mode 100644 index 000000000..ce9e209cf --- /dev/null +++ b/b2g/branding/horizon/locales/en-US/brand.properties @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +brandShortName=Horizon +brandFullName=Mozilla Horizon diff --git a/b2g/branding/horizon/locales/jar.mn b/b2g/branding/horizon/locales/jar.mn new file mode 100644 index 000000000..2ea47e168 --- /dev/null +++ b/b2g/branding/horizon/locales/jar.mn @@ -0,0 +1,11 @@ +#filter substitution +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +@AB_CD@.jar: +% locale branding @AB_CD@ %locale/branding/ +# Branding only exists in en-US + locale/branding/brand.dtd (en-US/brand.dtd) + locale/branding/brand.properties (en-US/brand.properties) diff --git a/b2g/branding/horizon/locales/moz.build b/b2g/branding/horizon/locales/moz.build new file mode 100644 index 000000000..eb4454d28 --- /dev/null +++ b/b2g/branding/horizon/locales/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/horizon/moz.build b/b2g/branding/horizon/moz.build new file mode 100644 index 000000000..bf7aff4c0 --- /dev/null +++ b/b2g/branding/horizon/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['content', 'locales'] + +include('../branding-common.mozbuild') +B2GBranding() diff --git a/b2g/branding/official/app.icns b/b2g/branding/official/app.icns new file mode 100644 index 000000000..eba850aae Binary files /dev/null and b/b2g/branding/official/app.icns differ diff --git a/b2g/branding/official/app.ico b/b2g/branding/official/app.ico new file mode 100644 index 000000000..5d4a61dc9 Binary files /dev/null and b/b2g/branding/official/app.ico differ diff --git a/b2g/branding/official/background.png b/b2g/branding/official/background.png new file mode 100644 index 000000000..db5576a33 Binary files /dev/null and b/b2g/branding/official/background.png differ diff --git a/b2g/branding/official/configure.sh b/b2g/branding/official/configure.sh new file mode 100644 index 000000000..127a0f1a1 --- /dev/null +++ b/b2g/branding/official/configure.sh @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +MOZ_APP_DISPLAYNAME=B2G +MOZ_UPDATER= diff --git a/b2g/branding/official/content/about.png b/b2g/branding/official/content/about.png new file mode 100644 index 000000000..3cc1444f6 Binary files /dev/null and b/b2g/branding/official/content/about.png differ diff --git a/b2g/branding/official/content/favicon32.png b/b2g/branding/official/content/favicon32.png new file mode 100644 index 000000000..ac4a6968b Binary files /dev/null and b/b2g/branding/official/content/favicon32.png differ diff --git a/b2g/branding/official/content/icon48.png b/b2g/branding/official/content/icon48.png new file mode 100644 index 000000000..b7513c2e4 Binary files /dev/null and b/b2g/branding/official/content/icon48.png differ diff --git a/b2g/branding/official/content/icon64.png b/b2g/branding/official/content/icon64.png new file mode 100644 index 000000000..c8bee8fca Binary files /dev/null and b/b2g/branding/official/content/icon64.png differ diff --git a/b2g/branding/official/content/jar.mn b/b2g/branding/official/content/jar.mn new file mode 100644 index 000000000..8a2c16964 --- /dev/null +++ b/b2g/branding/official/content/jar.mn @@ -0,0 +1,10 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +chrome.jar: +% content branding %content/branding/ contentaccessible=yes + content/branding/about.png (about.png) + content/branding/logoWordmark.png (logoWordmark.png) + content/branding/logo.png (logo.png) + content/branding/favicon32.png (favicon32.png) diff --git a/b2g/branding/official/content/logo.png b/b2g/branding/official/content/logo.png new file mode 100644 index 000000000..9d9d0c57e Binary files /dev/null and b/b2g/branding/official/content/logo.png differ diff --git a/b2g/branding/official/content/logoWordmark.png b/b2g/branding/official/content/logoWordmark.png new file mode 100644 index 000000000..878363181 Binary files /dev/null and b/b2g/branding/official/content/logoWordmark.png differ diff --git a/b2g/branding/official/content/moz.build b/b2g/branding/official/content/moz.build new file mode 100644 index 000000000..eb4454d28 --- /dev/null +++ b/b2g/branding/official/content/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/official/content/splash.png b/b2g/branding/official/content/splash.png new file mode 100644 index 000000000..84ab581d2 Binary files /dev/null and b/b2g/branding/official/content/splash.png differ diff --git a/b2g/branding/official/default.png b/b2g/branding/official/default.png new file mode 100644 index 000000000..c4307fc84 Binary files /dev/null and b/b2g/branding/official/default.png differ diff --git a/b2g/branding/official/disk.icns b/b2g/branding/official/disk.icns new file mode 100644 index 000000000..c49b7b878 Binary files /dev/null and b/b2g/branding/official/disk.icns differ diff --git a/b2g/branding/official/dsstore b/b2g/branding/official/dsstore new file mode 100644 index 000000000..657101d6e Binary files /dev/null and b/b2g/branding/official/dsstore differ diff --git a/b2g/branding/official/locales/en-US/brand.dtd b/b2g/branding/official/locales/en-US/brand.dtd new file mode 100644 index 000000000..1a6f39148 --- /dev/null +++ b/b2g/branding/official/locales/en-US/brand.dtd @@ -0,0 +1,8 @@ + + + + + + diff --git a/b2g/branding/official/locales/en-US/brand.properties b/b2g/branding/official/locales/en-US/brand.properties new file mode 100644 index 000000000..d0203e35a --- /dev/null +++ b/b2g/branding/official/locales/en-US/brand.properties @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +brandShortName=Firefox +brandFullName=Mozilla Firefox diff --git a/b2g/branding/official/locales/jar.mn b/b2g/branding/official/locales/jar.mn new file mode 100644 index 000000000..2ea47e168 --- /dev/null +++ b/b2g/branding/official/locales/jar.mn @@ -0,0 +1,11 @@ +#filter substitution +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +@AB_CD@.jar: +% locale branding @AB_CD@ %locale/branding/ +# Branding only exists in en-US + locale/branding/brand.dtd (en-US/brand.dtd) + locale/branding/brand.properties (en-US/brand.properties) diff --git a/b2g/branding/official/locales/moz.build b/b2g/branding/official/locales/moz.build new file mode 100644 index 000000000..eb4454d28 --- /dev/null +++ b/b2g/branding/official/locales/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/official/moz.build b/b2g/branding/official/moz.build new file mode 100644 index 000000000..bf7aff4c0 --- /dev/null +++ b/b2g/branding/official/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['content', 'locales'] + +include('../branding-common.mozbuild') +B2GBranding() diff --git a/b2g/branding/unofficial/app.icns b/b2g/branding/unofficial/app.icns new file mode 100644 index 000000000..eba850aae Binary files /dev/null and b/b2g/branding/unofficial/app.icns differ diff --git a/b2g/branding/unofficial/app.ico b/b2g/branding/unofficial/app.ico new file mode 100644 index 000000000..5d4a61dc9 Binary files /dev/null and b/b2g/branding/unofficial/app.ico differ diff --git a/b2g/branding/unofficial/background.png b/b2g/branding/unofficial/background.png new file mode 100644 index 000000000..db5576a33 Binary files /dev/null and b/b2g/branding/unofficial/background.png differ diff --git a/b2g/branding/unofficial/configure.sh b/b2g/branding/unofficial/configure.sh new file mode 100644 index 000000000..127a0f1a1 --- /dev/null +++ b/b2g/branding/unofficial/configure.sh @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +MOZ_APP_DISPLAYNAME=B2G +MOZ_UPDATER= diff --git a/b2g/branding/unofficial/content/about.png b/b2g/branding/unofficial/content/about.png new file mode 100644 index 000000000..3819f6337 Binary files /dev/null and b/b2g/branding/unofficial/content/about.png differ diff --git a/b2g/branding/unofficial/content/favicon32.png b/b2g/branding/unofficial/content/favicon32.png new file mode 100644 index 000000000..3f04acd50 Binary files /dev/null and b/b2g/branding/unofficial/content/favicon32.png differ diff --git a/b2g/branding/unofficial/content/icon48.png b/b2g/branding/unofficial/content/icon48.png new file mode 100644 index 000000000..3ae248c85 Binary files /dev/null and b/b2g/branding/unofficial/content/icon48.png differ diff --git a/b2g/branding/unofficial/content/icon64.png b/b2g/branding/unofficial/content/icon64.png new file mode 100644 index 000000000..fe980153b Binary files /dev/null and b/b2g/branding/unofficial/content/icon64.png differ diff --git a/b2g/branding/unofficial/content/jar.mn b/b2g/branding/unofficial/content/jar.mn new file mode 100644 index 000000000..8a2c16964 --- /dev/null +++ b/b2g/branding/unofficial/content/jar.mn @@ -0,0 +1,10 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +chrome.jar: +% content branding %content/branding/ contentaccessible=yes + content/branding/about.png (about.png) + content/branding/logoWordmark.png (logoWordmark.png) + content/branding/logo.png (logo.png) + content/branding/favicon32.png (favicon32.png) diff --git a/b2g/branding/unofficial/content/logo.png b/b2g/branding/unofficial/content/logo.png new file mode 100644 index 000000000..91377a312 Binary files /dev/null and b/b2g/branding/unofficial/content/logo.png differ diff --git a/b2g/branding/unofficial/content/logoWordmark.png b/b2g/branding/unofficial/content/logoWordmark.png new file mode 100644 index 000000000..a3017f59e Binary files /dev/null and b/b2g/branding/unofficial/content/logoWordmark.png differ diff --git a/b2g/branding/unofficial/content/moz.build b/b2g/branding/unofficial/content/moz.build new file mode 100644 index 000000000..eb4454d28 --- /dev/null +++ b/b2g/branding/unofficial/content/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/unofficial/content/splash.png b/b2g/branding/unofficial/content/splash.png new file mode 100644 index 000000000..25a0830ea Binary files /dev/null and b/b2g/branding/unofficial/content/splash.png differ diff --git a/b2g/branding/unofficial/default.png b/b2g/branding/unofficial/default.png new file mode 100644 index 000000000..c4307fc84 Binary files /dev/null and b/b2g/branding/unofficial/default.png differ diff --git a/b2g/branding/unofficial/disk.icns b/b2g/branding/unofficial/disk.icns new file mode 100644 index 000000000..c49b7b878 Binary files /dev/null and b/b2g/branding/unofficial/disk.icns differ diff --git a/b2g/branding/unofficial/dsstore b/b2g/branding/unofficial/dsstore new file mode 100644 index 000000000..657101d6e Binary files /dev/null and b/b2g/branding/unofficial/dsstore differ diff --git a/b2g/branding/unofficial/locales/en-US/brand.dtd b/b2g/branding/unofficial/locales/en-US/brand.dtd new file mode 100644 index 000000000..1a6f39148 --- /dev/null +++ b/b2g/branding/unofficial/locales/en-US/brand.dtd @@ -0,0 +1,8 @@ + + + + + + diff --git a/b2g/branding/unofficial/locales/en-US/brand.properties b/b2g/branding/unofficial/locales/en-US/brand.properties new file mode 100644 index 000000000..d0203e35a --- /dev/null +++ b/b2g/branding/unofficial/locales/en-US/brand.properties @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +brandShortName=Firefox +brandFullName=Mozilla Firefox diff --git a/b2g/branding/unofficial/locales/jar.mn b/b2g/branding/unofficial/locales/jar.mn new file mode 100644 index 000000000..5a77695c9 --- /dev/null +++ b/b2g/branding/unofficial/locales/jar.mn @@ -0,0 +1,11 @@ +#filter substitution +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +@AB_CD@.jar: +% locale branding @AB_CD@ %locale/branding/ +# Nightly branding only exists in en-US + locale/branding/brand.dtd (en-US/brand.dtd) + locale/branding/brand.properties (en-US/brand.properties) diff --git a/b2g/branding/unofficial/locales/moz.build b/b2g/branding/unofficial/locales/moz.build new file mode 100644 index 000000000..eb4454d28 --- /dev/null +++ b/b2g/branding/unofficial/locales/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/unofficial/moz.build b/b2g/branding/unofficial/moz.build new file mode 100644 index 000000000..bf7aff4c0 --- /dev/null +++ b/b2g/branding/unofficial/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['content', 'locales'] + +include('../branding-common.mozbuild') +B2GBranding() diff --git a/b2g/build.mk b/b2g/build.mk new file mode 100644 index 000000000..31e20b580 --- /dev/null +++ b/b2g/build.mk @@ -0,0 +1,31 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk + +installer: + @$(MAKE) -C b2g/installer installer + +package: + @$(MAKE) -C b2g/installer + +install:: + @echo 'B2G can't be installed directly.' + @exit 1 + +upload:: + @$(MAKE) -C b2g/installer upload + +ifdef ENABLE_TESTS +# Implemented in testing/testsuite-targets.mk + +mochitest-browser-chrome: + $(RUN_MOCHITEST) --flavor=browser + $(CHECK_TEST_ERROR) + +mochitest:: mochitest-browser-chrome + +.PHONY: mochitest-browser-chrome +endif + diff --git a/b2g/chrome/content/ErrorPage.js b/b2g/chrome/content/ErrorPage.js new file mode 100644 index 000000000..d51782466 --- /dev/null +++ b/b2g/chrome/content/ErrorPage.js @@ -0,0 +1,73 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +var Cu = Components.utils; +var Cc = Components.classes; +var Ci = Components.interfaces; + +dump("############ ErrorPage.js\n"); + +var ErrorPageHandler = { + _reload: function() { + docShell.QueryInterface(Ci.nsIWebNavigation).reload(Ci.nsIWebNavigation.LOAD_FLAGS_NONE); + }, + + _certErrorPageEventHandler: function(e) { + let target = e.originalTarget; + let errorDoc = target.ownerDocument; + + // If the event came from an ssl error page, it is one of the "Add + // Exception…" buttons. + if (/^about:certerror\?e=nssBadCert/.test(errorDoc.documentURI)) { + let permanent = errorDoc.getElementById("permanentExceptionButton"); + let temp = errorDoc.getElementById("temporaryExceptionButton"); + if (target == temp || target == permanent) { + sendAsyncMessage("ErrorPage:AddCertException", { + url: errorDoc.location.href, + isPermanent: target == permanent + }); + } + } + }, + + _bindPageEvent: function(target) { + if (!target) { + return; + } + + if (/^about:certerror/.test(target.documentURI)) { + let errorPageEventHandler = this._certErrorPageEventHandler.bind(this); + addEventListener("click", errorPageEventHandler, true, false); + let listener = function() { + removeEventListener("click", errorPageEventHandler, true); + removeEventListener("pagehide", listener, true); + }.bind(this); + + addEventListener("pagehide", listener, true); + } + }, + + domContentLoadedHandler: function(e) { + let target = e.originalTarget; + let targetDocShell = target.defaultView + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation); + if (targetDocShell != docShell) { + return; + } + this._bindPageEvent(target); + }, + + init: function() { + addMessageListener("ErrorPage:ReloadPage", this._reload.bind(this)); + addEventListener('DOMContentLoaded', + this.domContentLoadedHandler.bind(this), + true); + this._bindPageEvent(content.document); + } +}; + +ErrorPageHandler.init(); diff --git a/b2g/chrome/content/aboutCertError.xhtml b/b2g/chrome/content/aboutCertError.xhtml new file mode 100644 index 000000000..616657e54 --- /dev/null +++ b/b2g/chrome/content/aboutCertError.xhtml @@ -0,0 +1,233 @@ + + + + %htmlDTD; + + %globalDTD; + + %certerrorDTD; +]> + + + + + &certerror.pagetitle; + + + + + + + + + + + +
+

&certerror.longpagetitle;

+
+ + +
+ + +
+
+

&certerror.introPara1;

+
+ + +
+

&certerror.technical.heading;

+

+

+ +
+

&certerror.expert.heading;

+
+

&certerror.expert.content;

+

&certerror.expert.contentPara2;

+ + +
+
+
+
+ + + + + + diff --git a/b2g/chrome/content/arrow.svg b/b2g/chrome/content/arrow.svg new file mode 100644 index 000000000..d3d9e8246 --- /dev/null +++ b/b2g/chrome/content/arrow.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/b2g/chrome/content/blank.css b/b2g/chrome/content/blank.css new file mode 100644 index 000000000..71914be1f --- /dev/null +++ b/b2g/chrome/content/blank.css @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +body { + background: black; +} diff --git a/b2g/chrome/content/blank.html b/b2g/chrome/content/blank.html new file mode 100644 index 000000000..b8b20e2c6 --- /dev/null +++ b/b2g/chrome/content/blank.html @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/b2g/chrome/content/content.css b/b2g/chrome/content/content.css new file mode 100644 index 000000000..bb478087e --- /dev/null +++ b/b2g/chrome/content/content.css @@ -0,0 +1,321 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.w3.org/1999/xhtml"); +@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +/* Style the scrollbars */ +xul|window xul|scrollbar { + display: none; +} + +/* Bug 1041576 - Scrollable with scrollgrab should not have scrollbars */ + +@-moz-document domain(system.gaiamobile.org) { + .browser-container > xul|scrollbar { + display: none; + } +} + +%ifdef MOZ_GRAPHENE +.moz-noscrollbars > xul|scrollbar { + display: none; +} +%endif + +xul|scrollbar[root="true"] { + position: relative; + z-index: 2147483647; +} + +xul|scrollbar { + -moz-appearance: none !important; + background-color: transparent !important; + background-image: none !important; + border: 0px solid transparent !important; + pointer-events: none; +} + +/* Scrollbar code will reset the margin to the correct side depending on + where layout actually puts the scrollbar */ +xul|scrollbar[orient="vertical"] { + margin-left: -8px; + min-width: 8px; + max-width: 8px; +} + +xul|scrollbar[orient="vertical"] xul|thumb { + max-width: 6px !important; + min-width: 6px !important; +} + +xul|scrollbar[orient="horizontal"] { + margin-top: -8px; + min-height: 8px; + max-height: 8px; +} + +xul|scrollbar[orient="horizontal"] xul|thumb { + max-height: 6px !important; + min-height: 6px !important; +} + +xul|scrollbar:not([active="true"]), +xul|scrollbar[disabled] { + opacity: 0; +} + +xul|scrollbarbutton { + min-height: 8px !important; + min-width: 8px !important; + -moz-appearance: none !important; + visibility: hidden; +} + +xul|scrollbarbutton[sbattr="scrollbar-up-top"], +xul|scrollbarbutton[sbattr="scrollbar-bottom-top"] { + display: none; +} + +xul|thumb { + background-color: rgba(0, 0, 0, 0.4) !important; + -moz-border-top-colors: none !important; + -moz-border-bottom-colors: none !important; + -moz-border-right-colors: none !important; + -moz-border-left-colors: none !important; + border: 1px solid rgba(255, 255, 255, 0.4) !important; + border-radius: 3px; +} + +xul|scrollbarbutton { + background-image: none !important; +} + +%ifndef MOZ_GRAPHENE +/* -moz-touch-enabled? media elements */ +:-moz-any(video, audio) > xul|videocontrols { + -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#touchControlsGonk"); +} + +select:not([size]):not([multiple]) > xul|scrollbar, +select[size="1"] > xul|scrollbar, +select:not([size]):not([multiple]) xul|scrollbarbutton, +select[size="1"] xul|scrollbarbutton { + display: block; + margin-left: 0; + min-width: 16px; +} + +/* Override inverse OS themes */ +select, +textarea, +button, +xul|button, +* > input:not([type="image"]) { + -moz-appearance: none !important; /* See bug 598421 for fixing the platform */ + border-radius: 3px; +} + +select[size], +select[multiple], +select[size][multiple], +textarea, +* > input:not([type="image"]) { + border-style: solid; + border-color: #7d7d7d; + color: #414141; + background-color: white; +} + +/* Selects are handled by the form helper, see bug 685197 */ +select option, select optgroup { + pointer-events: none; +} + +select:not([size]):not([multiple]), +select[size="0"], +select[size="1"], +* > input[type="button"], +* > input[type="submit"], +* > input[type="reset"], +button { + border-style: solid; + border-color: #7d7d7d; + color: #414141; + background: white linear-gradient(rgba(255,255,255,0.2) 0, rgba(215,215,215,0.5) 18px, rgba(115,115,115,0.5) 100%); +} + +input[type="checkbox"] { + background-color: white; +} + +input[type="radio"] { + background-color: white; +} + +select { + border-width: 1px; + padding: 1px; +} + +select:not([size]):not([multiple]), +select[size="0"], +select[size="1"] { + padding: 0 1px 0 1px; +} + +* > input:not([type="image"]) { + border-width: 1px; + padding: 1px; +} + +textarea { + resize: none; + border-width: 1px; + padding-inline-start: 1px; + padding-inline-end: 1px; + padding-block-start: 2px; + padding-block-end: 2px; +} + +input[type="button"], +input[type="submit"], +input[type="reset"], +button { + border-width: 1px; + padding-inline-start: 7px; + padding-inline-end: 7px; + padding-block-start: 0; + padding-block-end: 0; +} + +input[type="radio"], +input[type="checkbox"] { + border: 1px solid #a7a7a7 !important; + padding-inline-start: 1px; + padding-inline-end: 1px; + padding-block-start: 2px; + padding-block-end: 2px; +} + +select > button { + border-width: 0px !important; + margin: 0px !important; + padding: 0px !important; + border-radius: 0; + color: #414141; + + background-image: radial-gradient(at bottom left, #bbbbbb 40%, #f5f5f5), url(arrow.svg) !important; + background-color: transparent; + background-position: -15px center, 4px center !important; + background-repeat: no-repeat, no-repeat !important; + background-size: 100% 90%, auto auto; + + -moz-binding: none !important; + position: relative !important; + font-size: inherit; +} + +select[size]:focus, +select[multiple]:focus, +select[size][multiple]:focus, +textarea:focus, +input[type="file"]:focus > input[type="text"], +* > input:not([type="image"]):focus { + outline: 0px !important; + border-style: solid; + border-color: rgb(94,128,153); + background-color: white; +} + +select:not([size]):not([multiple]):focus, +select[size="0"]:focus, +select[size="1"]:focus, +input[type="button"]:focus, +input[type="submit"]:focus, +input[type="reset"]:focus, +button:focus { + outline: 0px !important; + border-style: solid; + border-color: rgb(94,128,153); + background: white linear-gradient(rgba(255,255,255,0.2) 0, rgba(198,225,256,0.2) 18px, rgba(27,113,177,0.5) 100%); +} + +input[type="checkbox"]:focus, +input[type="radio"]:focus { + border-color: #99c6e0 !important; +} + +/* we need to be specific for selects because the above rules are specific too */ +textarea[disabled], +select[size][disabled], +select[multiple][disabled], +select[size][multiple][disabled], +select:not([size]):not([multiple])[disabled], +select[size="0"][disabled], +select[size="1"][disabled], +button[disabled], +* > input:not([type="image"])[disabled] { + color: rgba(0,0,0,0.3); + border-color: rgba(125,125,125,0.4); + border-style: solid; + border-width: 1px; + background-color: #f5f5f5; +} + +select:not([size]):not([multiple])[disabled], +select[size="0"][disabled], +select[size="1"][disabled] { + background-color: #f5f5f5; +} + +input[type="button"][disabled], +input[type="submit"][disabled], +input[type="reset"][disabled], +button[disabled] { + padding-inline-start: 7px; + padding-inline-end: 7px; + padding-block-start: 0; + padding-block-end: 0; + background-color: #f5f5f5; +} + +input[type="radio"][disabled], +input[type="radio"][disabled]:active, +input[type="radio"][disabled]:hover, +input[type="radio"][disabled]:hover:active, +input[type="checkbox"][disabled], +input[type="checkbox"][disabled]:active, +input[type="checkbox"][disabled]:hover, +input[type="checkbox"][disabled]:hover:active { + border:1px solid rgba(125,125,125,0.4) !important; +} + +select[disabled] > button { + opacity: 0.6; + padding: 1px 7px 1px 7px; +} + +*:any-link:active, +*[role=button]:active, +button:active, +option:active, +select:active, +label:active { + background-color: rgba(141, 184, 216, 0.5); +} + +input[type=number] > div > div, /* work around bug 946184 */ +input[type=number]::-moz-number-spin-box { + display: none; +} +%endif + +%ifdef MOZ_WIDGET_GONK +/* This binding only provide key shortcuts that we can't use on devices */ +input, +textarea { +-moz-binding: none !important; +} +%endif diff --git a/b2g/chrome/content/desktop.css b/b2g/chrome/content/desktop.css new file mode 100644 index 000000000..9612d732c --- /dev/null +++ b/b2g/chrome/content/desktop.css @@ -0,0 +1,59 @@ +#controls { + position: absolute; + left: 0; + bottom:0; + right: 0; + height: 30px; + background-color: -moz-dialog; +} + +#home-button { + margin: auto; + margin-top: 3px; + width: 24px; + height: 24px; + background: #eee url("images/desktop/home-black.png") center no-repeat; + border: 1px solid #888; + border-radius: 12px; + display: block; +} + +#home-button::-moz-focus-inner { + padding: 0; + border: 0; +} + +#home-button:hover { + background-image: url("images/desktop/home-white.png"); + background-color: #ccc; + border-color: #555; +} + +#home-button.active { + background-image: url("images/desktop/home-white.png"); + background-color: #888; + border-color: black; +} + +#rotate-button { + position: absolute; + top: 3px; + bottom: 3px; + right: 3px; + width: 24px; + height: 24px; + background: #eee url("images/desktop/rotate.png") center no-repeat; + border: 1px solid #888; + border-radius: 12px; + display: block; +} + +#rotate-button:hover { + background-color: #ccc; + border-color: #555; +} + +#rotate-button.active { + background-color: #888; + border-color: black; +} diff --git a/b2g/chrome/content/desktop.js b/b2g/chrome/content/desktop.js new file mode 100644 index 000000000..5a1e7ff04 --- /dev/null +++ b/b2g/chrome/content/desktop.js @@ -0,0 +1,179 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var browserWindow = Services.wm.getMostRecentWindow("navigator:browser"); +var isMulet = "ResponsiveUI" in browserWindow; + +// Enable touch event shim on desktop that translates mouse events +// into touch ones +function enableTouch() { + let require = Cu.import('resource://devtools/shared/Loader.jsm', {}) + .devtools.require; + let { TouchEventSimulator } = require('devtools/shared/touch/simulator'); + let touchEventSimulator = new TouchEventSimulator(shell.contentBrowser); + touchEventSimulator.start(); +} + +// Some additional buttons are displayed on simulators to fake hardware buttons. +function setupButtons() { + let link = document.createElement('link'); + link.type = 'text/css'; + link.rel = 'stylesheet'; + link.href = 'chrome://b2g/content/desktop.css'; + document.head.appendChild(link); + + let footer = document.createElement('footer'); + footer.id = 'controls'; + document.body.appendChild(footer); + let homeButton = document.createElement('button'); + homeButton.id = 'home-button'; + footer.appendChild(homeButton); + let rotateButton = document.createElement('button'); + rotateButton.id = 'rotate-button'; + footer.appendChild(rotateButton); + + homeButton.addEventListener('mousedown', function() { + let window = shell.contentBrowser.contentWindow; + let e = new window.KeyboardEvent('keydown', {key: 'Home'}); + window.dispatchEvent(e); + homeButton.classList.add('active'); + }); + homeButton.addEventListener('mouseup', function() { + let window = shell.contentBrowser.contentWindow; + let e = new window.KeyboardEvent('keyup', {key: 'Home'}); + window.dispatchEvent(e); + homeButton.classList.remove('active'); + }); + + Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm"); + rotateButton.addEventListener('mousedown', function() { + rotateButton.classList.add('active'); + }); + rotateButton.addEventListener('mouseup', function() { + GlobalSimulatorScreen.flipScreen(); + rotateButton.classList.remove('active'); + }); +} + +function setupStorage() { + let directory = null; + + // Get the --storage-path argument from the command line. + try { + let service = Cc['@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds'].getService(Ci.nsISupports); + let args = service.wrappedJSObject.cmdLine; + if (args) { + let path = args.handleFlagWithParam('storage-path', false); + directory = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile); + directory.initWithPath(path); + } + } catch(e) { + directory = null; + } + + // Otherwise, default to 'storage' folder within current profile. + if (!directory) { + directory = Services.dirsvc.get('ProfD', Ci.nsIFile); + directory.append('storage'); + if (!directory.exists()) { + directory.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("755", 8)); + } + } + dump("Set storage path to: " + directory.path + "\n"); + + // This is the magic, where we override the default location for the storages. + Services.prefs.setCharPref('device.storage.overrideRootDir', directory.path); +} + +function checkDebuggerPort() { + // XXX: To be removed once bug 942756 lands. + // We are hacking 'unix-domain-socket' pref by setting a tcp port (number). + // SocketListener.open detects that it isn't a file path (string), and starts + // listening on the tcp port given here as command line argument. + + // Get the command line arguments that were passed to the b2g client + let args; + try { + let service = Cc["@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds"].getService(Ci.nsISupports); + args = service.wrappedJSObject.cmdLine; + } catch(e) {} + + if (!args) { + return; + } + + let dbgport; + try { + dbgport = args.handleFlagWithParam('start-debugger-server', false); + } catch(e) {} + + if (dbgport) { + dump('Opening debugger server on ' + dbgport + '\n'); + Services.prefs.setCharPref('devtools.debugger.unix-domain-socket', dbgport); + navigator.mozSettings.createLock().set( + {'debugger.remote-mode': 'adb-devtools'}); + } +} + + +function initResponsiveDesign() { + Cu.import('resource://devtools/client/responsivedesign/responsivedesign.jsm'); + ResponsiveUIManager.on('on', function(event, {tab:tab}) { + let responsive = ResponsiveUIManager.getResponsiveUIForTab(tab); + let document = tab.ownerDocument; + + // Only tweak reponsive mode for shell.html tabs. + if (tab.linkedBrowser.contentWindow != window) { + return; + } + + // Disable transition as they mess up with screen size handler + responsive.transitionsEnabled = false; + + responsive.buildPhoneUI(); + + responsive.rotatebutton.addEventListener('command', function (evt) { + GlobalSimulatorScreen.flipScreen(); + evt.stopImmediatePropagation(); + evt.preventDefault(); + }, true); + + // Enable touch events + responsive.enableTouch(); + }); + + + let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager; + mgr.toggle(browserWindow, browserWindow.gBrowser.selectedTab); + +} + +function openDevtools() { + // Open devtool panel while maximizing its size according to screen size + Services.prefs.setIntPref('devtools.toolbox.sidebar.width', + browserWindow.outerWidth - 550); + Services.prefs.setCharPref('devtools.toolbox.host', 'side'); + let {gDevTools} = Cu.import('resource://devtools/client/framework/gDevTools.jsm', {}); + let {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {}); + let target = devtools.TargetFactory.forTab(browserWindow.gBrowser.selectedTab); + gDevTools.showToolbox(target); +} + +window.addEventListener('ContentStart', function() { + // On Firefox Mulet, touch events are enabled within the responsive mode + if (!isMulet) { + enableTouch(); + } + if (Services.prefs.getBoolPref('b2g.software-buttons')) { + setupButtons(); + } + checkDebuggerPort(); + setupStorage(); + // On Firefox mulet, we automagically enable the responsive mode + // and show the devtools + if (isMulet) { + initResponsiveDesign(browserWindow); + openDevtools(); + } +}); diff --git a/b2g/chrome/content/devtools/adb.js b/b2g/chrome/content/devtools/adb.js new file mode 100644 index 000000000..cebc6696b --- /dev/null +++ b/b2g/chrome/content/devtools/adb.js @@ -0,0 +1,233 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +// This file is only loaded on Gonk to manage ADB state + +Components.utils.import("resource://gre/modules/FileUtils.jsm"); + +const DEBUG = false; +var debug = function(str) { + dump("AdbController: " + str + "\n"); +} + +var AdbController = { + locked: undefined, + remoteDebuggerEnabled: undefined, + lockEnabled: undefined, + disableAdbTimer: null, + disableAdbTimeoutHours: 12, + umsActive: false, + + setLockscreenEnabled: function(value) { + this.lockEnabled = value; + DEBUG && debug("setLockscreenEnabled = " + this.lockEnabled); + this.updateState(); + }, + + setLockscreenState: function(value) { + this.locked = value; + DEBUG && debug("setLockscreenState = " + this.locked); + this.updateState(); + }, + + setRemoteDebuggerState: function(value) { + this.remoteDebuggerEnabled = value; + DEBUG && debug("setRemoteDebuggerState = " + this.remoteDebuggerEnabled); + this.updateState(); + }, + + startDisableAdbTimer: function() { + if (this.disableAdbTimer) { + this.disableAdbTimer.cancel(); + } else { + this.disableAdbTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + try { + this.disableAdbTimeoutHours = + Services.prefs.getIntPref("b2g.adb.timeout-hours"); + } catch (e) { + // This happens if the pref doesn't exist, in which case + // disableAdbTimeoutHours will still be set to the default. + } + } + if (this.disableAdbTimeoutHours <= 0) { + DEBUG && debug("Timer to disable ADB not started due to zero timeout"); + return; + } + + DEBUG && debug("Starting timer to disable ADB in " + + this.disableAdbTimeoutHours + " hours"); + let timeoutMilliseconds = this.disableAdbTimeoutHours * 60 * 60 * 1000; + this.disableAdbTimer.initWithCallback(this, timeoutMilliseconds, + Ci.nsITimer.TYPE_ONE_SHOT); + }, + + stopDisableAdbTimer: function() { + DEBUG && debug("Stopping timer to disable ADB"); + if (this.disableAdbTimer) { + this.disableAdbTimer.cancel(); + this.disableAdbTimer = null; + } + }, + + notify: function(aTimer) { + if (aTimer == this.disableAdbTimer) { + this.disableAdbTimer = null; + // The following dump will be the last thing that shows up in logcat, + // and will at least give the user a clue about why logcat was + // disconnected, if the user happens to be using logcat. + debug("ADB timer expired - disabling ADB\n"); + navigator.mozSettings.createLock().set( + {'debugger.remote-mode': 'disabled'}); + } + }, + + updateState: function() { + this.umsActive = false; + }, + + updateStateInternal: function() { + DEBUG && debug("updateStateInternal: called"); + + if (this.remoteDebuggerEnabled === undefined || + this.lockEnabled === undefined || + this.locked === undefined) { + // Part of initializing the settings database will cause the observers + // to trigger. We want to wait until both have been initialized before + // we start changing ther adb state. Without this then we can wind up + // toggling adb off and back on again (or on and back off again). + // + // For completeness, one scenario which toggles adb is using the unagi. + // The unagi has adb enabled by default (prior to b2g starting). If you + // have the phone lock disabled and remote debugging enabled, then we'll + // receive an unlock event and an rde event. However at the time we + // receive the unlock event we haven't yet received the rde event, so + // we turn adb off momentarily, which disconnects a logcat that might + // be running. Changing the defaults (in AdbController) just moves the + // problem to a different phone, which has adb disabled by default and + // we wind up turning on adb for a short period when we shouldn't. + // + // By waiting until both values are properly initialized, we avoid + // turning adb on or off accidentally. + DEBUG && debug("updateState: Waiting for all vars to be initialized"); + return; + } + + // Check if we have a remote debugging session going on. If so, we won't + // disable adb even if the screen is locked. + let isDebugging = USBRemoteDebugger.isDebugging; + DEBUG && debug("isDebugging=" + isDebugging); + + // If USB Mass Storage, USB tethering, or a debug session is active, + // then we don't want to disable adb in an automatic fashion (i.e. + // when the screen locks or due to timeout). + let sysUsbConfig = libcutils.property_get("sys.usb.config").split(","); + let usbFuncActive = this.umsActive || isDebugging; + usbFuncActive |= (sysUsbConfig.indexOf("rndis") >= 0); + usbFuncActive |= (sysUsbConfig.indexOf("mtp") >= 0); + + let enableAdb = this.remoteDebuggerEnabled && + (!(this.lockEnabled && this.locked) || usbFuncActive); + + let useDisableAdbTimer = true; + try { + if (Services.prefs.getBoolPref("marionette.defaultPrefs.enabled")) { + // Marionette is enabled. Marionette requires that adb be on (and also + // requires that remote debugging be off). The fact that marionette + // is enabled also implies that we're doing a non-production build, so + // we want adb enabled all of the time. + enableAdb = true; + useDisableAdbTimer = false; + } + } catch (e) { + // This means that the pref doesn't exist. Which is fine. We just leave + // enableAdb alone. + } + + // Check wakelock to prevent adb from disconnecting when phone is locked + let lockFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile); + lockFile.initWithPath('/sys/power/wake_lock'); + if(lockFile.exists()) { + let foStream = Cc["@mozilla.org/network/file-input-stream;1"] + .createInstance(Ci.nsIFileInputStream); + let coStream = Cc["@mozilla.org/intl/converter-input-stream;1"] + .createInstance(Ci.nsIConverterInputStream); + let str = {}; + foStream.init(lockFile, FileUtils.MODE_RDONLY, 0, 0); + coStream.init(foStream, "UTF-8", 0, 0); + coStream.readString(-1, str); + coStream.close(); + foStream.close(); + let wakeLockContents = str.value.replace(/\n/, ""); + let wakeLockList = wakeLockContents.split(" "); + if (wakeLockList.indexOf("adb") >= 0) { + enableAdb = true; + useDisableAdbTimer = false; + DEBUG && debug("Keeping ADB enabled as ADB wakelock is present."); + } else { + DEBUG && debug("ADB wakelock not found."); + } + } else { + DEBUG && debug("Wake_lock file not found."); + } + + DEBUG && debug("updateState: enableAdb = " + enableAdb + + " remoteDebuggerEnabled = " + this.remoteDebuggerEnabled + + " lockEnabled = " + this.lockEnabled + + " locked = " + this.locked + + " usbFuncActive = " + usbFuncActive); + + // Configure adb. + let currentConfig = libcutils.property_get("persist.sys.usb.config"); + let configFuncs = currentConfig.split(","); + if (currentConfig == "" || currentConfig == "none") { + // We want to treat none like the empty string. + // "".split(",") yields [""] and not [] + configFuncs = []; + } + let adbIndex = configFuncs.indexOf("adb"); + + if (enableAdb) { + // Add adb to the list of functions, if not already present + if (adbIndex < 0) { + configFuncs.push("adb"); + } + } else { + // Remove adb from the list of functions, if present + if (adbIndex >= 0) { + configFuncs.splice(adbIndex, 1); + } + } + let newConfig = configFuncs.join(","); + if (newConfig == "") { + // Convert the empty string back into none, since that's what init.rc + // needs. + newConfig = "none"; + } + if (newConfig != currentConfig) { + DEBUG && debug("updateState: currentConfig = " + currentConfig); + DEBUG && debug("updateState: newConfig = " + newConfig); + try { + libcutils.property_set("persist.sys.usb.config", newConfig); + } catch(e) { + Cu.reportError("Error configuring adb: " + e); + } + } + if (useDisableAdbTimer) { + if (enableAdb && !usbFuncActive) { + this.startDisableAdbTimer(); + } else { + this.stopDisableAdbTimer(); + } + } + } +}; + +SettingsListener.observe("lockscreen.locked", false, + AdbController.setLockscreenState.bind(AdbController)); +SettingsListener.observe("lockscreen.enabled", false, + AdbController.setLockscreenEnabled.bind(AdbController)); diff --git a/b2g/chrome/content/devtools/debugger.js b/b2g/chrome/content/devtools/debugger.js new file mode 100644 index 000000000..11987a839 --- /dev/null +++ b/b2g/chrome/content/devtools/debugger.js @@ -0,0 +1,397 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +XPCOMUtils.defineLazyGetter(this, "devtools", function() { + const { devtools } = + Cu.import("resource://devtools/shared/Loader.jsm", {}); + return devtools; +}); + +XPCOMUtils.defineLazyGetter(this, "DebuggerServer", function() { + const { DebuggerServer } = devtools.require("devtools/server/main"); + return DebuggerServer; +}); + +XPCOMUtils.defineLazyGetter(this, "B2GTabList", function() { + const { B2GTabList } = + devtools.require("resource://gre/modules/DebuggerActors.js"); + return B2GTabList; +}); + +// Load the discovery module eagerly, so that it can set a device name at +// startup. This does not cause discovery to start listening for packets, as +// that only happens once DevTools is enabled. +devtools.require("devtools/shared/discovery/discovery"); + +var RemoteDebugger = { + _listening: false, + + /** + * Prompt the user to accept or decline the incoming connection. + * + * @param session object + * The session object will contain at least the following fields: + * { + * authentication, + * client: { + * host, + * port + * }, + * server: { + * host, + * port + * } + * } + * Specific authentication modes may include additional fields. Check + * the different |allowConnection| methods in + * devtools/shared/security/auth.js. + * @return An AuthenticationResult value. + * A promise that will be resolved to the above is also allowed. + */ + allowConnection(session) { + if (this._promptingForAllow) { + // Don't stack connection prompts if one is already open + return DebuggerServer.AuthenticationResult.DENY; + } + this._listen(); + + this._promptingForAllow = new Promise(resolve => { + this._handleAllowResult = detail => { + this._handleAllowResult = null; + this._promptingForAllow = null; + // Newer Gaia supplies |authResult|, which is one of the + // AuthenticationResult values. + if (detail.authResult) { + resolve(detail.authResult); + } else if (detail.value) { + resolve(DebuggerServer.AuthenticationResult.ALLOW); + } else { + resolve(DebuggerServer.AuthenticationResult.DENY); + } + }; + + shell.sendChromeEvent({ + type: "remote-debugger-prompt", + session + }); + }); + + return this._promptingForAllow; + }, + + /** + * During OOB_CERT authentication, the user must transfer some data through some + * out of band mechanism from the client to the server to authenticate the + * devices. + * + * This implementation instructs Gaia to continually capture images which are + * passed back here and run through a QR decoder. + * + * @return An object containing: + * * sha256: hash(ClientCert) + * * k : K(random 128-bit number) + * A promise that will be resolved to the above is also allowed. + */ + receiveOOB() { + if (this._receivingOOB) { + return this._receivingOOB; + } + this._listen(); + + const QR = devtools.require("devtools/shared/qrcode/index"); + this._receivingOOB = new Promise((resolve, reject) => { + this._handleAuthEvent = detail => { + debug(detail.action); + if (detail.action === "abort") { + this._handleAuthEvent = null; + this._receivingOOB = null; + reject(); + return; + } + + if (detail.action !== "capture") { + return; + } + + let url = detail.url; + QR.decodeFromURI(url).then(data => { + debug("Got auth data: " + data); + let oob = JSON.parse(data); + + shell.sendChromeEvent({ + type: "devtools-auth", + action: "stop" + }); + + this._handleAuthEvent = null; + this._receivingOOB = null; + resolve(oob); + }).catch(() => { + debug("No auth data, requesting new capture"); + shell.sendChromeEvent({ + type: "devtools-auth", + action: "capture" + }); + }); + }; + + // Show QR scanning dialog, get an initial capture + shell.sendChromeEvent({ + type: "devtools-auth", + action: "start" + }); + }); + + return this._receivingOOB; + }, + + _listen: function() { + if (this._listening) { + return; + } + + this.handleEvent = this.handleEvent.bind(this); + let content = shell.contentBrowser.contentWindow; + content.addEventListener("mozContentEvent", this, false, true); + this._listening = true; + }, + + handleEvent: function(event) { + let detail = event.detail; + if (detail.type === "remote-debugger-prompt" && this._handleAllowResult) { + this._handleAllowResult(detail); + } + if (detail.type === "devtools-auth" && this._handleAuthEvent) { + this._handleAuthEvent(detail); + } + }, + + initServer: function() { + if (DebuggerServer.initialized) { + return; + } + + // Ask for remote connections. + DebuggerServer.init(); + + // /!\ Be careful when adding a new actor, especially global actors. + // Any new global actor will be exposed and returned by the root actor. + + // Add Firefox-specific actors, but prevent tab actors to be loaded in + // the parent process, unless we enable certified apps debugging. + let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps"); + DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges); + + // Allow debugging of chrome for any process + if (!restrictPrivileges) { + DebuggerServer.allowChromeProcess = true; + } + + /** + * Construct a root actor appropriate for use in a server running in B2G. + * The returned root actor respects the factories registered with + * DebuggerServer.addGlobalActor only if certified apps debugging is on, + * otherwise we used an explicit limited list of global actors + * + * * @param connection DebuggerServerConnection + * The conection to the client. + */ + DebuggerServer.createRootActor = function createRootActor(connection) + { + let parameters = { + tabList: new B2GTabList(connection), + // Use an explicit global actor list to prevent exposing + // unexpected actors + globalActorFactories: restrictPrivileges ? { + webappsActor: DebuggerServer.globalActorFactories.webappsActor, + deviceActor: DebuggerServer.globalActorFactories.deviceActor, + settingsActor: DebuggerServer.globalActorFactories.settingsActor + } : DebuggerServer.globalActorFactories + }; + let { RootActor } = devtools.require("devtools/server/actors/root"); + let root = new RootActor(connection, parameters); + root.applicationType = "operating-system"; + return root; + }; + + if (isGonk) { + DebuggerServer.on("connectionchange", function() { + AdbController.updateState(); + }); + } + } +}; + +RemoteDebugger.allowConnection = + RemoteDebugger.allowConnection.bind(RemoteDebugger); +RemoteDebugger.receiveOOB = + RemoteDebugger.receiveOOB.bind(RemoteDebugger); + +var USBRemoteDebugger = { + + get isDebugging() { + if (!this._listener) { + return false; + } + + return DebuggerServer._connections && + Object.keys(DebuggerServer._connections).length > 0; + }, + + start: function() { + if (this._listener) { + return; + } + + RemoteDebugger.initServer(); + + let portOrPath = + Services.prefs.getCharPref("devtools.debugger.unix-domain-socket") || + "/data/local/debugger-socket"; + + try { + debug("Starting USB debugger on " + portOrPath); + let AuthenticatorType = DebuggerServer.Authenticators.get("PROMPT"); + let authenticator = new AuthenticatorType.Server(); + authenticator.allowConnection = RemoteDebugger.allowConnection; + this._listener = DebuggerServer.createListener(); + this._listener.portOrPath = portOrPath; + this._listener.authenticator = authenticator; + this._listener.open(); + // Temporary event, until bug 942756 lands and offers a way to know + // when the server is up and running. + Services.obs.notifyObservers(null, "debugger-server-started", null); + } catch (e) { + debug("Unable to start USB debugger server: " + e); + } + }, + + stop: function() { + if (!this._listener) { + return; + } + + try { + this._listener.close(); + this._listener = null; + } catch (e) { + debug("Unable to stop USB debugger server: " + e); + } + } + +}; + +var WiFiRemoteDebugger = { + + start: function() { + if (this._listener) { + return; + } + + RemoteDebugger.initServer(); + + try { + debug("Starting WiFi debugger"); + let AuthenticatorType = DebuggerServer.Authenticators.get("OOB_CERT"); + let authenticator = new AuthenticatorType.Server(); + authenticator.allowConnection = RemoteDebugger.allowConnection; + authenticator.receiveOOB = RemoteDebugger.receiveOOB; + this._listener = DebuggerServer.createListener(); + this._listener.portOrPath = -1 /* any available port */; + this._listener.authenticator = authenticator; + this._listener.discoverable = true; + this._listener.encryption = true; + this._listener.open(); + let port = this._listener.port; + debug("Started WiFi debugger on " + port); + } catch (e) { + debug("Unable to start WiFi debugger server: " + e); + } + }, + + stop: function() { + if (!this._listener) { + return; + } + + try { + this._listener.close(); + this._listener = null; + } catch (e) { + debug("Unable to stop WiFi debugger server: " + e); + } + } + +}; + +(function() { + // Track these separately here so we can determine the correct value for the + // pref "devtools.debugger.remote-enabled", which is true when either mode of + // using DevTools is enabled. + let devtoolsUSB = false; + let devtoolsWiFi = false; + + // Keep the old setting to not break people that won't have updated + // gaia and gecko. + SettingsListener.observe("devtools.debugger.remote-enabled", false, + function(value) { + devtoolsUSB = value; + Services.prefs.setBoolPref("devtools.debugger.remote-enabled", + devtoolsUSB || devtoolsWiFi); + // This preference is consulted during startup + Services.prefs.savePrefFile(null); + try { + value ? USBRemoteDebugger.start() : USBRemoteDebugger.stop(); + } catch(e) { + dump("Error while initializing USB devtools: " + + e + "\n" + e.stack + "\n"); + } + }); + + SettingsListener.observe("debugger.remote-mode", "disabled", function(value) { + if (["disabled", "adb-only", "adb-devtools"].indexOf(value) == -1) { + dump("Illegal value for debugger.remote-mode: " + value + "\n"); + return; + } + + devtoolsUSB = value == "adb-devtools"; + Services.prefs.setBoolPref("devtools.debugger.remote-enabled", + devtoolsUSB || devtoolsWiFi); + // This preference is consulted during startup + Services.prefs.savePrefFile(null); + + try { + (value == "adb-devtools") ? USBRemoteDebugger.start() + : USBRemoteDebugger.stop(); + } catch(e) { + dump("Error while initializing USB devtools: " + + e + "\n" + e.stack + "\n"); + } + + isGonk && AdbController.setRemoteDebuggerState(value != "disabled"); + }); + + SettingsListener.observe("devtools.remote.wifi.enabled", false, + function(value) { + devtoolsWiFi = value; + Services.prefs.setBoolPref("devtools.debugger.remote-enabled", + devtoolsUSB || devtoolsWiFi); + // Allow remote debugging on non-local interfaces when WiFi debug is enabled + // TODO: Bug 1034411: Lock down to WiFi interface, instead of all interfaces + Services.prefs.setBoolPref("devtools.debugger.force-local", !value); + // This preference is consulted during startup + Services.prefs.savePrefFile(null); + + try { + value ? WiFiRemoteDebugger.start() : WiFiRemoteDebugger.stop(); + } catch(e) { + dump("Error while initializing WiFi devtools: " + + e + "\n" + e.stack + "\n"); + } + }); +})(); diff --git a/b2g/chrome/content/devtools/hud.js b/b2g/chrome/content/devtools/hud.js new file mode 100644 index 000000000..64e9d553d --- /dev/null +++ b/b2g/chrome/content/devtools/hud.js @@ -0,0 +1,1017 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +// settings.js loads this file when the HUD setting is enabled. + +const DEVELOPER_HUD_LOG_PREFIX = 'DeveloperHUD'; +const CUSTOM_HISTOGRAM_PREFIX = 'DEVTOOLS_HUD_CUSTOM_'; +const APPNAME_IDX = 3; +const HISTNAME_IDX = 4; + +XPCOMUtils.defineLazyGetter(this, 'devtools', function() { + const {devtools} = Cu.import('resource://devtools/shared/Loader.jsm', {}); + return devtools; +}); + +XPCOMUtils.defineLazyGetter(this, 'DebuggerClient', function() { + return devtools.require('devtools/shared/client/main').DebuggerClient; +}); + +XPCOMUtils.defineLazyGetter(this, 'WebConsoleUtils', function() { + return devtools.require('devtools/shared/webconsole/utils').Utils; +}); + +XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() { + return devtools.require('devtools/shared/fronts/eventlooplag').EventLoopLagFront; +}); + +XPCOMUtils.defineLazyGetter(this, 'PerformanceEntriesFront', function() { + return devtools.require('devtools/server/actors/performance-entries').PerformanceEntriesFront; +}); + +XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() { + return devtools.require('devtools/server/actors/memory').MemoryFront; +}); + +Cu.import('resource://gre/modules/Frames.jsm'); + +var _telemetryDebug = false; + +function telemetryDebug(...args) { + if (_telemetryDebug) { + args.unshift('[AdvancedTelemetry]'); + console.log(...args); + } +} + +/** + * The Developer HUD is an on-device developer tool that displays widgets, + * showing visual debug information about apps. Each widget corresponds to a + * metric as tracked by a metric watcher (e.g. consoleWatcher). + */ +var developerHUD = { + + _targets: new Map(), + _histograms: new Set(), + _customHistograms: new Set(), + _client: null, + _conn: null, + _watchers: [], + _logging: true, + _telemetry: false, + + /** + * This method registers a metric watcher that will watch one or more metrics + * on app frames that are being tracked. A watcher must implement the + * `trackTarget(target)` and `untrackTarget(target)` methods, register + * observed metrics with `target.register(metric)`, and keep them up-to-date + * with `target.update(metric, message)` when necessary. + */ + registerWatcher(watcher) { + this._watchers.unshift(watcher); + }, + + init() { + if (this._client) { + return; + } + + if (!DebuggerServer.initialized) { + RemoteDebugger.initServer(); + } + + // We instantiate a local debugger connection so that watchers can use our + // DebuggerClient to send requests to tab actors (e.g. the consoleActor). + // Note the special usage of the private _serverConnection, which we need + // to call connectToChild and set up child process actors on a frame we + // intend to track. These actors will use the connection to communicate with + // our DebuggerServer in the parent process. + let transport = DebuggerServer.connectPipe(); + this._conn = transport._serverConnection; + this._client = new DebuggerClient(transport); + + for (let w of this._watchers) { + if (w.init) { + w.init(this._client); + } + } + + Frames.addObserver(this); + + let appFrames = Frames.list().filter(frame => frame.getAttribute('mozapp')); + for (let frame of appFrames) { + this.trackFrame(frame); + } + + SettingsListener.observe('hud.logging', this._logging, enabled => { + this._logging = enabled; + }); + + SettingsListener.observe('hud.telemetry.logging', _telemetryDebug, enabled => { + _telemetryDebug = enabled; + }); + + SettingsListener.observe('metrics.selectedMetrics.level', "", level => { + this._telemetry = (level === 'Enhanced'); + }); + }, + + uninit() { + if (!this._client) { + return; + } + + for (let frame of this._targets.keys()) { + this.untrackFrame(frame); + } + + Frames.removeObserver(this); + + this._client.close(); + delete this._client; + }, + + /** + * This method will ask all registered watchers to track and update metrics + * on an app frame. + */ + trackFrame(frame) { + if (this._targets.has(frame)) { + return; + } + + DebuggerServer.connectToChild(this._conn, frame).then(actor => { + let target = new Target(frame, actor); + this._targets.set(frame, target); + + for (let w of this._watchers) { + w.trackTarget(target); + } + }); + }, + + untrackFrame(frame) { + let target = this._targets.get(frame); + if (target) { + for (let w of this._watchers) { + w.untrackTarget(target); + } + + target.destroy(); + this._targets.delete(frame); + } + }, + + onFrameCreated(frame, isFirstAppFrame) { + let mozapp = frame.getAttribute('mozapp'); + if (!mozapp) { + return; + } + this.trackFrame(frame); + }, + + onFrameDestroyed(frame, isLastAppFrame) { + let mozapp = frame.getAttribute('mozapp'); + if (!mozapp) { + return; + } + this.untrackFrame(frame); + }, + + log(message) { + if (this._logging) { + dump(DEVELOPER_HUD_LOG_PREFIX + ': ' + message + '\n'); + } + } + +}; + + +/** + * A Target object represents all there is to know about a Firefox OS app frame + * that is being tracked, e.g. a pointer to the frame, current values of watched + * metrics, and how to notify the front-end when metrics have changed. + */ +function Target(frame, actor) { + this.frame = frame; + this.actor = actor; + this.metrics = new Map(); + this._appName = null; +} + +Target.prototype = { + + get manifest() { + return this.frame.appManifestURL; + }, + + get appName() { + + if (this._appName) { + return this._appName; + } + + let manifest = this.manifest; + if (!manifest) { + let msg = DEVELOPER_HUD_LOG_PREFIX + ': Unable to determine app for telemetry metric. src: ' + + this.frame.src; + console.error(msg); + return null; + } + + // "communications" apps are a special case + if (manifest.indexOf('communications') === -1) { + let start = manifest.indexOf('/') + 2; + let end = manifest.indexOf('.', start); + this._appName = manifest.substring(start, end).toLowerCase(); + } else { + let src = this.frame.src; + if (src) { + // e.g., `app://communications.gaiamobile.org/contacts/index.html` + let parts = src.split('/'); + let APP = 3; + let EXPECTED_PARTS_LENGTH = 5; + if (parts.length === EXPECTED_PARTS_LENGTH) { + this._appName = parts[APP]; + } + } + } + + return this._appName; + }, + + /** + * Register a metric that can later be updated. Does not update the front-end. + */ + register(metric) { + this.metrics.set(metric, 0); + }, + + /** + * Modify one of a target's metrics, and send out an event to notify relevant + * parties (e.g. the developer HUD, automated tests, etc). + */ + update(metric, message) { + if (!metric.name) { + throw new Error('Missing metric.name'); + } + + if (!metric.value) { + metric.value = 0; + } + + let metrics = this.metrics; + if (metrics) { + metrics.set(metric.name, metric.value); + } + + let data = { + metrics: [], // FIXME(Bug 982066) Remove this field. + manifest: this.manifest, + metric: metric, + message: message + }; + + // FIXME(Bug 982066) Remove this loop. + if (metrics && metrics.size > 0) { + for (let name of metrics.keys()) { + data.metrics.push({name: name, value: metrics.get(name)}); + } + } + + if (message) { + developerHUD.log('[' + data.manifest + '] ' + data.message); + } + + this._send(data); + }, + + /** + * Nicer way to call update() when the metric value is a number that needs + * to be incremented. + */ + bump(metric, message) { + metric.value = (this.metrics.get(metric.name) || 0) + 1; + this.update(metric, message); + }, + + /** + * Void a metric value and make sure it isn't displayed on the front-end + * anymore. + */ + clear(metric) { + metric.value = 0; + this.update(metric); + }, + + /** + * Tear everything down, including the front-end by sending a message without + * widgets. + */ + destroy() { + delete this.metrics; + this._send({metric: {skipTelemetry: true}}); + }, + + _send(data) { + let frame = this.frame; + + shell.sendEvent(frame, 'developer-hud-update', Cu.cloneInto(data, frame)); + this._logHistogram(data.metric); + }, + + _getAddonHistogram(item) { + let appName = this._getAddonHistogramName(item, APPNAME_IDX); + let histName = this._getAddonHistogramName(item, HISTNAME_IDX); + + return Services.telemetry.getAddonHistogram(appName, CUSTOM_HISTOGRAM_PREFIX + + histName); + }, + + _getAddonHistogramName(item, index) { + let array = item.split('_'); + return array[index].toUpperCase(); + }, + + _clearTelemetryData() { + developerHUD._histograms.forEach(function(item) { + Services.telemetry.getKeyedHistogramById(item).clear(); + }); + + developerHUD._customHistograms.forEach(item => { + this._getAddonHistogram(item).clear(); + }); + }, + + _sendTelemetryData() { + if (!developerHUD._telemetry) { + return; + } + telemetryDebug('calling sendTelemetryData'); + let frame = this.frame; + let payload = { + keyedHistograms: {}, + addonHistograms: {} + }; + // Package the hud histograms. + developerHUD._histograms.forEach(function(item) { + payload.keyedHistograms[item] = + Services.telemetry.getKeyedHistogramById(item).snapshot(); + }); + + // Package the registered hud custom histograms + developerHUD._customHistograms.forEach(item => { + let appName = this._getAddonHistogramName(item, APPNAME_IDX); + let histName = CUSTOM_HISTOGRAM_PREFIX + + this._getAddonHistogramName(item, HISTNAME_IDX); + let addonHist = Services.telemetry.getAddonHistogram(appName, histName).snapshot(); + if (!(appName in payload.addonHistograms)) { + payload.addonHistograms[appName] = {}; + } + // Do not include histograms with sum of 0. + if (addonHist.sum > 0) { + payload.addonHistograms[appName][histName] = addonHist; + } + }); + shell.sendEvent(frame, 'advanced-telemetry-update', Cu.cloneInto(payload, frame)); + }, + + _logHistogram(metric) { + if (!developerHUD._telemetry || metric.skipTelemetry) { + return; + } + + metric.appName = this.appName; + if (!metric.appName) { + return; + } + + let metricName = metric.name.toUpperCase(); + let metricAppName = metric.appName.toUpperCase(); + if (!metric.custom) { + let keyedMetricName = 'DEVTOOLS_HUD_' + metricName; + try { + let keyed = Services.telemetry.getKeyedHistogramById(keyedMetricName); + if (keyed) { + keyed.add(metric.appName, parseInt(metric.value, 10)); + developerHUD._histograms.add(keyedMetricName); + telemetryDebug(keyedMetricName, metric.value, metric.appName); + } + } catch(err) { + console.error('Histogram error is metricname added to histograms.json:' + + keyedMetricName); + } + } else { + let histogramName = CUSTOM_HISTOGRAM_PREFIX + metricAppName + '_' + + metricName; + // This is a call to add a value to an existing histogram. + if (typeof metric.value !== 'undefined') { + Services.telemetry.getAddonHistogram(metricAppName, + CUSTOM_HISTOGRAM_PREFIX + metricName).add(parseInt(metric.value, 10)); + telemetryDebug(histogramName, metric.value); + return; + } + + // The histogram already exists and are not adding data to it. + if (developerHUD._customHistograms.has(histogramName)) { + return; + } + + // This is a call to create a new histogram. + try { + let metricType = parseInt(metric.type, 10); + if (metricType === Services.telemetry.HISTOGRAM_COUNT) { + Services.telemetry.registerAddonHistogram(metricAppName, + CUSTOM_HISTOGRAM_PREFIX + metricName, metricType); + } else { + Services.telemetry.registerAddonHistogram(metricAppName, + CUSTOM_HISTOGRAM_PREFIX + metricName, metricType, metric.min, + metric.max, metric.buckets); + } + developerHUD._customHistograms.add(histogramName); + } catch (err) { + console.error('Histogram error: ' + err); + } + } + } +}; + + +/** + * The Console Watcher tracks the following metrics in apps: reflows, warnings, + * and errors, with security errors reported separately. + */ +var consoleWatcher = { + + _client: null, + _targets: new Map(), + _watching: { + reflows: false, + warnings: false, + errors: false, + security: false + }, + _security: [ + 'Mixed Content Blocker', + 'Mixed Content Message', + 'CSP', + 'Invalid HSTS Headers', + 'Invalid HPKP Headers', + 'Insecure Password Field', + 'SSL', + 'CORS' + ], + _reflowThreshold: 0, + + init(client) { + this._client = client; + this.consoleListener = this.consoleListener.bind(this); + + let watching = this._watching; + + for (let key in watching) { + let metric = key; + SettingsListener.observe('hud.' + metric, watching[metric], watch => { + // Watch or unwatch the metric. + if (watching[metric] = watch) { + return; + } + + // If unwatched, remove any existing widgets for that metric. + for (let target of this._targets.values()) { + target.clear({name: metric}); + } + }); + } + + SettingsListener.observe('hud.reflows.duration', this._reflowThreshold, threshold => { + this._reflowThreshold = threshold; + }); + + client.addListener('logMessage', this.consoleListener); + client.addListener('pageError', this.consoleListener); + client.addListener('consoleAPICall', this.consoleListener); + client.addListener('reflowActivity', this.consoleListener); + }, + + trackTarget(target) { + target.register('reflows'); + target.register('warnings'); + target.register('errors'); + target.register('security'); + + this._client.request({ + to: target.actor.consoleActor, + type: 'startListeners', + listeners: ['LogMessage', 'PageError', 'ConsoleAPI', 'ReflowActivity'] + }, (res) => { + this._targets.set(target.actor.consoleActor, target); + }); + }, + + untrackTarget(target) { + this._client.request({ + to: target.actor.consoleActor, + type: 'stopListeners', + listeners: ['LogMessage', 'PageError', 'ConsoleAPI', 'ReflowActivity'] + }, (res) => { }); + + this._targets.delete(target.actor.consoleActor); + }, + + consoleListener(type, packet) { + let target = this._targets.get(packet.from); + let metric = {}; + let output = ''; + + switch (packet.type) { + + case 'pageError': + let pageError = packet.pageError; + + if (pageError.warning || pageError.strict) { + metric.name = 'warnings'; + output += 'Warning ('; + } else { + metric.name = 'errors'; + output += 'Error ('; + } + + if (this._security.indexOf(pageError.category) > -1) { + metric.name = 'security'; + + // Telemetry sends the security error category not the + // count of security errors. + target._logHistogram({ + name: 'security_category', + value: pageError.category + }); + + // Indicate that the 'hud' security metric (the count of security + // errors) should not be sent as a telemetry metric since the + // security error category is being sent instead. + metric.skipTelemetry = true; + } + + let {errorMessage, sourceName, category, lineNumber, columnNumber} = pageError; + output += category + '): "' + (errorMessage.initial || errorMessage) + + '" in ' + sourceName + ':' + lineNumber + ':' + columnNumber; + break; + + case 'consoleAPICall': + switch (packet.message.level) { + + case 'error': + metric.name = 'errors'; + output += 'Error (console)'; + break; + + case 'warn': + metric.name = 'warnings'; + output += 'Warning (console)'; + break; + + case 'info': + this.handleTelemetryMessage(target, packet); + + // Currently, informational log entries are tracked only by + // telemetry. Nonetheless, for consistency, we continue here + // and let the function return normally, when it concludes 'info' + // entries are not being watched. + metric.name = 'info'; + break; + + default: + return; + } + break; + + case 'reflowActivity': + metric.name = 'reflows'; + + let {start, end, sourceURL, interruptible} = packet; + metric.interruptible = interruptible; + let duration = Math.round((end - start) * 100) / 100; + + // Record the reflow if the duration exceeds the threshold. + if (duration < this._reflowThreshold) { + return; + } + + output += 'Reflow: ' + duration + 'ms'; + if (sourceURL) { + output += ' ' + this.formatSourceURL(packet); + } + + // Telemetry also records reflow duration. + target._logHistogram({ + name: 'reflow_duration', + value: Math.round(duration) + }); + break; + + default: + return; + } + + if (developerHUD._telemetry) { + // Always record telemetry for these metrics. + if (metric.name === 'errors' || metric.name === 'warnings' || metric.name === 'reflows') { + let value = target.metrics.get(metric.name); + metric.value = (value || 0) + 1; + target._logHistogram(metric); + + // Telemetry has already been recorded. + metric.skipTelemetry = true; + + // If the metric is not being watched, persist the incremented value. + // If the metric is being watched, `target.bump` will increment the value + // of the metric and will persist the incremented value. + if (!this._watching[metric.name]) { + target.metrics.set(metric.name, metric.value); + } + } + } + + if (!this._watching[metric.name]) { + return; + } + + target.bump(metric, output); + }, + + formatSourceURL(packet) { + // Abbreviate source URL + let source = WebConsoleUtils.abbreviateSourceURL(packet.sourceURL); + + // Add function name and line number + let {functionName, sourceLine} = packet; + source = 'in ' + (functionName || '') + + ', ' + source + ':' + sourceLine; + + return source; + }, + + handleTelemetryMessage(target, packet) { + if (!developerHUD._telemetry) { + return; + } + + // If this is a 'telemetry' log entry, create a telemetry metric from + // the log content. + let separator = '|'; + let logContent = packet.message.arguments.toString(); + + if (logContent.indexOf('telemetry') < 0) { + return; + } + + let telemetryData = logContent.split(separator); + + // Positions of the components of a telemetry log entry. + let TELEMETRY_IDENTIFIER_IDX = 0; + let NAME_IDX = 1; + let VALUE_IDX = 2; + let TYPE_IDX = 2; + let MIN_IDX = 3; + let MAX_IDX = 4; + let BUCKETS_IDX = 5; + let MAX_CUSTOM_ARGS = 6; + let MIN_CUSTOM_ARGS = 3; + + if (telemetryData[TELEMETRY_IDENTIFIER_IDX] != 'telemetry' || + telemetryData.length < MIN_CUSTOM_ARGS || + telemetryData.length > MAX_CUSTOM_ARGS) { + return; + } + + let metric = { + name: telemetryData[NAME_IDX] + }; + + if (metric.name === 'MGMT') { + metric.value = telemetryData[VALUE_IDX]; + if (metric.value === 'TIMETOSHIP') { + telemetryDebug('Received a Ship event'); + target._sendTelemetryData(); + } else if (metric.value === 'CLEARMETRICS') { + target._clearTelemetryData(); + } + } else { + if (telemetryData.length === MIN_CUSTOM_ARGS) { + metric.value = telemetryData[VALUE_IDX]; + } else if (telemetryData.length === MAX_CUSTOM_ARGS) { + metric.type = telemetryData[TYPE_IDX]; + metric.min = telemetryData[MIN_IDX]; + metric.max = telemetryData[MAX_IDX]; + metric.buckets = telemetryData[BUCKETS_IDX]; + } + metric.custom = true; + target._logHistogram(metric); + } + } +}; +developerHUD.registerWatcher(consoleWatcher); + + +var eventLoopLagWatcher = { + _client: null, + _fronts: new Map(), + _active: false, + + init(client) { + this._client = client; + + SettingsListener.observe('hud.jank', false, this.settingsListener.bind(this)); + }, + + settingsListener(value) { + if (this._active == value) { + return; + } + + this._active = value; + + // Toggle the state of existing fronts. + let fronts = this._fronts; + for (let target of fronts.keys()) { + if (value) { + fronts.get(target).start(); + } else { + fronts.get(target).stop(); + target.clear({name: 'jank'}); + } + } + }, + + trackTarget(target) { + target.register('jank'); + + let front = new EventLoopLagFront(this._client, target.actor); + this._fronts.set(target, front); + + front.on('event-loop-lag', time => { + target.update({name: 'jank', value: time}, 'Jank: ' + time + 'ms'); + }); + + if (this._active) { + front.start(); + } + }, + + untrackTarget(target) { + let fronts = this._fronts; + if (fronts.has(target)) { + fronts.get(target).destroy(); + fronts.delete(target); + } + } +}; +developerHUD.registerWatcher(eventLoopLagWatcher); + +/* + * The performanceEntriesWatcher determines the delta between the epoch + * of an app's launch time and the epoch of the app's performance entry marks. + * When it receives an "appLaunch" performance entry mark it records the + * name of the app being launched and the epoch of when the launch ocurred. + * When it receives subsequent performance entry events for the app being + * launched, it records the delta of the performance entry opoch compared + * to the app-launch epoch and emits an "app-start-time-" + * event containing the delta. + * + * Additionally, while recording the "app-start-time" for a performance mark, + * USS memory at the time of the performance mark is also recorded. + */ +var performanceEntriesWatcher = { + _client: null, + _fronts: new Map(), + _appLaunch: new Map(), + _supported: [ + 'contentInteractive', + 'navigationInteractive', + 'navigationLoaded', + 'visuallyLoaded', + 'fullyLoaded', + 'mediaEnumerated', + 'scanEnd' + ], + + init(client) { + this._client = client; + let setting = 'devtools.telemetry.supported_performance_marks'; + let defaultValue = this._supported.join(','); + + SettingsListener.observe(setting, defaultValue, supported => { + this._supported = supported.split(','); + }); + }, + + trackTarget(target) { + // The performanceEntries watcher doesn't register a metric because + // currently the metrics generated are not displayed in + // in the front-end. + + let front = new PerformanceEntriesFront(this._client, target.actor); + this._fronts.set(target, front); + + // User timings are always gathered; there is no setting to enable/ + // disable. + front.start(); + + front.on('entry', detail => { + + // Only process performance marks. + if (detail.type !== 'mark') { + return; + } + + let name = detail.name; + let epoch = detail.epoch; + + // If this is an "app launch" mark, record the app that was + // launched and the epoch of when it was launched. + if (name.indexOf('appLaunch') !== -1) { + let CHARS_UNTIL_APP_NAME = 7; // '@app://' + let startPos = name.indexOf('@app') + CHARS_UNTIL_APP_NAME; + let endPos = name.indexOf('.'); + let appName = name.slice(startPos, endPos); + this._appLaunch.set(appName, epoch); + return; + } + + // Only process supported performance marks + if (this._supported.indexOf(name) === -1) { + return; + } + + let origin = detail.origin; + origin = origin.slice(0, origin.indexOf('.')); + + let appLaunchTime = this._appLaunch.get(origin); + + // Sanity check: ensure we have an app launch time for the app + // corresponding to this performance mark. + if (!appLaunchTime) { + return; + } + + let time = epoch - appLaunchTime; + let eventName = 'app_startup_time_' + name; + + // Events based on performance marks are for telemetry only, they are + // not displayed in the HUD front end. + target._logHistogram({name: eventName, value: time}); + + memoryWatcher.front(target).residentUnique().then(value => { + // bug 1215277, need 'v2' for app-memory histograms + eventName = 'app_memory_' + name + '_v2'; + target._logHistogram({name: eventName, value: value}); + }, err => { + console.error(err); + }); + }); + }, + + untrackTarget(target) { + let fronts = this._fronts; + if (fronts.has(target)) { + fronts.get(target).destroy(); + fronts.delete(target); + } + } +}; +developerHUD.registerWatcher(performanceEntriesWatcher); + +/** + * The Memory Watcher uses devtools actors to track memory usage. + */ +var memoryWatcher = { + + _client: null, + _fronts: new Map(), + _timers: new Map(), + _watching: { + uss: false, + appmemory: false, + jsobjects: false, + jsstrings: false, + jsother: false, + dom: false, + style: false, + other: false + }, + _active: false, + + init(client) { + this._client = client; + let watching = this._watching; + + for (let key in watching) { + let category = key; + SettingsListener.observe('hud.' + category, false, watch => { + watching[category] = watch; + this.update(); + }); + } + }, + + update() { + let watching = this._watching; + let active = watching.appmemory || watching.uss; + + if (this._active) { + for (let target of this._fronts.keys()) { + if (!watching.appmemory) target.clear({name: 'memory'}); + if (!watching.uss) target.clear({name: 'uss'}); + if (!active) clearTimeout(this._timers.get(target)); + } + } else if (active) { + for (let target of this._fronts.keys()) { + this.measure(target); + } + } + this._active = active; + }, + + measure(target) { + let watch = this._watching; + let format = this.formatMemory; + + if (watch.uss) { + this.front(target).residentUnique().then(value => { + target.update({name: 'uss', value: value}, 'USS: ' + format(value)); + }, err => { + console.error(err); + }); + } + + if (watch.appmemory) { + front.measure().then(data => { + let total = 0; + let details = []; + + function item(name, condition, value) { + if (!condition) { + return; + } + + let v = parseInt(value); + total += v; + details.push(name + ': ' + format(v)); + } + + item('JS objects', watch.jsobjects, data.jsObjectsSize); + item('JS strings', watch.jsstrings, data.jsStringsSize); + item('JS other', watch.jsother, data.jsOtherSize); + item('DOM', watch.dom, data.domSize); + item('Style', watch.style, data.styleSize); + item('Other', watch.other, data.otherSize); + // TODO Also count images size (bug #976007). + + target.update({name: 'memory', value: total}, + 'App Memory: ' + format(total) + ' (' + details.join(', ') + ')'); + }, err => { + console.error(err); + }); + } + + let timer = setTimeout(() => this.measure(target), 2000); + this._timers.set(target, timer); + }, + + formatMemory(bytes) { + var prefix = ['','K','M','G','T','P','E','Z','Y']; + var i = 0; + for (; bytes > 1024 && i < prefix.length; ++i) { + bytes /= 1024; + } + return (Math.round(bytes * 100) / 100) + ' ' + prefix[i] + 'B'; + }, + + trackTarget(target) { + target.register('uss'); + target.register('memory'); + this._fronts.set(target, MemoryFront(this._client, target.actor)); + if (this._active) { + this.measure(target); + } + }, + + untrackTarget(target) { + let front = this._fronts.get(target); + if (front) { + front.destroy(); + clearTimeout(this._timers.get(target)); + this._fronts.delete(target); + this._timers.delete(target); + } + }, + + front(target) { + return this._fronts.get(target); + } +}; +developerHUD.registerWatcher(memoryWatcher); diff --git a/b2g/chrome/content/identity.js b/b2g/chrome/content/identity.js new file mode 100644 index 000000000..9c0ad50a2 --- /dev/null +++ b/b2g/chrome/content/identity.js @@ -0,0 +1,166 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This JS shim contains the callbacks to fire DOMRequest events for +// navigator.pay API within the payment processor's scope. + +"use strict"; + +var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "cpmm", + "@mozilla.org/childprocessmessagemanager;1", + "nsIMessageSender"); + +XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", + "@mozilla.org/uuid-generator;1", + "nsIUUIDGenerator"); + +XPCOMUtils.defineLazyModuleGetter(this, "Logger", + "resource://gre/modules/identity/LogUtils.jsm"); + +function log(...aMessageArgs) { + Logger.log.apply(Logger, ["injected identity.js"].concat(aMessageArgs)); +} + +log("\n\n======================= identity.js =======================\n\n"); + +// This script may be injected more than once into an iframe. +// It's hard to do this with |const| like we should, so use var instead. +if (typeof kIdentityJSLoaded === 'undefined') { + var kIdentityDelegateWatch = "identity-delegate-watch"; + var kIdentityDelegateRequest = "identity-delegate-request"; + var kIdentityDelegateLogout = "identity-delegate-logout"; + var kIdentityDelegateReady = "identity-delegate-ready"; + var kIdentityDelegateFinished = "identity-delegate-finished"; + var kIdentityControllerDoMethod = "identity-controller-doMethod"; + var kIdentktyJSLoaded = true; +} + +var showUI = false; +var options = {}; +var isLoaded = false; +var func = null; + +/* + * Message back to the SignInToWebsite pipe. Message should be an + * object with the following keys: + * + * method: one of 'login', 'logout', 'ready' + * assertion: optional assertion + */ +function identityCall(message) { + if (options._internal) { + message._internal = options._internal; + } + sendAsyncMessage(kIdentityControllerDoMethod, message); +} + +/* + * To close the dialog, we first tell the gecko SignInToWebsite manager that it + * can clean up. Then we tell the gaia component that we are finished. It is + * necessary to notify gecko first, so that the message can be sent before gaia + * destroys our context. + */ +function closeIdentityDialog() { + // tell gecko we're done. + func = null; options = null; + sendAsyncMessage(kIdentityDelegateFinished); +} + +/* + * doInternalWatch - call the internal.watch api and relay the results + * up to the controller. + */ +function doInternalWatch() { + log("doInternalWatch:", options, isLoaded); + if (options && isLoaded) { + let BrowserID = content.wrappedJSObject.BrowserID; + BrowserID.internal.watch(function(aParams, aInternalParams) { + identityCall(aParams); + if (aParams.method === "ready") { + closeIdentityDialog(); + } + }, + JSON.stringify(options), + function(...things) { + // internal watch log callback + log("(watch) internal: ", things); + } + ); + } +} + +function doInternalRequest() { + log("doInternalRequest:", options && isLoaded); + if (options && isLoaded) { + var stringifiedOptions = JSON.stringify(options); + content.wrappedJSObject.BrowserID.internal.get( + options.origin, + function(assertion, internalParams) { + internalParams = internalParams || {}; + if (assertion) { + identityCall({ + method: 'login', + assertion: assertion, + _internalParams: internalParams}); + } else { + identityCall({ + method: 'cancel' + }); + } + closeIdentityDialog(); + }, + stringifiedOptions); + } +} +function doInternalLogout(aOptions) { + log("doInternalLogout:", (options && isLoaded)); + if (options && isLoaded) { + let BrowserID = content.wrappedJSObject.BrowserID; + BrowserID.internal.logout(options.origin, function() { + identityCall({method:'logout'}); + closeIdentityDialog(); + }); + } +} + +addEventListener("DOMContentLoaded", function(e) { + content.addEventListener("load", function(e) { + isLoaded = true; + // bring da func + if (func) func(); + }); +}); + +// listen for request +addMessageListener(kIdentityDelegateRequest, function(aMessage) { + log("injected identity.js received", kIdentityDelegateRequest); + options = aMessage.json; + showUI = true; + func = doInternalRequest; + func(); +}); + +// listen for watch +addMessageListener(kIdentityDelegateWatch, function(aMessage) { + log("injected identity.js received", kIdentityDelegateWatch); + options = aMessage.json; + showUI = false; + func = doInternalWatch; + func(); +}); + +// listen for logout +addMessageListener(kIdentityDelegateLogout, function(aMessage) { + log("injected identity.js received", kIdentityDelegateLogout); + options = aMessage.json; + showUI = false; + func = doInternalLogout; + func(); +}); diff --git a/b2g/chrome/content/images/arrowdown-16.png b/b2g/chrome/content/images/arrowdown-16.png new file mode 100644 index 000000000..c982426f2 Binary files /dev/null and b/b2g/chrome/content/images/arrowdown-16.png differ diff --git a/b2g/chrome/content/images/arrowright-16.png b/b2g/chrome/content/images/arrowright-16.png new file mode 100644 index 000000000..859e98ba6 Binary files /dev/null and b/b2g/chrome/content/images/arrowright-16.png differ diff --git a/b2g/chrome/content/images/desktop/home-black.png b/b2g/chrome/content/images/desktop/home-black.png new file mode 100644 index 000000000..c51187ed4 Binary files /dev/null and b/b2g/chrome/content/images/desktop/home-black.png differ diff --git a/b2g/chrome/content/images/desktop/home-white.png b/b2g/chrome/content/images/desktop/home-white.png new file mode 100644 index 000000000..43379d0e9 Binary files /dev/null and b/b2g/chrome/content/images/desktop/home-white.png differ diff --git a/b2g/chrome/content/images/desktop/rotate.png b/b2g/chrome/content/images/desktop/rotate.png new file mode 100644 index 000000000..9da1b5674 Binary files /dev/null and b/b2g/chrome/content/images/desktop/rotate.png differ diff --git a/b2g/chrome/content/images/error.png b/b2g/chrome/content/images/error.png new file mode 100644 index 000000000..58e37283a Binary files /dev/null and b/b2g/chrome/content/images/error.png differ diff --git a/b2g/chrome/content/images/errorpage-larry-black.png b/b2g/chrome/content/images/errorpage-larry-black.png new file mode 100644 index 000000000..9f2e4a6e7 Binary files /dev/null and b/b2g/chrome/content/images/errorpage-larry-black.png differ diff --git a/b2g/chrome/content/images/errorpage-larry-white.png b/b2g/chrome/content/images/errorpage-larry-white.png new file mode 100644 index 000000000..fc153c731 Binary files /dev/null and b/b2g/chrome/content/images/errorpage-larry-white.png differ diff --git a/b2g/chrome/content/images/errorpage-warning.png b/b2g/chrome/content/images/errorpage-warning.png new file mode 100644 index 000000000..8bf9d8e7d Binary files /dev/null and b/b2g/chrome/content/images/errorpage-warning.png differ diff --git a/b2g/chrome/content/images/exitfullscreen-hdpi.png b/b2g/chrome/content/images/exitfullscreen-hdpi.png new file mode 100644 index 000000000..826e53408 Binary files /dev/null and b/b2g/chrome/content/images/exitfullscreen-hdpi.png differ diff --git a/b2g/chrome/content/images/fullscreen-hdpi.png b/b2g/chrome/content/images/fullscreen-hdpi.png new file mode 100644 index 000000000..980e78731 Binary files /dev/null and b/b2g/chrome/content/images/fullscreen-hdpi.png differ diff --git a/b2g/chrome/content/images/mute-hdpi.png b/b2g/chrome/content/images/mute-hdpi.png new file mode 100644 index 000000000..6daf7cf71 Binary files /dev/null and b/b2g/chrome/content/images/mute-hdpi.png differ diff --git a/b2g/chrome/content/images/pause-hdpi.png b/b2g/chrome/content/images/pause-hdpi.png new file mode 100644 index 000000000..c7837f822 Binary files /dev/null and b/b2g/chrome/content/images/pause-hdpi.png differ diff --git a/b2g/chrome/content/images/play-hdpi.png b/b2g/chrome/content/images/play-hdpi.png new file mode 100644 index 000000000..fd64f9697 Binary files /dev/null and b/b2g/chrome/content/images/play-hdpi.png differ diff --git a/b2g/chrome/content/images/scrubber-hdpi.png b/b2g/chrome/content/images/scrubber-hdpi.png new file mode 100644 index 000000000..b965b73d5 Binary files /dev/null and b/b2g/chrome/content/images/scrubber-hdpi.png differ diff --git a/b2g/chrome/content/images/throbber.png b/b2g/chrome/content/images/throbber.png new file mode 100644 index 000000000..c601ec80b Binary files /dev/null and b/b2g/chrome/content/images/throbber.png differ diff --git a/b2g/chrome/content/images/unmute-hdpi.png b/b2g/chrome/content/images/unmute-hdpi.png new file mode 100644 index 000000000..5de342bda Binary files /dev/null and b/b2g/chrome/content/images/unmute-hdpi.png differ diff --git a/b2g/chrome/content/netError.css b/b2g/chrome/content/netError.css new file mode 100644 index 000000000..59d06a00c --- /dev/null +++ b/b2g/chrome/content/netError.css @@ -0,0 +1,131 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This defines the look-and-feel styling of the error pages. + * (see: netError.xhtml) + * + * Original styling by William Price + * Updated for mobile by: Wes Johnston + */ + +body { + margin: 0; + padding: 0 8px 8px; + font-family: "Nokia Sans", Tahoma, sans-serif !important; +} + +h1 { + font-size: 22px; +} + +h2 { + font-size: 16px; +} + +ul { + margin: 0px; + padding: 0px 0px 0px 1em; +} + +li { + margin: 0px; + padding: 8px 0px; +} + +#errorPage { + background-color: #CEE6F4; +} + +#errorPage.certerror { + background-color: #EFD400; +} + +#errorPage.blockedsite { + background-color: #BF0000; +} + +#errorTitle { + background: url("chrome://b2g/content/images/errorpage-warning.png") left center no-repeat; + /* Scaled by .666 of their actual size */ + background-size: 40px 40px; + background-origin: content-box; + min-height: 60px; + margin-left: auto; + margin-right: auto; + max-width: 500px; + margin-left: auto; + margin-right: auto; +} + +#errorPage.certerror #errorTitle { + background-image: url("chrome://b2g/content/images/errorpage-larry-black.png"); +} + +#errorPage.blockedsite #errorTitle { + background-image: url("chrome://b2g/content/images/errorpage-larry-white.png"); + color: white; +} + +.errorTitleText { + padding: 0px 0px 0px 50px; + display: inline-block; + vertical-align: middle +} + +#errorPageContainer { + background-color: white; + border: 1px solid #999999; + border-radius: 6px; + padding: 6px 20px 20px; + font-size: 14px; + max-width: 500px; + margin-left: auto; + margin-right: auto; +} + +#errorShortDesc > p:empty { + display: none; +} + +#errorShortDesc > p { + overflow: auto; + border-bottom: 1px solid #999999; + padding-bottom: 1em; +} + +#errorPage.blockedsite #errorShortDesc > p { + font-weight: bold; + border-bottom: none; + padding-bottom: 0px; +} + +#securityOverrideDiv { + padding-top: 10px; +} + +div[collapsed] { + padding-left: 15px; + background-image: url("chrome://b2g/content/images/arrowright-16.png"); + background-size: 11px 11px; + background-repeat: no-repeat; + background-position: left 0.3em; +} + +div[collapsed="true"] { + background-image: url("chrome://b2g/content/images/arrowright-16.png"); +} + +div[collapsed="false"] { + background-image: url("chrome://b2g/content/images/arrowdown-16.png"); +} + +div[collapsed="true"] > p, +div[collapsed="true"] > div { + display: none; +} + +button { + padding: 0.3em !important; +} diff --git a/b2g/chrome/content/screen.js b/b2g/chrome/content/screen.js new file mode 100644 index 000000000..a893e8844 --- /dev/null +++ b/b2g/chrome/content/screen.js @@ -0,0 +1,276 @@ +// screen.js: +// Set the screen size, pixel density and scaling of the b2g client screen +// based on the --screen command-line option, if there is one. +// +// TODO: support multiple device pixels per CSS pixel +// + +var browserWindow = Services.wm.getMostRecentWindow("navigator:browser"); +var isMulet = "ResponsiveUI" in browserWindow; +Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm"); + +window.addEventListener('ContentStart', onStart); +window.addEventListener('SafeModeStart', onStart); + +// We do this on ContentStart and SafeModeStart because querying the +// displayDPI fails otherwise. +function onStart() { + // This is the toplevel element + let shell = document.getElementById('shell'); + + // The element inside it + let browser = document.getElementById('systemapp'); + + // Figure out the native resolution of the screen + let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindowUtils); + let hostDPI = windowUtils.displayDPI; + + let DEFAULT_SCREEN = '320x480'; + + // This is a somewhat random selection of named screens. + // Add more to this list when we support more hardware. + // Data from: http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density + let screens = { + iphone: { + name: 'Apple iPhone', width:320, height:480, dpi:163 + }, + ipad: { + name: 'Apple iPad', width:1024, height:768, dpi:132 + }, + nexus_s: { + name: 'Samsung Nexus S', width:480, height:800, dpi:235 + }, + galaxy_s2: { + name: 'Samsung Galaxy SII (I9100)', width:480, height:800, dpi:219 + }, + galaxy_nexus: { + name: 'Samsung Galaxy Nexus', width:720, height:1280, dpi:316 + }, + galaxy_tab: { + name: 'Samsung Galaxy Tab 10.1', width:800, height:1280, dpi:149 + }, + wildfire: { + name: 'HTC Wildfire', width:240, height:320, dpi:125 + }, + tattoo: { + name: 'HTC Tattoo', width:240, height:320, dpi:143 + }, + salsa: { + name: 'HTC Salsa', width:320, height:480, dpi:170 + }, + chacha: { + name: 'HTC ChaCha', width:320, height:480, dpi:222 + }, + }; + + // Get the command line arguments that were passed to the b2g client + let args; + try { + let service = Cc["@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds"].getService(Ci.nsISupports); + args = service.wrappedJSObject.cmdLine; + } catch(e) {} + + let screenarg = null; + + // Get the --screen argument from the command line + try { + if (args) { + screenarg = args.handleFlagWithParam('screen', false); + } + + // Override default screen size with a pref + if (screenarg === null && Services.prefs.prefHasUserValue('b2g.screen.size')) { + screenarg = Services.prefs.getCharPref('b2g.screen.size'); + } + + // If there isn't one, use the default screen + if (screenarg === null) + screenarg = DEFAULT_SCREEN; + + // With no value, tell the user how to use it + if (screenarg == '') + usage(); + } + catch(e) { + // If getting the argument value fails, its an error + usage(); + } + + // Special case --screen=full goes into fullscreen mode + if (screenarg === 'full') { + shell.setAttribute('sizemode', 'fullscreen'); + return; + } + + let width, height, ratio = 1.0; + let lastResizedWidth; + + if (screenarg in screens) { + // If this is a named screen, get its data + let screen = screens[screenarg]; + width = screen.width; + height = screen.height; + ratio = screen.ratio; + } else { + // Otherwise, parse the resolution and density from the --screen value. + // The supported syntax is WIDTHxHEIGHT[@DPI] + let match = screenarg.match(/^(\d+)x(\d+)(@(\d+(\.\d+)?))?$/); + + // Display usage information on syntax errors + if (match == null) + usage(); + + // Convert strings to integers + width = parseInt(match[1], 10); + height = parseInt(match[2], 10); + if (match[4]) + ratio = parseFloat(match[4], 10); + + // If any of the values came out 0 or NaN or undefined, display usage + if (!width || !height || !ratio) { + usage(); + } + } + + Services.prefs.setCharPref('layout.css.devPixelsPerPx', + ratio == 1 ? -1 : ratio); + let defaultOrientation = width < height ? 'portrait' : 'landscape'; + GlobalSimulatorScreen.mozOrientation = GlobalSimulatorScreen.screenOrientation = defaultOrientation; + + function resize() { + GlobalSimulatorScreen.width = width; + GlobalSimulatorScreen.height = height; + + // Set the window width and height to desired size plus chrome + // Include the size of the toolbox displayed under the system app + let controls = document.getElementById('controls'); + let controlsHeight = controls ? controls.getBoundingClientRect().height : 0; + + if (isMulet) { + let tab = browserWindow.gBrowser.selectedTab; + let responsive = ResponsiveUIManager.getResponsiveUIForTab(tab); + responsive.setSize(width + 16*2, + height + controlsHeight + 61); + } else { + let chromewidth = window.outerWidth - window.innerWidth; + let chromeheight = window.outerHeight - window.innerHeight + controlsHeight; + + if (lastResizedWidth == width) { + return; + } + lastResizedWidth = width; + + window.resizeTo(width + chromewidth, + height + chromeheight); + } + + let frameWidth = width, frameHeight = height; + + // If the current app doesn't supports the current screen orientation + // still resize the window, but rotate its frame so that + // it is displayed rotated on the side + let shouldFlip = GlobalSimulatorScreen.mozOrientation != GlobalSimulatorScreen.screenOrientation; + + if (shouldFlip) { + frameWidth = height; + frameHeight = width; + } + + // Set the browser element to the full unscaled size of the screen + let style = browser.style; + style.transform = ''; + style.height = 'calc(100% - ' + controlsHeight + 'px)'; + style.bottom = controlsHeight; + + style.width = frameWidth + "px"; + style.height = frameHeight + "px"; + + if (shouldFlip) { + // Display the system app with a 90° clockwise rotation + let shift = Math.floor(Math.abs(frameWidth - frameHeight) / 2); + style.transform += + ' rotate(0.25turn) translate(-' + shift + 'px, -' + shift + 'px)'; + } + } + + // Resize on startup + resize(); + + // Catch manual resizes to update the internal device size. + window.onresize = function() { + let controls = document.getElementById('controls'); + let controlsHeight = controls ? controls.getBoundingClientRect().height : 0; + + width = window.innerWidth; + height = window.innerHeight - controlsHeight; + + queueResize(); + }; + + // Then resize on each rotation button click, + // or when the system app lock/unlock the orientation + Services.obs.addObserver(function orientationChangeListener(subject) { + let screen = subject.wrappedJSObject; + let { mozOrientation, screenOrientation } = screen; + + // If we have an orientation different than the current one, + // we switch the sizes + if (screenOrientation != defaultOrientation) { + let w = width; + width = height; + height = w; + } + defaultOrientation = screenOrientation; + + queueResize(); + }, 'simulator-adjust-window-size', false); + + // Queue resize request in order to prevent race and slowdowns + // by requesting resize multiple times per loop + let resizeTimeout; + function queueResize() { + if (resizeTimeout) { + clearTimeout(resizeTimeout); + } + resizeTimeout = setTimeout(function () { + resizeTimeout = null; + resize(); + }, 0); + } + + // A utility function like console.log() for printing to the terminal window + // Uses dump(), but enables it first, if necessary + function print() { + let dump_enabled = + Services.prefs.getBoolPref('browser.dom.window.dump.enabled'); + + if (!dump_enabled) + Services.prefs.setBoolPref('browser.dom.window.dump.enabled', true); + + dump(Array.prototype.join.call(arguments, ' ') + '\n'); + + if (!dump_enabled) + Services.prefs.setBoolPref('browser.dom.window.dump.enabled', false); + } + + // Print usage info for --screen and exit + function usage() { + // Documentation for the --screen argument + let msg = + 'The --screen argument specifies the desired resolution and\n' + + 'pixel density of the simulated device screen. Use it like this:\n' + + '\t--screen=WIDTHxHEIGHT\t\t\t// E.g.: --screen=320x480\n' + + '\t--screen=WIDTHxHEIGHT@DOTS_PER_INCH\t// E.g.: --screen=480x800@250\n' + + '\t--screen=full\t\t\t\t// run in fullscreen mode\n' + + '\nYou can also specify certain device names:\n'; + for(let p in screens) + msg += '\t--screen=' + p + '\t// ' + screens[p].name + '\n'; + + // Display the usage message + print(msg); + + // Exit the b2g client + Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit); + } +} diff --git a/b2g/chrome/content/settings.js b/b2g/chrome/content/settings.js new file mode 100644 index 000000000..95921da4c --- /dev/null +++ b/b2g/chrome/content/settings.js @@ -0,0 +1,698 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +window.performance.mark('gecko-settings-loadstart'); + +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; +var Cr = Components.results; + +// The load order is important here SettingsRequestManager _must_ be loaded +// prior to using SettingsListener otherwise there is a race in acquiring the +// lock and fulfilling it. If we ever move SettingsListener or this file down in +// the load order of shell.html things will likely break. +Cu.import('resource://gre/modules/SettingsRequestManager.jsm'); +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); +Cu.import('resource://gre/modules/Services.jsm'); +Cu.import('resource://gre/modules/AppConstants.jsm'); + +const isGonk = AppConstants.platform === 'gonk'; + +if (isGonk) { + XPCOMUtils.defineLazyGetter(this, "libcutils", function () { + Cu.import("resource://gre/modules/systemlibs.js"); + return libcutils; + }); +} + +XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", + "@mozilla.org/uuid-generator;1", + "nsIUUIDGenerator"); + +// Once Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget +// is resolved this helper could be removed. +var SettingsListener = { + _callbacks: {}, + + init: function sl_init() { + if ('mozSettings' in navigator && navigator.mozSettings) { + navigator.mozSettings.onsettingchange = this.onchange.bind(this); + } + }, + + onchange: function sl_onchange(evt) { + var callback = this._callbacks[evt.settingName]; + if (callback) { + callback(evt.settingValue); + } + }, + + observe: function sl_observe(name, defaultValue, callback) { + var settings = window.navigator.mozSettings; + if (!settings) { + window.setTimeout(function() { callback(defaultValue); }); + return; + } + + if (!callback || typeof callback !== 'function') { + throw new Error('Callback is not a function'); + } + + var req = settings.createLock().get(name); + req.addEventListener('success', (function onsuccess() { + callback(typeof(req.result[name]) != 'undefined' ? + req.result[name] : defaultValue); + })); + + this._callbacks[name] = callback; + } +}; + +SettingsListener.init(); + +// =================== Mono Audio ====================== + +SettingsListener.observe('accessibility.monoaudio.enable', false, function(value) { + Services.prefs.setBoolPref('accessibility.monoaudio.enable', value); +}); + +// =================== Console ====================== + +SettingsListener.observe('debug.console.enabled', true, function(value) { + Services.prefs.setBoolPref('consoleservice.enabled', value); + Services.prefs.setBoolPref('layout.css.report_errors', value); +}); + +SettingsListener.observe('homescreen.manifestURL', 'Sentinel Value' , function(value) { + Services.prefs.setCharPref('dom.mozApps.homescreenURL', value); +}); + +// =================== Languages ==================== +SettingsListener.observe('language.current', 'en-US', function(value) { + Services.prefs.setCharPref('general.useragent.locale', value); + + let prefName = 'intl.accept_languages'; + let defaultBranch = Services.prefs.getDefaultBranch(null); + + let intl = ''; + try { + intl = defaultBranch.getComplexValue(prefName, + Ci.nsIPrefLocalizedString).data; + } catch(e) {} + + // Bug 830782 - Homescreen is in English instead of selected locale after + // the first run experience. + // In order to ensure the current intl value is reflected on the child + // process let's always write a user value, even if this one match the + // current localized pref value. + if (!((new RegExp('^' + value + '[^a-z-_] *[,;]?', 'i')).test(intl))) { + value = value + ', ' + intl; + } else { + value = intl; + } + Services.prefs.setCharPref(prefName, value); + + if (shell.hasStarted() == false) { + shell.bootstrap(); + } +}); + +// =================== RIL ==================== +(function RILSettingsToPrefs() { + // DSDS default service IDs + ['mms', 'sms', 'telephony'].forEach(function(key) { + SettingsListener.observe('ril.' + key + '.defaultServiceId', 0, + function(value) { + if (value != null) { + Services.prefs.setIntPref('dom.' + key + '.defaultServiceId', value); + } + }); + }); +})(); + +//=================== DeviceInfo ==================== +Components.utils.import('resource://gre/modules/XPCOMUtils.jsm'); +Components.utils.import('resource://gre/modules/ctypes.jsm'); +(function DeviceInfoToSettings() { + // MOZ_B2G_VERSION is set in b2g/confvars.sh, and is output as a #define value + // from configure.in, defaults to 1.0.0 if this value is not exist. + let os_version = AppConstants.MOZ_B2G_VERSION; + let os_name = AppConstants.MOZ_B2G_OS_NAME; + + let appInfo = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULAppInfo); + + // Get the hardware info and firmware revision from device properties. + let hardware_info = null; + let firmware_revision = null; + let product_manufacturer = null; + let product_model = null; + let product_device = null; + let build_number = null; + if (isGonk) { + hardware_info = libcutils.property_get('ro.hardware'); + firmware_revision = libcutils.property_get('ro.firmware_revision'); + product_manufacturer = libcutils.property_get('ro.product.manufacturer'); + product_model = libcutils.property_get('ro.product.model'); + product_device = libcutils.property_get('ro.product.device'); + build_number = libcutils.property_get('ro.build.version.incremental'); + } + + // Populate deviceinfo settings, + // copying any existing deviceinfo.os into deviceinfo.previous_os + let lock = window.navigator.mozSettings.createLock(); + let req = lock.get('deviceinfo.os'); + req.onsuccess = req.onerror = () => { + let previous_os = req.result && req.result['deviceinfo.os'] || ''; + let software = os_name + ' ' + os_version; + let setting = { + 'deviceinfo.build_number': build_number, + 'deviceinfo.os': os_version, + 'deviceinfo.previous_os': previous_os, + 'deviceinfo.software': software, + 'deviceinfo.platform_version': appInfo.platformVersion, + 'deviceinfo.platform_build_id': appInfo.platformBuildID, + 'deviceinfo.hardware': hardware_info, + 'deviceinfo.firmware_revision': firmware_revision, + 'deviceinfo.product_manufacturer': product_manufacturer, + 'deviceinfo.product_model': product_model, + 'deviceinfo.product_device': product_device + } + lock.set(setting); + } +})(); + +// =================== DevTools ==================== + +var developerHUD; +SettingsListener.observe('devtools.overlay', false, (value) => { + if (value) { + if (!developerHUD) { + let scope = {}; + Services.scriptloader.loadSubScript('chrome://b2g/content/devtools/hud.js', scope); + developerHUD = scope.developerHUD; + } + developerHUD.init(); + } else { + if (developerHUD) { + developerHUD.uninit(); + } + } +}); + +if (isGonk) { + var LogShake; + (function() { + let scope = {}; + Cu.import('resource://gre/modules/LogShake.jsm', scope); + LogShake = scope.LogShake; + LogShake.init(); + })(); + + SettingsListener.observe('devtools.logshake.enabled', false, value => { + if (value) { + LogShake.enableDeviceMotionListener(); + } else { + LogShake.disableDeviceMotionListener(); + } + }); + + SettingsListener.observe('devtools.logshake.qa_enabled', false, value => { + if (value) { + LogShake.enableQAMode(); + } else { + LogShake.disableQAMode(); + } + }); +} + +// =================== Device Storage ==================== +SettingsListener.observe('device.storage.writable.name', 'sdcard', function(value) { + if (Services.prefs.getPrefType('device.storage.writable.name') != Ci.nsIPrefBranch.PREF_STRING) { + // We clear the pref because it used to be erroneously written as a bool + // and we need to clear it before we can change it to have the correct type. + Services.prefs.clearUserPref('device.storage.writable.name'); + } + Services.prefs.setCharPref('device.storage.writable.name', value); +}); + +// =================== Privacy ==================== +SettingsListener.observe('privacy.donottrackheader.value', 1, function(value) { + Services.prefs.setIntPref('privacy.donottrackheader.value', value); + // If the user specifically disallows tracking, we set the value of + // app.update.custom (update tracking ID) to an empty string. + if (value == 1) { + Services.prefs.setCharPref('app.update.custom', ''); + return; + } + // Otherwise, we assure that the update tracking ID exists. + setUpdateTrackingId(); +}); + +// =================== Crash Reporting ==================== +SettingsListener.observe('app.reportCrashes', 'ask', function(value) { + if (value == 'always') { + Services.prefs.setBoolPref('app.reportCrashes', true); + } else if (value == 'never') { + Services.prefs.setBoolPref('app.reportCrashes', false); + } else { + Services.prefs.clearUserPref('app.reportCrashes'); + } + // This preference is consulted during startup. + Services.prefs.savePrefFile(null); +}); + +// ================ Updates ================ +/** + * For tracking purposes some partners require us to add an UUID to the + * update URL. The update tracking ID will be an empty string if the + * do-not-track feature specifically disallows tracking and it is reseted + * to a different ID if the do-not-track value changes from disallow to allow. + */ +function setUpdateTrackingId() { + try { + let dntEnabled = Services.prefs.getBoolPref('privacy.donottrackheader.enabled'); + let dntValue = Services.prefs.getIntPref('privacy.donottrackheader.value'); + // If the user specifically decides to disallow tracking (1), we just bail out. + if (dntEnabled && (dntValue == 1)) { + return; + } + + let trackingId = + Services.prefs.getPrefType('app.update.custom') == + Ci.nsIPrefBranch.PREF_STRING && + Services.prefs.getCharPref('app.update.custom'); + + // If there is no previous registered tracking ID, we generate a new one. + // This should only happen on first usage or after changing the + // do-not-track value from disallow to allow. + if (!trackingId) { + trackingId = uuidgen.generateUUID().toString().replace(/[{}]/g, ""); + Services.prefs.setCharPref('app.update.custom', trackingId); + } + } catch(e) { + dump('Error getting tracking ID ' + e + '\n'); + } +} +setUpdateTrackingId(); + +(function syncUpdatePrefs() { + // The update service reads the prefs from the default branch. This is by + // design, as explained in bug 302721 comment 43. If we are to successfully + // modify them, that's where we need to make our changes. + let defaultBranch = Services.prefs.getDefaultBranch(null); + + function syncPrefDefault(prefName) { + // The pref value at boot-time will serve as default for the setting. + let defaultValue = defaultBranch.getCharPref(prefName); + let defaultSetting = {}; + defaultSetting[prefName] = defaultValue; + + // We back up that value in order to detect pref changes across reboots. + // Such a change can happen e.g. when the user installs an OTA update that + // changes the update URL format. + let backupName = prefName + '.old'; + try { + // Everything relies on the comparison below: When pushing a new Gecko + // that changes app.update.url or app.update.channel, we overwrite any + // existing setting with the new pref value. + let backupValue = Services.prefs.getCharPref(backupName); + if (defaultValue !== backupValue) { + // If the pref has changed since our last backup, overwrite the setting. + navigator.mozSettings.createLock().set(defaultSetting); + } + } catch(e) { + // There was no backup: Overwrite the setting and create a backup below. + navigator.mozSettings.createLock().set(defaultSetting); + } + + // Initialize or update the backup value. + Services.prefs.setCharPref(backupName, defaultValue); + + // Propagate setting changes to the pref. + SettingsListener.observe(prefName, defaultValue, value => { + if (!value) { + // If the setting value is invalid, reset it to its default. + navigator.mozSettings.createLock().set(defaultSetting); + return; + } + // Here we will overwrite the pref with the setting value. + defaultBranch.setCharPref(prefName, value); + }); + } + + syncPrefDefault('app.update.url'); + syncPrefDefault('app.update.channel'); +})(); + +// ================ Debug ================ +(function Composer2DSettingToPref() { + //layers.composer.enabled can be enabled in three ways + //In order of precedence they are: + // + //1. mozSettings "layers.composer.enabled" + //2. a gecko pref "layers.composer.enabled" + //3. presence of ro.display.colorfill at the Gonk level + + var req = navigator.mozSettings.createLock().get('layers.composer2d.enabled'); + req.onsuccess = function() { + if (typeof(req.result['layers.composer2d.enabled']) === 'undefined') { + var enabled = false; + if (Services.prefs.getPrefType('layers.composer2d.enabled') == Ci.nsIPrefBranch.PREF_BOOL) { + enabled = Services.prefs.getBoolPref('layers.composer2d.enabled'); + } else if (isGonk) { + let androidVersion = libcutils.property_get("ro.build.version.sdk"); + if (androidVersion >= 17 ) { + enabled = true; + } else { + enabled = (libcutils.property_get('ro.display.colorfill') === '1'); + } + } + navigator.mozSettings.createLock().set({'layers.composer2d.enabled': enabled }); + } + + SettingsListener.observe("layers.composer2d.enabled", true, function(value) { + Services.prefs.setBoolPref("layers.composer2d.enabled", value); + }); + }; + req.onerror = function() { + dump("Error configuring layers.composer2d.enabled setting"); + }; + +})(); + +// ================ Accessibility ============ +(function setupAccessibility() { + let accessibilityScope = {}; + SettingsListener.observe("accessibility.screenreader", false, function(value) { + if (!value) { + return; + } + if (!('AccessFu' in accessibilityScope)) { + Cu.import('resource://gre/modules/accessibility/AccessFu.jsm', + accessibilityScope); + accessibilityScope.AccessFu.attach(window); + } + }); +})(); + +// ================ Theming ============ +(function themingSettingsListener() { + let themingPrefs = ['ui.menu', 'ui.menutext', 'ui.infobackground', 'ui.infotext', + 'ui.window', 'ui.windowtext', 'ui.highlight']; + + themingPrefs.forEach(function(pref) { + SettingsListener.observe('gaia.' + pref, null, function(value) { + if (value) { + Services.prefs.setCharPref(pref, value); + } + }); + }); +})(); + +// =================== Telemetry ====================== +(function setupTelemetrySettings() { + let gaiaSettingName = 'debug.performance_data.shared'; + let geckoPrefName = 'toolkit.telemetry.enabled'; + SettingsListener.observe(gaiaSettingName, null, function(value) { + if (value !== null) { + // Gaia setting has been set; update Gecko pref to that. + Services.prefs.setBoolPref(geckoPrefName, value); + return; + } + // Gaia setting has not been set; set the gaia setting to default. + let prefValue = AppConstants.MOZ_TELEMETRY_ON_BY_DEFAULT; + try { + prefValue = Services.prefs.getBoolPref(geckoPrefName); + } catch (e) { + // Pref not set; use default value. + } + let setting = {}; + setting[gaiaSettingName] = prefValue; + window.navigator.mozSettings.createLock().set(setting); + }); +})(); + +// =================== Low-precision buffer ====================== +(function setupLowPrecisionSettings() { + // The gaia setting layers.low-precision maps to two gecko prefs + SettingsListener.observe('layers.low-precision', null, function(value) { + if (value !== null) { + // Update gecko from the new Gaia setting + Services.prefs.setBoolPref('layers.low-precision-buffer', value); + Services.prefs.setBoolPref('layers.progressive-paint', value); + } else { + // Update gaia setting from gecko value + try { + let prefValue = Services.prefs.getBoolPref('layers.low-precision-buffer'); + let setting = { 'layers.low-precision': prefValue }; + window.navigator.mozSettings.createLock().set(setting); + } catch (e) { + console.log('Unable to read pref layers.low-precision-buffer: ' + e); + } + } + }); + + // The gaia setting layers.low-opacity maps to a string gecko pref (0.5/1.0) + SettingsListener.observe('layers.low-opacity', null, function(value) { + if (value !== null) { + // Update gecko from the new Gaia setting + Services.prefs.setCharPref('layers.low-precision-opacity', value ? '0.5' : '1.0'); + } else { + // Update gaia setting from gecko value + try { + let prefValue = Services.prefs.getCharPref('layers.low-precision-opacity'); + let setting = { 'layers.low-opacity': (prefValue == '0.5') }; + window.navigator.mozSettings.createLock().set(setting); + } catch (e) { + console.log('Unable to read pref layers.low-precision-opacity: ' + e); + } + } + }); +})(); + +// ======================= Dogfooders FOTA ========================== +if (AppConstants.MOZ_B2G_RIL) { + XPCOMUtils.defineLazyModuleGetter(this, "AppsUtils", + "resource://gre/modules/AppsUtils.jsm"); + + SettingsListener.observe('debug.performance_data.dogfooding', false, + isDogfooder => { + if (!isDogfooder) { + dump('AUS:Settings: Not a dogfooder!\n'); + return; + } + + if (!('mozTelephony' in navigator)) { + dump('AUS:Settings: There is no mozTelephony!\n'); + return; + } + + if (!('mozMobileConnections' in navigator)) { + dump('AUS:Settings: There is no mozMobileConnections!\n'); + return; + } + + let conn = navigator.mozMobileConnections[0]; + conn.addEventListener('radiostatechange', function onradiostatechange() { + if (conn.radioState !== 'enabled') { + return; + } + + conn.removeEventListener('radiostatechange', onradiostatechange); + navigator.mozTelephony.dial('*#06#').then(call => { + return call.result.then(res => { + if (res.success && res.statusMessage + && (res.serviceCode === 'scImei')) { + Services.prefs.setCharPref("app.update.imei_hash", + AppsUtils.computeHash(res.statusMessage, "SHA512")); + } + }); + }); + }); + }); +} + +// =================== Various simple mapping ====================== +var settingsToObserve = { + 'accessibility.screenreader_quicknav_modes': { + prefName: 'accessibility.accessfu.quicknav_modes', + resetToPref: true, + defaultValue: '' + }, + 'accessibility.screenreader_quicknav_index': { + prefName: 'accessibility.accessfu.quicknav_index', + resetToPref: true, + defaultValue: 0 + }, + 'app.update.interval': 86400, + 'apz.overscroll.enabled': true, + 'browser.safebrowsing.phishing.enabled': true, + 'browser.safebrowsing.malware.enabled': true, + 'debug.fps.enabled': { + prefName: 'layers.acceleration.draw-fps', + defaultValue: false + }, + 'debug.log-animations.enabled': { + prefName: 'layers.offmainthreadcomposition.log-animations', + defaultValue: false + }, + 'debug.paint-flashing.enabled': { + prefName: 'nglayout.debug.paint_flashing', + defaultValue: false + }, + // FIXME: Bug 1185806 - Provide a common device name setting. + // Borrow device name from developer's menu to avoid multiple name settings. + 'devtools.discovery.device': { + prefName: 'dom.presentation.device.name', + defaultValue: 'Firefox OS' + }, + 'devtools.eventlooplag.threshold': 100, + 'devtools.remote.wifi.visible': { + resetToPref: true + }, + 'devtools.telemetry.supported_performance_marks': { + resetToPref: true + }, + + 'dom.presentation.discovery.enabled': false, + 'dom.presentation.discoverable': false, + 'dom.serviceWorkers.testing.enabled': false, + 'gfx.layerscope.enabled': false, + 'layers.draw-borders': false, + 'layers.draw-tile-borders': false, + 'layers.dump': false, + 'layers.enable-tiles': AppConstants.platform !== "win", + 'layers.enable-tiles': true, + 'layers.effect.invert': false, + 'layers.effect.grayscale': false, + 'layers.effect.contrast': '0.0', + 'layout.display-list.dump': false, + 'mms.debugging.enabled': false, + 'network.debugging.enabled': false, + 'privacy.donottrackheader.enabled': false, + 'privacy.trackingprotection.enabled': false, + 'ril.debugging.enabled': false, + 'ril.radio.disabled': false, + 'ril.mms.requestReadReport.enabled': { + prefName: 'dom.mms.requestReadReport', + defaultValue: true + }, + 'ril.mms.requestStatusReport.enabled': { + prefName: 'dom.mms.requestStatusReport', + defaultValue: false + }, + 'ril.mms.retrieval_mode': { + prefName: 'dom.mms.retrieval_mode', + defaultValue: 'manual' + }, + 'ril.sms.requestStatusReport.enabled': { + prefName: 'dom.sms.requestStatusReport', + defaultValue: false + }, + 'ril.sms.strict7BitEncoding.enabled': { + prefName: 'dom.sms.strict7BitEncoding', + defaultValue: false + }, + 'ril.sms.maxReadAheadEntries': { + prefName: 'dom.sms.maxReadAheadEntries', + defaultValue: 7 + }, + 'services.sync.enabled': { + defaultValue: false, + notifyChange: true + }, + 'ui.touch.radius.leftmm': { + resetToPref: true + }, + 'ui.touch.radius.topmm': { + resetToPref: true + }, + 'ui.touch.radius.rightmm': { + resetToPref: true + }, + 'ui.touch.radius.bottommm': { + resetToPref: true + }, + 'ui.click_hold_context_menus.delay': { + resetToPref: true + }, + 'wap.UAProf.tagname': 'x-wap-profile', + 'wap.UAProf.url': '' +}; + +if (AppConstants.MOZ_GRAPHENE) { + // Restart required + settingsToObserve['layers.async-pan-zoom.enabled'] = false; +} + +function settingObserver(setPref, prefName, setting) { + return value => { + setPref(prefName, value); + if (setting.notifyChange) { + SystemAppProxy._sendCustomEvent('mozPrefChromeEvent', { + prefName: prefName, + value: value + }); + } + }; +} + +for (let key in settingsToObserve) { + let setting = settingsToObserve[key]; + + // Allow setting to contain flags redefining prefName and defaultValue. + let prefName = setting.prefName || key; + let defaultValue = setting.defaultValue; + if (defaultValue === undefined) { + defaultValue = setting; + } + + let prefs = Services.prefs; + + // If requested, reset setting value and defaultValue to the pref value. + if (setting.resetToPref) { + switch (prefs.getPrefType(prefName)) { + case Ci.nsIPrefBranch.PREF_BOOL: + defaultValue = prefs.getBoolPref(prefName); + break; + + case Ci.nsIPrefBranch.PREF_INT: + defaultValue = prefs.getIntPref(prefName); + break; + + case Ci.nsIPrefBranch.PREF_STRING: + defaultValue = prefs.getCharPref(prefName); + break; + } + + let setting = {}; + setting[key] = defaultValue; + window.navigator.mozSettings.createLock().set(setting); + } + + // Figure out the right setter function for this type of pref. + let setPref; + switch (typeof defaultValue) { + case 'boolean': + setPref = prefs.setBoolPref.bind(prefs); + break; + + case 'number': + setPref = prefs.setIntPref.bind(prefs); + break; + + case 'string': + setPref = prefs.setCharPref.bind(prefs); + break; + } + + SettingsListener.observe(key, defaultValue, + settingObserver(setPref, prefName, setting)); +}; diff --git a/b2g/chrome/content/shell.css b/b2g/chrome/content/shell.css new file mode 100644 index 000000000..34daafd99 --- /dev/null +++ b/b2g/chrome/content/shell.css @@ -0,0 +1,81 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +html { + background: black; + overflow: hidden; + width: 100%; + height: 100%; + padding: 0 !important; +} +body { + margin: 0; + width: 100%; + height: 100%; + overflow: hidden; +} +iframe { + overflow: hidden; + height: 100%; + width: 100%; + border: none; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + z-index: 1; + -moz-user-select: none; +} + +%ifdef MOZ_GRAPHENE + +body.content-loaded > #installing { + display: none; +} + +#installing { + z-index: 2; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + background-color: #F1C40F; + color: #FFF; +} + +.throbber { + width: 3px; + height: 3px; + border-radius: 100px; + background-color: #FFF; + animation-name: throbber; + animation-duration: 1500ms; + animation-iteration-count: infinite; + animation-timing-function: linear; +} + +#titlebar-buttonbox { + margin: 6px 7px; + -moz-appearance: -moz-window-button-box; +} + +@keyframes throbber{ + from { + transform: scale(0); + opacity: 0.4; + } + to { + transform: scale(400); + opacity: 0; + } +} + +%endif diff --git a/b2g/chrome/content/shell.html b/b2g/chrome/content/shell.html new file mode 100644 index 000000000..5507a65aa --- /dev/null +++ b/b2g/chrome/content/shell.html @@ -0,0 +1,66 @@ + + + + + + + + + + + +#ifndef ANDROID +#ifndef MOZ_GRAPHENE + + + + +#endif +#else + + +#endif + + + + +#ifndef MOZ_GRAPHENE +#ifdef MOZ_WIDGET_COCOA + +

wtf mac os!

+#endif +#else +
+
+
+
+
+#endif + + + diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js new file mode 100644 index 000000000..d483f9a64 --- /dev/null +++ b/b2g/chrome/content/shell.js @@ -0,0 +1,1308 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +window.performance.mark('gecko-shell-loadstart'); + +Cu.import('resource://gre/modules/NotificationDB.jsm'); +Cu.import("resource://gre/modules/AppsUtils.jsm"); +Cu.import('resource://gre/modules/UserAgentOverrides.jsm'); +Cu.import('resource://gre/modules/Keyboard.jsm'); +Cu.import('resource://gre/modules/ErrorPage.jsm'); +Cu.import('resource://gre/modules/AlertsHelper.jsm'); +Cu.import('resource://gre/modules/SystemUpdateService.jsm'); + +if (isGonk) { + Cu.import('resource://gre/modules/NetworkStatsService.jsm'); + Cu.import('resource://gre/modules/ResourceStatsService.jsm'); +} + +// Identity +Cu.import('resource://gre/modules/SignInToWebsite.jsm'); +SignInToWebsiteController.init(); + +Cu.import('resource://gre/modules/FxAccountsMgmtService.jsm'); +Cu.import('resource://gre/modules/DownloadsAPI.jsm'); +Cu.import('resource://gre/modules/PresentationDeviceInfoManager.jsm'); +Cu.import('resource://gre/modules/AboutServiceWorkers.jsm'); + +XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", + "resource://gre/modules/SystemAppProxy.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "Screenshot", + "resource://gre/modules/Screenshot.jsm"); + +XPCOMUtils.defineLazyServiceGetter(Services, 'env', + '@mozilla.org/process/environment;1', + 'nsIEnvironment'); + +XPCOMUtils.defineLazyServiceGetter(Services, 'ss', + '@mozilla.org/content/style-sheet-service;1', + 'nsIStyleSheetService'); + +XPCOMUtils.defineLazyServiceGetter(this, 'gSystemMessenger', + '@mozilla.org/system-message-internal;1', + 'nsISystemMessagesInternal'); + +XPCOMUtils.defineLazyGetter(this, "ppmm", function() { + return Cc["@mozilla.org/parentprocessmessagemanager;1"] + .getService(Ci.nsIMessageListenerManager); +}); + +if (isGonk) { + XPCOMUtils.defineLazyGetter(this, "libcutils", function () { + Cu.import("resource://gre/modules/systemlibs.js"); + return libcutils; + }); +} + +XPCOMUtils.defineLazyServiceGetter(Services, 'captivePortalDetector', + '@mozilla.org/toolkit/captive-detector;1', + 'nsICaptivePortalDetector'); + +XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing", + "resource://gre/modules/SafeBrowsing.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "SafeMode", + "resource://gre/modules/SafeMode.jsm"); + +window.performance.measure('gecko-shell-jsm-loaded', 'gecko-shell-loadstart'); + +function debug(str) { + dump(' -*- Shell.js: ' + str + '\n'); +} + +const once = event => { + let target = shell.contentBrowser; + return new Promise((resolve, reject) => { + target.addEventListener(event, function gotEvent(evt) { + target.removeEventListener(event, gotEvent, false); + resolve(evt); + }, false); + }); +} + +function clearCache() { + let cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"] + .getService(Ci.nsICacheStorageService); + cache.clear(); +} + +function clearCacheAndReload() { + // Reload the main frame with a cleared cache. + debug('Reloading ' + shell.contentBrowser.contentWindow.location); + clearCache(); + shell.contentBrowser.contentWindow.location.reload(true); + once('mozbrowserlocationchange').then( + evt => { + shell.sendEvent(window, "ContentStart"); + }); +} + +function restart() { + let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'] + .getService(Ci.nsIAppStartup); + appStartup.quit(Ci.nsIAppStartup.eForceQuit | Ci.nsIAppStartup.eRestart); +} + +function debugCrashReport(aStr) { + AppConstants.MOZ_CRASHREPORTER && dump('Crash reporter : ' + aStr); +} + +var shell = { + + get CrashSubmit() { + delete this.CrashSubmit; + if (AppConstants.MOZ_CRASHREPORTER) { + Cu.import("resource://gre/modules/CrashSubmit.jsm", this); + return this.CrashSubmit; + } else { + dump('Crash reporter : disabled at build time.'); + return this.CrashSubmit = null; + } + }, + + onlineForCrashReport: function shell_onlineForCrashReport() { + let wifiManager = navigator.mozWifiManager; + let onWifi = (wifiManager && + (wifiManager.connection.status == 'connected')); + return !Services.io.offline && onWifi; + }, + + reportCrash: function shell_reportCrash(isChrome, aCrashID) { + let crashID = aCrashID; + try { + // For chrome crashes, we want to report the lastRunCrashID. + if (isChrome) { + crashID = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime).lastRunCrashID; + } + } catch(e) { + debugCrashReport('Failed to fetch crash id. Crash ID is "' + crashID + + '" Exception: ' + e); + } + + // Bail if there isn't a valid crashID. + if (!this.CrashSubmit || !crashID && !this.CrashSubmit.pendingIDs().length) { + return; + } + + // purge the queue. + this.CrashSubmit.pruneSavedDumps(); + + // check for environment affecting crash reporting + let env = Cc["@mozilla.org/process/environment;1"] + .getService(Ci.nsIEnvironment); + let shutdown = env.get("MOZ_CRASHREPORTER_SHUTDOWN"); + if (shutdown) { + let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] + .getService(Ci.nsIAppStartup); + appStartup.quit(Ci.nsIAppStartup.eForceQuit); + } + + let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT"); + if (noReport) { + return; + } + + try { + // Check if we should automatically submit this crash. + if (Services.prefs.getBoolPref('app.reportCrashes')) { + this.submitCrash(crashID); + } else { + this.deleteCrash(crashID); + } + } catch (e) { + debugCrashReport('Can\'t fetch app.reportCrashes. Exception: ' + e); + } + + // We can get here if we're just submitting old pending crashes. + // Check that there's a valid crashID so that we only notify the + // user if a crash just happened and not when we OOM. Bug 829477 + if (crashID) { + this.sendChromeEvent({ + type: "handle-crash", + crashID: crashID, + chrome: isChrome + }); + } + }, + + deleteCrash: function shell_deleteCrash(aCrashID) { + if (aCrashID) { + debugCrashReport('Deleting pending crash: ' + aCrashID); + shell.CrashSubmit.delete(aCrashID); + } + }, + + // this function submit the pending crashes. + // make sure you are online. + submitQueuedCrashes: function shell_submitQueuedCrashes() { + // submit the pending queue. + let pending = shell.CrashSubmit.pendingIDs(); + for (let crashid of pending) { + debugCrashReport('Submitting crash: ' + crashid); + shell.CrashSubmit.submit(crashid); + } + }, + + // This function submits a crash when we're online. + submitCrash: function shell_submitCrash(aCrashID) { + if (this.onlineForCrashReport()) { + this.submitQueuedCrashes(); + return; + } + + debugCrashReport('Not online, postponing.'); + + Services.obs.addObserver(function observer(subject, topic, state) { + let network = subject.QueryInterface(Ci.nsINetworkInfo); + if (network.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED + && network.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI) { + shell.submitQueuedCrashes(); + + Services.obs.removeObserver(observer, topic); + } + }, "network-connection-state-changed", false); + }, + + get homeURL() { + try { + let homeSrc = Services.env.get('B2G_HOMESCREEN'); + if (homeSrc) + return homeSrc; + } catch (e) {} + + return Services.prefs.getCharPref('b2g.system_startup_url'); + }, + + get manifestURL() { + return Services.prefs.getCharPref('b2g.system_manifest_url'); + }, + + _started: false, + hasStarted: function shell_hasStarted() { + return this._started; + }, + + bootstrap: function() { + window.performance.mark('gecko-shell-bootstrap'); + + // Before anything, check if we want to start in safe mode. + SafeMode.check(window).then(() => { + let startManifestURL = + Cc['@mozilla.org/commandlinehandler/general-startup;1?type=b2gbootstrap'] + .getService(Ci.nsISupports).wrappedJSObject.startManifestURL; + + // If --start-manifest hasn't been specified, we re-use the latest specified manifest. + // If it's the first launch, we will fallback to b2g.default.start_manifest_url + if (AppConstants.MOZ_GRAPHENE && !startManifestURL) { + try { + startManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url"); + } catch(e) {} + } + + if (!startManifestURL) { + try { + startManifestURL = Services.prefs.getCharPref("b2g.default.start_manifest_url"); + } catch(e) {} + } + + if (startManifestURL) { + Cu.import('resource://gre/modules/Bootstraper.jsm'); + + if (AppConstants.MOZ_GRAPHENE && Bootstraper.isInstallRequired(startManifestURL)) { + // Installing the app my take some time. We don't want to keep the + // native window hidden. + showInstallScreen(); + } + + Bootstraper.ensureSystemAppInstall(startManifestURL) + .then(this.start.bind(this)) + .catch(Bootstraper.bailout); + } else { + this.start(); + } + }); + }, + + start: function shell_start() { + window.performance.mark('gecko-shell-start'); + this._started = true; + + // This forces the initialization of the cookie service before we hit the + // network. + // See bug 810209 + let cookies = Cc["@mozilla.org/cookieService;1"]; + + try { + let cr = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsICrashReporter); + // Dogfood id. We might want to remove it in the future. + // see bug 789466 + try { + let dogfoodId = Services.prefs.getCharPref('prerelease.dogfood.id'); + if (dogfoodId != "") { + cr.annotateCrashReport("Email", dogfoodId); + } + } + catch (e) { } + + if (isGonk) { + // Annotate crash report + let annotations = [ [ "Android_Hardware", "ro.hardware" ], + [ "Android_Device", "ro.product.device" ], + [ "Android_CPU_ABI2", "ro.product.cpu.abi2" ], + [ "Android_CPU_ABI", "ro.product.cpu.abi" ], + [ "Android_Manufacturer", "ro.product.manufacturer" ], + [ "Android_Brand", "ro.product.brand" ], + [ "Android_Model", "ro.product.model" ], + [ "Android_Board", "ro.product.board" ], + ]; + + annotations.forEach(function (element) { + cr.annotateCrashReport(element[0], libcutils.property_get(element[1])); + }); + + let androidVersion = libcutils.property_get("ro.build.version.sdk") + + "(" + libcutils.property_get("ro.build.version.codename") + ")"; + cr.annotateCrashReport("Android_Version", androidVersion); + + SettingsListener.observe("deviceinfo.os", "", function(value) { + try { + let cr = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsICrashReporter); + cr.annotateCrashReport("B2G_OS_Version", value); + } catch(e) { } + }); + } + } catch(e) { + debugCrashReport('exception: ' + e); + } + + let homeURL = this.homeURL; + if (!homeURL) { + let msg = 'Fatal error during startup: No homescreen found: try setting B2G_HOMESCREEN'; + alert(msg); + return; + } + + let manifestURL = this.manifestURL; + // + let systemAppFrame = + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:iframe'); + systemAppFrame.setAttribute('id', 'systemapp'); + systemAppFrame.setAttribute('mozbrowser', 'true'); + systemAppFrame.setAttribute('mozapp', manifestURL); + systemAppFrame.setAttribute('allowfullscreen', 'true'); + systemAppFrame.setAttribute('src', 'blank.html'); + let container = document.getElementById('container'); + + if (AppConstants.platform == 'macosx') { + // See shell.html + let hotfix = document.getElementById('placeholder'); + if (hotfix) { + container.removeChild(hotfix); + } + } + + this.contentBrowser = container.appendChild(systemAppFrame); + + let webNav = systemAppFrame.contentWindow + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation); + webNav.sessionHistory = Cc["@mozilla.org/browser/shistory;1"].createInstance(Ci.nsISHistory); + + if (AppConstants.MOZ_GRAPHENE) { + webNav.QueryInterface(Ci.nsIDocShell).windowDraggingAllowed = true; + } + + let audioChannels = systemAppFrame.allowedAudioChannels; + audioChannels && audioChannels.forEach(function(audioChannel) { + // Set all audio channels as unmuted by default + // because some audio in System app will be played + // before AudioChannelService[1] is Gaia is loaded. + // [1]: https://github.com/mozilla-b2g/gaia/blob/master/apps/system/js/audio_channel_service.js + audioChannel.setMuted(false); + }); + + // On firefox mulet, shell.html is loaded in a tab + // and we have to listen on the chrome event handler + // to catch key events + let chromeEventHandler = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .chromeEventHandler || window; + // Capture all key events so we can filter out hardware buttons + // And send them to Gaia via mozChromeEvents. + // Ideally, hardware buttons wouldn't generate key events at all, or + // if they did, they would use keycodes that conform to DOM 3 Events. + // See discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=762362 + chromeEventHandler.addEventListener('keydown', this, true); + chromeEventHandler.addEventListener('keyup', this, true); + + window.addEventListener('MozApplicationManifest', this); + window.addEventListener('MozAfterPaint', this); + window.addEventListener('sizemodechange', this); + window.addEventListener('unload', this); + this.contentBrowser.addEventListener('mozbrowserloadstart', this, true); + this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true); + this.contentBrowser.addEventListener('mozbrowsercaretstatechanged', this); + + CustomEventManager.init(); + UserAgentOverrides.init(); + CaptivePortalLoginHelper.init(); + + this.contentBrowser.src = homeURL; + + this._isEventListenerReady = false; + + window.performance.mark('gecko-shell-system-frame-set'); + + ppmm.addMessageListener("content-handler", this); + ppmm.addMessageListener("dial-handler", this); + ppmm.addMessageListener("sms-handler", this); + ppmm.addMessageListener("mail-handler", this); + ppmm.addMessageListener("file-picker", this); + + setTimeout(function() { + SafeBrowsing.init(); + }, 5000); + }, + + stop: function shell_stop() { + window.removeEventListener('unload', this); + window.removeEventListener('keydown', this, true); + window.removeEventListener('keyup', this, true); + window.removeEventListener('MozApplicationManifest', this); + window.removeEventListener('sizemodechange', this); + this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true); + this.contentBrowser.removeEventListener('mozbrowserscrollviewchange', this, true); + this.contentBrowser.removeEventListener('mozbrowsercaretstatechanged', this); + ppmm.removeMessageListener("content-handler", this); + + UserAgentOverrides.uninit(); + }, + + // If this key event represents a hardware button which needs to be send as + // a message, broadcasts it with the message set to 'xxx-button-press' or + // 'xxx-button-release'. + broadcastHardwareKeys: function shell_broadcastHardwareKeys(evt) { + let type; + let message; + + let mediaKeys = { + 'MediaTrackNext': 'media-next-track-button', + 'MediaTrackPrevious': 'media-previous-track-button', + 'MediaPause': 'media-pause-button', + 'MediaPlay': 'media-play-button', + 'MediaPlayPause': 'media-play-pause-button', + 'MediaStop': 'media-stop-button', + 'MediaRewind': 'media-rewind-button', + 'MediaFastForward': 'media-fast-forward-button' + }; + + if (evt.keyCode == evt.DOM_VK_F1) { + type = 'headset-button'; + message = 'headset-button'; + } else if (mediaKeys[evt.key]) { + type = 'media-button'; + message = mediaKeys[evt.key]; + } else { + return; + } + + switch (evt.type) { + case 'keydown': + message = message + '-press'; + break; + case 'keyup': + message = message + '-release'; + break; + } + + // Let applications receive the headset button and media key press/release message. + if (message !== this.lastHardwareButtonMessage) { + this.lastHardwareButtonMessage = message; + gSystemMessenger.broadcastMessage(type, message); + } + }, + + lastHardwareButtonMessage: null, // property for the hack above + visibleNormalAudioActive: false, + + handleEvent: function shell_handleEvent(evt) { + function checkReloadKey() { + if (evt.type !== 'keyup') { + return false; + } + + try { + let key = JSON.parse(Services.prefs.getCharPref('b2g.reload_key')); + return (evt.keyCode == key.key && + evt.ctrlKey == key.ctrl && + evt.altKey == key.alt && + evt.shiftKey == key.shift && + evt.metaKey == key.meta); + } catch(e) { + debug('Failed to get key: ' + e); + } + + return false; + } + + let content = this.contentBrowser.contentWindow; + switch (evt.type) { + case 'keydown': + case 'keyup': + if (checkReloadKey()) { + clearCacheAndReload(); + } else { + this.broadcastHardwareKeys(evt); + } + break; + case 'sizemodechange': + if (window.windowState == window.STATE_MINIMIZED && !this.visibleNormalAudioActive) { + this.contentBrowser.setVisible(false); + } else { + this.contentBrowser.setVisible(true); + } + break; + case 'load': + if (content.document.location == 'about:blank') { + return; + } + content.removeEventListener('load', this, true); + this.notifyContentWindowLoaded(); + break; + case 'mozbrowserloadstart': + if (content.document.location == 'about:blank') { + this.contentBrowser.addEventListener('mozbrowserlocationchange', this, true); + return; + } + + this.notifyContentStart(); + break; + case 'mozbrowserlocationchange': + if (content.document.location == 'about:blank') { + return; + } + + this.notifyContentStart(); + break; + case 'mozbrowserscrollviewchange': + this.sendChromeEvent({ + type: 'scrollviewchange', + detail: evt.detail, + }); + break; + case 'mozbrowsercaretstatechanged': + { + let elt = evt.target; + let win = elt.ownerDocument.defaultView; + let offsetX = win.mozInnerScreenX - window.mozInnerScreenX; + let offsetY = win.mozInnerScreenY - window.mozInnerScreenY; + + let rect = elt.getBoundingClientRect(); + offsetX += rect.left; + offsetY += rect.top; + + let data = evt.detail; + data.offsetX = offsetX; + data.offsetY = offsetY; + data.sendDoCommandMsg = null; + + shell.sendChromeEvent({ + type: 'caretstatechanged', + detail: data, + }); + } + break; + + case 'MozApplicationManifest': + try { + if (!Services.prefs.getBoolPref('browser.cache.offline.enable')) + return; + + let contentWindow = evt.originalTarget.defaultView; + let documentElement = contentWindow.document.documentElement; + if (!documentElement) + return; + + let manifest = documentElement.getAttribute('manifest'); + if (!manifest) + return; + + let principal = contentWindow.document.nodePrincipal; + if (Services.perms.testPermissionFromPrincipal(principal, 'offline-app') == Ci.nsIPermissionManager.UNKNOWN_ACTION) { + if (Services.prefs.getBoolPref('browser.offline-apps.notify')) { + // FIXME Bug 710729 - Add a UI for offline cache notifications + return; + } + return; + } + + Services.perms.addFromPrincipal(principal, 'offline-app', + Ci.nsIPermissionManager.ALLOW_ACTION); + + let documentURI = Services.io.newURI(contentWindow.document.documentURI, + null, + null); + let manifestURI = Services.io.newURI(manifest, null, documentURI); + let updateService = Cc['@mozilla.org/offlinecacheupdate-service;1'] + .getService(Ci.nsIOfflineCacheUpdateService); + updateService.scheduleUpdate(manifestURI, documentURI, principal, window); + } catch (e) { + dump('Error while creating offline cache: ' + e + '\n'); + } + break; + case 'MozAfterPaint': + window.removeEventListener('MozAfterPaint', this); + // This event should be sent before System app returns with + // system-message-listener-ready mozContentEvent, because it's on + // the critical launch path of the app. + SystemAppProxy._sendCustomEvent('mozChromeEvent', { + type: 'system-first-paint' + }, /* noPending */ true); + break; + case 'unload': + this.stop(); + break; + } + }, + + // Send an event to a specific window, document or element. + sendEvent: function shell_sendEvent(target, type, details) { + if (target === this.contentBrowser) { + // We must ask SystemAppProxy to send the event in this case so + // that event would be dispatched from frame.contentWindow instead of + // on the System app frame. + SystemAppProxy._sendCustomEvent(type, details); + return; + } + + let doc = target.document || target.ownerDocument || target; + let event = doc.createEvent('CustomEvent'); + event.initCustomEvent(type, true, true, details ? details : {}); + target.dispatchEvent(event); + }, + + sendCustomEvent: function shell_sendCustomEvent(type, details) { + SystemAppProxy._sendCustomEvent(type, details); + }, + + sendChromeEvent: function shell_sendChromeEvent(details) { + this.sendCustomEvent("mozChromeEvent", details); + }, + + receiveMessage: function shell_receiveMessage(message) { + var activities = { 'content-handler': { name: 'view', response: null }, + 'dial-handler': { name: 'dial', response: null }, + 'mail-handler': { name: 'new', response: null }, + 'sms-handler': { name: 'new', response: null }, + 'file-picker': { name: 'pick', response: 'file-picked' } }; + + if (!(message.name in activities)) + return; + + let data = message.data; + let activity = activities[message.name]; + + let a = new MozActivity({ + name: activity.name, + data: data + }); + + if (activity.response) { + a.onsuccess = function() { + let sender = message.target.QueryInterface(Ci.nsIMessageSender); + sender.sendAsyncMessage(activity.response, { success: true, + result: a.result }); + } + a.onerror = function() { + let sender = message.target.QueryInterface(Ci.nsIMessageSender); + sender.sendAsyncMessage(activity.response, { success: false }); + } + } + }, + + notifyContentStart: function shell_notifyContentStart() { + window.performance.mark('gecko-shell-notify-content-start'); + this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true); + this.contentBrowser.removeEventListener('mozbrowserlocationchange', this, true); + + let content = this.contentBrowser.contentWindow; + content.addEventListener('load', this, true); + + this.reportCrash(true); + + SystemAppProxy.registerFrame(shell.contentBrowser); + + this.sendEvent(window, 'ContentStart'); + + Services.obs.notifyObservers(null, 'content-start', null); + + if (AppConstants.MOZ_GRAPHENE && + Services.prefs.getBoolPref("b2g.nativeWindowGeometry.fullscreen")) { + window.fullScreen = true; + } + + shell.handleCmdLine(); + }, + + handleCmdLine: function() { + // This isn't supported on devices. + if (!isGonk) { + let b2gcmds = Cc["@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds"] + .getService(Ci.nsISupports); + let args = b2gcmds.wrappedJSObject.cmdLine; + try { + // Returns null if -url is not present. + let url = args.handleFlagWithParam("url", false); + if (url) { + this.sendChromeEvent({type: "mozbrowseropenwindow", url}); + args.preventDefault = true; + } + } catch(e) { + // Throws if -url is present with no params. + } + } + }, + + // This gets called when window.onload fires on the System app content window, + // which means things in are parsed and statically referenced + + + + diff --git a/b2g/chrome/content/shell_remote.js b/b2g/chrome/content/shell_remote.js new file mode 100644 index 000000000..1f1115ef0 --- /dev/null +++ b/b2g/chrome/content/shell_remote.js @@ -0,0 +1,139 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +var {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/SystemAppProxy.jsm"); + +function debug(aStr) { + // dump(" -*- ShellRemote.js: " + aStr + "\n"); +} + +var remoteShell = { + + _started: false, + + get homeURL() { + let systemAppManifestURL = Services.io.newURI(this.systemAppManifestURL, null, null); + let shellRemoteURL = Services.prefs.getCharPref("b2g.multiscreen.system_remote_url"); + shellRemoteURL = Services.io.newURI(shellRemoteURL, null, systemAppManifestURL); + return shellRemoteURL.spec; + }, + + get systemAppManifestURL() { + return Services.prefs.getCharPref("b2g.system_manifest_url"); + }, + + hasStarted: function () { + return this._started; + }, + + start: function () { + this._started = true; + this._isEventListenerReady = false; + this.id = window.location.hash.substring(1); + + let homeURL = this.homeURL; + if (!homeURL) { + debug("ERROR! Remote home URL undefined."); + return; + } + let manifestURL = this.systemAppManifestURL; + // + let systemAppFrame = + document.createElementNS("http://www.w3.org/1999/xhtml", "html:iframe"); + systemAppFrame.setAttribute("id", this.id); + systemAppFrame.setAttribute("mozbrowser", "true"); + systemAppFrame.setAttribute("mozapp", manifestURL); + systemAppFrame.setAttribute("allowfullscreen", "true"); + systemAppFrame.setAttribute("src", "blank.html"); + + let container = document.getElementById("container"); + this.contentBrowser = container.appendChild(systemAppFrame); + this.contentBrowser.src = homeURL + window.location.hash; + + window.addEventListener("unload", this); + this.contentBrowser.addEventListener("mozbrowserloadstart", this); + }, + + stop: function () { + window.removeEventListener("unload", this); + this.contentBrowser.removeEventListener("mozbrowserloadstart", this); + this.contentBrowser.removeEventListener("mozbrowserlocationchange", this, true); + SystemAppProxy.unregisterFrameWithId(this.id); + }, + + notifyContentStart: function(evt) { + this.contentBrowser.removeEventListener("mozbrowserloadstart", this); + this.contentBrowser.removeEventListener("mozbrowserlocationchange", this, true); + + SystemAppProxy.registerFrameWithId(remoteShell.id, remoteShell.contentBrowser); + SystemAppProxy.addEventListenerWithId(this.id, "mozContentEvent", this); + + let content = this.contentBrowser.contentWindow; + content.addEventListener("load", this, true); + }, + + notifyContentWindowLoaded: function () { + SystemAppProxy.setIsLoadedWithId(this.id); + }, + + notifyEventListenerReady: function () { + if (this._isEventListenerReady) { + Cu.reportError("shell_remote.js: SystemApp has already been declared as being ready."); + return; + } + this._isEventListenerReady = true; + SystemAppProxy.setIsReadyWithId(this.id); + }, + + handleEvent: function(evt) { + debug("Got an event: " + evt.type); + let content = this.contentBrowser.contentWindow; + + switch(evt.type) { + case "mozContentEvent": + if (evt.detail.type === "system-message-listener-ready") { + this.notifyEventListenerReady(); + } + break; + case "load": + if (content.document.location == "about:blank") { + return; + } + content.removeEventListener("load", this, true); + this.notifyContentWindowLoaded(); + break; + case "mozbrowserloadstart": + if (content.document.location == "about:blank") { + this.contentBrowser.addEventListener("mozbrowserlocationchange", this, true); + return; + } + case "mozbrowserlocationchange": + if (content.document.location == "about:blank") { + return; + } + this.notifyContentStart(); + break; + case "unload": + this.stop(); + break; + } + } +}; + +window.onload = function() { + if (remoteShell.hasStarted() == false) { + remoteShell.start(); + } +}; + diff --git a/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js b/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js new file mode 100644 index 000000000..1a5ed8274 --- /dev/null +++ b/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js @@ -0,0 +1,40 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; +const { Services } = Cu.import('resource://gre/modules/Services.jsm'); +const { SystemAppProxy } = Cu.import('resource://gre/modules/SystemAppProxy.jsm'); + +var processId; + +function peekChildId(aSubject, aTopic, aData) { + Services.obs.removeObserver(peekChildId, 'recording-device-events'); + Services.obs.removeObserver(peekChildId, 'recording-device-ipc-events'); + let props = aSubject.QueryInterface(Ci.nsIPropertyBag2); + if (props.hasKey('childID')) { + processId = props.get('childID'); + } +} + +addMessageListener('init-chrome-event', function(message) { + // listen mozChromeEvent and forward to content process. + let type = message.type; + SystemAppProxy.addEventListener('mozChromeEvent', function(event) { + let details = event.detail; + if (details.type === type) { + sendAsyncMessage('chrome-event', details); + } + }, true); + + Services.obs.addObserver(peekChildId, 'recording-device-events', false); + Services.obs.addObserver(peekChildId, 'recording-device-ipc-events', false); +}); + +addMessageListener('fake-content-shutdown', function(message) { + let props = Cc["@mozilla.org/hash-property-bag;1"] + .createInstance(Ci.nsIWritablePropertyBag2); + if (processId) { + props.setPropertyAsUint64('childID', processId); + } + Services.obs.notifyObservers(props, 'recording-device-ipc-events', 'content-shutdown'); +}); diff --git a/b2g/chrome/content/test/mochitest/RecordingStatusHelper.js b/b2g/chrome/content/test/mochitest/RecordingStatusHelper.js new file mode 100644 index 000000000..5e3e6814e --- /dev/null +++ b/b2g/chrome/content/test/mochitest/RecordingStatusHelper.js @@ -0,0 +1,82 @@ +'use strict'; + +// resolve multiple promise in parallel +function expectAll(aValue) { + let deferred = new Promise(function(resolve, reject) { + let countdown = aValue.length; + let resolutionValues = new Array(countdown); + + for (let i = 0; i < aValue.length; i++) { + let index = i; + aValue[i].then(function(val) { + resolutionValues[index] = val; + if (--countdown === 0) { + resolve(resolutionValues); + } + }, reject); + } + }); + + return deferred; +} + +function TestInit() { + let url = SimpleTest.getTestFileURL("RecordingStatusChromeScript.js") + let script = SpecialPowers.loadChromeScript(url); + + let helper = { + finish: function () { + script.destroy(); + }, + fakeShutdown: function () { + script.sendAsyncMessage('fake-content-shutdown', {}); + } + }; + + script.addMessageListener('chrome-event', function (message) { + if (helper.hasOwnProperty('onEvent')) { + helper.onEvent(message); + } else { + ok(false, 'unexpected message: ' + JSON.stringify(message)); + } + }); + + script.sendAsyncMessage("init-chrome-event", { + type: 'recording-status' + }); + + return Promise.resolve(helper); +} + +function expectEvent(expected, eventHelper) { + return new Promise(function(resolve, reject) { + eventHelper.onEvent = function(message) { + delete eventHelper.onEvent; + ok(message, JSON.stringify(message)); + is(message.type, 'recording-status', 'event type: ' + message.type); + is(message.active, expected.active, 'recording active: ' + message.active); + is(message.isAudio, expected.isAudio, 'audio recording active: ' + message.isAudio); + is(message.isVideo, expected.isVideo, 'video recording active: ' + message.isVideo); + resolve(eventHelper); + }; + info('waiting for recording-status'); + }); +} + +function expectStream(params, callback) { + return new Promise(function(resolve, reject) { + var req = navigator.mozGetUserMedia( + params, + function(stream) { + ok(true, 'create media stream'); + callback(stream); + resolve(); + }, + function(err) { + ok(false, 'fail to create media stream'); + reject(err); + } + ); + info('waiting for gUM result'); + }); +} diff --git a/b2g/chrome/content/test/mochitest/file_getusermedia_iframe.html b/b2g/chrome/content/test/mochitest/file_getusermedia_iframe.html new file mode 100644 index 000000000..f2b18eab3 --- /dev/null +++ b/b2g/chrome/content/test/mochitest/file_getusermedia_iframe.html @@ -0,0 +1,36 @@ + + + + Iframe for Recording Status + + + + + + +
+
+
+ + diff --git a/b2g/chrome/content/test/mochitest/mochitest.ini b/b2g/chrome/content/test/mochitest/mochitest.ini new file mode 100644 index 000000000..d18a20401 --- /dev/null +++ b/b2g/chrome/content/test/mochitest/mochitest.ini @@ -0,0 +1,11 @@ +[DEFAULT] +skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #require OOP support for mochitest-b2g-desktop, Bug 957554 +support-files = + RecordingStatusChromeScript.js + RecordingStatusHelper.js + file_getusermedia_iframe.html + +[test_recordingStatus_basic.html] +[test_recordingStatus_multiple_requests.html] +[test_recordingStatus_iframe.html] +[test_recordingStatus_kill_content_process.html] diff --git a/b2g/chrome/content/test/mochitest/moz.build b/b2g/chrome/content/test/mochitest/moz.build new file mode 100644 index 000000000..3b13ba431 --- /dev/null +++ b/b2g/chrome/content/test/mochitest/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +MOCHITEST_MANIFESTS += ['mochitest.ini'] diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_basic.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_basic.html new file mode 100644 index 000000000..21f746d33 --- /dev/null +++ b/b2g/chrome/content/test/mochitest/test_recordingStatus_basic.html @@ -0,0 +1,119 @@ + + + + Test for Recording Status + + + + + + +
+
+
+ + diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_iframe.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_iframe.html new file mode 100644 index 000000000..88c33c897 --- /dev/null +++ b/b2g/chrome/content/test/mochitest/test_recordingStatus_iframe.html @@ -0,0 +1,71 @@ + + + + Test for Recording Status in iframe + + + + + + +
+
+
+
+ + diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_kill_content_process.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_kill_content_process.html new file mode 100644 index 000000000..239c2c2d5 --- /dev/null +++ b/b2g/chrome/content/test/mochitest/test_recordingStatus_kill_content_process.html @@ -0,0 +1,72 @@ + + + + Test for Recording Status after process shutdown + + + + + + +
+
+
+ + diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_multiple_requests.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_multiple_requests.html new file mode 100644 index 000000000..7d31a94f8 --- /dev/null +++ b/b2g/chrome/content/test/mochitest/test_recordingStatus_multiple_requests.html @@ -0,0 +1,108 @@ + + + + Test for Recording Status with multiple gUM requests + + + + + + +
+
+
+ + diff --git a/b2g/chrome/content/touchcontrols.css b/b2g/chrome/content/touchcontrols.css new file mode 100644 index 000000000..7c407c331 --- /dev/null +++ b/b2g/chrome/content/touchcontrols.css @@ -0,0 +1,233 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul); + +/* video controls */ +.controlsOverlay { + -moz-box-pack: center; + -moz-box-align: end; + -moz-box-flex: 1; + -moz-box-orient: horizontal; +} + +.controlsOverlay[scaled] { + /* scaled attribute in videocontrols.css causes conflict + due to different -moz-box-orient values */ + -moz-box-align: end; +} + +.controlBar { + -moz-box-flex: 1; + background-color: rgba(50,50,50,0.8); + width: 100%; +} + +.buttonsBar { + -moz-box-flex: 1; + -moz-box-align: center; +} + +.controlsSpacer { + display: none; + -moz-box-flex: 0; +} + +.fullscreenButton, +.playButton, +.castingButton, +.muteButton { + -moz-appearance: none; + padding: 2px; + border: none !important; + min-height: 24px; + min-width: 24px; +} + +.fullscreenButton { + background: url("chrome://b2g/content/images/fullscreen-hdpi.png") no-repeat center; + background-size: contain; + background-origin: content-box; +} + +.fullscreenButton[fullscreened="true"] { + background: url("chrome://b2g/content/images/exitfullscreen-hdpi.png") no-repeat center; + background-size: contain; + background-origin: content-box; +} + +.controlBar[fullscreen-unavailable] .fullscreenButton { + display: none; +} + +.playButton { + background: url("chrome://b2g/content/images/pause-hdpi.png") no-repeat center; + background-size: contain; + background-origin: content-box; +} + +/* + * Normally the button bar has fullscreen spacer play spacer mute, but if + * this is an audio control rather than a video control, the fullscreen button + * is hidden by videocontrols.xml, and that alters the position of the + * play button. This workaround moves it back to center. + */ +.controlBar[fullscreen-unavailable] .playButton { + transform: translateX(28px); +} + +.playButton[paused="true"] { + background: url("chrome://b2g/content/images/play-hdpi.png") no-repeat center; + background-size: contain; + background-origin: content-box; +} + +.castingButton { + display: none; +} + +.muteButton { + background: url("chrome://b2g/content/images/mute-hdpi.png") no-repeat center; + background-size: contain; + background-origin: content-box; +} + +.muteButton[muted="true"] { + background: url("chrome://b2g/content/images/unmute-hdpi.png") no-repeat center; + background-size: contain; + background-origin: content-box; +} + +/* bars */ +.scrubberStack { + -moz-box-flex: 1; + padding: 0px 18px; +} + +.flexibleBar, +.flexibleBar .progress-bar, +.bufferBar, +.bufferBar .progress-bar, +.progressBar, +.progressBar .progress-bar, +.scrubber, +.scrubber .scale-slider, +.scrubber .scale-thumb { + -moz-appearance: none; + border: none; + padding: 0px; + margin: 0px; + background-color: transparent; +} + +.flexibleBar, +.bufferBar, +.progressBar { + height: 24px; + padding: 11px 0px; +} + +.flexibleBar { + padding: 12px 0px; +} + +.flexibleBar .progress-bar { + border: 1px #777777 solid; + border-radius: 1px; +} + +.bufferBar .progress-bar { + border: 2px #AFB1B3 solid; + border-radius: 2px; +} + +.progressBar .progress-bar { + border: 2px #FF9500 solid; + border-radius: 2px; +} + + +.scrubber { + margin-left: -8px; + margin-right: -8px; +} + +.positionLabel, .durationLabel { + font-family: 'Roboto', Helvetica, Arial, sans-serif; + font-size: 12px; + color: white; +} + +.scrubber .scale-thumb { + display: -moz-box; + margin: 0px !important; + padding: 0px !important; + background: url("chrome://b2g/content/images/scrubber-hdpi.png") no-repeat; + background-size: 12px 12px; + height: 12px; + width: 12px; +} + +.statusOverlay { + -moz-box-align: center; + -moz-box-pack: center; + background-color: rgb(50,50,50); +} + +.statusIcon { + margin-bottom: 28px; + width: 36px; + height: 36px; +} + +.statusIcon[type="throbber"] { + background: url("chrome://b2g/content/images/throbber.png") no-repeat center; +} + +.statusIcon[type="error"] { + background: url("chrome://b2g/content/images/error.png") no-repeat center; +} + +/* CSS Transitions */ +.controlBar:not([immediate]) { + transition-property: opacity; + transition-duration: 200ms; +} + +.controlBar[fadeout] { + opacity: 0; +} + +.statusOverlay:not([immediate]) { + transition-property: opacity; + transition-duration: 300ms; + transition-delay: 750ms; +} + +.statusOverlay[fadeout] { + opacity: 0; +} + +.volumeStack, +.controlBar[firstshow="true"] .fullscreenButton, +.controlBar[firstshow="true"] .muteButton, +.controlBar[firstshow="true"] .scrubberStack, +.controlBar[firstshow="true"] .durationBox, +.timeLabel { + display: none; +} + +/* Error description formatting */ +.errorLabel { + font-family: Helvetica, Arial, sans-serif; + font-size: 11px; + color: #bbb; + text-shadow: + -1px -1px 0 #000, + 1px -1px 0 #000, + -1px 1px 0 #000, + 1px 1px 0 #000; + padding: 0 10px; + text-align: center; +} diff --git a/b2g/chrome/jar.mn b/b2g/chrome/jar.mn new file mode 100644 index 000000000..1fdea9a50 --- /dev/null +++ b/b2g/chrome/jar.mn @@ -0,0 +1,60 @@ +#filter substitution +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +chrome.jar: +% content branding %content/branding/ contentaccessible=yes +% content b2g %content/ + + content/arrow.svg (content/arrow.svg) + content/settings.js (content/settings.js) +* content/shell.html (content/shell.html) + content/shell.js (content/shell.js) + content/shell_remote.html (content/shell_remote.html) + content/shell_remote.js (content/shell_remote.js) +* content/shell.css (content/shell.css) + content/blank.html (content/blank.html) + content/blank.css (content/blank.css) +#ifdef MOZ_WIDGET_GONK + content/devtools/adb.js (content/devtools/adb.js) +#endif + content/devtools/debugger.js (content/devtools/debugger.js) + content/devtools/hud.js (content/devtools/hud.js) +#ifndef MOZ_WIDGET_GONK + content/desktop.css (content/desktop.css) + content/images/desktop/home-black.png (content/images/desktop/home-black.png) + content/images/desktop/home-white.png (content/images/desktop/home-white.png) + content/images/desktop/rotate.png (content/images/desktop/rotate.png) + content/desktop.js (content/desktop.js) + content/screen.js (content/screen.js) +#endif +* content/content.css (content/content.css) + content/touchcontrols.css (content/touchcontrols.css) + + content/identity.js (content/identity.js) + +#ifndef MOZ_GRAPHENE +% override chrome://global/skin/media/videocontrols.css chrome://b2g/content/touchcontrols.css +#endif +% override chrome://global/content/aboutCertError.xhtml chrome://b2g/content/aboutCertError.xhtml +% override chrome://global/skin/netError.css chrome://b2g/content/netError.css + + content/ErrorPage.js (content/ErrorPage.js) + content/aboutCertError.xhtml (content/aboutCertError.xhtml) + content/netError.css (content/netError.css) + content/images/errorpage-larry-black.png (content/images/errorpage-larry-black.png) + content/images/errorpage-larry-white.png (content/images/errorpage-larry-white.png) + content/images/errorpage-warning.png (content/images/errorpage-warning.png) + content/images/arrowdown-16.png (content/images/arrowdown-16.png) + content/images/arrowright-16.png (content/images/arrowright-16.png) + content/images/scrubber-hdpi.png (content/images/scrubber-hdpi.png) + content/images/unmute-hdpi.png (content/images/unmute-hdpi.png) + content/images/pause-hdpi.png (content/images/pause-hdpi.png) + content/images/play-hdpi.png (content/images/play-hdpi.png) + content/images/mute-hdpi.png (content/images/mute-hdpi.png) + content/images/fullscreen-hdpi.png (content/images/fullscreen-hdpi.png) + content/images/exitfullscreen-hdpi.png (content/images/exitfullscreen-hdpi.png) + content/images/throbber.png (content/images/throbber.png) + content/images/error.png (content/images/error.png) diff --git a/b2g/chrome/moz.build b/b2g/chrome/moz.build new file mode 100644 index 000000000..99af44a5c --- /dev/null +++ b/b2g/chrome/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DEFINES['AB_CD'] = CONFIG['MOZ_UI_LOCALE'] +DEFINES['PACKAGE'] = 'b2g' +DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] + +JAR_MANIFESTS += ['jar.mn'] + +TEST_DIRS += ['content/test/mochitest'] diff --git a/b2g/common.configure b/b2g/common.configure new file mode 100644 index 000000000..854de4b15 --- /dev/null +++ b/b2g/common.configure @@ -0,0 +1,32 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Truetype fonts for B2G +# ============================================================== +option(env='MOZTTDIR', nargs=1, help='Path to truetype fonts for B2G') + +@depends('MOZTTDIR') +@imports('os') +def mozttdir(value): + if value: + path = value[0] + if not os.path.isdir(path): + die('MOZTTDIR "%s" is not a valid directory', path) + return path + +set_config('MOZTTDIR', mozttdir) + +@depends('MOZTTDIR') +def package_moztt(value): + if value: + return True + +set_define('PACKAGE_MOZTT', package_moztt) + +imply_option('MOZ_ENABLE_WARNINGS_AS_ERRORS', + depends(target)(lambda t: t.os == 'Android'), reason='--target') + +include('../toolkit/moz.configure') diff --git a/b2g/components/AboutServiceWorkers.jsm b/b2g/components/AboutServiceWorkers.jsm new file mode 100644 index 000000000..fe67e9c34 --- /dev/null +++ b/b2g/components/AboutServiceWorkers.jsm @@ -0,0 +1,183 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict" + +this.EXPORTED_SYMBOLS = ["AboutServiceWorkers"]; + +const { interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", + "resource://gre/modules/SystemAppProxy.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "gServiceWorkerManager", + "@mozilla.org/serviceworkers/manager;1", + "nsIServiceWorkerManager"); + +function debug(aMsg) { + dump("AboutServiceWorkers - " + aMsg + "\n"); +} + +function serializeServiceWorkerInfo(aServiceWorkerInfo) { + if (!aServiceWorkerInfo) { + throw new Error("Invalid service worker information"); + } + + let result = {}; + + result.principal = { + origin: aServiceWorkerInfo.principal.originNoSuffix, + originAttributes: aServiceWorkerInfo.principal.originAttributes + }; + + ["scope", "scriptSpec"].forEach(property => { + result[property] = aServiceWorkerInfo[property]; + }); + + return result; +} + + +this.AboutServiceWorkers = { + get enabled() { + if (this._enabled) { + return this._enabled; + } + this._enabled = false; + try { + this._enabled = Services.prefs.getBoolPref("dom.serviceWorkers.enabled"); + } catch(e) {} + return this._enabled; + }, + + init: function() { + SystemAppProxy.addEventListener("mozAboutServiceWorkersContentEvent", + AboutServiceWorkers); + }, + + sendResult: function(aId, aResult) { + SystemAppProxy._sendCustomEvent("mozAboutServiceWorkersChromeEvent", { + id: aId, + result: aResult + }); + }, + + sendError: function(aId, aError) { + SystemAppProxy._sendCustomEvent("mozAboutServiceWorkersChromeEvent", { + id: aId, + error: aError + }); + }, + + handleEvent: function(aEvent) { + let message = aEvent.detail; + + debug("Got content event " + JSON.stringify(message)); + + if (!message.id || !message.name) { + dump("Invalid event " + JSON.stringify(message) + "\n"); + return; + } + + let self = AboutServiceWorkers; + + switch(message.name) { + case "init": + if (!self.enabled) { + self.sendResult(message.id, { + enabled: false, + registrations: [] + }); + return; + }; + + let data = gServiceWorkerManager.getAllRegistrations(); + if (!data) { + self.sendError(message.id, "NoServiceWorkersRegistrations"); + return; + } + + let registrations = []; + + for (let i = 0; i < data.length; i++) { + let info = data.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo); + if (!info) { + dump("AboutServiceWorkers: Invalid nsIServiceWorkerRegistrationInfo " + + "interface.\n"); + continue; + } + registrations.push(serializeServiceWorkerInfo(info)); + } + + self.sendResult(message.id, { + enabled: self.enabled, + registrations: registrations + }); + break; + + case "update": + if (!message.scope) { + self.sendError(message.id, "MissingScope"); + return; + } + + if (!message.principal || + !message.principal.originAttributes) { + self.sendError(message.id, "MissingOriginAttributes"); + return; + } + + gServiceWorkerManager.propagateSoftUpdate( + message.principal.originAttributes, + message.scope + ); + + self.sendResult(message.id, true); + break; + + case "unregister": + if (!message.principal || + !message.principal.origin || + !message.principal.originAttributes || + !message.principal.originAttributes.appId || + (message.principal.originAttributes.inIsolatedMozBrowser == null)) { + self.sendError(message.id, "MissingPrincipal"); + return; + } + + let principal = Services.scriptSecurityManager.createCodebasePrincipal( + // TODO: Bug 1196652. use originNoSuffix + Services.io.newURI(message.principal.origin, null, null), + message.principal.originAttributes); + + if (!message.scope) { + self.sendError(message.id, "MissingScope"); + return; + } + + let serviceWorkerUnregisterCallback = { + unregisterSucceeded: function() { + self.sendResult(message.id, true); + }, + + unregisterFailed: function() { + self.sendError(message.id, "UnregisterError"); + }, + + QueryInterface: XPCOMUtils.generateQI([ + Ci.nsIServiceWorkerUnregisterCallback + ]) + }; + gServiceWorkerManager.propagateUnregister(principal, + serviceWorkerUnregisterCallback, + message.scope); + break; + } + } +}; + +AboutServiceWorkers.init(); diff --git a/b2g/components/ActivityChannel.jsm b/b2g/components/ActivityChannel.jsm new file mode 100644 index 000000000..9dfa13d67 --- /dev/null +++ b/b2g/components/ActivityChannel.jsm @@ -0,0 +1,64 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); + +XPCOMUtils.defineLazyServiceGetter(this, "cpmm", + "@mozilla.org/childprocessmessagemanager;1", + "nsIMessageSender"); + +XPCOMUtils.defineLazyServiceGetter(this, "contentSecManager", + "@mozilla.org/contentsecuritymanager;1", + "nsIContentSecurityManager"); + +this.EXPORTED_SYMBOLS = ["ActivityChannel"]; + +this.ActivityChannel = function(aURI, aLoadInfo, aName, aDetails) { + this._activityName = aName; + this._activityDetails = aDetails; + this.originalURI = aURI; + this.URI = aURI; + this.loadInfo = aLoadInfo; +} + +this.ActivityChannel.prototype = { + originalURI: null, + URI: null, + owner: null, + notificationCallbacks: null, + securityInfo: null, + contentType: null, + contentCharset: null, + contentLength: 0, + contentDisposition: Ci.nsIChannel.DISPOSITION_INLINE, + contentDispositionFilename: null, + contentDispositionHeader: null, + loadInfo: null, + + open: function() { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + + open2: function() { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + + asyncOpen: function(aListener, aContext) { + cpmm.sendAsyncMessage(this._activityName, this._activityDetails); + // Let the listener cleanup. + aListener.onStopRequest(this, aContext, Cr.NS_OK); + }, + + asyncOpen2: function(aListener) { + // throws an error if security checks fail + var outListener = contentSecManager.performSecurityCheck(this, aListener); + this.asyncOpen(outListener, null); + }, + + QueryInterface2: XPCOMUtils.generateQI([Ci.nsIChannel]) +} diff --git a/b2g/components/AlertsHelper.jsm b/b2g/components/AlertsHelper.jsm new file mode 100644 index 000000000..820f2406c --- /dev/null +++ b/b2g/components/AlertsHelper.jsm @@ -0,0 +1,279 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = []; + +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cc = Components.classes; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AppsUtils.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", + "@mozilla.org/system-message-internal;1", + "nsISystemMessagesInternal"); + +XPCOMUtils.defineLazyServiceGetter(this, "appsService", + "@mozilla.org/AppsService;1", + "nsIAppsService"); + +XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", + "resource://gre/modules/SystemAppProxy.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "notificationStorage", + "@mozilla.org/notificationStorage;1", + "nsINotificationStorage"); + +XPCOMUtils.defineLazyGetter(this, "ppmm", function() { + return Cc["@mozilla.org/parentprocessmessagemanager;1"] + .getService(Ci.nsIMessageListenerManager); +}); + +function debug(str) { + //dump("=*= AlertsHelper.jsm : " + str + "\n"); +} + +const kNotificationIconSize = 128; + +const kDesktopNotificationPerm = "desktop-notification"; + +const kNotificationSystemMessageName = "notification"; + +const kDesktopNotification = "desktop-notification"; +const kDesktopNotificationShow = "desktop-notification-show"; +const kDesktopNotificationClick = "desktop-notification-click"; +const kDesktopNotificationClose = "desktop-notification-close"; + +const kTopicAlertClickCallback = "alertclickcallback"; +const kTopicAlertShow = "alertshow"; +const kTopicAlertFinished = "alertfinished"; + +const kMozChromeNotificationEvent = "mozChromeNotificationEvent"; +const kMozContentNotificationEvent = "mozContentNotificationEvent"; + +const kMessageAlertNotificationSend = "alert-notification-send"; +const kMessageAlertNotificationClose = "alert-notification-close"; + +const kMessages = [ + kMessageAlertNotificationSend, + kMessageAlertNotificationClose +]; + +var AlertsHelper = { + + _listeners: {}, + + init: function() { + Services.obs.addObserver(this, "xpcom-shutdown", false); + for (let message of kMessages) { + ppmm.addMessageListener(message, this); + } + SystemAppProxy.addEventListener(kMozContentNotificationEvent, this); + }, + + observe: function(aSubject, aTopic, aData) { + switch (aTopic) { + case "xpcom-shutdown": + Services.obs.removeObserver(this, "xpcom-shutdown"); + for (let message of kMessages) { + ppmm.removeMessageListener(message, this); + } + SystemAppProxy.removeEventListener(kMozContentNotificationEvent, this); + break; + } + }, + + handleEvent: function(evt) { + let detail = evt.detail; + + switch(detail.type) { + case kDesktopNotificationShow: + case kDesktopNotificationClick: + case kDesktopNotificationClose: + this.handleNotificationEvent(detail); + break; + default: + debug("FIXME: Unhandled notification event: " + detail.type); + break; + } + }, + + handleNotificationEvent: function(detail) { + if (!detail || !detail.id) { + return; + } + + let uid = detail.id; + let listener = this._listeners[uid]; + if (!listener) { + return; + } + + let topic; + if (detail.type === kDesktopNotificationClick) { + topic = kTopicAlertClickCallback; + } else if (detail.type === kDesktopNotificationShow) { + topic = kTopicAlertShow; + } else { + /* kDesktopNotificationClose */ + topic = kTopicAlertFinished; + } + + if (listener.cookie) { + try { + listener.observer.observe(null, topic, listener.cookie); + } catch (e) { } + } else { + if (detail.type === kDesktopNotificationClose && listener.dbId) { + notificationStorage.delete(listener.manifestURL, listener.dbId); + } + } + + // we"re done with this notification + if (detail.type === kDesktopNotificationClose) { + delete this._listeners[uid]; + } + }, + + registerListener: function(alertId, cookie, alertListener) { + this._listeners[alertId] = { observer: alertListener, cookie: cookie }; + }, + + registerAppListener: function(uid, listener) { + this._listeners[uid] = listener; + + appsService.getManifestFor(listener.manifestURL).then((manifest) => { + let app = appsService.getAppByManifestURL(listener.manifestURL); + let helper = new ManifestHelper(manifest, app.origin, app.manifestURL); + let getNotificationURLFor = function(messages) { + if (!messages) { + return null; + } + + for (let i = 0; i < messages.length; i++) { + let message = messages[i]; + if (message === kNotificationSystemMessageName) { + return helper.fullLaunchPath(); + } else if (typeof message === "object" && + kNotificationSystemMessageName in message) { + return helper.resolveURL(message[kNotificationSystemMessageName]); + } + } + + // No message found... + return null; + } + + listener.target = getNotificationURLFor(manifest.messages); + + // Bug 816944 - Support notification messages for entry_points. + }); + }, + + deserializeStructuredClone: function(dataString) { + if (!dataString) { + return null; + } + let scContainer = Cc["@mozilla.org/docshell/structured-clone-container;1"]. + createInstance(Ci.nsIStructuredCloneContainer); + + // The maximum supported structured-clone serialization format version + // as defined in "js/public/StructuredClone.h" + let JS_STRUCTURED_CLONE_VERSION = 4; + scContainer.initFromBase64(dataString, JS_STRUCTURED_CLONE_VERSION); + let dataObj = scContainer.deserializeToVariant(); + + // We have to check whether dataObj contains DOM objects (supported by + // nsIStructuredCloneContainer, but not by Cu.cloneInto), e.g. ImageData. + // After the structured clone callback systems will be unified, we'll not + // have to perform this check anymore. + try { + let data = Cu.cloneInto(dataObj, {}); + } catch(e) { dataObj = null; } + + return dataObj; + }, + + showNotification: function(imageURL, title, text, textClickable, cookie, + uid, dir, lang, dataObj, manifestURL, timestamp, + behavior) { + function send(appName, appIcon) { + SystemAppProxy._sendCustomEvent(kMozChromeNotificationEvent, { + type: kDesktopNotification, + id: uid, + icon: imageURL, + title: title, + text: text, + dir: dir, + lang: lang, + appName: appName, + appIcon: appIcon, + manifestURL: manifestURL, + timestamp: timestamp, + data: dataObj, + mozbehavior: behavior + }); + } + + if (!manifestURL || !manifestURL.length) { + send(null, null); + return; + } + + // If we have a manifest URL, get the icon and title from the manifest + // to prevent spoofing. + appsService.getManifestFor(manifestURL).then((manifest) => { + let app = appsService.getAppByManifestURL(manifestURL); + let helper = new ManifestHelper(manifest, app.origin, manifestURL); + send(helper.name, helper.iconURLForSize(kNotificationIconSize)); + }); + }, + + showAlertNotification: function(aMessage) { + let data = aMessage.data; + let currentListener = this._listeners[data.name]; + if (currentListener && currentListener.observer) { + currentListener.observer.observe(null, kTopicAlertFinished, currentListener.cookie); + } + + let dataObj = this.deserializeStructuredClone(data.dataStr); + this.registerListener(data.name, data.cookie, data.alertListener); + this.showNotification(data.imageURL, data.title, data.text, + data.textClickable, data.cookie, data.name, data.dir, + data.lang, dataObj, null, data.inPrivateBrowsing); + }, + + closeAlert: function(name) { + SystemAppProxy._sendCustomEvent(kMozChromeNotificationEvent, { + type: kDesktopNotificationClose, + id: name + }); + }, + + receiveMessage: function(aMessage) { + if (!aMessage.target.assertAppHasPermission(kDesktopNotificationPerm)) { + Cu.reportError("Desktop-notification message " + aMessage.name + + " from a content process with no " + kDesktopNotificationPerm + + " privileges."); + return; + } + + switch(aMessage.name) { + case kMessageAlertNotificationSend: + this.showAlertNotification(aMessage); + break; + + case kMessageAlertNotificationClose: + this.closeAlert(aMessage.data.name); + break; + } + + }, +} + +AlertsHelper.init(); diff --git a/b2g/components/AlertsService.js b/b2g/components/AlertsService.js new file mode 100644 index 000000000..19a164f0e --- /dev/null +++ b/b2g/components/AlertsService.js @@ -0,0 +1,153 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cc = Components.classes; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", + "@mozilla.org/system-message-internal;1", + "nsISystemMessagesInternal"); + +XPCOMUtils.defineLazyServiceGetter(this, "uuidGenerator", + "@mozilla.org/uuid-generator;1", + "nsIUUIDGenerator"); + +XPCOMUtils.defineLazyServiceGetter(this, "notificationStorage", + "@mozilla.org/notificationStorage;1", + "nsINotificationStorage"); + +XPCOMUtils.defineLazyGetter(this, "cpmm", function() { + return Cc["@mozilla.org/childprocessmessagemanager;1"] + .getService(Ci.nsIMessageSender); +}); + +function debug(str) { + dump("=*= AlertsService.js : " + str + "\n"); +} + +// ----------------------------------------------------------------------- +// Alerts Service +// ----------------------------------------------------------------------- + +const kNotificationSystemMessageName = "notification"; + +const kMessageAlertNotificationSend = "alert-notification-send"; +const kMessageAlertNotificationClose = "alert-notification-close"; + +const kTopicAlertShow = "alertshow"; +const kTopicAlertFinished = "alertfinished"; +const kTopicAlertClickCallback = "alertclickcallback"; + +function AlertsService() { + Services.obs.addObserver(this, "xpcom-shutdown", false); +} + +AlertsService.prototype = { + classID: Components.ID("{fe33c107-82a4-41d6-8c64-5353267e04c9}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService, + Ci.nsIObserver]), + + observe: function(aSubject, aTopic, aData) { + switch (aTopic) { + case "xpcom-shutdown": + Services.obs.removeObserver(this, "xpcom-shutdown"); + break; + } + }, + + // nsIAlertsService + showAlert: function(aAlert, aAlertListener) { + if (!aAlert) { + return; + } + cpmm.sendAsyncMessage(kMessageAlertNotificationSend, { + imageURL: aAlert.imageURL, + title: aAlert.title, + text: aAlert.text, + clickable: aAlert.textClickable, + cookie: aAlert.cookie, + listener: aAlertListener, + id: aAlert.name, + dir: aAlert.dir, + lang: aAlert.lang, + dataStr: aAlert.data, + inPrivateBrowsing: aAlert.inPrivateBrowsing + }); + }, + + showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable, + aCookie, aAlertListener, aName, aBidi, + aLang, aDataStr, aPrincipal, + aInPrivateBrowsing) { + let alert = Cc["@mozilla.org/alert-notification;1"]. + createInstance(Ci.nsIAlertNotification); + + alert.init(aName, aImageUrl, aTitle, aText, aTextClickable, aCookie, + aBidi, aLang, aDataStr, aPrincipal, aInPrivateBrowsing); + + this.showAlert(alert, aAlertListener); + }, + + closeAlert: function(aName) { + cpmm.sendAsyncMessage(kMessageAlertNotificationClose, { + name: aName + }); + }, + + // AlertsService.js custom implementation + _listeners: [], + + receiveMessage: function(aMessage) { + let data = aMessage.data; + let listener = this._listeners[data.uid]; + if (!listener) { + return; + } + + let topic = data.topic; + + try { + listener.observer.observe(null, topic, null); + } catch (e) { + if (topic === kTopicAlertFinished && listener.dbId) { + notificationStorage.delete(listener.manifestURL, listener.dbId); + } + } + + // we're done with this notification + if (topic === kTopicAlertFinished) { + delete this._listeners[data.uid]; + } + }, + + deserializeStructuredClone: function(dataString) { + if (!dataString) { + return null; + } + let scContainer = Cc["@mozilla.org/docshell/structured-clone-container;1"]. + createInstance(Ci.nsIStructuredCloneContainer); + + // The maximum supported structured-clone serialization format version + // as defined in "js/public/StructuredClone.h" + let JS_STRUCTURED_CLONE_VERSION = 4; + scContainer.initFromBase64(dataString, JS_STRUCTURED_CLONE_VERSION); + let dataObj = scContainer.deserializeToVariant(); + + // We have to check whether dataObj contains DOM objects (supported by + // nsIStructuredCloneContainer, but not by Cu.cloneInto), e.g. ImageData. + // After the structured clone callback systems will be unified, we'll not + // have to perform this check anymore. + try { + let data = Cu.cloneInto(dataObj, {}); + } catch(e) { dataObj = null; } + + return dataObj; + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AlertsService]); diff --git a/b2g/components/B2GAboutRedirector.js b/b2g/components/B2GAboutRedirector.js new file mode 100644 index 000000000..f4bcf47f4 --- /dev/null +++ b/b2g/components/B2GAboutRedirector.js @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +const Cc = Components.classes; +const Ci = Components.interfaces; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/Services.jsm"); + +function debug(msg) { + //dump("B2GAboutRedirector: " + msg + "\n"); +} + +function netErrorURL() { + let systemManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url"); + systemManifestURL = Services.io.newURI(systemManifestURL, null, null); + let netErrorURL = Services.prefs.getCharPref("b2g.neterror.url"); + netErrorURL = Services.io.newURI(netErrorURL, null, systemManifestURL); + return netErrorURL.spec; +} + +var modules = { + certerror: { + uri: "chrome://b2g/content/aboutCertError.xhtml", + privileged: false, + hide: true + }, + neterror: { + uri: netErrorURL(), + privileged: false, + hide: true + } +}; + +function B2GAboutRedirector() {} +B2GAboutRedirector.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]), + classID: Components.ID("{920400b1-cf8f-4760-a9c4-441417b15134}"), + + _getModuleInfo: function (aURI) { + let moduleName = aURI.path.replace(/[?#].*/, "").toLowerCase(); + return modules[moduleName]; + }, + + // nsIAboutModule + getURIFlags: function(aURI) { + let flags; + let moduleInfo = this._getModuleInfo(aURI); + if (moduleInfo.hide) + flags = Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT; + + return flags | Ci.nsIAboutModule.ALLOW_SCRIPT; + }, + + newChannel: function(aURI, aLoadInfo) { + let moduleInfo = this._getModuleInfo(aURI); + + var ios = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); + + var newURI = ios.newURI(moduleInfo.uri, null, null); + + var channel = ios.newChannelFromURIWithLoadInfo(newURI, aLoadInfo); + + if (!moduleInfo.privileged) { + // Setting the owner to null means that we'll go through the normal + // path in GetChannelPrincipal and create a codebase principal based + // on the channel's originalURI + channel.owner = null; + } + + channel.originalURI = aURI; + + return channel; + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([B2GAboutRedirector]); diff --git a/b2g/components/B2GAppMigrator.js b/b2g/components/B2GAppMigrator.js new file mode 100644 index 000000000..65671d151 --- /dev/null +++ b/b2g/components/B2GAppMigrator.js @@ -0,0 +1,152 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +function debug(s) { + dump("-*- B2GAppMigrator.js: " + s + "\n"); +} +const DEBUG = false; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +const kMigrationMessageName = "webapps-before-update-merge"; + +const kIDBDirType = "indexedDBPDir"; +const kProfileDirType = "ProfD"; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/FileUtils.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "appsService", + "@mozilla.org/AppsService;1", + "nsIAppsService"); + +function B2GAppMigrator() { +} + +B2GAppMigrator.prototype = { + classID: Components.ID('{7211ece0-b458-4635-9afc-f8d7f376ee95}'), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, + Ci.nsISupportsWeakReference]), + executeBrowserMigration: function() { + if (DEBUG) debug("Executing Browser Migration"); + // The browser db file and directory names are hashed the same way + // everywhere, so it should be the same on all systems. We should + // be able to just hardcode it. + let browserDBDirName = "2959517650brreosw"; + let browserDBFileName = browserDBDirName + ".sqlite"; + + // Storage directories need to be prefixed with the local id of + // the app + let browserLocalAppId = appsService.getAppLocalIdByManifestURL("app://browser.gaiamobile.org/manifest.webapp"); + let browserAppStorageDirName = browserLocalAppId + "+f+app+++browser.gaiamobile.org"; + + // On the phone, the browser db will only be in the old IDB + // directory, since it only existed up until v2.0. On desktop, it + // will exist in the profile directory. + // + // Uses getDir with filename appending to make sure we don't + // create extra directories along the way if they don't already + // exist. + let browserDBFile = FileUtils.getDir(kIDBDirType, + ["storage", + "persistent", + browserAppStorageDirName, + "idb"], false, true); + browserDBFile.append(browserDBFileName); + let browserDBDir = FileUtils.getDir(kIDBDirType, + ["storage", + "persistent", + browserAppStorageDirName, + "idb", + browserDBDirName + ], false, true); + + if (!browserDBFile.exists()) { + if (DEBUG) debug("Browser DB " + browserDBFile.path + " does not exist, trying profile location"); + browserDBFile = FileUtils.getDir(kProfileDirType, + ["storage", + "persistent", + browserAppStorageDirName, + "idb"], false, true); + browserDBFile.append(browserDBFileName); + if (!browserDBFile.exists()) { + if (DEBUG) debug("Browser DB " + browserDBFile.path + " does not exist. Cannot copy browser db."); + return; + } + // If we have confirmed we have a DB file, we should also have a + // directory. + browserDBDir = FileUtils.getDir(kProfileDirType, + ["storage", + "persistent", + browserAppStorageDirName, + "idb", + browserDBDirName + ], false, true); + } + + let systemLocalAppId = appsService.getAppLocalIdByManifestURL("app://system.gaiamobile.org/manifest.webapp"); + let systemAppStorageDirName = systemLocalAppId + "+f+app+++system.gaiamobile.org"; + + // This check futureproofs the system DB storage directory. It + // currently exists outside of the profile but will most likely + // move into the profile at some point. + let systemDBDir = FileUtils.getDir(kIDBDirType, + ["storage", + "persistent", + systemAppStorageDirName, + "idb"], false, true); + + if (!systemDBDir.exists()) { + if (DEBUG) debug("System DB directory " + systemDBDir.path + " does not exist, trying profile location"); + systemDBDir = FileUtils.getDir(kProfileDirType, + ["storage", + "persistent", + systemAppStorageDirName, + "idb"], false, true); + if (!systemDBDir.exists()) { + if (DEBUG) debug("System DB directory " + systemDBDir.path + " does not exist. Cannot copy browser db."); + return; + } + } + + if (DEBUG) { + debug("Browser DB file exists, copying"); + debug("Browser local id: " + browserLocalAppId + ""); + debug("System local id: " + systemLocalAppId + ""); + debug("Browser DB file path: " + browserDBFile.path + ""); + debug("Browser DB dir path: " + browserDBDir.path + ""); + debug("System DB directory path: " + systemDBDir.path + ""); + } + + try { + browserDBFile.copyTo(systemDBDir, browserDBFileName); + } catch (e) { + debug("File copy caused error! " + e.name); + } + try { + browserDBDir.copyTo(systemDBDir, browserDBDirName); + } catch (e) { + debug("Dir copy caused error! " + e.name); + } + if (DEBUG) debug("Browser DB copied successfully"); + }, + + observe: function(subject, topic, data) { + switch (topic) { + case kMigrationMessageName: + this.executeBrowserMigration(); + break; + default: + debug("Unhandled topic: " + topic); + break; + } + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([B2GAppMigrator]); diff --git a/b2g/components/B2GComponents.manifest b/b2g/components/B2GComponents.manifest new file mode 100644 index 000000000..53d0032f9 --- /dev/null +++ b/b2g/components/B2GComponents.manifest @@ -0,0 +1,108 @@ +# Scrollbars +category agent-style-sheets browser-content-stylesheet chrome://b2g/content/content.css + +# AlertsService.js +component {fe33c107-82a4-41d6-8c64-5353267e04c9} AlertsService.js +contract @mozilla.org/system-alerts-service;1 {fe33c107-82a4-41d6-8c64-5353267e04c9} + +# ContentPermissionPrompt.js +component {8c719f03-afe0-4aac-91ff-6c215895d467} ContentPermissionPrompt.js +contract @mozilla.org/content-permission/prompt;1 {8c719f03-afe0-4aac-91ff-6c215895d467} + +#ifdef MOZ_UPDATER +# UpdatePrompt.js +component {88b3eb21-d072-4e3b-886d-f89d8c49fe59} UpdatePrompt.js +contract @mozilla.org/updates/update-prompt;1 {88b3eb21-d072-4e3b-886d-f89d8c49fe59} +category system-update-provider MozillaProvider @mozilla.org/updates/update-prompt;1,{88b3eb21-d072-4e3b-886d-f89d8c49fe59} +#endif + +#ifdef MOZ_B2G +# DirectoryProvider.js +component {9181eb7c-6f87-11e1-90b1-4f59d80dd2e5} DirectoryProvider.js +contract @mozilla.org/b2g/directory-provider;1 {9181eb7c-6f87-11e1-90b1-4f59d80dd2e5} +category xpcom-directory-providers b2g-directory-provider @mozilla.org/b2g/directory-provider;1 +#endif + +# SystemMessageGlue.js +component {2846f034-e614-11e3-93cd-74d02b97e723} SystemMessageGlue.js +contract @mozilla.org/dom/messages/system-message-glue;1 {2846f034-e614-11e3-93cd-74d02b97e723} + +# ProcessGlobal.js +component {1a94c87a-5ece-4d11-91e1-d29c29f21b28} ProcessGlobal.js +contract @mozilla.org/b2g-process-global;1 {1a94c87a-5ece-4d11-91e1-d29c29f21b28} +category app-startup ProcessGlobal service,@mozilla.org/b2g-process-global;1 + +# OMAContentHandler.js +component {a6b2ab13-9037-423a-9897-dde1081be323} OMAContentHandler.js +contract @mozilla.org/uriloader/content-handler;1?type=application/vnd.oma.drm.message {a6b2ab13-9037-423a-9897-dde1081be323} +contract @mozilla.org/uriloader/content-handler;1?type=application/vnd.oma.dd+xml {a6b2ab13-9037-423a-9897-dde1081be323} + +# TelProtocolHandler.js +component {782775dd-7351-45ea-aff1-0ffa872cfdd2} TelProtocolHandler.js +contract @mozilla.org/network/protocol;1?name=tel {782775dd-7351-45ea-aff1-0ffa872cfdd2} + +# SmsProtocolHandler.js +component {81ca20cb-0dad-4e32-8566-979c8998bd73} SmsProtocolHandler.js +contract @mozilla.org/network/protocol;1?name=sms {81ca20cb-0dad-4e32-8566-979c8998bd73} + +# MailtoProtocolHandler.js +component {50777e53-0331-4366-a191-900999be386c} MailtoProtocolHandler.js +contract @mozilla.org/network/protocol;1?name=mailto {50777e53-0331-4366-a191-900999be386c} + +# RecoveryService.js +component {b3caca5d-0bb0-48c6-912b-6be6cbf08832} RecoveryService.js +contract @mozilla.org/recovery-service;1 {b3caca5d-0bb0-48c6-912b-6be6cbf08832} + +# B2GAboutRedirector +component {920400b1-cf8f-4760-a9c4-441417b15134} B2GAboutRedirector.js +contract @mozilla.org/network/protocol/about;1?what=certerror {920400b1-cf8f-4760-a9c4-441417b15134} +contract @mozilla.org/network/protocol/about;1?what=neterror {920400b1-cf8f-4760-a9c4-441417b15134} + +#ifndef MOZ_GRAPHENE +# FilePicker.js +component {436ff8f9-0acc-4b11-8ec7-e293efba3141} FilePicker.js +contract @mozilla.org/filepicker;1 {436ff8f9-0acc-4b11-8ec7-e293efba3141} +#endif + +# FxAccountsUIGlue.js +component {51875c14-91d7-4b8c-b65d-3549e101228c} FxAccountsUIGlue.js +contract @mozilla.org/fxaccounts/fxaccounts-ui-glue;1 {51875c14-91d7-4b8c-b65d-3549e101228c} + +# HelperAppDialog.js +component {710322af-e6ae-4b0c-b2c9-1474a87b077e} HelperAppDialog.js +contract @mozilla.org/helperapplauncherdialog;1 {710322af-e6ae-4b0c-b2c9-1474a87b077e} + +#ifndef MOZ_WIDGET_GONK +component {c83c02c0-5d43-4e3e-987f-9173b313e880} SimulatorScreen.js +contract @mozilla.org/simulator-screen;1 {c83c02c0-5d43-4e3e-987f-9173b313e880} +category profile-after-change SimulatorScreen @mozilla.org/simulator-screen;1 + +component {e30b0e13-2d12-4cb0-bc4c-4e617a1bf76e} OopCommandLine.js +contract @mozilla.org/commandlinehandler/general-startup;1?type=b2goop {e30b0e13-2d12-4cb0-bc4c-4e617a1bf76e} +category command-line-handler m-b2goop @mozilla.org/commandlinehandler/general-startup;1?type=b2goop + +component {385993fe-8710-4621-9fb1-00a09d8bec37} CommandLine.js +contract @mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds {385993fe-8710-4621-9fb1-00a09d8bec37} +category command-line-handler m-b2gcmds @mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds +#endif + +# BootstrapCommandLine.js +component {fd663ec8-cf3f-4c2b-aacb-17a6915ccb44} BootstrapCommandLine.js +contract @mozilla.org/commandlinehandler/general-startup;1?type=b2gbootstrap {fd663ec8-cf3f-4c2b-aacb-17a6915ccb44} +category command-line-handler m-b2gbootstrap @mozilla.org/commandlinehandler/general-startup;1?type=b2gbootstrap + +# B2GAppMigrator.js +component {7211ece0-b458-4635-9afc-f8d7f376ee95} B2GAppMigrator.js +contract @mozilla.org/app-migrator;1 {7211ece0-b458-4635-9afc-f8d7f376ee95} + +# B2GPresentationDevicePrompt.js +component {4a300c26-e99b-4018-ab9b-c48cf9bc4de1} B2GPresentationDevicePrompt.js +contract @mozilla.org/presentation-device/prompt;1 {4a300c26-e99b-4018-ab9b-c48cf9bc4de1} + +# PresentationRequestUIGlue.js +component {ccc8a839-0b64-422b-8a60-fb2af0e376d0} PresentationRequestUIGlue.js +contract @mozilla.org/presentation/requestuiglue;1 {ccc8a839-0b64-422b-8a60-fb2af0e376d0} + +# SystemMessageInternal.js +component {70589ca5-91ac-4b9e-b839-d6a88167d714} SystemMessageInternal.js +contract @mozilla.org/system-message-internal;1 {70589ca5-91ac-4b9e-b839-d6a88167d714} diff --git a/b2g/components/B2GPresentationDevicePrompt.js b/b2g/components/B2GPresentationDevicePrompt.js new file mode 100644 index 000000000..998e0b7ac --- /dev/null +++ b/b2g/components/B2GPresentationDevicePrompt.js @@ -0,0 +1,87 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +function debug(aMsg) { + //dump("-*- B2GPresentationDevicePrompt: " + aMsg + "\n"); +} + +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + +const kB2GPRESENTATIONDEVICEPROMPT_CONTRACTID = "@mozilla.org/presentation-device/prompt;1"; +const kB2GPRESENTATIONDEVICEPROMPT_CID = Components.ID("{4a300c26-e99b-4018-ab9b-c48cf9bc4de1}"); + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", + "resource://gre/modules/SystemAppProxy.jsm"); + +function B2GPresentationDevicePrompt() {} + +B2GPresentationDevicePrompt.prototype = { + classID: kB2GPRESENTATIONDEVICEPROMPT_CID, + contractID: kB2GPRESENTATIONDEVICEPROMPT_CONTRACTID, + classDescription: "B2G Presentation Device Prompt", + QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt]), + + // nsIPresentationDevicePrompt + promptDeviceSelection: function(aRequest) { + let self = this; + let requestId = Cc["@mozilla.org/uuid-generator;1"] + .getService(Ci.nsIUUIDGenerator).generateUUID().toString(); + + SystemAppProxy.addEventListener("mozContentEvent", function contentEvent(aEvent) { + let detail = aEvent.detail; + if (detail.id !== requestId) { + return; + } + + SystemAppProxy.removeEventListener("mozContentEvent", contentEvent); + + switch (detail.type) { + case "presentation-select-result": + debug("device " + detail.deviceId + " is selected by user"); + let device = self._getDeviceById(detail.deviceId); + if (!device) { + debug("cancel request because device is not found"); + aRequest.cancel(Cr.NS_ERROR_DOM_NOT_FOUND_ERR); + } + aRequest.select(device); + break; + case "presentation-select-deny": + debug("request canceled by user"); + aRequest.cancel(Cr.NS_ERROR_DOM_NOT_ALLOWED_ERR); + break; + } + }); + + let detail = { + type: "presentation-select-device", + origin: aRequest.origin, + requestURL: aRequest.requestURL, + id: requestId, + }; + + SystemAppProxy.dispatchEvent(detail); + }, + + _getDeviceById: function(aDeviceId) { + let deviceManager = Cc["@mozilla.org/presentation-device/manager;1"] + .getService(Ci.nsIPresentationDeviceManager); + let devices = deviceManager.getAvailableDevices().QueryInterface(Ci.nsIArray); + + for (let i = 0; i < devices.length; i++) { + let device = devices.queryElementAt(i, Ci.nsIPresentationDevice); + if (device.id === aDeviceId) { + return device; + } + } + + return null; + }, +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([B2GPresentationDevicePrompt]); diff --git a/b2g/components/BootstrapCommandLine.js b/b2g/components/BootstrapCommandLine.js new file mode 100644 index 000000000..24d9f5461 --- /dev/null +++ b/b2g/components/BootstrapCommandLine.js @@ -0,0 +1,52 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/AppsUtils.jsm"); + +function BootstrapCommandlineHandler() { + this.wrappedJSObject = this; + this.startManifestURL = null; +} + +BootstrapCommandlineHandler.prototype = { + bailout: function(aMsg) { + dump("************************************************************\n"); + dump("* /!\\ " + aMsg + "\n"); + dump("************************************************************\n"); + let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] + .getService(Ci.nsIAppStartup); + appStartup.quit(appStartup.eForceQuit); + }, + + handle: function(aCmdLine) { + this.startManifestURL = null; + + try { + // Returns null if the argument was not specified. Throws + // NS_ERROR_INVALID_ARG if there is no parameter specified (because + // it was the last argument or the next argument starts with '-'). + // However, someone could still explicitly pass an empty argument! + this.startManifestURL = aCmdLine.handleFlagWithParam("start-manifest", false); + } catch(e) { + return; + } + + if (!this.startManifestURL) { + return; + } + + if (!isAbsoluteURI(this.startManifestURL)) { + this.bailout("The start manifest url must be absolute."); + return; + } + }, + + helpInfo: "--start-manifest=manifest_url", + classID: Components.ID("{fd663ec8-cf3f-4c2b-aacb-17a6915ccb44}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]) +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BootstrapCommandlineHandler]); diff --git a/b2g/components/Bootstraper.jsm b/b2g/components/Bootstraper.jsm new file mode 100644 index 000000000..3d3fb37d9 --- /dev/null +++ b/b2g/components/Bootstraper.jsm @@ -0,0 +1,156 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["Bootstraper"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const CC = Components.Constructor; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AppsUtils.jsm"); + +function debug(aMsg) { + //dump("-*- Bootstraper: " + aMsg + "\n"); +} + +/** + * This module loads the manifest for app from the --start-url enpoint and + * ensures that it's installed as the system app. + */ +this.Bootstraper = { + _manifestURL: null, + _startupURL: null, + + bailout: function(aMsg) { + dump("************************************************************\n"); + dump("* /!\\ " + aMsg + "\n"); + dump("************************************************************\n"); + let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] + .getService(Ci.nsIAppStartup); + appStartup.quit(appStartup.eForceQuit); + }, + + installSystemApp: function(aManifest) { + // Get the appropriate startup url from the manifest launch_path. + let base = Services.io.newURI(this._manifestURL, null, null); + let origin = base.prePath; + let helper = new ManifestHelper(aManifest, origin, this._manifestURL); + this._startupURL = helper.fullLaunchPath(); + + return new Promise((aResolve, aReject) => { + debug("Origin is " + origin); + let appData = { + app: { + installOrigin: origin, + origin: origin, + manifest: aManifest, + manifestURL: this._manifestURL, + manifestHash: AppsUtils.computeHash(JSON.stringify(aManifest)), + appStatus: Ci.nsIPrincipal.APP_STATUS_CERTIFIED + }, + appId: 1, + isBrowser: false, + isPackage: false + }; + + //DOMApplicationRegistry.confirmInstall(appData, null, aResolve); + }); + }, + + /** + * Resolves to a json manifest. + */ + loadManifest: function() { + return new Promise((aResolve, aReject) => { + debug("Loading manifest " + this._manifestURL); + + let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Ci.nsIXMLHttpRequest); + xhr.mozBackgroundRequest = true; + xhr.open("GET", this._manifestURL); + xhr.responseType = "json"; + xhr.addEventListener("load", () => { + if (xhr.status >= 200 && xhr.status < 400) { + debug("Success loading " + this._manifestURL); + aResolve(xhr.response); + } else { + aReject("Error loading " + this._manifestURL); + } + }); + xhr.addEventListener("error", () => { + aReject("Error loading " + this._manifestURL); + }); + xhr.send(null); + }); + }, + + configure: function() { + debug("Setting startup prefs... " + this._startupURL); + Services.prefs.setCharPref("b2g.system_manifest_url", this._manifestURL); + Services.prefs.setCharPref("b2g.system_startup_url", this._startupURL); + return Promise.resolve(); + }, + + /** + * If a system app is already installed, uninstall it so that we can + * cleanly replace it by the current one. + */ + uninstallPreviousSystemApp: function() { + // TODO: FIXME + return Promise.resolve(); + + let oldManifestURL; + try{ + oldManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url"); + } catch(e) { + // No preference set, so nothing to uninstall. + return Promise.resolve(); + } + + let id = DOMApplicationRegistry.getAppLocalIdByManifestURL(oldManifestURL); + if (id == Ci.nsIScriptSecurityManager.NO_APP_ID) { + return Promise.resolve(); + } + debug("Uninstalling " + oldManifestURL); + return DOMApplicationRegistry.uninstall(oldManifestURL); + }, + + /** + * Check if we are already configured to run from this manifest url. + */ + isInstallRequired: function(aManifestURL) { + try { + if (Services.prefs.getCharPref("b2g.system_manifest_url") == aManifestURL) { + return false; + } + } catch(e) { } + return true; + }, + + /** + * Resolves once we have installed the app. + */ + ensureSystemAppInstall: function(aManifestURL) { + this._manifestURL = aManifestURL; + debug("Installing app from " + this._manifestURL); + + if (!this.isInstallRequired(this._manifestURL)) { + debug("Already configured for " + this._manifestURL); + return Promise.resolve(); + } + + return new Promise((aResolve, aReject) => { + this.uninstallPreviousSystemApp.bind(this) + .then(this.loadManifest.bind(this)) + .then(this.installSystemApp.bind(this)) + .then(this.configure.bind(this)) + .then(aResolve) + .catch(aReject); + }); + } +}; diff --git a/b2g/components/CommandLine.js b/b2g/components/CommandLine.js new file mode 100644 index 000000000..6dc48bd33 --- /dev/null +++ b/b2g/components/CommandLine.js @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); + +// Small helper to expose nsICommandLine object to chrome code + +function CommandlineHandler() { + this.wrappedJSObject = this; +} + +CommandlineHandler.prototype = { + handle: function(cmdLine) { + this.cmdLine = cmdLine; + let win = Services.wm.getMostRecentWindow("navigator:browser"); + if (win && win.shell) { + win.shell.handleCmdLine(); + } + }, + + helpInfo: "", + classID: Components.ID("{385993fe-8710-4621-9fb1-00a09d8bec37}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]), +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([CommandlineHandler]); diff --git a/b2g/components/ContentPermissionPrompt.js b/b2g/components/ContentPermissionPrompt.js new file mode 100644 index 000000000..e11b1b458 --- /dev/null +++ b/b2g/components/ContentPermissionPrompt.js @@ -0,0 +1,461 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict" + +function debug(str) { + //dump("-*- ContentPermissionPrompt: " + str + "\n"); +} + +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; +const Cc = Components.classes; + +const PROMPT_FOR_UNKNOWN = ["audio-capture", + "desktop-notification", + "geolocation", + "video-capture"]; +// Due to privary issue, permission requests like GetUserMedia should prompt +// every time instead of providing session persistence. +const PERMISSION_NO_SESSION = ["audio-capture", "video-capture"]; +const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"]; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AppsUtils.jsm"); +Cu.import("resource://gre/modules/PermissionsInstaller.jsm"); +Cu.import("resource://gre/modules/PermissionsTable.jsm"); + +var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager); +var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); + +var permissionSpecificChecker = {}; + +XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", + "resource://gre/modules/SystemAppProxy.jsm"); + +/** + * Determine if a permission should be prompt to user or not. + * + * @param aPerm requested permission + * @param aAction the action according to principal + * @return true if prompt is required + */ +function shouldPrompt(aPerm, aAction) { + return ((aAction == Ci.nsIPermissionManager.PROMPT_ACTION) || + (aAction == Ci.nsIPermissionManager.UNKNOWN_ACTION && + PROMPT_FOR_UNKNOWN.indexOf(aPerm) >= 0)); +} + +/** + * Create the default choices for the requested permissions + * + * @param aTypesInfo requested permissions + * @return the default choices for permissions with options, return + * undefined if no option in all requested permissions. + */ +function buildDefaultChoices(aTypesInfo) { + let choices; + for (let type of aTypesInfo) { + if (type.options.length > 0) { + if (!choices) { + choices = {}; + } + choices[type.access] = type.options[0]; + } + } + return choices; +} + +/** + * aTypesInfo is an array of {permission, access, action, deny} which keeps + * the information of each permission. This arrary is initialized in + * ContentPermissionPrompt.prompt and used among functions. + * + * aTypesInfo[].permission : permission name + * aTypesInfo[].access : permission name + request.access + * aTypesInfo[].action : the default action of this permission + * aTypesInfo[].deny : true if security manager denied this app's origin + * principal. + * Note: + * aTypesInfo[].permission will be sent to prompt only when + * aTypesInfo[].action is PROMPT_ACTION and aTypesInfo[].deny is false. + */ +function rememberPermission(aTypesInfo, aPrincipal, aSession) +{ + function convertPermToAllow(aPerm, aPrincipal) + { + let type = + permissionManager.testExactPermissionFromPrincipal(aPrincipal, aPerm); + if (shouldPrompt(aPerm, type)) { + debug("add " + aPerm + " to permission manager with ALLOW_ACTION"); + if (!aSession) { + permissionManager.addFromPrincipal(aPrincipal, + aPerm, + Ci.nsIPermissionManager.ALLOW_ACTION); + } else if (PERMISSION_NO_SESSION.indexOf(aPerm) < 0) { + permissionManager.addFromPrincipal(aPrincipal, + aPerm, + Ci.nsIPermissionManager.ALLOW_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION, 0); + } + } + } + + for (let i in aTypesInfo) { + // Expand the permission to see if we have multiple access properties + // to convert + let perm = aTypesInfo[i].permission; + let access = PermissionsTable[perm].access; + if (access) { + for (let idx in access) { + convertPermToAllow(perm + "-" + access[idx], aPrincipal); + } + } else { + convertPermToAllow(perm, aPrincipal); + } + } +} + +function ContentPermissionPrompt() {} + +ContentPermissionPrompt.prototype = { + + handleExistingPermission: function handleExistingPermission(request, + typesInfo) { + typesInfo.forEach(function(type) { + type.action = + Services.perms.testExactPermissionFromPrincipal(request.principal, + type.access); + if (shouldPrompt(type.access, type.action)) { + type.action = Ci.nsIPermissionManager.PROMPT_ACTION; + } + }); + + // If all permissions are allowed already and no more than one option, + // call allow() without prompting. + let checkAllowPermission = function(type) { + if (type.action == Ci.nsIPermissionManager.ALLOW_ACTION && + type.options.length <= 1) { + return true; + } + return false; + } + if (typesInfo.every(checkAllowPermission)) { + debug("all permission requests are allowed"); + request.allow(buildDefaultChoices(typesInfo)); + return true; + } + + // If all permissions are DENY_ACTION or UNKNOWN_ACTION, call cancel() + // without prompting. + let checkDenyPermission = function(type) { + if (type.action == Ci.nsIPermissionManager.DENY_ACTION || + type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION) { + return true; + } + return false; + } + if (typesInfo.every(checkDenyPermission)) { + debug("all permission requests are denied"); + request.cancel(); + return true; + } + return false; + }, + + // multiple requests should be audio and video + checkMultipleRequest: function checkMultipleRequest(typesInfo) { + if (typesInfo.length == 1) { + return true; + } else if (typesInfo.length > 1) { + let checkIfAllowMultiRequest = function(type) { + return (ALLOW_MULTIPLE_REQUESTS.indexOf(type.access) !== -1); + } + if (typesInfo.every(checkIfAllowMultiRequest)) { + debug("legal multiple requests"); + return true; + } + } + + return false; + }, + + handledByApp: function handledByApp(request, typesInfo) { + if (request.principal.appId == Ci.nsIScriptSecurityManager.NO_APP_ID || + request.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) { + // This should not really happen + request.cancel(); + return true; + } + + let appsService = Cc["@mozilla.org/AppsService;1"] + .getService(Ci.nsIAppsService); + let app = appsService.getAppByLocalId(request.principal.appId); + + // Check each permission if it's denied by permission manager with app's + // URL. + let notDenyAppPrincipal = function(type) { + let url = Services.io.newURI(app.origin, null, null); + let principal = + secMan.createCodebasePrincipal(url, + {appId: request.principal.appId}); + let result = Services.perms.testExactPermissionFromPrincipal(principal, + type.access); + + if (result == Ci.nsIPermissionManager.ALLOW_ACTION || + result == Ci.nsIPermissionManager.PROMPT_ACTION) { + type.deny = false; + } + return !type.deny; + } + // Cancel the entire request if one of the requested permissions is denied + if (!typesInfo.every(notDenyAppPrincipal)) { + request.cancel(); + return true; + } + + return false; + }, + + handledByPermissionType: function handledByPermissionType(request, typesInfo) { + for (let i in typesInfo) { + if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) && + permissionSpecificChecker[typesInfo[i].permission](request)) { + return true; + } + } + + return false; + }, + + prompt: function(request) { + // Initialize the typesInfo and set the default value. + let typesInfo = []; + let perms = request.types.QueryInterface(Ci.nsIArray); + for (let idx = 0; idx < perms.length; idx++) { + let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType); + let tmp = { + permission: perm.type, + access: (perm.access && perm.access !== "unused") ? + perm.type + "-" + perm.access : perm.type, + options: [], + deny: true, + action: Ci.nsIPermissionManager.UNKNOWN_ACTION + }; + + // Append available options, if any. + let options = perm.options.QueryInterface(Ci.nsIArray); + for (let i = 0; i < options.length; i++) { + let option = options.queryElementAt(i, Ci.nsISupportsString).data; + tmp.options.push(option); + } + typesInfo.push(tmp); + } + + if (secMan.isSystemPrincipal(request.principal)) { + request.allow(buildDefaultChoices(typesInfo)); + return; + } + + + if (typesInfo.length == 0) { + request.cancel(); + return; + } + + if(!this.checkMultipleRequest(typesInfo)) { + request.cancel(); + return; + } + + if (this.handledByApp(request, typesInfo) || + this.handledByPermissionType(request, typesInfo)) { + return; + } + + // returns true if the request was handled + if (this.handleExistingPermission(request, typesInfo)) { + return; + } + + // prompt PROMPT_ACTION request or request with options. + typesInfo = typesInfo.filter(function(type) { + return !type.deny && (type.action == Ci.nsIPermissionManager.PROMPT_ACTION || type.options.length > 0) ; + }); + + if (!request.element) { + this.delegatePrompt(request, typesInfo); + return; + } + + var cancelRequest = function() { + request.requester.onVisibilityChange = null; + request.cancel(); + } + + var self = this; + + // If the request was initiated from a hidden iframe + // we don't forward it to content and cancel it right away + request.requester.getVisibility( { + notifyVisibility: function(isVisible) { + if (!isVisible) { + cancelRequest(); + return; + } + + // Monitor the frame visibility and cancel the request if the frame goes + // away but the request is still here. + request.requester.onVisibilityChange = { + notifyVisibility: function(isVisible) { + if (isVisible) + return; + + self.cancelPrompt(request, typesInfo); + cancelRequest(); + } + } + + self.delegatePrompt(request, typesInfo, function onCallback() { + request.requester.onVisibilityChange = null; + }); + } + }); + + }, + + cancelPrompt: function(request, typesInfo) { + this.sendToBrowserWindow("cancel-permission-prompt", request, + typesInfo); + }, + + delegatePrompt: function(request, typesInfo, callback) { + this.sendToBrowserWindow("permission-prompt", request, typesInfo, + function(type, remember, choices) { + if (type == "permission-allow") { + rememberPermission(typesInfo, request.principal, !remember); + if (callback) { + callback(); + } + request.allow(choices); + return; + } + + let addDenyPermission = function(type) { + debug("add " + type.permission + + " to permission manager with DENY_ACTION"); + if (remember) { + Services.perms.addFromPrincipal(request.principal, type.access, + Ci.nsIPermissionManager.DENY_ACTION); + } else if (PERMISSION_NO_SESSION.indexOf(type.access) < 0) { + Services.perms.addFromPrincipal(request.principal, type.access, + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION, + 0); + } + } + try { + // This will trow if we are canceling because the remote process died. + // Just eat the exception and call the callback that will cleanup the + // visibility event listener. + typesInfo.forEach(addDenyPermission); + } catch(e) { } + + if (callback) { + callback(); + } + + try { + request.cancel(); + } catch(e) { } + }); + }, + + sendToBrowserWindow: function(type, request, typesInfo, callback) { + let requestId = Cc["@mozilla.org/uuid-generator;1"] + .getService(Ci.nsIUUIDGenerator).generateUUID().toString(); + if (callback) { + SystemAppProxy.addEventListener("mozContentEvent", function contentEvent(evt) { + let detail = evt.detail; + if (detail.id != requestId) + return; + SystemAppProxy.removeEventListener("mozContentEvent", contentEvent); + + callback(detail.type, detail.remember, detail.choices); + }) + } + + let principal = request.principal; + let isApp = principal.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED; + let remember = (principal.appStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED || + principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED) + ? true + : request.remember; + let isGranted = typesInfo.every(function(type) { + return type.action == Ci.nsIPermissionManager.ALLOW_ACTION; + }); + let permissions = {}; + for (let i in typesInfo) { + debug("prompt " + typesInfo[i].permission); + permissions[typesInfo[i].permission] = typesInfo[i].options; + } + + let details = { + type: type, + permissions: permissions, + id: requestId, + // This system app uses the origin from permission events to + // compare against the mozApp.origin of app windows, so we + // are not concerned with origin suffixes here (appId, etc). + origin: principal.originNoSuffix, + isApp: isApp, + remember: remember, + isGranted: isGranted, + }; + + if (isApp) { + details.manifestURL = DOMApplicationRegistry.getManifestURLByLocalId(principal.appId); + } + + // request.element is defined for OOP content, while request.window + // is defined for In-Process content. + // In both cases the message needs to be dispatched to the top-level + //