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