Skip to content

Commit

Permalink
Add stream action interface allowing native code to notify Eche Web to
Browse files Browse the repository at this point in the history
close stream

In order to make sure WebRtc is clear when close Eche bubble widget, add
stream action interface allowing native code to notify web code to close
stream

Bug: b/223476848
Test: manual test
Change-Id: I16402f4442c90daecf8fbb60efe345cfcbf0b56a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3545498
Reviewed-by: Will Harris <wfh@chromium.org>
Reviewed-by: Daniel Nishi <dhnishi@chromium.org>
Reviewed-by: Alex Newcomer <newcomer@chromium.org>
Commit-Queue: Andy Chou <andychou@google.com>
Cr-Commit-Position: refs/heads/main@{#987309}
  • Loading branch information
Andy Chou authored and Chromium LUCI CQ committed Mar 31, 2022
1 parent 6d44f17 commit a7efeb2
Show file tree
Hide file tree
Showing 16 changed files with 227 additions and 18 deletions.
57 changes: 49 additions & 8 deletions ash/system/eche/eche_tray.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ constexpr gfx::Size kDefaultBubbleSize(360, 360 * kDefaultAspectRatio);
// Max percentage of the screen height that can be covered by the eche bubble.
constexpr float kMaxHeightPercentage = 0.85;

// Unload timeout to close Eche Bubble in case error from Ech web during closing
constexpr base::TimeDelta kUnloadTimeoutDuration = base::Milliseconds(500);

// Creates a button with the given callback, icon, and tooltip text.
// `message_id` is the resource id of the tooltip text of the icon.
std::unique_ptr<views::Button> CreateButton(
Expand Down Expand Up @@ -270,10 +273,38 @@ void EcheTray::PurgeAndClose() {
if (bubble_view)
bubble_view->ResetDelegate();

bubble_.reset();
SetIsActive(false);
SetVisiblePreferred(false);
web_view_ = nullptr;
close_button_ = nullptr;
minimize_button_ = nullptr;
unload_timer_.reset();
bubble_.reset();
}

void EcheTray::SetGracefulCloseCallback(
GracefulCloseCallback graceful_close_callback) {
if (!graceful_close_callback)
return;
graceful_close_callback_ = std::move(graceful_close_callback);
}

void EcheTray::StartGracefulClose() {
if (!graceful_close_callback_) {
PurgeAndClose();
return;
}
HideBubble();
std::move(graceful_close_callback_).Run();
// Graceful close will let Eche Web to close connection release then notify
// back to native code to close window. In case there is any exception happens
// in js layer, start a timer to force close widget in case unload can't be
// finished.
if (!unload_timer_) {
unload_timer_ = std::make_unique<base::DelayTimer>(
FROM_HERE, kUnloadTimeoutDuration, this, &EcheTray::PurgeAndClose);
unload_timer_->Reset();
}
}

void EcheTray::HideBubble() {
Expand All @@ -295,7 +326,8 @@ void EcheTray::InitBubble() {
init_params.anchor_rect = shelf()->GetSystemTrayAnchorRect();
init_params.insets = GetTrayBubbleInsets();
init_params.shelf_alignment = shelf()->alignment();
init_params.preferred_width = GetSizeForEche().width();
const gfx::Size eche_size = CalculateSizeForEche();
init_params.preferred_width = eche_size.width();
init_params.close_on_deactivate = false;
init_params.has_shadow = false;
init_params.translucent = true;
Expand All @@ -315,7 +347,7 @@ void EcheTray::InitBubble() {
AshWebView::InitParams params;
params.can_record_media = true;
auto web_view = AshWebViewFactory::Get()->Create(params);
web_view->SetPreferredSize(GetSizeForEche());
web_view->SetPreferredSize(eche_size);
if (!url_.is_empty())
web_view->Navigate(url_);
web_view_ = bubble_view->AddChildView(std::move(web_view));
Expand All @@ -327,7 +359,7 @@ void EcheTray::InitBubble() {
bubble_->GetBubbleView()->UpdateBubble();
}

gfx::Size EcheTray::GetSizeForEche() const {
gfx::Size EcheTray::CalculateSizeForEche() const {
const gfx::Rect work_area_bounds =
display::Screen::GetScreen()
->GetDisplayNearestWindow(
Expand Down Expand Up @@ -375,18 +407,27 @@ std::unique_ptr<views::View> EcheTray::CreateBubbleHeaderView() {
title->SetHorizontalAlignment(gfx::ALIGN_LEFT);

// Add minimize button
header->AddChildView(CreateButton(
minimize_button_ = header->AddChildView(CreateButton(
base::BindRepeating(&EcheTray::CloseBubble, weak_factory_.GetWeakPtr()),
kEcheMinimizeIcon, IDS_APP_ACCNAME_MINIMIZE));

// Add close button
header->AddChildView(CreateButton(
base::BindRepeating(&EcheTray::PurgeAndClose, weak_factory_.GetWeakPtr()),
kEcheCloseIcon, IDS_APP_ACCNAME_CLOSE));
close_button_ = header->AddChildView(
CreateButton(base::BindRepeating(&EcheTray::StartGracefulClose,
weak_factory_.GetWeakPtr()),
kEcheCloseIcon, IDS_APP_ACCNAME_CLOSE));

return header;
}

views::Button* EcheTray::GetMinimizeButtonForTesting() const {
return minimize_button_;
}

views::Button* EcheTray::GetCloseButtonForTesting() const {
return close_button_;
}

views::ImageButton* EcheTray::GetIcon() {
PhoneHubTray* phone_hub_tray = GetPhoneHubTray();
if (!phone_hub_tray)
Expand Down
31 changes: 28 additions & 3 deletions ash/system/eche/eche_tray.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "ash/system/tray/tray_background_view.h"
#include "ash/webui/eche_app_ui/mojom/eche_app.mojom.h"
#include "base/gtest_prod_util.h"
#include "base/timer/timer.h"
#include "components/session_manager/session_manager_types.h"
#include "ui/views/controls/button/button.h"
#include "url/gurl.h"
Expand Down Expand Up @@ -50,6 +51,8 @@ class ASH_EXPORT EcheTray : public TrayBackgroundView, public SessionObserver {
public:
METADATA_HEADER(EcheTray);

using GracefulCloseCallback = base::OnceCallback<void()>;

explicit EcheTray(Shelf* shelf);
EcheTray(const EcheTray&) = delete;
EcheTray& operator=(const EcheTray&) = delete;
Expand Down Expand Up @@ -85,6 +88,16 @@ class ASH_EXPORT EcheTray : public TrayBackgroundView, public SessionObserver {
// Sets the icon that will be used on the tray.
void SetIcon(const gfx::Image& icon, const std::u16string& tooltip_text);

// Sets graceful close callback functiion. When close Eche Bubble, it will
// notify to Eche Web to release connection resource. Be aware that once this
// is set, close button will not call PurgeAndClose() but rely on Eche Web to
// close window when connection resource is released; if it is not set, then
// it will immediaely call PurgeAndClose() to close window.
void SetGracefulCloseCallback(GracefulCloseCallback graceful_close_callback);

views::Button* GetMinimizeButtonForTesting() const;
views::Button* GetCloseButtonForTesting() const;

// Initializes the bubble with given parameters. If there is any previous
// bubble already shown with a different URL it is going to be closed. The
// bubble is not shown initially until `ShowBubble` is called.
Expand Down Expand Up @@ -118,9 +131,9 @@ class ASH_EXPORT EcheTray : public TrayBackgroundView, public SessionObserver {
private:
FRIEND_TEST_ALL_PREFIXES(EcheTrayTest, EcheTrayCreatesBubbleButHideFirst);

// Returns the size of the Exo bubble based on the screen size and
// orientation.
gfx::Size GetSizeForEche() const;
// Calculates and returns the size of the Exo bubble based on the screen size
// and orientation.
gfx::Size CalculateSizeForEche() const;

// Handles the click on the "back" arrow in the header.
void OnArrowBackActivated();
Expand All @@ -134,6 +147,10 @@ class ASH_EXPORT EcheTray : public TrayBackgroundView, public SessionObserver {
void StartLoadingAnimation();
void SetIconVisibility(bool visibility);

// Starts graceful close to ensure connection resource is released before
// window is closed.
void StartGracefulClose();

PhoneHubTray* GetPhoneHubTray();
EcheIconLoadingIndicatorView* GetLoadingIndicator();

Expand All @@ -156,6 +173,14 @@ class ASH_EXPORT EcheTray : public TrayBackgroundView, public SessionObserver {
base::ScopedObservation<SessionControllerImpl, SessionObserver>
observed_session_{this};

GracefulCloseCallback graceful_close_callback_;

// The unload timer to force close EcheTray in case unload error.
std::unique_ptr<base::DelayTimer> unload_timer_;

views::Button* close_button_ = nullptr;
views::Button* minimize_button_ = nullptr;

base::WeakPtrFactory<EcheTray> weak_factory_{this};
};

Expand Down
44 changes: 44 additions & 0 deletions ash/system/eche/eche_tray_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@

namespace ash {

namespace {

bool is_web_content_unloaded_ = false;

void UnloadWebContent() {
is_web_content_unloaded_ = true;
}

void ResetUnloadWebContent() {
is_web_content_unloaded_ = false;
}

} // namespace

class EcheTrayTest : public AshTestBase {
public:
EcheTrayTest() = default;
Expand Down Expand Up @@ -53,6 +67,11 @@ class EcheTrayTest : public AshTestBase {
eche_tray_->GetBoundsInScreen().CenterPoint());
}

void ClickButton(views::Button* button) {
GetEventGenerator()->GestureTapAt(
button->GetBoundsInScreen().CenterPoint());
}

EcheTray* eche_tray() { return eche_tray_; }
PhoneHubTray* phone_hub_tray() { return phone_hub_tray_; }

Expand Down Expand Up @@ -173,4 +192,29 @@ TEST_F(EcheTrayTest, EcheTrayCreatesBubbleButStreamStatusChanged) {
EXPECT_FALSE(eche_tray()->GetVisible());
}

TEST_F(EcheTrayTest, EcheTrayMinimizeButtonClicked) {
eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1");
eche_tray()->ShowBubble();

EXPECT_TRUE(
eche_tray()->get_bubble_wrapper_for_test()->bubble_view()->GetVisible());

ClickButton(eche_tray()->GetMinimizeButtonForTesting());

EXPECT_FALSE(
eche_tray()->get_bubble_wrapper_for_test()->bubble_view()->GetVisible());
EXPECT_FALSE(is_web_content_unloaded_);
}

TEST_F(EcheTrayTest, EcheTrayCloseButtonClicked) {
ResetUnloadWebContent();
eche_tray()->SetGracefulCloseCallback(base::BindOnce(&UnloadWebContent));
eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1");
eche_tray()->ShowBubble();

ClickButton(eche_tray()->GetCloseButtonForTesting());

EXPECT_TRUE(is_web_content_unloaded_);
}

} // namespace ash
5 changes: 5 additions & 0 deletions ash/webui/eche_app_ui/eche_app_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const char kMetricNameResult[] = "Eche.Connection.Result";
const char kMetricNameDuration[] = "Eche.Connection.Duration";
const char kMetricNameLatency[] = "Eche.Connectivity.Latency";
} // namespace

namespace eche_app {

EcheAppManager::EcheAppManager(
Expand Down Expand Up @@ -136,6 +137,10 @@ void EcheAppManager::BindDisplayStreamHandlerInterface(
stream_status_change_handler_->Bind(std::move(receiver));
}

void EcheAppManager::CloseStream() {
stream_status_change_handler_->CloseStream();
}

AppsAccessManager* EcheAppManager::GetAppsAccessManager() {
return apps_access_manager_.get();
}
Expand Down
3 changes: 3 additions & 0 deletions ash/webui/eche_app_ui/eche_app_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class EcheAppManager : public KeyedService {

AppsAccessManager* GetAppsAccessManager();

// This trigger Eche Web to release connection resource.
void CloseStream();

// KeyedService:
void Shutdown() override;

Expand Down
1 change: 0 additions & 1 deletion ash/webui/eche_app_ui/eche_recent_app_click_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

#include "ash/webui/eche_app_ui/eche_recent_app_click_handler.h"

#include "ash/components/multidevice/logging/logging.h"
#include "ash/components/phonehub/phone_hub_manager.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
Expand Down
13 changes: 13 additions & 0 deletions ash/webui/eche_app_ui/eche_stream_status_change_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ void EcheStreamStatusChangeHandler::OnStreamStatusChanged(
NotifyStreamStatusChanged(status);
}

void EcheStreamStatusChangeHandler::SetStreamActionObserver(
mojo::PendingRemote<mojom::StreamActionObserver> observer) {
PA_LOG(INFO) << "echeapi EcheDisplayStreamHandler SetStreamActionObserver";
observer_remote_.reset();
observer_remote_.Bind(std::move(observer));
}

void EcheStreamStatusChangeHandler::Bind(
mojo::PendingReceiver<mojom::DisplayStreamHandler> receiver) {
display_stream_receiver_.reset();
Expand All @@ -51,5 +58,11 @@ void EcheStreamStatusChangeHandler::NotifyStreamStatusChanged(
observer.OnStreamStatusChanged(status);
}

void EcheStreamStatusChangeHandler::CloseStream() {
if (!observer_remote_.is_bound())
return;
observer_remote_->OnStreamAction(mojom::StreamAction::kStreamActionClose);
}

} // namespace eche_app
} // namespace ash
7 changes: 7 additions & 0 deletions ash/webui/eche_app_ui/eche_stream_status_change_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
#include "ash/webui/eche_app_ui/mojom/eche_app.mojom.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace ash {
namespace eche_app {
Expand All @@ -34,9 +36,13 @@ class EcheStreamStatusChangeHandler : public mojom::DisplayStreamHandler {
EcheStreamStatusChangeHandler& operator=(
const EcheStreamStatusChangeHandler&) = delete;

void CloseStream();

// mojom::DisplayStreamHandler:
void StartStreaming() override;
void OnStreamStatusChanged(mojom::StreamStatus status) override;
void SetStreamActionObserver(
mojo::PendingRemote<mojom::StreamActionObserver> observer) override;

void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
Expand All @@ -49,6 +55,7 @@ class EcheStreamStatusChangeHandler : public mojom::DisplayStreamHandler {

private:
mojo::Receiver<mojom::DisplayStreamHandler> display_stream_receiver_{this};
mojo::Remote<mojom::StreamActionObserver> observer_remote_;
base::ObserverList<Observer> observer_list_;
};

Expand Down
4 changes: 3 additions & 1 deletion ash/webui/eche_app_ui/eche_tray_stream_status_observer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ namespace eche_app {

void LaunchBubble(const GURL& url,
const gfx::Image& icon,
const std::u16string& visible_name) {
const std::u16string& visible_name,
EcheTray::GracefulCloseCallback graceful_close_callback) {
auto* eche_tray = ash::GetEcheTray();
DCHECK(eche_tray);
eche_tray->LoadBubble(url, icon, visible_name);
eche_tray->SetGracefulCloseCallback(std::move(graceful_close_callback));
}

void CloseBubble() {
Expand Down
4 changes: 3 additions & 1 deletion ash/webui/eche_app_ui/eche_tray_stream_status_observer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef ASH_WEBUI_ECHE_APP_UI_ECHE_TRAY_STREAM_STATUS_OBSERVER_H_
#define ASH_WEBUI_ECHE_APP_UI_ECHE_TRAY_STREAM_STATUS_OBSERVER_H_

#include "ash/system/eche/eche_tray.h"
#include "ash/webui/eche_app_ui/eche_stream_status_change_handler.h"
#include "ash/webui/eche_app_ui/mojom/eche_app.mojom.h"
#include "base/scoped_observation.h"
Expand All @@ -22,7 +23,8 @@ namespace eche_app {
// `GetEcheTray` everywhere.
void LaunchBubble(const GURL& url,
const gfx::Image& icon,
const std::u16string& visible_name);
const std::u16string& visible_name,
EcheTray::GracefulCloseCallback graceful_close_callback);

// It is called from chrome/browser/ash/eche_app/eche_app_manager_factory.cc.
void CloseBubble();
Expand Down

0 comments on commit a7efeb2

Please sign in to comment.