1// Copyright 2014 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_base.h" 6 7#include "base/android/jni_android.h" 8#include "base/android/jni_string.h" 9#include "base/android/jni_weak_ref.h" 10#include "base/metrics/histogram.h" 11#include "base/time/time.h" 12#include "chrome/browser/android/tab_android.h" 13#include "chrome/browser/browser_process.h" 14#include "chrome/browser/profiles/profile.h" 15#include "chrome/browser/profiles/profile_android.h" 16#include "chrome/browser/profiles/profile_manager.h" 17#include "chrome/browser/ui/android/tab_model/tab_model.h" 18#include "chrome/browser/ui/android/tab_model/tab_model_list.h" 19#include "chrome/browser/ui/toolbar/toolbar_model.h" 20#include "content/public/browser/web_contents.h" 21#include "jni/TabModelBase_jni.h" 22 23using base::android::AttachCurrentThread; 24using base::android::CheckException; 25using base::android::ConvertUTF8ToJavaString; 26using base::android::ConvertUTF16ToJavaString; 27using base::android::ScopedJavaLocalRef; 28 29TabModelBase::TabModelBase(JNIEnv* env, jobject obj, Profile* profile) 30 : TabModel(profile), 31 java_object_(env, env->NewWeakGlobalRef(obj)) { 32} 33 34void TabModelBase::Destroy(JNIEnv* env, jobject obj) { 35 TabModelList::RemoveTabModel(this); 36 delete this; 37} 38 39ScopedJavaLocalRef<jobject> TabModelBase::GetProfileAndroid(JNIEnv* env, 40 jobject obj) { 41 ProfileAndroid* profile_android = ProfileAndroid::FromProfile(GetProfile()); 42 if (!profile_android) 43 return ScopedJavaLocalRef<jobject>(); 44 45 return profile_android->GetJavaObject(); 46} 47 48void TabModelBase::TabAddedToModel(JNIEnv* env, jobject obj, jobject jtab) { 49 TabAndroid* tab = TabAndroid::GetNativeTab(env, jtab); 50 51 // Tab#initialize() should have been called by now otherwise we can't push 52 // the window id. 53 DCHECK(tab); 54 55 tab->SetWindowSessionID(GetSessionId()); 56} 57 58int TabModelBase::GetTabCount() const { 59 JNIEnv* env = AttachCurrentThread(); 60 jint count = Java_TabModelBase_getCount( 61 env, java_object_.get(env).obj()); 62 return count; 63} 64 65int TabModelBase::GetActiveIndex() const { 66 JNIEnv* env = AttachCurrentThread(); 67 jint index = Java_TabModelBase_index( 68 env, java_object_.get(env).obj()); 69 return index; 70} 71 72content::WebContents* TabModelBase::GetWebContentsAt( 73 int index) const { 74 TabAndroid* tab = GetTabAt(index); 75 return tab == NULL ? NULL : tab->web_contents(); 76} 77 78TabAndroid* TabModelBase::GetTabAt(int index) const { 79 JNIEnv* env = AttachCurrentThread(); 80 ScopedJavaLocalRef<jobject> jtab = 81 Java_TabModelBase_getTabAt(env, 82 java_object_.get(env).obj(), 83 index); 84 DCHECK(!jtab.is_null()); 85 86 return TabAndroid::GetNativeTab(env, jtab.obj()); 87} 88 89void TabModelBase::SetActiveIndex(int index) { 90 JNIEnv* env = AttachCurrentThread(); 91 Java_TabModelBase_setIndex( 92 env, 93 java_object_.get(env).obj(), 94 index); 95} 96 97void TabModelBase::CloseTabAt(int index) { 98 JNIEnv* env = AttachCurrentThread(); 99 ScopedJavaLocalRef<jobject> jtab = 100 Java_TabModelBase_getTabAt(env, 101 java_object_.get(env).obj(), 102 index); 103 if (!jtab.is_null()) { 104 Java_TabModelBase_closeTab(env, 105 java_object_.get(env).obj(), 106 jtab.obj()); 107 } 108} 109 110void TabModelBase::CreateTab(content::WebContents* web_contents, 111 int parent_tab_id) { 112 JNIEnv* env = AttachCurrentThread(); 113 Java_TabModelBase_createTabWithNativeContents( 114 env, java_object_.get(env).obj(), 115 web_contents->GetBrowserContext()->IsOffTheRecord(), 116 reinterpret_cast<intptr_t>(web_contents), parent_tab_id); 117} 118 119content::WebContents* TabModelBase::CreateNewTabForDevTools(const GURL& url) { 120 JNIEnv* env = AttachCurrentThread(); 121 ScopedJavaLocalRef<jstring> jurl = ConvertUTF8ToJavaString(env, url.spec()); 122 ScopedJavaLocalRef<jobject> obj = 123 Java_TabModelBase_createNewTabForDevTools( 124 env, 125 java_object_.get(env).obj(), 126 jurl.obj()); 127 if (obj.is_null()) { 128 VLOG(0) << "Failed to create java tab"; 129 return NULL; 130 } 131 TabAndroid* tab = TabAndroid::GetNativeTab(env, obj.obj()); 132 if (!tab) { 133 VLOG(0) << "Failed to create java tab"; 134 return NULL; 135 } 136 return tab->web_contents(); 137} 138 139bool TabModelBase::IsSessionRestoreInProgress() const { 140 JNIEnv* env = AttachCurrentThread(); 141 return Java_TabModelBase_isSessionRestoreInProgress( 142 env, java_object_.get(env).obj()); 143} 144 145void TabModelBase::BroadcastSessionRestoreComplete(JNIEnv* env, 146 jobject obj) { 147 TabModel::BroadcastSessionRestoreComplete(); 148} 149 150TabModelBase::~TabModelBase() { 151} 152 153namespace { 154 155static Profile* FindProfile(jboolean is_incognito) { 156 if (g_browser_process == NULL || 157 g_browser_process->profile_manager() == NULL) { 158 LOG(ERROR) << "Browser process or profile manager not initialized"; 159 return NULL; 160 } 161 Profile* profile = ProfileManager::GetActiveUserProfile(); 162 if (is_incognito) { 163 return profile->GetOffTheRecordProfile(); 164 } 165 return profile; 166} 167 168} // namespace 169 170// ---------------------------------------------------------------------------- 171// Native JNI methods 172// ---------------------------------------------------------------------------- 173 174static jlong Init(JNIEnv* env, jobject obj, jboolean is_incognito) { 175 Profile* profile = FindProfile(is_incognito); 176 TabModel* tab_model = new TabModelBase(env, obj, profile); 177 TabModelList::AddTabModel(tab_model); 178 return reinterpret_cast<intptr_t>(tab_model); 179} 180 181inline static base::TimeDelta GetTimeDelta(jlong ms) { 182 return base::TimeDelta::FromMilliseconds(static_cast<int64>(ms)); 183} 184 185void LogFromCloseMetric(JNIEnv* env, 186 jclass jcaller, 187 jlong ms, 188 jboolean perceived) { 189 if (perceived) { 190 UMA_HISTOGRAM_TIMES("Tabs.SwitchFromCloseLatency_Perceived", 191 GetTimeDelta(ms)); 192 } else { 193 UMA_HISTOGRAM_TIMES("Tabs.SwitchFromCloseLatency_Actual", 194 GetTimeDelta(ms)); 195 } 196} 197 198void LogFromExitMetric(JNIEnv* env, 199 jclass jcaller, 200 jlong ms, 201 jboolean perceived) { 202 if (perceived) { 203 UMA_HISTOGRAM_TIMES("Tabs.SwitchFromExitLatency_Perceived", 204 GetTimeDelta(ms)); 205 } else { 206 UMA_HISTOGRAM_TIMES("Tabs.SwitchFromExitLatency_Actual", 207 GetTimeDelta(ms)); 208 } 209} 210 211void LogFromNewMetric(JNIEnv* env, 212 jclass jcaller, 213 jlong ms, 214 jboolean perceived) { 215 if (perceived) { 216 UMA_HISTOGRAM_TIMES("Tabs.SwitchFromNewLatency_Perceived", 217 GetTimeDelta(ms)); 218 } else { 219 UMA_HISTOGRAM_TIMES("Tabs.SwitchFromNewLatency_Actual", 220 GetTimeDelta(ms)); 221 } 222} 223 224void LogFromUserMetric(JNIEnv* env, 225 jclass jcaller, 226 jlong ms, 227 jboolean perceived) { 228 if (perceived) { 229 UMA_HISTOGRAM_TIMES("Tabs.SwitchFromUserLatency_Perceived", 230 GetTimeDelta(ms)); 231 } else { 232 UMA_HISTOGRAM_TIMES("Tabs.SwitchFromUserLatency_Actual", 233 GetTimeDelta(ms)); 234 } 235} 236 237// Register native methods 238 239bool RegisterTabModelBase(JNIEnv* env) { 240 return RegisterNativesImpl(env); 241} 242