1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_launcher.h>
6 
7 #include <memory>
8 #include <string>
9 
10 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
11 #include "chromeos/ui/base/window_pin_type.h"
12 #include "chromeos/ui/base/window_properties.h"
13 #include "components/arc/arc_util.h"
14 #include "components/arc/metrics/arc_metrics_constants.h"
15 #include "ui/aura/env.h"
16 #include "ui/base/ui_base_features.h"
17 #include "ui/events/event_constants.h"
18 
19 namespace chromeos {
20 
ArcKioskAppLauncher(content::BrowserContext * context,ArcAppListPrefs * prefs,const std::string & app_id,Delegate * delegate)21 ArcKioskAppLauncher::ArcKioskAppLauncher(content::BrowserContext* context,
22                                          ArcAppListPrefs* prefs,
23                                          const std::string& app_id,
24                                          Delegate* delegate)
25     : app_id_(app_id), prefs_(prefs), delegate_(delegate) {
26   prefs_->AddObserver(this);
27   aura::Env::GetInstance()->AddObserver(this);
28   // Launching the app by app id in landscape mode and in non-touch mode.
29   arc::LaunchApp(context, app_id_, ui::EF_NONE,
30                  arc::UserInteractionType::NOT_USER_INITIATED);
31 }
32 
~ArcKioskAppLauncher()33 ArcKioskAppLauncher::~ArcKioskAppLauncher() {
34   StopObserving();
35 }
36 
OnTaskCreated(int32_t task_id,const std::string & package_name,const std::string & activity,const std::string & intent)37 void ArcKioskAppLauncher::OnTaskCreated(int32_t task_id,
38                                         const std::string& package_name,
39                                         const std::string& activity,
40                                         const std::string& intent) {
41   std::unique_ptr<ArcAppListPrefs::AppInfo> app = prefs_->GetApp(app_id_);
42   if (!app || app->package_name != package_name || app->activity != activity)
43     return;
44   task_id_ = task_id;
45   // The app window may have been created already.
46   for (aura::Window* window : windows_) {
47     if (CheckAndPinWindow(window))
48       break;
49   }
50 }
51 
OnWindowInitialized(aura::Window * window)52 void ArcKioskAppLauncher::OnWindowInitialized(aura::Window* window) {
53   // The |window|’s task ID is not set yet. We need to observe
54   // the window until the |kApplicationIdKey| property is set.
55   window->AddObserver(this);
56   windows_.insert(window);
57 }
58 
OnWindowPropertyChanged(aura::Window * window,const void * key,intptr_t old)59 void ArcKioskAppLauncher::OnWindowPropertyChanged(aura::Window* window,
60                                                   const void* key,
61                                                   intptr_t old) {
62   // If we do not know yet what task ID to look for, do nothing.
63   // Existing windows will be revisited the moment the task ID
64   // becomes known.
65   if (task_id_ == -1)
66     return;
67 
68   // We are only interested in changes to |kApplicationIdKey|,
69   // but that constant is not accessible outside shell_surface.cc.
70   // So we react to all property changes.
71   CheckAndPinWindow(window);
72 }
73 
OnWindowDestroying(aura::Window * window)74 void ArcKioskAppLauncher::OnWindowDestroying(aura::Window* window) {
75   window->RemoveObserver(this);
76   windows_.erase(window);
77 }
78 
CheckAndPinWindow(aura::Window * const window)79 bool ArcKioskAppLauncher::CheckAndPinWindow(aura::Window* const window) {
80   DCHECK_GE(task_id_, 0);
81   if (arc::GetWindowTaskId(window) != task_id_)
82     return false;
83   // Stop observing as target window is already found.
84   StopObserving();
85   window->SetProperty(chromeos::kWindowPinTypeKey,
86                       chromeos::WindowPinType::kTrustedPinned);
87   if (delegate_)
88     delegate_->OnAppWindowLaunched();
89   return true;
90 }
91 
StopObserving()92 void ArcKioskAppLauncher::StopObserving() {
93   aura::Env::GetInstance()->RemoveObserver(this);
94   for (auto* window : windows_)
95     window->RemoveObserver(this);
96   windows_.clear();
97   prefs_->RemoveObserver(this);
98 }
99 
100 }  // namespace chromeos
101