Home | History | Annotate | Download | only in background
      1 // Copyright (c) 2011 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 "base/bind.h"
      6 #include "base/command_line.h"
      7 #include "base/mac/mac_util.h"
      8 #include "base/prefs/pref_service.h"
      9 #include "chrome/browser/background/background_mode_manager.h"
     10 #include "chrome/browser/browser_process.h"
     11 #include "chrome/common/chrome_switches.h"
     12 #include "chrome/common/pref_names.h"
     13 #include "content/public/browser/browser_thread.h"
     14 #include "grit/generated_resources.h"
     15 #include "ui/base/l10n/l10n_util.h"
     16 
     17 using content::BrowserThread;
     18 
     19 namespace {
     20 void SetUserRemovedLoginItemPrefOnUIThread() {
     21   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
     22   PrefService* service = g_browser_process->local_state();
     23   service->SetBoolean(prefs::kUserRemovedLoginItem, true);
     24 }
     25 
     26 void SetCreatedLoginItemPrefOnUIThread() {
     27   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
     28   PrefService* service = g_browser_process->local_state();
     29   service->SetBoolean(prefs::kChromeCreatedLoginItem, true);
     30 }
     31 
     32 void DisableLaunchOnStartupOnFileThread() {
     33   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
     34   // If the LoginItem is not hidden, it means it's user created, so don't
     35   // delete it.
     36   bool is_hidden = false;
     37   if (base::mac::CheckLoginItemStatus(&is_hidden) && is_hidden)
     38     base::mac::RemoveFromLoginItems();
     39 }
     40 
     41 void CheckForUserRemovedLoginItemOnFileThread() {
     42   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
     43   if (!base::mac::CheckLoginItemStatus(NULL)) {
     44     // There's no LoginItem, so set the kUserRemovedLoginItem pref.
     45     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
     46                             base::Bind(SetUserRemovedLoginItemPrefOnUIThread));
     47   }
     48 }
     49 
     50 void EnableLaunchOnStartupOnFileThread(bool need_migration) {
     51   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
     52   if (need_migration) {
     53     // This is the first time running Chrome since the kChromeCreatedLoginItem
     54     // pref was added. Initialize the status of this pref based on whether
     55     // there is already a hidden login item.
     56     bool is_hidden = false;
     57     if (base::mac::CheckLoginItemStatus(&is_hidden)) {
     58       if (is_hidden) {
     59       // We already have a hidden login item, so set the kChromeCreatedLoginItem
     60       // flag.
     61         BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
     62                                 base::Bind(SetCreatedLoginItemPrefOnUIThread));
     63       }
     64       // LoginItem already exists - just exit.
     65       return;
     66     }
     67   }
     68 
     69   // Check if Chrome is already a Login Item - if not, create one.
     70   if (!base::mac::CheckLoginItemStatus(NULL)) {
     71     // Call back to the UI thread to set our preference so we know that Chrome
     72     // created the login item (which means we are allowed to delete it later).
     73     // There's a race condition here if the user disables launch on startup
     74     // before our callback is run, but the user can manually disable
     75     // "Open At Login" via the dock if this happens.
     76     base::mac::AddToLoginItems(true);  // Hide on startup.
     77     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
     78                             base::Bind(SetCreatedLoginItemPrefOnUIThread));
     79   }
     80 }
     81 
     82 }  // namespace
     83 
     84 void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
     85   // LoginItems are associated with an executable, not with a specific
     86   // user-data-dir, so only mess with the LoginItem when running with the
     87   // default user-data-dir. So if a user is running multiple instances of
     88   // Chrome with different user-data-dirs, they won't conflict in their
     89   // use of LoginItems.
     90   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir))
     91     return;
     92 
     93   // There are a few cases we need to handle:
     94   //
     95   // 1) Chrome is transitioning to "launch on startup" state, and there's no
     96   // login item currently. We create a new item if the kUserRemovedLoginItem
     97   // and kChromeCreatedLoginItem flags are already false, and set the
     98   // kChromeCreatedLoginItem flag to true. If kChromeCreatedLoginItem is
     99   // already set (meaning that we created a login item that has since been
    100   // deleted) then we will set the kUserRemovedLoginItem so we do not create
    101   // login items in the future.
    102   //
    103   // 2) Chrome is transitioning to the "do not launch on startup" state. If
    104   // the kChromeCreatedLoginItem flag is false, we do nothing. Otherwise, we
    105   // will delete the login item if it's present, and not we will set
    106   // kUserRemovedLoginItem to true to prevent future login items from being
    107   // created.
    108   if (should_launch) {
    109     PrefService* service = g_browser_process->local_state();
    110     // If the user removed the login item, don't ever create another one.
    111     if (service->GetBoolean(prefs::kUserRemovedLoginItem))
    112       return;
    113 
    114     if (service->GetBoolean(prefs::kChromeCreatedLoginItem)) {
    115       DCHECK(service->GetBoolean(prefs::kMigratedLoginItemPref));
    116       // If we previously created a login item, we don't need to create
    117       // a new one - just check to see if the user removed it so we don't
    118       // ever create another one.
    119       BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
    120                               base::Bind(
    121                                   CheckForUserRemovedLoginItemOnFileThread));
    122     } else {
    123       bool need_migration = !service->GetBoolean(
    124           prefs::kMigratedLoginItemPref);
    125       service->SetBoolean(prefs::kMigratedLoginItemPref, true);
    126       BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
    127                               base::Bind(EnableLaunchOnStartupOnFileThread,
    128                                          need_migration));
    129     }
    130   } else {
    131     PrefService* service = g_browser_process->local_state();
    132     // If Chrome didn't create any login items, just exit.
    133     if (!service->GetBoolean(prefs::kChromeCreatedLoginItem))
    134       return;
    135 
    136     // Clear the pref now that we're removing the login item.
    137     service->ClearPref(prefs::kChromeCreatedLoginItem);
    138 
    139     // If the user removed our login item, note this so we don't ever create
    140     // another one.
    141     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
    142                             base::Bind(
    143                                 CheckForUserRemovedLoginItemOnFileThread));
    144 
    145     // Call to the File thread to remove the login item since it requires
    146     // accessing the disk.
    147     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
    148                             base::Bind(DisableLaunchOnStartupOnFileThread));
    149   }
    150 }
    151 
    152 void BackgroundModeManager::DisplayAppInstalledNotification(
    153     const extensions::Extension* extension) {
    154   // TODO(atwilson): Display a platform-appropriate notification here.
    155   // http://crbug.com/74970
    156 }
    157 
    158 base::string16 BackgroundModeManager::GetPreferencesMenuLabel() {
    159   return l10n_util::GetStringUTF16(IDS_OPTIONS);
    160 }
    161