Commit d09dd117 authored by Quan Nguyen's avatar Quan Nguyen Committed by Commit Bot

Launch kiosk apps from Login screen "Apps" menu.

Bug: 836861
Change-Id: Ib480dfa25b45a1cc6dd1424e8f84d0891eec1a0e
Reviewed-on: https://chromium-review.googlesource.com/1092095
Commit-Queue: Quan Nguyen <qnnguyen@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarJacob Dufault <jdufault@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568560}
parent 02521e4b
......@@ -5,10 +5,13 @@
#include "ash/login/login_screen_controller.h"
#include "ash/login/ui/lock_screen.h"
#include "ash/login/ui/lock_window.h"
#include "ash/login/ui/login_data_dispatcher.h"
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/root_window_controller.h"
#include "ash/session/session_controller.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ash/system/status_area_widget.h"
#include "base/debug/alias.h"
......@@ -391,6 +394,17 @@ void LoginScreenController::SetFingerprintUnlockState(
DataDispatcher()->SetFingerprintUnlockState(account_id, state);
}
void LoginScreenController::SetKioskApps(
std::vector<mojom::KioskAppInfoPtr> kiosk_apps) {
Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
->shelf_widget()
->SetLoginKioskApps(std::move(kiosk_apps));
}
void LoginScreenController::LaunchKioskApp(const std::string& app_id) {
login_screen_client_->LaunchKioskApp(app_id);
}
void LoginScreenController::DoAuthenticateUser(const AccountId& account_id,
const std::string& password,
bool authenticated_by_pin,
......
......@@ -7,6 +7,7 @@
#include "ash/ash_export.h"
#include "ash/login/login_screen_controller_observer.h"
#include "ash/public/interfaces/kiosk_app_info.mojom.h"
#include "ash/public/interfaces/login_screen.mojom.h"
#include "base/macros.h"
#include "base/observer_list.h"
......@@ -78,6 +79,7 @@ class ASH_EXPORT LoginScreenController : public mojom::LoginScreen {
void RequestPublicSessionKeyboardLayouts(const AccountId& account_id,
const std::string& locale);
void ShowFeedback();
void LaunchKioskApp(const std::string& app_id);
// Add or remove an observer.
void AddObserver(LoginScreenControllerObserver* observer);
......@@ -131,7 +133,7 @@ class ASH_EXPORT LoginScreenController : public mojom::LoginScreen {
std::vector<mojom::InputMethodItemPtr> keyboard_layouts) override;
void SetFingerprintUnlockState(const AccountId& account_id,
mojom::FingerprintUnlockState state) override;
void SetKioskApps(std::vector<mojom::KioskAppInfoPtr> kiosk_apps) override;
// Flushes the mojo pipes - to be used in tests.
void FlushForTesting();
......
......@@ -5,6 +5,7 @@
#ifndef ASH_LOGIN_MOCK_LOGIN_SCREEN_CLIENT_H_
#define ASH_LOGIN_MOCK_LOGIN_SCREEN_CLIENT_H_
#include "ash/public/interfaces/kiosk_app_info.mojom.h"
#include "ash/public/interfaces/login_screen.mojom.h"
#include "components/password_manager/core/browser/hash_password_manager.h"
#include "mojo/public/cpp/bindings/binding_set.h"
......@@ -67,6 +68,7 @@ class MockLoginScreenClient : public mojom::LoginScreenClient {
MOCK_METHOD2(RequestPublicSessionKeyboardLayouts,
void(const AccountId& account_id, const std::string& locale));
MOCK_METHOD0(ShowFeedback, void());
MOCK_METHOD1(LaunchKioskApp, void(const std::string& app_id));
private:
bool authenticate_user_callback_result_ = true;
......
......@@ -5,6 +5,7 @@
#include "ash/login/ui/login_keyboard_test_base.h"
#include "ash/login/login_screen_controller.h"
#include "ash/login/mock_login_screen_client.h"
#include "ash/login/ui/lock_screen.h"
#include "ash/login/ui/login_test_utils.h"
#include "ash/root_window_controller.h"
......
......@@ -6,6 +6,7 @@ module ash.mojom;
import "ash/public/interfaces/user_info.mojom";
import "ash/public/interfaces/login_user_info.mojom";
import "ash/public/interfaces/kiosk_app_info.mojom";
import "chromeos/components/proximity_auth/public/interfaces/auth_type.mojom";
import "components/account_id/interfaces/account_id.mojom";
import "mojo/public/mojom/base/string16.mojom";
......@@ -125,6 +126,9 @@ interface LoginScreen {
// Set the fingerprint unlock state for user with |account_id|.
SetFingerprintUnlockState(signin.mojom.AccountId account_id,
FingerprintUnlockState state);
// Update the kiosk app data for the login screen.
SetKioskApps(array<KioskAppInfo> kiosk_apps);
};
// Allows ash lock screen to control a client (e.g. Chrome browser). Requests
......@@ -216,4 +220,7 @@ interface LoginScreenClient {
// Request to show a feedback report dialog in chrome.
ShowFeedback();
// Launch the specific kiosk app.
LaunchKioskApp(string app_id);
};
......@@ -31,12 +31,14 @@
#include "ash/tray_action/tray_action.h"
#include "ash/wm/lock_state_controller.h"
#include "base/metrics/user_metrics.h"
#include "skia/ext/image_operations.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/animation/ink_drop_impl.h"
......@@ -83,6 +85,9 @@ constexpr int kButtonMarginDp = 13;
// The color of the button image and label.
constexpr SkColor kButtonColor = SK_ColorWHITE;
// The size of the icons in the apps menu.
constexpr gfx::Size kAppIconSize(16, 16);
class LoginShelfButton : public views::LabelButton {
public:
LoginShelfButton(views::ButtonListener* listener,
......@@ -166,16 +171,27 @@ class KioskAppsButton : public views::MenuButton,
void SetApps(std::vector<mojom::KioskAppInfoPtr> kiosk_apps) {
kiosk_apps_ = std::move(kiosk_apps);
Clear();
for (size_t i = 0; i < kiosk_apps_.size(); ++i)
AddItem(i, kiosk_apps_[i]->name);
for (size_t i = 0; i < kiosk_apps_.size(); ++i) {
gfx::ImageSkia icon = gfx::ImageSkiaOperations::CreateResizedImage(
kiosk_apps_[i]->icon, skia::ImageOperations::RESIZE_GOOD,
kAppIconSize);
AddItemWithIcon(i, kiosk_apps_[i]->name, icon);
}
}
bool HasApps() const { return !kiosk_apps_.empty(); }
void ResetState() {
is_launch_enabled_ = true;
SetVisible(true);
}
// views::MenuButtonListener:
void OnMenuButtonClicked(MenuButton* source,
const gfx::Point& point,
const ui::Event* event) override {
if (!is_launch_enabled_)
return;
menu_runner_.reset(
new views::MenuRunner(this, views::MenuRunner::HAS_MNEMONICS));
......@@ -189,7 +205,14 @@ class KioskAppsButton : public views::MenuButton,
// ui::MenuModel:
void ExecuteCommand(int command_id, int event_flags) override {
// TODO(qnnguyen): implement kiosk app launch.
DCHECK(command_id >= 0 &&
base::checked_cast<size_t>(command_id) < kiosk_apps_.size());
// Once an app is clicked on, don't allow any additional clicks until
// the state is reset (when login screen reappears).
is_launch_enabled_ = false;
Shell::Get()->login_screen_controller()->LaunchKioskApp(
kiosk_apps_[command_id]->app_id);
}
bool IsCommandIdChecked(int command_id) const override { return false; }
......@@ -215,6 +238,7 @@ class KioskAppsButton : public views::MenuButton,
std::vector<mojom::KioskAppInfoPtr> kiosk_apps_;
// Passed to set_menu_marker to remove menu marker
gfx::ImageSkia empty_menu_marker_;
bool is_launch_enabled_ = true;
DISALLOW_COPY_AND_ASSIGN(KioskAppsButton);
};
......@@ -411,12 +435,15 @@ void LoginShelfView::UpdateUi() {
is_lock_screen_note_in_foreground);
GetViewByID(kCancel)->SetVisible(session_state ==
SessionState::LOGIN_SECONDARY);
kiosk_apps_button_->SetVisible(kiosk_apps_button_->HasApps());
// TODO(agawronska): Implement full list of conditions for buttons visibility,
// when views based shelf if enabled during OOBE. https://crbug.com/798869
bool is_login_primary = (session_state == SessionState::LOGIN_PRIMARY);
GetViewByID(kBrowseAsGuest)->SetVisible(is_login_primary);
GetViewByID(kAddUser)->SetVisible(is_login_primary);
if (kiosk_apps_button_->HasApps() && is_login_primary)
kiosk_apps_button_->ResetState();
else
kiosk_apps_button_->SetVisible(false);
Layout();
}
......
......@@ -258,17 +258,23 @@ TEST_F(LoginShelfViewTest, ShouldUpdateUiAfterLockScreenNoteState) {
}
TEST_F(LoginShelfViewTest, ShouldUpdateUiAfterKioskAppsLoaded) {
EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown}));
NotifySessionStateChanged(SessionState::LOGIN_PRIMARY);
EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown,
LoginShelfView::kBrowseAsGuest,
LoginShelfView::kAddUser}));
std::vector<mojom::KioskAppInfoPtr> kiosk_apps;
kiosk_apps.push_back(mojom::KioskAppInfo::New());
kiosk_apps.push_back(mojom::KioskAppInfo::New());
login_shelf_view_->SetKioskApps(std::move(kiosk_apps));
EXPECT_TRUE(
ShowsShelfButtons({LoginShelfView::kShutdown, LoginShelfView::kApps}));
EXPECT_TRUE(ShowsShelfButtons(
{LoginShelfView::kShutdown, LoginShelfView::kBrowseAsGuest,
LoginShelfView::kAddUser, LoginShelfView::kApps}));
login_shelf_view_->SetKioskApps(std::vector<mojom::KioskAppInfoPtr>());
EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown}));
EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown,
LoginShelfView::kBrowseAsGuest,
LoginShelfView::kAddUser}));
}
TEST_F(LoginShelfViewTest, ClickShutdownButton) {
......
......@@ -1159,6 +1159,8 @@ source_set("chromeos") {
"login/ui/captive_portal_window_proxy.h",
"login/ui/input_events_blocker.cc",
"login/ui/input_events_blocker.h",
"login/ui/kiosk_app_menu_updater.cc",
"login/ui/kiosk_app_menu_updater.h",
"login/ui/login_display.cc",
"login/ui/login_display.h",
"login/ui/login_display_host.cc",
......
......@@ -166,12 +166,17 @@ void AppLaunchController::StartAppLaunch(bool is_auto_launch) {
RecordKioskLaunchUMA(is_auto_launch);
// Ensure WebUILoginView is enabled so that bailout shortcut key works.
host_->GetWebUILoginView()->SetUIEnabled(true);
webui_visible_ = host_->GetWebUILoginView()->webui_visible();
if (!webui_visible_) {
registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
content::NotificationService::AllSources());
WebUILoginView* webui = host_->GetWebUILoginView();
if (webui) {
webui->SetUIEnabled(true);
login_screen_visible_ = webui->webui_visible();
if (!login_screen_visible_) {
registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
content::NotificationService::AllSources());
}
} else {
login_screen_visible_ = true;
}
launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
......@@ -268,8 +273,8 @@ void AppLaunchController::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, type);
DCHECK(!webui_visible_);
webui_visible_ = true;
DCHECK(!login_screen_visible_);
login_screen_visible_ = true;
launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
if (launcher_ready_)
OnReadyToLaunch();
......@@ -482,7 +487,7 @@ void AppLaunchController::OnReadyToLaunch() {
if (network_config_requested_)
return;
if (!webui_visible_)
if (!login_screen_visible_)
return;
if (splash_wait_timer_.IsRunning())
......
......@@ -129,7 +129,7 @@ class AppLaunchController : public AppLaunchSplashScreenView::Delegate,
std::unique_ptr<AppWindowWatcher> app_window_watcher_;
content::NotificationRegistrar registrar_;
bool webui_visible_ = false;
bool login_screen_visible_ = false;
bool launcher_ready_ = false;
// A timer to ensure the app splash is shown for a minimum amount of time.
......
// Copyright 2018 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.
#include "chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.h"
#include "ash/public/interfaces/kiosk_app_info.mojom.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
#include "chrome/browser/ui/ash/login_screen_client.h"
#include "extensions/grit/extensions_browser_resources.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image_skia.h"
namespace chromeos {
KioskAppMenuUpdater::KioskAppMenuUpdater() {
KioskAppManager::Get()->AddObserver(this);
}
KioskAppMenuUpdater::~KioskAppMenuUpdater() {
KioskAppManager::Get()->RemoveObserver(this);
}
void KioskAppMenuUpdater::OnKioskAppDataChanged(const std::string& app_id) {
SendKioskApps();
}
void KioskAppMenuUpdater::OnKioskAppDataLoadFailure(const std::string& app_id) {
SendKioskApps();
}
void KioskAppMenuUpdater::OnKioskAppsSettingsChanged() {
SendKioskApps();
}
void KioskAppMenuUpdater::SendKioskApps() {
if (!LoginScreenClient::HasInstance())
return;
std::vector<ash::mojom::KioskAppInfoPtr> output;
std::vector<chromeos::KioskAppManager::App> apps;
chromeos::KioskAppManager::Get()->GetApps(&apps);
for (const auto& app : apps) {
auto mojo_app = ash::mojom::KioskAppInfo::New();
mojo_app->app_id = app.app_id;
mojo_app->name = base::UTF8ToUTF16(app.name);
if (app.icon.isNull()) {
mojo_app->icon = *ui::ResourceBundle::GetSharedInstance()
.GetImageNamed(IDR_APP_DEFAULT_ICON)
.ToImageSkia();
} else {
mojo_app->icon = gfx::ImageSkia(app.icon);
}
output.push_back(std::move(mojo_app));
}
LoginScreenClient::Get()->login_screen()->SetKioskApps(std::move(output));
}
} // namespace chromeos
// Copyright 2018 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.
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_UI_KIOSK_APP_MENU_UPDATER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_UI_KIOSK_APP_MENU_UPDATER_H_
#include "base/macros.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
namespace chromeos {
// Observer class to update the Kiosk app menu when Kiosk app data is changed.
class KioskAppMenuUpdater : public KioskAppManagerObserver {
public:
KioskAppMenuUpdater();
~KioskAppMenuUpdater() override;
// Manually dispatch kiosk app data to Ash.
void SendKioskApps();
// KioskAppManagerObserver:
void OnKioskAppDataChanged(const std::string& app_id) override;
void OnKioskAppDataLoadFailure(const std::string& app_id) override;
void OnKioskAppsSettingsChanged() override;
private:
DISALLOW_COPY_AND_ASSIGN(KioskAppMenuUpdater);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_UI_KIOSK_APP_MENU_UPDATER_H_
......@@ -16,6 +16,7 @@
#include "chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h"
#include "chrome/browser/chromeos/login/user_board_view_mojo.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/ui/ash/login_screen_client.h"
#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
#include "chromeos/login/auth/user_context.h"
......@@ -181,6 +182,8 @@ void LoginDisplayHostMojo::OnStartSignInScreen(
existing_user_controller_->Init(user_manager::UserManager::Get()->GetUsers());
user_selection_screen_->InitEasyUnlock();
kiosk_updater_.SendKioskApps();
}
void LoginDisplayHostMojo::OnPreferencesChanged() {
......@@ -188,7 +191,7 @@ void LoginDisplayHostMojo::OnPreferencesChanged() {
}
void LoginDisplayHostMojo::OnStartAppLaunch() {
NOTIMPLEMENTED();
dialog_->ShowFullScreen();
}
void LoginDisplayHostMojo::OnStartArcKiosk() {
......
......@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/chromeos/login/ui/kiosk_app_menu_updater.h"
#include "chrome/browser/chromeos/login/ui/login_display_host_common.h"
#include "chrome/browser/ui/ash/login_screen_client.h"
#include "chromeos/login/auth/auth_status_consumer.h"
......@@ -134,6 +135,8 @@ class LoginDisplayHostMojo : public LoginDisplayHostCommon,
// The account id of the user pod that's being focused.
AccountId focused_pod_account_id_;
KioskAppMenuUpdater kiosk_updater_;
base::WeakPtrFactory<LoginDisplayHostMojo> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(LoginDisplayHostMojo);
......
......@@ -64,6 +64,13 @@ void OobeUIDialogDelegate::Show(bool closable_by_esc) {
dialog_widget_->Show();
}
void OobeUIDialogDelegate::ShowFullScreen() {
const gfx::Size& size =
display::Screen::GetScreen()->GetPrimaryDisplay().size();
SetSize(size.width(), size.height());
Show(false /*closable_by_esc*/);
}
void OobeUIDialogDelegate::Hide() {
if (dialog_widget_)
dialog_widget_->Hide();
......
......@@ -43,6 +43,9 @@ class OobeUIDialogDelegate : public ui::WebDialogDelegate {
// key.
void Show(bool closable_by_esc);
// Show the dialog widget stretched to full screen.
void ShowFullScreen();
// Close the widget, and it will delete this object.
void Close();
......
......@@ -151,6 +151,11 @@ void LoginScreenClient::ShowFeedback() {
chromeos::LoginDisplayHost::default_host()->ShowFeedback();
}
void LoginScreenClient::LaunchKioskApp(const std::string& app_id) {
chromeos::LoginDisplayHost::default_host()->StartAppLaunch(app_id, false,
false);
}
void LoginScreenClient::LoadWallpaper(const AccountId& account_id) {
WallpaperControllerClient::Get()->ShowUserWallpaper(account_id);
}
......
......@@ -83,6 +83,7 @@ class LoginScreenClient : public ash::mojom::LoginScreenClient {
void RequestPublicSessionKeyboardLayouts(const AccountId& account_id,
const std::string& locale) override;
void ShowFeedback() override;
void LaunchKioskApp(const std::string& app_id) override;
private:
void SetPublicSessionKeyboardLayout(
......
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