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/ui/android/tab_model/tab_model.h"
6
7#include "base/logging.h"
8#include "chrome/browser/browser_process.h"
9#include "chrome/browser/chrome_notification_types.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/search_engines/search_terms_data.h"
12#include "chrome/browser/sync/glue/synced_window_delegate_android.h"
13#include "chrome/browser/ui/toolbar/toolbar_model_impl.h"
14#include "content/public/browser/notification_service.h"
15
16using content::NotificationService;
17
18TabModel::TabModel(Profile* profile)
19  : profile_(profile),
20    synced_window_delegate_(
21        new browser_sync::SyncedWindowDelegateAndroid(this)),
22    toolbar_model_(new ToolbarModelImpl(this)) {
23
24  if (profile) {
25    // A normal Profile creates an OTR profile if it does not exist when
26    // GetOffTheRecordProfile() is called, so we guard it with
27    // HasOffTheRecordProfile(). An OTR profile returns itself when you call
28    // GetOffTheRecordProfile().
29    is_off_the_record_ = (profile->HasOffTheRecordProfile() &&
30        profile == profile->GetOffTheRecordProfile());
31
32    // A profile can be destroyed, for example in the case of closing all
33    // incognito tabs. We therefore must listen for when this happens, and
34    // remove our pointer to the profile accordingly.
35    registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
36                   content::Source<Profile>(profile_));
37    registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
38                   content::NotificationService::AllSources());
39  } else {
40    is_off_the_record_ = false;
41  }
42}
43
44TabModel::TabModel()
45  : profile_(NULL),
46    is_off_the_record_(false),
47    synced_window_delegate_(
48        new browser_sync::SyncedWindowDelegateAndroid(this)) {
49}
50
51TabModel::~TabModel() {
52}
53
54content::WebContents* TabModel::GetActiveWebContents() const {
55  if (GetTabCount() == 0 || GetActiveIndex() < 0 ||
56      GetActiveIndex() > GetTabCount())
57    return NULL;
58  return GetWebContentsAt(GetActiveIndex());
59}
60
61Profile* TabModel::GetProfile() const {
62  return profile_;
63}
64
65bool TabModel::IsOffTheRecord() const {
66  return is_off_the_record_;
67}
68
69browser_sync::SyncedWindowDelegate* TabModel::GetSyncedWindowDelegate() const {
70  return synced_window_delegate_.get();
71}
72
73SessionID::id_type TabModel::GetSessionId() const {
74  return session_id_.id();
75}
76
77void TabModel::BroadcastSessionRestoreComplete() {
78  if (profile_) {
79    NotificationService::current()->Notify(
80        chrome::NOTIFICATION_SESSION_RESTORE_COMPLETE,
81        content::Source<Profile>(profile_),
82        NotificationService::NoDetails());
83  } else {
84    // TODO(nyquist): Uncomment this once downstream Android uses new
85    // constructor that takes a Profile* argument. See crbug.com/159704.
86    // NOTREACHED();
87  }
88}
89
90ToolbarModel* TabModel::GetToolbarModel() {
91  return toolbar_model_.get();
92}
93
94ToolbarModel::SecurityLevel TabModel::GetSecurityLevelForCurrentTab() {
95  return toolbar_model_->GetSecurityLevel(false);
96}
97
98string16 TabModel::GetSearchTermsForCurrentTab() {
99  return toolbar_model_->GetText(true);
100}
101
102std::string TabModel::GetQueryExtractionParam() {
103  if (!profile_)
104    return std::string();
105  UIThreadSearchTermsData search_terms_data(profile_);
106  return search_terms_data.InstantExtendedEnabledParam();
107}
108
109string16 TabModel::GetCorpusNameForCurrentTab() {
110  return toolbar_model_->GetCorpusNameForMobile();
111}
112
113void TabModel::Observe(
114    int type,
115    const content::NotificationSource& source,
116    const content::NotificationDetails& details) {
117  switch (type) {
118    case chrome::NOTIFICATION_PROFILE_DESTROYED:
119      // Our profile just got destroyed, so we delete our pointer to it.
120      profile_ = NULL;
121      break;
122    case chrome::NOTIFICATION_PROFILE_CREATED:
123      // Our incognito tab model out lives the profile, so we need to recapture
124      // the pointer if ours was previously deleted.
125      // NOTIFICATION_PROFILE_DESTROYED is not sent for every destruction, so
126      // we overwrite the pointer regardless of whether it's NULL.
127      if (is_off_the_record_) {
128        Profile* profile = content::Source<Profile>(source).ptr();
129        if (profile && profile->IsOffTheRecord())
130          profile_ = profile;
131      }
132      break;
133    default:
134      NOTREACHED();
135  }
136}
137