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