Skip to content

Commit

Permalink
Changes in app.window and app.runtime to support lock screen note taking
Browse files Browse the repository at this point in the history
Implements changes in app.window and app.runtime to support launching
app window for handling actions on lock screen. Currently, this is
restricted to note taking action (at time of writing, no other actions
exist), which will be restricted to a whitelisted apps on lock screen
(guarded by lockScreen permsission).

Changes to APIs:
chrome.app.runtime:
 * add isLockScreenAction to LaunchData.AcionData, which will be set
   when the launch event is fired in order to handle the action on lock
   screen (and it will be fired to the app running in lock screen
   context - script context with reduced access to chrome APIs)

chrome.app.window:
 * add lockScreenAction app window option. When passer to window.create,
   if set, the option will indicate that the app window is being
   launched to handle an action that should be handled on lock screen.
   The created app window would be added to ash window container visible
   on the Chrome OS lock screen (LockActionHandlerContainer).
   This option will be restricted to apps running in lock screen context
   with lockScreen permission (whitelisted to Keep app).

Note that creation of app windows visible on lock screen will succeed
only if user session is locked and the action in question was requested
from the lock screen - this will be determined by delegating to
AppWindowClient (which already creates app window instances).
This CL adds a CreateAppWindowForLockScreenAction method to the client
which will use lock_screen_apps:StateController to verify that the app
was asked to handle the lock screen action before creating the app
window. If created, the lock screen window is registered with the
lock_screen_apps::StateController so lock screen apps state can be
updated depending on the window state (e.g. exit active state when the
app window is closed), and vice-versa.

Tests for launching lock screen note taking action to be added in:
https://codereview.chromium.org/2927303003

BUG=715781

