blob: e9fbe7348d673dbfb63a41796612080fba603ed9 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/ash/tablet_mode_client.h"
#include <utility>
#include "ash/public/cpp/tablet_mode.h"
#include "base/bind.h"
#include "chrome/browser/chromeos/arc/arc_web_contents_data.h"
#include "chrome/browser/ui/ash/tablet_mode_client_observer.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_tab_strip_tracker.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/service_manager_connection.h"
#include "services/service_manager/public/cpp/connector.h"
#include "ui/base/material_design/material_design_controller.h"
namespace {
TabletModeClient* g_tablet_mode_client_instance = nullptr;
} // namespace
TabletModeClient::TabletModeClient() {
DCHECK(!g_tablet_mode_client_instance);
g_tablet_mode_client_instance = this;
}
TabletModeClient::~TabletModeClient() {
DCHECK_EQ(this, g_tablet_mode_client_instance);
g_tablet_mode_client_instance = nullptr;
// The Ash Shell and TabletMode instance should have been destroyed by now.
DCHECK(!ash::TabletMode::Get());
}
void TabletModeClient::Init() {
ash::TabletMode::Get()->SetTabletModeToggleObserver(this);
OnTabletModeToggled(ash::TabletMode::Get()->InTabletMode());
}
// static
TabletModeClient* TabletModeClient::Get() {
return g_tablet_mode_client_instance;
}
void TabletModeClient::AddObserver(TabletModeClientObserver* observer) {
observers_.AddObserver(observer);
}
void TabletModeClient::RemoveObserver(TabletModeClientObserver* observer) {
observers_.RemoveObserver(observer);
}
void TabletModeClient::OnTabletModeToggled(bool enabled) {
if (tablet_mode_enabled_ == enabled)
return;
tablet_mode_enabled_ = enabled;
SetMobileLikeBehaviorEnabled(enabled);
ui::MaterialDesignController::OnTabletModeToggled(enabled);
for (auto& observer : observers_)
observer.OnTabletModeToggled(enabled);
}
bool TabletModeClient::ShouldTrackBrowser(Browser* browser) {
return tablet_mode_enabled_;
}
void TabletModeClient::OnTabStripModelChanged(
TabStripModel* tab_strip_model,
const TabStripModelChange& change,
const TabStripSelectionChange& selection) {
if (change.type() != TabStripModelChange::kInserted)
return;
// We limit the mobile-like behavior to webcontents in tabstrips since many
// apps and extensions draw their own caption buttons and header frames. We
// don't want those to shrink down and resize to fit the width of their
// windows like webpages on mobile do. So this behavior is limited to webpages
// in tabs and packaged apps.
for (const auto& contents : change.GetInsert()->contents)
contents.contents->NotifyPreferencesChanged();
}
void TabletModeClient::SetMobileLikeBehaviorEnabled(bool enabled) {
// Toggling tablet mode on/off should trigger refreshing the WebKit
// preferences, since in tablet mode, we enable certain mobile-like features
// such as "double tap to zoom", "shrink page contents to fit", ... etc.
// Do this only for webpages that belong to existing browsers as well as
// future browsers and webcontents.
if (enabled) {
// On calling Init() of the |tab_strip_tracker_|, we will get a call to
// TabInsertedAt() for all the existing webcontents, upon which we will
// trigger a refresh of their WebKit preferences.
tab_strip_tracker_ =
std::make_unique<BrowserTabStripTracker>(this, this, nullptr);
tab_strip_tracker_->Init();
} else {
// Manually trigger a refresh for the existing webcontents' preferences.
for (Browser* browser : *BrowserList::GetInstance()) {
TabStripModel* tab_strip_model = browser->tab_strip_model();
for (int i = 0; i < tab_strip_model->count(); ++i) {
content::WebContents* web_contents =
tab_strip_model->GetWebContentsAt(i);
DCHECK(web_contents);
web_contents->NotifyPreferencesChanged();
// For a tab that is requesting its mobile version site (via
// chrome::ToggleRequestTabletSite()), and is not originated from ARC
// context, return to its normal version site when exiting tablet mode.
content::NavigationController& controller =
web_contents->GetController();
content::NavigationEntry* entry = controller.GetLastCommittedEntry();
if (entry && entry->GetIsOverridingUserAgent() &&
!web_contents->GetUserData(
arc::ArcWebContentsData::ArcWebContentsData::
kArcTransitionFlag)) {
entry->SetIsOverridingUserAgent(false);
controller.Reload(content::ReloadType::ORIGINAL_REQUEST_URL, true);
}
}
}
tab_strip_tracker_ = nullptr;
}
}