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 23 using base::android::AttachCurrentThread; 24 using base::android::CheckException; 25 using base::android::ConvertUTF8ToJavaString; 26 using base::android::ConvertUTF16ToJavaString; 27 using base::android::ScopedJavaLocalRef; 28 29 TabModelBase::TabModelBase(JNIEnv* env, jobject obj, Profile* profile) 30 : TabModel(profile), 31 java_object_(env, env->NewWeakGlobalRef(obj)) { 32 } 33 34 void TabModelBase::Destroy(JNIEnv* env, jobject obj) { 35 TabModelList::RemoveTabModel(this); 36 delete this; 37 } 38 39 ScopedJavaLocalRef<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 48 void 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 58 int 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 65 int 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 72 content::WebContents* TabModelBase::GetWebContentsAt( 73 int index) const { 74 TabAndroid* tab = GetTabAt(index); 75 return tab == NULL ? NULL : tab->web_contents(); 76 } 77 78 TabAndroid* 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 89 void TabModelBase::SetActiveIndex(int index) { 90 JNIEnv* env = AttachCurrentThread(); 91 Java_TabModelBase_setIndex( 92 env, 93 java_object_.get(env).obj(), 94 index); 95 } 96 97 void 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 110 void 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 119 content::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 139 bool TabModelBase::IsSessionRestoreInProgress() const { 140 JNIEnv* env = AttachCurrentThread(); 141 return Java_TabModelBase_isSessionRestoreInProgress( 142 env, java_object_.get(env).obj()); 143 } 144 145 void TabModelBase::BroadcastSessionRestoreComplete(JNIEnv* env, 146 jobject obj) { 147 TabModel::BroadcastSessionRestoreComplete(); 148 } 149 150 TabModelBase::~TabModelBase() { 151 } 152 153 namespace { 154 155 static 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 174 static 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 181 inline static base::TimeDelta GetTimeDelta(jlong ms) { 182 return base::TimeDelta::FromMilliseconds(static_cast<int64>(ms)); 183 } 184 185 void 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 198 void 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 211 void 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 224 void 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 239 bool RegisterTabModelBase(JNIEnv* env) { 240 return RegisterNativesImpl(env); 241 } 242