Review-Url: https://codereview.chromium.org/2934513003
Cr-Commit-Position: refs/heads/master@{#481417}
  • Loading branch information
tbarzic authored and Commit Bot committed Jun 22, 2017
1 parent 1b0f374 commit 8bf50fc
Show file tree
Hide file tree
Showing 17 changed files with 649 additions and 148 deletions.
8 changes: 8 additions & 0 deletions apps/launcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
#include "extensions/common/api/app_runtime.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/kiosk_mode_info.h"
#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/permissions_data.h"
#include "net/base/filename_util.h"
#include "url/gurl.h"

Expand Down Expand Up @@ -434,6 +436,12 @@ void LaunchPlatformAppWithAction(
const extensions::Extension* app,
std::unique_ptr<app_runtime::ActionData> action_data,
const base::FilePath& file_path) {
CHECK(!action_data || !action_data->is_lock_screen_action ||
!*action_data->is_lock_screen_action ||
app->permissions_data()->HasAPIPermission(
extensions::APIPermission::kLockScreen))
<< "Launching lock screen action handler requires lockScreen permission.";

scoped_refptr<PlatformAppPathLauncher> launcher =
new PlatformAppPathLauncher(context, app, file_path);
launcher->set_action_data(std::move(action_data));
Expand Down
71 changes: 60 additions & 11 deletions chrome/browser/chromeos/lock_screen_apps/state_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include "chromeos/chromeos_switches.h"
#include "components/session_manager/core/session_manager.h"
#include "content/public/common/service_manager_connection.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/native_app_window.h"
#include "extensions/common/extension.h"
#include "services/service_manager/public/cpp/connector.h"

using ash::mojom::TrayActionState;
Expand All @@ -40,7 +43,8 @@ StateController* StateController::Get() {
return g_instance;
}

StateController::StateController() : binding_(this), session_observer_(this) {
StateController::StateController()
: binding_(this), app_window_observer_(this), session_observer_(this) {
DCHECK(!g_instance);
DCHECK(IsEnabled());

Expand Down Expand Up @@ -120,7 +124,7 @@ void StateController::RequestNewLockScreenNote() {
void StateController::OnSessionStateChanged() {
if (!session_manager::SessionManager::Get()->IsScreenLocked()) {
app_manager_->Stop();
UpdateLockScreenNoteState(TrayActionState::kNotAvailable);
ResetNoteTakingWindowAndMoveToNextState(true /* close_window */);
return;
}

Expand All @@ -133,9 +137,42 @@ void StateController::OnSessionStateChanged() {
OnNoteTakingAvailabilityChanged();
}

void StateController::OnAppWindowRemoved(extensions::AppWindow* app_window) {
if (note_app_window_ != app_window)
return;
ResetNoteTakingWindowAndMoveToNextState(false /* close_window */);
}

extensions::AppWindow* StateController::CreateAppWindowForLockScreenAction(
content::BrowserContext* context,
const extensions::Extension* extension,
extensions::api::app_runtime::ActionType action,
std::unique_ptr<extensions::AppDelegate> app_delegate) {
if (action != extensions::api::app_runtime::ACTION_TYPE_NEW_NOTE)
return nullptr;

if (lock_screen_note_state_ != TrayActionState::kLaunching)
return nullptr;

if (!chromeos::ProfileHelper::GetSigninProfile()->IsSameProfile(
Profile::FromBrowserContext(context))) {
return nullptr;
}

if (!extension || app_manager_->GetNoteTakingAppId() != extension->id())
return nullptr;

// The ownership of the window is passed to the caller of this method.
note_app_window_ =
new extensions::AppWindow(context, app_delegate.release(), extension);
app_window_observer_.Add(extensions::AppWindowRegistry::Get(
chromeos::ProfileHelper::GetSigninProfile()));
UpdateLockScreenNoteState(TrayActionState::kActive);
return note_app_window_;
}

void StateController::MoveToBackground() {
TrayActionState state = GetLockScreenNoteState();
if (state != TrayActionState::kActive && state != TrayActionState::kLaunching)
if (GetLockScreenNoteState() != TrayActionState::kActive)
return;
UpdateLockScreenNoteState(TrayActionState::kBackground);
}
Expand All @@ -146,21 +183,33 @@ void StateController::MoveToForeground() {
UpdateLockScreenNoteState(TrayActionState::kActive);
}

void StateController::SetLockScreenNoteStateForTesting(
ash::mojom::TrayActionState state) {
lock_screen_note_state_ = state;
}

void StateController::OnNoteTakingAvailabilityChanged() {
if (!app_manager_->IsNoteTakingAppAvailable()) {
UpdateLockScreenNoteState(TrayActionState::kNotAvailable);
if (!app_manager_->IsNoteTakingAppAvailable() ||
(note_app_window_ && note_app_window_->GetExtension()->id() !=
app_manager_->GetNoteTakingAppId())) {
ResetNoteTakingWindowAndMoveToNextState(true /* close_window */);
return;
}

if (GetLockScreenNoteState() == TrayActionState::kNotAvailable)
UpdateLockScreenNoteState(TrayActionState::kAvailable);
}

void StateController::ResetNoteTakingWindowAndMoveToNextState(
bool close_window) {
app_window_observer_.RemoveAll();

if (note_app_window_) {
if (close_window && note_app_window_->GetBaseWindow())
note_app_window_->GetBaseWindow()->Close();
note_app_window_ = nullptr;
}

UpdateLockScreenNoteState(app_manager_->IsNoteTakingAppAvailable()
? TrayActionState::kAvailable
: TrayActionState::kNotAvailable);
}

bool StateController::UpdateLockScreenNoteState(TrayActionState state) {
const TrayActionState old_state = GetLockScreenNoteState();
if (old_state == state)
Expand Down
45 changes: 40 additions & 5 deletions chrome/browser/chromeos/lock_screen_apps/state_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,22 @@
#include "chrome/browser/chromeos/lock_screen_apps/app_manager.h"
#include "chrome/browser/chromeos/lock_screen_apps/state_observer.h"
#include "components/session_manager/core/session_manager_observer.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/common/api/app_runtime.h"
#include "mojo/public/cpp/bindings/binding.h"

class Profile;

namespace content {
class BrowserContext;
}

namespace extensions {
class AppDelegate;
class AppWindow;
class Extension;
}

namespace session_manager {
class SessionManager;
}
Expand All @@ -29,7 +41,8 @@ class StateObserver;
// interested parties as the state changes.
// Currently assumes single supported action - NEW_NOTE.
class StateController : public ash::mojom::TrayActionClient,
public session_manager::SessionManagerObserver {
public session_manager::SessionManagerObserver,
public extensions::AppWindowRegistry::Observer {
public:
// Returns whether the StateController is enabled - it is currently guarded by
// a feature flag. If not enabled, |StateController| instance is not allowed
Expand Down Expand Up @@ -71,6 +84,21 @@ class StateController : public ash::mojom::TrayActionClient,
// session_manager::SessionManagerObserver:
void OnSessionStateChanged() override;

// extensions::AppWindowRegistry::Observer:
void OnAppWindowRemoved(extensions::AppWindow* app_window) override;

// Creates and registers an app window as action handler for the action on
// Chrome OS lock screen. The ownership of the returned app window is passed
// to the caller.
// If the app is not allowed to create an app window for handling the action
// on lock screen (e.g. if the action has not been requested), it will return
// nullptr.
extensions::AppWindow* CreateAppWindowForLockScreenAction(
content::BrowserContext* context,
const extensions::Extension* extension,
extensions::api::app_runtime::ActionType action,
std::unique_ptr<extensions::AppDelegate> app_delegate);

// If there are any active lock screen action handlers, moved their windows
// to background, to ensure lock screen UI is visible.
void MoveToBackground();
Expand All @@ -79,14 +107,16 @@ class StateController : public ash::mojom::TrayActionClient,
// windows back to foreground (i.e. visible over lock screen UI).
void MoveToForeground();

// Sets the current state - to be used in tests. Hopefully, when this class
// has more logic implemented, this will not be needed.
void SetLockScreenNoteStateForTesting(ash::mojom::TrayActionState state);

private:
// Called when app manager reports that note taking availability has changed.
void OnNoteTakingAvailabilityChanged();

// If there is an app window registered as a handler for note taking action
// on lock screen, unregisters the window, and closes is if |close_window| is
// set. It changes the current state to kAvailable or kNotAvailable, depending
// on whether lock screen note taking action can still be handled.
void ResetNoteTakingWindowAndMoveToNextState(bool close_window);

// Requests lock screen note action state change to |state|.
// Returns whether the action state has changed.
bool UpdateLockScreenNoteState(ash::mojom::TrayActionState state);
Expand All @@ -105,6 +135,11 @@ class StateController : public ash::mojom::TrayActionClient,

std::unique_ptr<AppManager> app_manager_;

extensions::AppWindow* note_app_window_ = nullptr;

ScopedObserver<extensions::AppWindowRegistry,
extensions::AppWindowRegistry::Observer>
app_window_observer_;
ScopedObserver<session_manager::SessionManager,
session_manager::SessionManagerObserver>
session_observer_;
Expand Down
Loading

0 comments on commit 8bf50fc

Please sign in to comment.