Home | History | Annotate | Download | only in browser
      1 // Copyright (c) 2012 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/shell_integration.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/file_util.h"
     10 #include "base/path_service.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "base/threading/thread_restrictions.h"
     15 #include "chrome/browser/policy/policy_path_parser.h"
     16 #include "chrome/common/chrome_paths.h"
     17 #include "chrome/common/chrome_switches.h"
     18 #include "chrome/common/pref_names.h"
     19 #include "content/public/browser/browser_thread.h"
     20 
     21 #if defined(OS_CHROMEOS)
     22 #include "chromeos/chromeos_switches.h"
     23 #endif
     24 
     25 using content::BrowserThread;
     26 
     27 ShellIntegration::DefaultWebClientSetPermission
     28     ShellIntegration::CanSetAsDefaultProtocolClient() {
     29   // Allowed as long as the browser can become the operating system default
     30   // browser.
     31   return CanSetAsDefaultBrowser();
     32 }
     33 
     34 ShellIntegration::ShortcutInfo::ShortcutInfo()
     35     : is_platform_app(false) {
     36 }
     37 
     38 ShellIntegration::ShortcutInfo::~ShortcutInfo() {}
     39 
     40 ShellIntegration::ShortcutLocations::ShortcutLocations()
     41     : on_desktop(false),
     42       in_applications_menu(false),
     43       in_quick_launch_bar(false),
     44       hidden(false) {
     45 }
     46 
     47 static const struct ShellIntegration::AppModeInfo* gAppModeInfo = NULL;
     48 
     49 // static
     50 void ShellIntegration::SetAppModeInfo(const struct AppModeInfo* info) {
     51   gAppModeInfo = info;
     52 }
     53 
     54 // static
     55 const struct ShellIntegration::AppModeInfo* ShellIntegration::AppModeInfo() {
     56   return gAppModeInfo;
     57 }
     58 
     59 // static
     60 bool ShellIntegration::IsRunningInAppMode() {
     61   return gAppModeInfo != NULL;
     62 }
     63 
     64 // static
     65 CommandLine ShellIntegration::CommandLineArgsForLauncher(
     66     const GURL& url,
     67     const std::string& extension_app_id,
     68     const base::FilePath& profile_path) {
     69   base::ThreadRestrictions::AssertIOAllowed();
     70   const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
     71   CommandLine new_cmd_line(CommandLine::NO_PROGRAM);
     72 
     73   // Use the same UserDataDir for new launches that we currently have set.
     74   base::FilePath user_data_dir =
     75       cmd_line.GetSwitchValuePath(switches::kUserDataDir);
     76 #if defined(OS_MACOSX) || defined(OS_WIN)
     77   policy::path_parser::CheckUserDataDirPolicy(&user_data_dir);
     78 #endif
     79   if (!user_data_dir.empty()) {
     80     // Make sure user_data_dir is an absolute path.
     81     user_data_dir = base::MakeAbsoluteFilePath(user_data_dir);
     82     if (!user_data_dir.empty() && base::PathExists(user_data_dir))
     83       new_cmd_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir);
     84   }
     85 
     86 #if defined(OS_CHROMEOS)
     87   base::FilePath profile = cmd_line.GetSwitchValuePath(
     88       chromeos::switches::kLoginProfile);
     89   if (!profile.empty())
     90     new_cmd_line.AppendSwitchPath(chromeos::switches::kLoginProfile, profile);
     91 #else
     92   if (!profile_path.empty() && !extension_app_id.empty())
     93     new_cmd_line.AppendSwitchPath(switches::kProfileDirectory,
     94                                   profile_path.BaseName());
     95 #endif
     96 
     97   // If |extension_app_id| is present, we use the kAppId switch rather than
     98   // the kApp switch (the launch url will be read from the extension app
     99   // during launch.
    100   if (!extension_app_id.empty()) {
    101     new_cmd_line.AppendSwitchASCII(switches::kAppId, extension_app_id);
    102   } else {
    103     // Use '--app=url' instead of just 'url' to launch the browser with minimal
    104     // chrome.
    105     // Note: Do not change this flag!  Old Gears shortcuts will break if you do!
    106     new_cmd_line.AppendSwitchASCII(switches::kApp, url.spec());
    107   }
    108   return new_cmd_line;
    109 }
    110 
    111 #if !defined(OS_WIN)
    112 // static
    113 bool ShellIntegration::SetAsDefaultBrowserInteractive() {
    114   return false;
    115 }
    116 
    117 // static
    118 bool ShellIntegration::SetAsDefaultProtocolClientInteractive(
    119     const std::string& protocol) {
    120   return false;
    121 }
    122 #endif
    123 
    124 bool ShellIntegration::DefaultWebClientObserver::IsOwnedByWorker() {
    125   return false;
    126 }
    127 
    128 bool ShellIntegration::DefaultWebClientObserver::
    129     IsInteractiveSetDefaultPermitted() {
    130   return false;
    131 }
    132 
    133 ///////////////////////////////////////////////////////////////////////////////
    134 // ShellIntegration::DefaultWebClientWorker
    135 //
    136 
    137 ShellIntegration::DefaultWebClientWorker::DefaultWebClientWorker(
    138     DefaultWebClientObserver* observer)
    139     : observer_(observer) {
    140 }
    141 
    142 void ShellIntegration::DefaultWebClientWorker::StartCheckIsDefault() {
    143   if (observer_) {
    144     observer_->SetDefaultWebClientUIState(STATE_PROCESSING);
    145     BrowserThread::PostTask(
    146         BrowserThread::FILE, FROM_HERE,
    147         base::Bind(
    148             &DefaultWebClientWorker::ExecuteCheckIsDefault, this));
    149   }
    150 }
    151 
    152 void ShellIntegration::DefaultWebClientWorker::StartSetAsDefault() {
    153   bool interactive_permitted = false;
    154   if (observer_) {
    155     observer_->SetDefaultWebClientUIState(STATE_PROCESSING);
    156     interactive_permitted = observer_->IsInteractiveSetDefaultPermitted();
    157   }
    158   BrowserThread::PostTask(
    159       BrowserThread::FILE, FROM_HERE,
    160       base::Bind(&DefaultWebClientWorker::ExecuteSetAsDefault, this,
    161                  interactive_permitted));
    162 }
    163 
    164 void ShellIntegration::DefaultWebClientWorker::ObserverDestroyed() {
    165   // Our associated view has gone away, so we shouldn't call back to it if
    166   // our worker thread returns after the view is dead.
    167   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    168   observer_ = NULL;
    169 }
    170 
    171 ///////////////////////////////////////////////////////////////////////////////
    172 // DefaultWebClientWorker, private:
    173 
    174 void ShellIntegration::DefaultWebClientWorker::ExecuteCheckIsDefault() {
    175   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    176   DefaultWebClientState state = CheckIsDefault();
    177   BrowserThread::PostTask(
    178       BrowserThread::UI, FROM_HERE,
    179       base::Bind(
    180           &DefaultWebClientWorker::CompleteCheckIsDefault, this, state));
    181 }
    182 
    183 void ShellIntegration::DefaultWebClientWorker::CompleteCheckIsDefault(
    184     DefaultWebClientState state) {
    185   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    186   UpdateUI(state);
    187   // The worker has finished everything it needs to do, so free the observer
    188   // if we own it.
    189   if (observer_ && observer_->IsOwnedByWorker()) {
    190     delete observer_;
    191     observer_ = NULL;
    192   }
    193 }
    194 
    195 void ShellIntegration::DefaultWebClientWorker::ExecuteSetAsDefault(
    196     bool interactive_permitted) {
    197   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    198 
    199   bool result = SetAsDefault(interactive_permitted);
    200   BrowserThread::PostTask(
    201       BrowserThread::UI, FROM_HERE,
    202       base::Bind(&DefaultWebClientWorker::CompleteSetAsDefault, this, result));
    203 }
    204 
    205 void ShellIntegration::DefaultWebClientWorker::CompleteSetAsDefault(
    206     bool succeeded) {
    207   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    208   // First tell the observer what the SetAsDefault call has returned.
    209   if (observer_)
    210     observer_->OnSetAsDefaultConcluded(succeeded);
    211   // Set as default completed, check again to make sure it stuck...
    212   StartCheckIsDefault();
    213 }
    214 
    215 void ShellIntegration::DefaultWebClientWorker::UpdateUI(
    216     DefaultWebClientState state) {
    217   if (observer_) {
    218     switch (state) {
    219       case NOT_DEFAULT:
    220         observer_->SetDefaultWebClientUIState(STATE_NOT_DEFAULT);
    221         break;
    222       case IS_DEFAULT:
    223         observer_->SetDefaultWebClientUIState(STATE_IS_DEFAULT);
    224         break;
    225       case UNKNOWN_DEFAULT:
    226         observer_->SetDefaultWebClientUIState(STATE_UNKNOWN);
    227         break;
    228       default:
    229         break;
    230     }
    231   }
    232 }
    233 
    234 ///////////////////////////////////////////////////////////////////////////////
    235 // ShellIntegration::DefaultBrowserWorker
    236 //
    237 
    238 ShellIntegration::DefaultBrowserWorker::DefaultBrowserWorker(
    239     DefaultWebClientObserver* observer)
    240     : DefaultWebClientWorker(observer) {
    241 }
    242 
    243 ///////////////////////////////////////////////////////////////////////////////
    244 // DefaultBrowserWorker, private:
    245 
    246 ShellIntegration::DefaultWebClientState
    247 ShellIntegration::DefaultBrowserWorker::CheckIsDefault() {
    248   return ShellIntegration::GetDefaultBrowser();
    249 }
    250 
    251 bool ShellIntegration::DefaultBrowserWorker::SetAsDefault(
    252     bool interactive_permitted) {
    253   bool result = false;
    254   switch (ShellIntegration::CanSetAsDefaultBrowser()) {
    255     case ShellIntegration::SET_DEFAULT_UNATTENDED:
    256       result = ShellIntegration::SetAsDefaultBrowser();
    257       break;
    258     case ShellIntegration::SET_DEFAULT_INTERACTIVE:
    259       if (interactive_permitted)
    260         result = ShellIntegration::SetAsDefaultBrowserInteractive();
    261       break;
    262     default:
    263       NOTREACHED();
    264   }
    265 
    266   return result;
    267 }
    268 
    269 ///////////////////////////////////////////////////////////////////////////////
    270 // ShellIntegration::DefaultProtocolClientWorker
    271 //
    272 
    273 ShellIntegration::DefaultProtocolClientWorker::DefaultProtocolClientWorker(
    274     DefaultWebClientObserver* observer, const std::string& protocol)
    275     : DefaultWebClientWorker(observer),
    276       protocol_(protocol) {
    277 }
    278 
    279 ///////////////////////////////////////////////////////////////////////////////
    280 // DefaultProtocolClientWorker, private:
    281 
    282 ShellIntegration::DefaultWebClientState
    283 ShellIntegration::DefaultProtocolClientWorker::CheckIsDefault() {
    284   return ShellIntegration::IsDefaultProtocolClient(protocol_);
    285 }
    286 
    287 bool ShellIntegration::DefaultProtocolClientWorker::SetAsDefault(
    288     bool interactive_permitted) {
    289   bool result = false;
    290   switch (ShellIntegration::CanSetAsDefaultProtocolClient()) {
    291     case ShellIntegration::SET_DEFAULT_UNATTENDED:
    292       result = ShellIntegration::SetAsDefaultProtocolClient(protocol_);
    293       break;
    294     case ShellIntegration::SET_DEFAULT_INTERACTIVE:
    295       if (interactive_permitted) {
    296         result = ShellIntegration::SetAsDefaultProtocolClientInteractive(
    297             protocol_);
    298       }
    299       break;
    300     default:
    301       NOTREACHED();
    302   }
    303 
    304   return result;
    305 }
    306