CCA: Prevent chromevox navigate to preview video element

The preview video element is not interactable with chromevox. This CL
prevent chromevox navigate to preview by creating preview video from
template with aria-hide=true.

Bug: 1135052
Test: Manually with chromevox
Test: tast run <DUT> "camera.CCAUI*"

(cherry picked from commit 43be207790e2dec2d1cf182c11cd3a684bc0df2a)

Change-Id: I1dfc87b564dd1db119c10643b587fa254470493a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2454913
Auto-Submit: Inker Kuo <[email protected]>
Commit-Queue: Shik Chen <[email protected]>
Reviewed-by: Shik Chen <[email protected]>
Cr-Original-Commit-Position: refs/heads/master@{#814585}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2459934
Reviewed-by: Inker Kuo <[email protected]>
Commit-Queue: Inker Kuo <[email protected]>
Cr-Commit-Position: refs/branch-heads/4280@{#127}
Cr-Branched-From: ea420fb963f9658c9969b6513c56b8f47efa1a2a-refs/heads/master@{#812852}
diff --git a/chromeos/components/camera_app_ui/resources/js/dom.js b/chromeos/components/camera_app_ui/resources/js/dom.js
index c915f1b..07bf306 100644
--- a/chromeos/components/camera_app_ui/resources/js/dom.js
+++ b/chromeos/components/camera_app_ui/resources/js/dom.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {assertInstanceof} from './chrome_util.js';
+import {setupI18nElements} from './util.js';
 
 // Disables eslint check for closure compiler constructor type.
 /* eslint-disable valid-jsdoc */
@@ -10,7 +11,7 @@
 /**
  * Gets an element matching css selector under the target element and checks its
  * type.
- * @param {(!HTMLElement|!HTMLDocument)} target
+ * @param {!Node} target
  * @param {string} selector
  * @param {function(new: T, ...)} type A user-defined constructor.
  * @return {T}
@@ -23,7 +24,7 @@
 /**
  * Gets all elements matching css selector under the target element and asserts
  * their type to be specific type.
- * @param {(!HTMLElement|!HTMLDocument)} target
+ * @param {!Node} target
  * @param {string} selector
  * @param {function(new: T, ...)} type A user-defined constructor.
  * @return {!NodeList<T>}
@@ -60,4 +61,16 @@
   return getAllFrom(document, selector, type);
 }
 
+/**
+ * Instantiates template with the target selector.
+ * @param {string} selector
+ * @return {!Node}
+ */
+export function instantiateTemplate(selector) {
+  const tpl = get(selector, HTMLTemplateElement);
+  const node = document.importNode(tpl.content, true);
+  setupI18nElements(node);
+  return node;
+}
+
 /* eslint-enable valid-jsdoc */
diff --git a/chromeos/components/camera_app_ui/resources/js/util.js b/chromeos/components/camera_app_ui/resources/js/util.js
index 19c03db..2e00b78 100644
--- a/chromeos/components/camera_app_ui/resources/js/util.js
+++ b/chromeos/components/camera_app_ui/resources/js/util.js
@@ -290,7 +290,8 @@
 
 /**
  * Sets up i18n messages on DOM subtree by i18n attributes.
- * @param {!HTMLElement} rootElement Root of DOM subtree to be set up with.
+ * @param {!Node} rootElement Root of DOM subtree to be set up
+ *     with.
  */
 export function setupI18nElements(rootElement) {
   const getElements = (attr) => rootElement.querySelectorAll('[' + attr + ']');
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
index d1bb54cb..4f2e886 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import {browserProxy} from '../../browser_proxy/browser_proxy.js';
-import {assertInstanceof} from '../../chrome_util.js';
 import * as dom from '../../dom.js';
 import {DeviceOperator, parseMetadata} from '../../mojo/device_operator.js';
 import * as nav from '../../nav.js';
@@ -109,11 +108,8 @@
    * @return {!Promise} Promise for the operation.
    */
   async setSource_(stream) {
-    const video =
-        assertInstanceof(document.createElement('video'), HTMLVideoElement);
-    video.id = 'preview-video';
-    video.classList = this.video_.classList;
-    video.muted = true;  // Mute to avoid echo from the captured audio.
+    const node = dom.instantiateTemplate('#preview-video-template');
+    const video = dom.getFrom(node, 'video', HTMLVideoElement);
     await new Promise((resolve) => {
       const handler = () => {
         video.removeEventListener('canplay', handler);
@@ -123,7 +119,7 @@
       video.srcObject = stream;
     });
     await video.play();
-    this.video_.parentElement.replaceChild(video, this.video_);
+    this.video_.parentElement.replaceChild(node, this.video_);
     this.video_.removeAttribute('srcObject');
     this.video_.load();
     this.video_ = video;
diff --git a/chromeos/components/camera_app_ui/resources/js/views/settings.js b/chromeos/components/camera_app_ui/resources/js/views/settings.js
index 1dd6ec3..f1384fc 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/settings.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/settings.js
@@ -226,20 +226,6 @@
     this.backVideoItem_ = dom.get('#settings-back-videores', HTMLElement);
 
     /**
-     * @type {!HTMLTemplateElement}
-     * @private
-     */
-    this.resItemTempl_ =
-        dom.get('#resolution-item-template', HTMLTemplateElement);
-
-    /**
-     * @type {!HTMLTemplateElement}
-     * @private
-     */
-    this.extcamItemTempl_ =
-        dom.get('#extcam-resolution-item-template', HTMLTemplateElement);
-
-    /**
      * Device setting of front camera. Null if no front camera.
      * @type {?DeviceSetting}
      * @private
@@ -454,9 +440,8 @@
       let /** !HTMLElement */ photoItem;
       let /** !HTMLElement */ videoItem;
       if (deviceId !== focusedId) {
-        const extItem = /** @type {!HTMLElement} */ (
-            document.importNode(this.extcamItemTempl_.content, true));
-        util.setupI18nElements(extItem);
+        const extItem =
+            dom.instantiateTemplate('#extcam-resolution-item-template');
         [titleItem, photoItem, videoItem] =
             dom.getAllFrom(extItem, '.menu-item', HTMLElement);
 
@@ -625,8 +610,7 @@
         .forEach((element) => element.parentNode.removeChild(element));
 
     resolutions.forEach((r) => {
-      const item = /** @type {!HTMLElement} */ (
-          document.importNode(this.resItemTempl_.content, true));
+      const item = dom.instantiateTemplate('#resolution-item-template');
       const label = dom.getFrom(item, 'label', HTMLLabelElement);
       util.setInkdropEffect(label);
       const input = dom.getFrom(item, 'input', HTMLInputElement);
diff --git a/chromeos/components/camera_app_ui/resources/views/main.html b/chromeos/components/camera_app_ui/resources/views/main.html
index ad272db..e0d6dcb 100644
--- a/chromeos/components/camera_app_ui/resources/views/main.html
+++ b/chromeos/components/camera_app_ui/resources/views/main.html
@@ -406,6 +406,10 @@
     <audio id="sound-rec-end" src="/sounds/record_end.ogg" data-timeout="450">
     <audio id="sound-rec-pause" src="/sounds/record_pause.ogg"
       data-timeout="500">
+    <template id="preview-video-template">
+      <video id="preview-video" class="preview-content" aria-hidden="true"
+        muted></video>
+    </template>
     <template id="resolution-item-template">
       <label class="menu-item circle resolution-option">
         <input class="icon" type="radio" tabindex="0">