Commit 6e3dfe5b authored by Kuo Jen Wei's avatar Kuo Jen Wei Committed by Commit Bot

[CCA] Add background_ops communicate between background and CCA window.

Add new window operations passing between background and foreground
window. Foreground and background will bind corresponding operations and
call methods across background and foreground.

Bug: b/141518806
Test: tast run <DUT> 'camera.CCAUI*'
Change-Id: I45801659712af6bc6f439e67c2ae37ad8ab6805d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1935634Reviewed-by: default avatarShik Chen <shik@chromium.org>
Reviewed-by: default avatarWei Lee <wtlee@chromium.org>
Commit-Queue: Kuo Jen Wei <inker@chromium.org>
Auto-Submit: Kuo Jen Wei <inker@chromium.org>
Cr-Commit-Position: refs/heads/master@{#722400}
parent f8b2d824
......@@ -109,6 +109,7 @@ copy("chrome_camera_app_images") {
copy("chrome_camera_app_js") {
sources = [
"src/js/background.js",
"src/js/background_ops.js",
"src/js/chrome_util.js",
"src/js/gallerybutton.js",
"src/js/google-analytics-bundle.js",
......
......@@ -20,6 +20,7 @@
<structure name="IDR_CAMERA_CONSTRAINTS_PREFERRER_JS" file="src/js/device/constraints_preferrer.js" type="chrome_html" />
<structure name="IDR_CAMERA_CHROME_HELPER_JS" file="src/js/mojo/chrome_helper.js" type="chrome_html" />
<structure name="IDR_CAMERA_CHROME_UTIL_JS" file="src/js/chrome_util.js" type="chrome_html" />
<structure name="IDR_CAMERA_BACKGROUND_OPS_JS" file="src/js/background_ops.js" type="chrome_html" />
<structure name="IDR_CAMERA_DEVICE_OPERATOR_JS" file="src/js/mojo/device_operator.js" type="chrome_html" />
<structure name="IDR_CAMERA_DEVICE_INFO_UPDATER_JS" file="src/js/device/device_info_updater.js" type="chrome_html" />
<structure name="IDR_CAMERA_DIALOG_JS" file="src/js/views/dialog.js" type="chrome_html" />
......
......@@ -18,6 +18,7 @@ group("closure_compile") {
js_type_check("compile_resources") {
deps = [
":background",
":background_ops",
":chrome_util",
":gallerybutton",
":intent",
......@@ -38,6 +39,8 @@ js_library("chrome_util") {
js_library("intent") {
deps = [
":chrome_util",
":type",
"mojo:chrome_helper",
]
}
......@@ -67,10 +70,12 @@ js_library("type") {
js_library("main") {
deps = [
":background_ops",
":chrome_util",
":gallerybutton",
":intent",
":state",
":type",
"device:constraints_preferrer",
"device:device_info_updater",
"models:gallery",
......@@ -94,6 +99,14 @@ js_library("state") {
js_library("background") {
deps = [
":background_ops",
":intent",
]
}
js_library("background_ops") {
deps = [
":chrome_util",
":intent",
]
}
......
......@@ -14,6 +14,11 @@ var cca = cca || {};
*/
cca.bg = {};
/**
* import {assert} from './chrome_util.js';
*/
var assert = assert || {};
/**
* Fixed minimum width of the window inner-bounds in pixels.
* @type {number}
......@@ -63,20 +68,9 @@ cca.bg.WindowState = {
CLOSED: 'closed',
};
/* eslint-disable no-unused-vars */
/**
* @typedef {{
* suspend: !function(),
* resume: !function(),
* }}
*/
cca.bg.WindowOperations;
/* eslint-enable no-unused-vars */
/**
* Wrapper of AppWindow for tracking its state.
* @implements {cca.bg.BackgroundOps}
*/
cca.bg.Window = class {
/**
......@@ -120,6 +114,12 @@ cca.bg.Window = class {
*/
this.appWindow_ = null;
/**
* @type {?cca.bg.ForegroundOps}
* @private
*/
this.foregroundOps_ = null;
/**
* @type {!cca.bg.WindowState}
* @private
......@@ -175,22 +175,7 @@ cca.bg.Window = class {
}
this.onClosed_(this);
});
const wnd = appWindow.contentWindow;
wnd.intent = this.intent_;
wnd.onActive = () => {
this.state_ = cca.bg.WindowState.ACTIVE;
// For intent only requiring open camera with specific mode without
// returning the capture result, called onIntentHandled() right
// after app successfully launched.
if (this.intent_ !== null && !this.intent_.shouldHandleResult) {
this.intent_.finish();
}
this.onActive_(this);
};
wnd.onSuspended = () => {
this.state_ = cca.bg.WindowState.SUSPENDED;
this.onSuspended_(this);
};
appWindow.contentWindow.backgroundOps = this;
if (cca.bg.onAppWindowCreatedForTesting !== null) {
cca.bg.onAppWindowCreatedForTesting(windowUrl);
}
......@@ -198,20 +183,39 @@ cca.bg.Window = class {
}
/**
* Gets WindowOperations associated with this window.
* @return {!cca.bg.WindowOperations}
* @throws {Error} Throws when no WindowOperations is associated with the
* window.
* @private
* @override
*/
getWindowOps_() {
const ops =
/** @type {(!cca.bg.WindowOperations|undefined)} */ (
this.appWindow_.contentWindow['ops']);
if (ops === undefined) {
throw new Error('WindowOperations not found on target window.');
bindForegroundOps(ops) {
this.foregroundOps_ = ops;
}
/**
* @override
*/
getIntent() {
return this.intent_;
}
/**
* @override
*/
notifyActivation() {
this.state_ = cca.bg.WindowState.ACTIVE;
// For intent only requiring open camera with specific mode without
// returning the capture result, called onIntentHandled() right
// after app successfully launched.
if (this.intent_ !== null && !this.intent_.shouldHandleResult) {
this.intent_.finish();
}
return ops;
this.onActive_(this);
}
/**
* @override
*/
notifySuspension() {
this.state_ = cca.bg.WindowState.SUSPENDED;
this.onSuspended_(this);
}
/**
......@@ -223,7 +227,7 @@ cca.bg.Window = class {
return;
}
this.state_ = cca.bg.WindowState.SUSPENDING;
this.getWindowOps_().suspend();
this.foregroundOps_.suspend();
}
/**
......@@ -231,7 +235,7 @@ cca.bg.Window = class {
*/
resume() {
this.state_ = cca.bg.WindowState.RESUMING;
this.getWindowOps_().resume();
this.foregroundOps_.resume();
}
/**
......
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
/**
* Namespace for the Camera app.
*/
var cca = cca || {};
/**
* Namespace for the background page.
*/
cca.bg = cca.bg || {};
/**
* Operations supported by foreground window.
* @interface
*/
cca.bg.ForegroundOps = class {
/**
* Suspend foreground window.
* @return {!Promise}
* @abstract
*/
async suspend() {}
/**
* Resume foreground window.
* @abstract
*/
resume() {}
};
/**
* Operations supported by background window.
* @interface
*/
cca.bg.BackgroundOps = class {
/**
* Sets the implementation of ForegroundOps from foreground window.
* @param {!cca.bg.ForegroundOps} ops
*/
bindForegroundOps(ops) {}
/**
* Gets intent associate with cca.bg.Window object.
* @return {?cca.intent.Intent}
* @abstract
*/
getIntent() {}
/**
* Called by foreground window when it's active.
* @abstract
*/
notifyActivation() {}
/**
* Called by foreground window when it's suspended.
* @abstract
*/
notifySuspension() {}
};
......@@ -15,13 +15,14 @@ var cca = cca || {};
cca.intent = cca.intent || {};
/**
* Available intent modes.
* @enum {string}
* import {assertNotReached} from './chrome_util.js';
*/
cca.intent.Mode = {
PHOTO: 'photo',
VIDEO: 'video',
};
var assertNotReached = assertNotReached || {};
/**
* import {Mode} from './type.js';
*/
var Mode = Mode || {};
/**
* Thrown when fails to parse intent url.
......@@ -49,7 +50,7 @@ cca.intent.Intent = class {
/**
* @param {!URL} url
* @param {number} intentId
* @param {cca.intent.Mode} mode
* @param {Mode} mode
* @param {boolean} shouldHandleResult
* @param {boolean} shouldDownScale
* @param {boolean} isSecure
......@@ -69,7 +70,7 @@ cca.intent.Intent = class {
/**
* Capture mode of intent.
* @const {!cca.intent.Mode}
* @const {Mode}
*/
this.mode = mode;
......@@ -179,10 +180,10 @@ cca.intent.Intent = class {
const intentId = parseInt(param, 10);
param = params.get('mode');
if (param === null || !Object.values(cca.intent.Mode).includes(param)) {
if (param === null || !Object.values(Mode).includes(param)) {
throw new cca.intent.ParseError(url);
}
const mode = /** @type {!cca.intent.Mode} */ (param);
const mode = /** @type {Mode} */ (param);
return new cca.intent.Intent(
url, intentId, mode, getBool('shouldHandleResult'),
......
......@@ -14,17 +14,25 @@ var cca = cca || {};
*/
var {assert, assertInstanceof} = {assert, assertInstanceof};
/**
* import {Mode} from './type.js';
*/
var Mode = Mode || {};
/**
* Creates the Camera App main object.
* @implements {cca.bg.ForegroundOps}
*/
cca.App = class {
/**
* @public
* @param {!cca.bg.BackgroundOps} backgroundOps
*/
constructor() {
const shouldHandleIntentResult =
window.intent !== null && window.intent.shouldHandleResult;
cca.state.set('should-handle-intent-result', shouldHandleIntentResult);
constructor(backgroundOps) {
/**
* @type {!cca.bg.BackgroundOps}
* @private
*/
this.backgroundOps_ = backgroundOps;
/**
* @type {!cca.models.Gallery}
......@@ -63,13 +71,19 @@ cca.App = class {
* @type {!cca.views.Camera}
* @private
*/
this.cameraView_ = window.intent !== null && shouldHandleIntentResult ?
new cca.views.CameraIntent(
window.intent, this.infoUpdater_, this.photoPreferrer_,
this.videoPreferrer_) :
new cca.views.Camera(
this.gallery_, this.infoUpdater_, this.photoPreferrer_,
this.cameraView_ = (() => {
const intent = this.backgroundOps_.getIntent();
if (intent !== null && intent.shouldHandleResult) {
cca.state.set('should-handle-intent-result', true);
return new cca.views.CameraIntent(
intent, this.infoUpdater_, this.photoPreferrer_,
this.videoPreferrer_);
} else {
return new cca.views.Camera(
this.gallery_, this.infoUpdater_, this.photoPreferrer_,
this.videoPreferrer_, intent !== null ? intent.mode : Mode.PHOTO);
}
})();
document.body.addEventListener('keydown', this.onKeyPressed_.bind(this));
......@@ -91,6 +105,8 @@ cca.App = class {
new cca.views.Warning(),
new cca.views.Dialog('#message-dialog'),
]);
this.backgroundOps_.bindForegroundOps(this);
}
/**
......@@ -173,6 +189,8 @@ cca.App = class {
.finally(() => {
cca.metrics.log(cca.metrics.Type.LAUNCH, ackMigrate);
});
chrome.app.window.current().show();
this.backgroundOps_.notifyActivation();
}
/**
......@@ -193,6 +211,7 @@ cca.App = class {
cca.state.set('suspend', true);
await this.cameraView_.restart();
chrome.app.window.current().hide();
this.backgroundOps_.notifySuspension();
}
/**
......@@ -201,6 +220,7 @@ cca.App = class {
resume() {
cca.state.set('suspend', false);
chrome.app.window.current().show();
this.backgroundOps_.notifyActivation();
}
};
......@@ -211,30 +231,15 @@ cca.App = class {
*/
cca.App.instance_ = null;
/**
* Intent associated with current app window.
* @type {?cca.intent.Intent}
*/
window.intent = window.intent || null;
/**
* Creates the App object and starts camera stream.
*/
document.addEventListener('DOMContentLoaded', async () => {
if (!cca.App.instance_) {
cca.App.instance_ = new cca.App();
if (cca.App.instance_ !== null) {
return;
}
assert(window['backgroundOps'] !== undefined);
cca.App.instance_ = new cca.App(
/** @type {!cca.bg.BackgroundOps} */ (window['backgroundOps']));
cca.App.instance_.start();
// Register methods called from background.
window.ops = {
suspend: () => {
cca.App.instance_.suspend().then(window.onSuspended);
},
resume: () => {
cca.App.instance_.resume();
window.onActive();
},
};
chrome.app.window.current().show();
window.onActive();
});
......@@ -47,8 +47,10 @@ cca.views.Camera = class extends cca.views.View {
* @param {!cca.device.DeviceInfoUpdater} infoUpdater
* @param {!cca.device.PhotoConstraintsPreferrer} photoPreferrer
* @param {!cca.device.VideoConstraintsPreferrer} videoPreferrer
* @param {Mode} defaultMode
*/
constructor(resultSaver, infoUpdater, photoPreferrer, videoPreferrer) {
constructor(
resultSaver, infoUpdater, photoPreferrer, videoPreferrer, defaultMode) {
super('#camera');
/**
......@@ -57,6 +59,12 @@ cca.views.Camera = class extends cca.views.View {
*/
this.infoUpdater_ = infoUpdater;
/**
* @type {!Mode}
* @protected
*/
this.defaultMode_ = defaultMode;
/**
* Layout handler for the camera view.
* @type {!cca.views.camera.Layout}
......@@ -173,21 +181,6 @@ cca.views.Camera = class extends cca.views.View {
cca.state.get('suspend');
}
/**
* @return {!Mode}
* @protected
*/
get defaultMode_() {
switch (window.intent && window.intent.mode) {
case cca.intent.Mode.PHOTO:
return Mode.PHOTO;
case cca.intent.Mode.VIDEO:
return Mode.VIDEO;
default:
return Mode.PHOTO;
}
}
/**
* @override
*/
......
......@@ -59,7 +59,8 @@ cca.views.CameraIntent = class extends cca.views.Camera {
this.videoResultFile_ = await video.endWrite();
},
});
super(resultSaver, infoUpdater, photoPreferrer, videoPreferrer);
super(
resultSaver, infoUpdater, photoPreferrer, videoPreferrer, intent.mode);
/**
* @type {!cca.intent.Intent}
......
......@@ -26,11 +26,14 @@
"app": {
"background": {
"scripts": [
"js/chrome_util.js",
"js/mojo/mojo_bindings_lite.js",
"js/mojo/camera_intent.mojom-lite.js",
"js/mojo/camera_app_helper.mojom-lite.js",
"js/mojo/chrome_helper.js",
"js/type.js",
"js/intent.js",
"js/background_ops.js",
"js/background.js"
]
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment