Commit 14560c1e authored by Wei Lee's avatar Wei Lee Committed by Commit Bot

Forwards Android Camera Intents to CCA

This CL supports forwarding Android camera intents from ARC++ intent
helper to CCA and is able to return the captured result back to the
ARC++ intent helper.

Bug: b/131809655, b/134635999, 980812, 967611
Test: am start -a android.media.action.IMAGE_CAPTURE
Test: am start -a android.media.action.VIDEO_CAPTURE
Test: Run CtsVerifier -> Camera Intents
Test: Run Hangout -> Capture photo/VIDEO_CAPTURE
Test: ./cts-tradefed run commandAndExit cts -m CtsCameraTestCases
Test: (Simulate camera v1 stack on Nocturne)
      (dut) $ mv /usr/bin/cros_camera_service /usr/bin/cros_camera_service_old
      (dut) $ (Tested with external camera)

Change-Id: I738483dfdf63c56bb0947bb1ff201fba9be02bce
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1592991
Commit-Queue: Wei Lee <wtlee@chromium.org>
Reviewed-by: default avatarRicky Liang <jcliang@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarcalamity <calamity@chromium.org>
Reviewed-by: default avatarDavid Jacobo <djacobo@chromium.org>
Reviewed-by: default avatarKen Rockot <rockot@google.com>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#680324}
parent 5b248de9
......@@ -5,6 +5,8 @@
#ifndef ASH_PUBLIC_CPP_NEW_WINDOW_DELEGATE_H_
#define ASH_PUBLIC_CPP_NEW_WINDOW_DELEGATE_H_
#include <string>
#include "ash/public/cpp/ash_public_export.h"
#include "base/macros.h"
......@@ -51,6 +53,10 @@ class ASH_PUBLIC_EXPORT NewWindowDelegate {
// true then the page is triggered from Assistant.
virtual void OpenFeedbackPage(bool from_assistant = false) = 0;
// Launches the camera app from Android camera intent with the intent
// information as url |queries|.
virtual void LaunchCameraApp(const std::string& queries) = 0;
protected:
NewWindowDelegate();
virtual ~NewWindowDelegate();
......
......@@ -20,5 +20,6 @@ void TestNewWindowDelegate::RestoreTab() {}
void TestNewWindowDelegate::ShowKeyboardShortcutViewer() {}
void TestNewWindowDelegate::ShowTaskManager() {}
void TestNewWindowDelegate::OpenFeedbackPage(bool from_assistant) {}
void TestNewWindowDelegate::LaunchCameraApp(const std::string& queries) {}
} // namespace ash
......@@ -28,6 +28,7 @@ class ASH_PUBLIC_EXPORT TestNewWindowDelegate : public NewWindowDelegate {
void ShowKeyboardShortcutViewer() override;
void ShowTaskManager() override;
void OpenFeedbackPage(bool from_assistant) override;
void LaunchCameraApp(const std::string& queries) override;
DISALLOW_COPY_AND_ASSIGN(TestNewWindowDelegate);
};
......
......@@ -48,5 +48,7 @@ void ShellNewWindowDelegate::ShowTaskManager() {}
void ShellNewWindowDelegate::OpenFeedbackPage(bool from_assistant) {}
void ShellNewWindowDelegate::LaunchCameraApp(const std::string& queries) {}
} // namespace shell
} // namespace ash
......@@ -32,6 +32,7 @@ class ShellNewWindowDelegate : public ash::NewWindowDelegate {
void ShowKeyboardShortcutViewer() override;
void ShowTaskManager() override;
void OpenFeedbackPage(bool from_assistant) override;
void LaunchCameraApp(const std::string& queries) override;
private:
DISALLOW_COPY_AND_ASSIGN(ShellNewWindowDelegate);
......
......@@ -11,9 +11,10 @@
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "chrome/browser/media/router/media_router_feature.h" // nogncheck
#include "chrome/browser/media/router/media_router_feature.h" // nogncheck
#include "chrome/browser/media/router/mojo/media_router_desktop.h" // nogncheck
#include "chrome/common/extensions/extension_constants.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/video_capture_service.h"
......@@ -24,9 +25,12 @@
#if defined(OS_CHROMEOS)
#include "base/task/post_task.h"
#include "chrome/common/pref_names.h"
#include "chromeos/services/ime/public/mojom/constants.mojom.h"
#include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
#include "chromeos/services/media_perception/public/mojom/media_perception.mojom.h"
#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/media_device_id.h"
#include "extensions/browser/api/extensions_api_client.h"
......@@ -73,6 +77,15 @@ void TranslateVideoDeviceId(
std::move(callback_on_io_thread));
}
void TriggerCameraIntent(content::BrowserContext* context,
uint32_t intent_id,
bool is_success,
const std::vector<uint8_t>& captured_data) {
auto* intent_helper =
arc::ArcIntentHelperBridge::GetForBrowserContext(context);
intent_helper->OnCameraIntentHandled(intent_id, is_success, captured_data);
}
// Binds CrosImageCaptureRequest to a proxy which translates the source id into
// video device id and then forward the request to video capture service.
void BindRendererFacingCrosImageCapture(
......@@ -91,10 +104,13 @@ void BindRendererFacingCrosImageCapture(
auto mapping_callback =
base::BindRepeating(&TranslateVideoDeviceId, media_device_id_salt,
std::move(security_origin));
auto intent_callback = base::BindRepeating(
&TriggerCameraIntent, source->GetProcess()->GetBrowserContext());
// Bind origin request to proxy implementation.
auto api_proxy = std::make_unique<media::RendererFacingCrosImageCapture>(
std::move(proxy_ptr), std::move(mapping_callback));
std::move(proxy_ptr), std::move(mapping_callback),
std::move(intent_callback));
mojo::MakeStrongBinding(std::move(api_proxy), std::move(request));
}
#endif
......
......@@ -6,6 +6,8 @@
#include <utility>
#include "apps/launcher.h"
#include "ash/public/cpp/app_list/internal_app_id_constants.h"
#include "ash/public/cpp/arc_custom_tab.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/keyboard_shortcut_viewer.h"
......@@ -38,6 +40,7 @@
#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
#include "chrome/browser/ui/settings_window_manager_chromeos.h"
#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/webui_url_constants.h"
#include "components/arc/arc_util.h"
......@@ -55,6 +58,7 @@
#include "content/public/common/service_manager_connection.h"
#include "content/public/common/user_agent.h"
#include "content/public/common/was_activated_option.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
......@@ -480,6 +484,23 @@ void ChromeNewWindowClient::OpenFeedbackPage(bool from_assistant) {
chrome::OpenFeedbackDialog(chrome::FindBrowserWithActiveWindow(), source);
}
void ChromeNewWindowClient::LaunchCameraApp(const std::string& queries) {
Profile* const profile = ProfileManager::GetActiveUserProfile();
const extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(profile);
const extensions::Extension* extension =
registry->GetInstalledExtension(extension_misc::kChromeCameraAppId);
auto url = GURL(extensions::Extension::GetBaseURLFromExtensionId(
extension_misc::kChromeCameraAppId)
.spec() +
queries);
apps::LaunchPlatformAppWithUrl(profile, extension,
/*handler_id=*/std::string(), url,
/*referrer_url=*/GURL());
}
void ChromeNewWindowClient::OpenUrlFromArc(const GURL& url) {
if (!url.is_valid())
return;
......
......@@ -46,6 +46,7 @@ class ChromeNewWindowClient : public ash::NewWindowDelegate,
void ShowKeyboardShortcutViewer() override;
void ShowTaskManager() override;
void OpenFeedbackPage(bool from_assistant) override;
void LaunchCameraApp(const std::string& queries) override;
// arc::OpenUrlDelegate:
void OpenUrlFromArc(const GURL& url) override;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Next MinVersion: 28
// Next MinVersion: 29
module arc.mojom;
......@@ -171,9 +171,14 @@ interface CustomTabSession {
[MinVersion=26] OnOpenInChromeClicked@0();
};
enum CameraIntentMode {
PHOTO,
VIDEO,
};
// Handles intents from ARC in Chrome.
// Deprecated method ID: 4
// Next method ID: 12
// Next method ID: 13
interface IntentHelperHost {
// Called when icons associated with the package are no longer up to date.
[MinVersion=3] OnIconInvalidated@1(string package_name);
......@@ -224,6 +229,21 @@ interface IntentHelperHost {
// Does a reset of ARC; this wipes /data, and then re-calls on OOBE for
// account binding to happen again, as if the user just went through OOBE.
[MinVersion=27] FactoryResetArc@11();
// Launches camera app from the camera intent.
// |mode| indicates which mode should camera app land on. If
// |should_handle_result| is true, the intent expects the captured result
// will be returned after capturing. If |should_down_scale| is true, the
// intent expects the captured image would be down-scaled to a small enough
// size. If |is_secure| is true, the intent is fired when the device is
// secured, which means the camera app should not show any user-sensitive
// data. |is_success| indicates that the capture is done successfully. If it
// succeed, the result should be filled in |captured_data| as a byte array.
[MinVersion=28] LaunchCameraApp@12(CameraIntentMode mode,
bool should_handle_result,
bool should_down_scale,
bool is_secure)
=> (bool is_success, array<uint8> captured_data);
};
// Sends intents to ARC on behalf of Chrome.
......
......@@ -115,6 +115,7 @@ ArcIntentHelperBridge::ArcIntentHelperBridge(content::BrowserContext* context,
ArcBridgeService* bridge_service)
: context_(context),
arc_bridge_service_(bridge_service),
camera_intent_id_(0),
allowed_arc_schemes_(std::cbegin(kArcSchemes), std::cend(kArcSchemes)) {
arc_bridge_service_->intent_helper()->SetHost(this);
}
......@@ -221,6 +222,30 @@ void ArcIntentHelperBridge::RecordShareFilesMetrics(mojom::ShareFiles flag) {
UMA_HISTOGRAM_ENUMERATION("Arc.ShareFilesOnExit", flag);
}
void ArcIntentHelperBridge::LaunchCameraApp(arc::mojom::CameraIntentMode mode,
bool should_handle_result,
bool should_down_scale,
bool is_secure,
LaunchCameraAppCallback callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
launch_camera_app_callback_map_.emplace(camera_intent_id_,
std::move(callback));
base::DictionaryValue intent_info;
std::string mode_str =
mode == arc::mojom::CameraIntentMode::PHOTO ? "photo" : "video";
std::stringstream queries;
queries << "?intentId=" << camera_intent_id_ << "&mode=" << mode_str
<< "&shouldHandleResult=" << should_handle_result
<< "&shouldDownScale=" << should_down_scale
<< "&isSecure=" << is_secure;
ash::NewWindowDelegate::GetInstance()->LaunchCameraApp(queries.str());
camera_intent_id_++;
}
ArcIntentHelperBridge::GetResult ArcIntentHelperBridge::GetActivityIcons(
const std::vector<ActivityName>& activities,
OnIconsReadyCallback callback) {
......@@ -258,6 +283,16 @@ bool ArcIntentHelperBridge::HasObserver(
return observer_list_.HasObserver(observer);
}
void ArcIntentHelperBridge::OnCameraIntentHandled(
uint32_t intent_id,
bool is_success,
const std::vector<uint8_t>& captured_data) {
CHECK(launch_camera_app_callback_map_.find(intent_id) !=
launch_camera_app_callback_map_.end());
std::move(launch_camera_app_callback_map_[intent_id])
.Run(is_success, captured_data);
}
// static
bool ArcIntentHelperBridge::IsIntentHelperPackage(
const std::string& package_name) {
......
......@@ -10,6 +10,7 @@
#include <string>
#include <vector>
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
......@@ -33,9 +34,8 @@ class IntentFilter;
class OpenUrlDelegate;
// Receives intents from ARC.
class ArcIntentHelperBridge
: public KeyedService,
public mojom::IntentHelperHost {
class ArcIntentHelperBridge : public KeyedService,
public mojom::IntentHelperHost {
public:
// Returns singleton instance for the given BrowserContext,
// or nullptr if the browser |context| is not allowed to use ARC.
......@@ -61,6 +61,10 @@ class ArcIntentHelperBridge
void RemoveObserver(ArcIntentHelperObserver* observer);
bool HasObserver(ArcIntentHelperObserver* observer) const;
void OnCameraIntentHandled(uint32_t intent_id,
bool is_success,
const std::vector<uint8_t>& captured_data);
// mojom::IntentHelperHost
void OnIconInvalidated(const std::string& package_name) override;
void OnIntentFiltersUpdated(
......@@ -79,6 +83,11 @@ class ArcIntentHelperBridge
void FactoryResetArc() override;
void OnOpenWebApp(const std::string& url) override;
void RecordShareFilesMetrics(mojom::ShareFiles flag) override;
void LaunchCameraApp(arc::mojom::CameraIntentMode mode,
bool should_handle_result,
bool should_down_scale,
bool is_secure,
LaunchCameraAppCallback callback) override;
// Retrieves icons for the |activities| and calls |callback|.
// See ActivityIconLoader::GetActivityIcons() for more details.
......@@ -123,6 +132,11 @@ class ArcIntentHelperBridge
base::ObserverList<ArcIntentHelperObserver>::Unchecked observer_list_;
base::flat_map<uint32_t, LaunchCameraAppCallback>
launch_camera_app_callback_map_;
uint32_t camera_intent_id_;
// Schemes that ARC is known to send via OnOpenUrl.
const std::set<std::string> allowed_arc_schemes_;
......
......@@ -51,4 +51,11 @@ void CrosImageCaptureImpl::OnGotCameraInfo(
std::move(callback).Run(std::move(camera_info));
}
void CrosImageCaptureImpl::OnIntentHandled(
uint32_t intent_id,
bool is_success,
const std::vector<uint8_t>& captured_data) {
NOTREACHED() << "Should be handled in RendererFacingCrosImageCapture";
}
} // namespace media
......@@ -17,6 +17,7 @@ namespace media {
class CrosImageCaptureImpl : public cros::mojom::CrosImageCapture {
public:
explicit CrosImageCaptureImpl(ReprocessManager* reprocess_manager);
~CrosImageCaptureImpl() override;
void BindRequest(cros::mojom::CrosImageCaptureRequest request);
......@@ -25,9 +26,11 @@ class CrosImageCaptureImpl : public cros::mojom::CrosImageCapture {
void GetCameraInfo(const std::string& device_id,
GetCameraInfoCallback callback) override;
void SetReprocessOption(const std::string& device_id,
cros::mojom::Effect effect,
SetReprocessOptionCallback callback) override;
void SetFpsRange(const std::string& device_id,
const uint32_t stream_width,
const uint32_t stream_height,
......@@ -35,6 +38,10 @@ class CrosImageCaptureImpl : public cros::mojom::CrosImageCapture {
const int32_t max_fps,
SetFpsRangeCallback callback) override;
void OnIntentHandled(uint32_t intent_id,
bool is_success,
const std::vector<uint8_t>& captured_data) override;
private:
void OnGotCameraInfo(GetCameraInfoCallback callback,
cros::mojom::CameraInfoPtr camera_info);
......
......@@ -44,4 +44,16 @@ interface CrosImageCapture {
SetFpsRange(string source_id, uint32 stream_width, uint32 stream_height,
int32 min_fps, int32 max_fps)
=> (bool is_success);
// Invoked when the intent is fulfilled or is failed. For the intent which
// expects to have result, it is fulfilled when the captured is done and is
// failed if the session ends without finishing the capture. For the intent
// which don't expect any result, it is fulfilled when the camera app is
// successfully launched and is failed when the camera fails to launch.
// |intent_id| should be the same id that was specified in the query when
// launching the camera app. |is_success| indicates the result status of the
// intent. The |captured_data| will be delivered to the handler as a byte
// array.
OnIntentHandled(uint32 intent_id, bool is_success,
array<uint8> captured_data);
};
\ No newline at end of file
......@@ -16,9 +16,11 @@ namespace media {
RendererFacingCrosImageCapture::RendererFacingCrosImageCapture(
cros::mojom::CrosImageCapturePtr api_ptr,
DeviceIdMappingCallback mapping_callback)
DeviceIdMappingCallback mapping_callback,
IntentCallback intent_callback)
: cros_image_capture_(std::move(api_ptr)),
mapping_callback_(std::move(mapping_callback)),
intent_callback_(std::move(intent_callback)),
weak_ptr_factory_(this) {}
RendererFacingCrosImageCapture::~RendererFacingCrosImageCapture() = default;
......@@ -86,4 +88,11 @@ void RendererFacingCrosImageCapture::SetFpsRange(const std::string& source_id,
min_frame_rate, max_frame_rate, std::move(callback))));
}
void RendererFacingCrosImageCapture::OnIntentHandled(
uint32_t intent_id,
bool is_success,
const std::vector<uint8_t>& captured_data) {
intent_callback_.Run(intent_id, is_success, captured_data);
}
} // namespace media
\ No newline at end of file
......@@ -23,6 +23,8 @@ class CAPTURE_EXPORT RendererFacingCrosImageCapture
base::OnceCallback<void(const base::Optional<std::string>&)>;
using DeviceIdMappingCallback =
base::RepeatingCallback<void(const std::string&, WithRealIdCallback)>;
using IntentCallback = base::RepeatingCallback<
void(uint32_t, bool, const std::vector<uint8_t>&)>;
// Create an intermediate layer between renderer to the actual
// CrosImageCapture implementation. This class should use |api_ptr| to
......@@ -30,7 +32,8 @@ class CAPTURE_EXPORT RendererFacingCrosImageCapture
// |mapping_callback| to map the device id for every calls that inputs device
// id.
RendererFacingCrosImageCapture(cros::mojom::CrosImageCapturePtr api_ptr,
DeviceIdMappingCallback mapping_callback);
DeviceIdMappingCallback mapping_callback,
IntentCallback intent_callback);
~RendererFacingCrosImageCapture() override;
void GetCameraInfoWithRealId(GetCameraInfoCallback callback,
......@@ -61,11 +64,17 @@ class CAPTURE_EXPORT RendererFacingCrosImageCapture
const int32_t max_frame_rate,
SetFpsRangeCallback callback) override;
void OnIntentHandled(uint32_t intent_id,
bool is_success,
const std::vector<uint8_t>& captured_data) override;
private:
cros::mojom::CrosImageCapturePtr cros_image_capture_;
DeviceIdMappingCallback mapping_callback_;
IntentCallback intent_callback_;
base::WeakPtrFactory<RendererFacingCrosImageCapture> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RendererFacingCrosImageCapture);
......
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