blob: a09654194c2e44e1d1cac65fea3d18f73b1fbc4e [file] [log] [blame]
// Copyright 2014 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/android/tab_model/tab_model_jni_bridge.h"
#include <stdint.h>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/jni_weak_ref.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_android.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
#include "chrome/browser/ui/android/tab_model/tab_model_observer_jni_bridge.h"
#include "content/public/browser/web_contents.h"
#include "jni/TabModelJniBridge_jni.h"
using base::android::AttachCurrentThread;
using base::android::ConvertUTF8ToJavaString;
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using content::WebContents;
namespace {
static Profile* FindProfile(jboolean is_incognito) {
if (g_browser_process == NULL ||
g_browser_process->profile_manager() == NULL) {
LOG(ERROR) << "Browser process or profile manager not initialized";
return NULL;
}
Profile* profile = ProfileManager::GetActiveUserProfile();
if (is_incognito)
return profile->GetOffTheRecordProfile();
return profile;
}
} // namespace
TabModelJniBridge::TabModelJniBridge(JNIEnv* env,
jobject jobj,
bool is_incognito,
bool is_tabbed_activity)
: TabModel(FindProfile(is_incognito), is_tabbed_activity),
java_object_(env, env->NewWeakGlobalRef(jobj)) {
TabModelList::AddTabModel(this);
}
void TabModelJniBridge::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
delete this;
}
ScopedJavaLocalRef<jobject> TabModelJniBridge::GetProfileAndroid(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
ProfileAndroid* profile_android = ProfileAndroid::FromProfile(GetProfile());
if (!profile_android)
return ScopedJavaLocalRef<jobject>();
return profile_android->GetJavaObject();
}
void TabModelJniBridge::TabAddedToModel(JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& jtab) {
// Tab#initialize() should have been called by now otherwise we can't push
// the window id.
TabAndroid* tab = TabAndroid::GetNativeTab(env, jtab);
if (tab)
tab->SetWindowSessionID(GetSessionId());
}
int TabModelJniBridge::GetTabCount() const {
JNIEnv* env = AttachCurrentThread();
return Java_TabModelJniBridge_getCount(env, java_object_.get(env));
}
int TabModelJniBridge::GetActiveIndex() const {
JNIEnv* env = AttachCurrentThread();
return Java_TabModelJniBridge_index(env, java_object_.get(env));
}
void TabModelJniBridge::CreateTab(TabAndroid* parent,
WebContents* web_contents,
int parent_tab_id) {
JNIEnv* env = AttachCurrentThread();
Java_TabModelJniBridge_createTabWithWebContents(
env, java_object_.get(env), (parent ? parent->GetJavaObject() : nullptr),
web_contents->GetBrowserContext()->IsOffTheRecord(),
web_contents->GetJavaWebContents(), parent_tab_id);
}
WebContents* TabModelJniBridge::GetWebContentsAt(int index) const {
TabAndroid* tab = GetTabAt(index);
return tab == NULL ? NULL : tab->web_contents();
}
TabAndroid* TabModelJniBridge::GetTabAt(int index) const {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> jtab =
Java_TabModelJniBridge_getTabAt(env, java_object_.get(env), index);
return jtab.is_null() ? NULL : TabAndroid::GetNativeTab(env, jtab);
}
void TabModelJniBridge::SetActiveIndex(int index) {
JNIEnv* env = AttachCurrentThread();
Java_TabModelJniBridge_setIndex(env, java_object_.get(env), index);
}
void TabModelJniBridge::CloseTabAt(int index) {
JNIEnv* env = AttachCurrentThread();
Java_TabModelJniBridge_closeTabAt(env, java_object_.get(env), index);
}
WebContents* TabModelJniBridge::CreateNewTabForDevTools(
const GURL& url) {
// TODO(dfalcantara): Change the Java side so that it creates and returns the
// WebContents, which we can load the URL on and return.
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jstring> jurl = ConvertUTF8ToJavaString(env, url.spec());
ScopedJavaLocalRef<jobject> obj =
Java_TabModelJniBridge_createNewTabForDevTools(env, java_object_.get(env),
jurl);
if (obj.is_null()) {
VLOG(0) << "Failed to create java tab";
return NULL;
}
TabAndroid* tab = TabAndroid::GetNativeTab(env, obj);
if (!tab) {
VLOG(0) << "Failed to create java tab";
return NULL;
}
return tab->web_contents();
}
bool TabModelJniBridge::IsSessionRestoreInProgress() const {
JNIEnv* env = AttachCurrentThread();
return Java_TabModelJniBridge_isSessionRestoreInProgress(
env, java_object_.get(env));
}
bool TabModelJniBridge::IsCurrentModel() const {
JNIEnv* env = AttachCurrentThread();
return Java_TabModelJniBridge_isCurrentModel(env, java_object_.get(env));
}
void TabModelJniBridge::AddObserver(TabModelObserver* observer) {
// If a first observer is being added then instantiate an observer bridge.
if (!observer_bridge_) {
JNIEnv* env = AttachCurrentThread();
observer_bridge_ =
std::make_unique<TabModelObserverJniBridge>(env, java_object_.get(env));
}
observer_bridge_->AddObserver(observer);
}
void TabModelJniBridge::RemoveObserver(TabModelObserver* observer) {
observer_bridge_->RemoveObserver(observer);
// Tear down the bridge if there are no observers left.
if (!observer_bridge_->might_have_observers())
observer_bridge_.reset();
}
void TabModelJniBridge::BroadcastSessionRestoreComplete(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
TabModel::BroadcastSessionRestoreComplete();
}
inline static base::TimeDelta GetTimeDelta(jlong ms) {
return base::TimeDelta::FromMilliseconds(static_cast<int64_t>(ms));
}
void JNI_TabModelJniBridge_LogFromCloseMetric(
JNIEnv* env,
const JavaParamRef<jclass>& jcaller,
jlong ms,
jboolean perceived) {
if (perceived) {
UMA_HISTOGRAM_TIMES("Tabs.SwitchFromCloseLatency_Perceived",
GetTimeDelta(ms));
} else {
UMA_HISTOGRAM_TIMES("Tabs.SwitchFromCloseLatency_Actual",
GetTimeDelta(ms));
}
}
void JNI_TabModelJniBridge_LogFromExitMetric(
JNIEnv* env,
const JavaParamRef<jclass>& jcaller,
jlong ms,
jboolean perceived) {
if (perceived) {
UMA_HISTOGRAM_TIMES("Tabs.SwitchFromExitLatency_Perceived",
GetTimeDelta(ms));
} else {
UMA_HISTOGRAM_TIMES("Tabs.SwitchFromExitLatency_Actual",
GetTimeDelta(ms));
}
}
void JNI_TabModelJniBridge_LogFromNewMetric(JNIEnv* env,
const JavaParamRef<jclass>& jcaller,
jlong ms,
jboolean perceived) {
if (perceived) {
UMA_HISTOGRAM_TIMES("Tabs.SwitchFromNewLatency_Perceived",
GetTimeDelta(ms));
} else {
UMA_HISTOGRAM_TIMES("Tabs.SwitchFromNewLatency_Actual",
GetTimeDelta(ms));
}
}
void JNI_TabModelJniBridge_LogFromUserMetric(
JNIEnv* env,
const JavaParamRef<jclass>& jcaller,
jlong ms,
jboolean perceived) {
if (perceived) {
UMA_HISTOGRAM_TIMES("Tabs.SwitchFromUserLatency_Perceived",
GetTimeDelta(ms));
} else {
UMA_HISTOGRAM_TIMES("Tabs.SwitchFromUserLatency_Actual",
GetTimeDelta(ms));
}
}
TabModelJniBridge::~TabModelJniBridge() {
TabModelList::RemoveTabModel(this);
}
static jlong JNI_TabModelJniBridge_Init(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jboolean is_incognito,
jboolean is_tabbed_activity) {
TabModel* tab_model =
new TabModelJniBridge(env, obj, is_incognito, is_tabbed_activity);
return reinterpret_cast<intptr_t>(tab_model);
}