Home | History | Annotate | Download | only in android
      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 "content/browser/android/web_contents_observer_android.h"
      6 
      7 #include <string>
      8 
      9 #include <jni.h>
     10 
     11 #include "base/android/jni_android.h"
     12 #include "base/android/jni_string.h"
     13 #include "base/android/scoped_java_ref.h"
     14 #include "content/browser/renderer_host/render_widget_host_impl.h"
     15 #include "content/browser/web_contents/web_contents_impl.h"
     16 #include "content/public/browser/navigation_details.h"
     17 #include "content/public/browser/navigation_entry.h"
     18 #include "jni/WebContentsObserverAndroid_jni.h"
     19 
     20 using base::android::AttachCurrentThread;
     21 using base::android::ScopedJavaLocalRef;
     22 using base::android::ConvertUTF8ToJavaString;
     23 using base::android::ConvertUTF16ToJavaString;
     24 
     25 namespace content {
     26 
     27 WebContentsObserverAndroid::WebContentsObserverAndroid(
     28     JNIEnv* env,
     29     jobject obj,
     30     WebContents* web_contents)
     31     : WebContentsObserver(web_contents),
     32       weak_java_observer_(env, obj){
     33 }
     34 
     35 WebContentsObserverAndroid::~WebContentsObserverAndroid() {
     36 }
     37 
     38 jlong Init(JNIEnv* env, jobject obj, jobject java_web_contents) {
     39   content::WebContents* web_contents =
     40         content::WebContents::FromJavaWebContents(java_web_contents);
     41   CHECK(web_contents);
     42 
     43   WebContentsObserverAndroid* native_observer = new WebContentsObserverAndroid(
     44       env, obj, web_contents);
     45   return reinterpret_cast<intptr_t>(native_observer);
     46 }
     47 
     48 void WebContentsObserverAndroid::Destroy(JNIEnv* env, jobject obj) {
     49   delete this;
     50 }
     51 
     52 void WebContentsObserverAndroid::WebContentsDestroyed() {
     53   JNIEnv* env = AttachCurrentThread();
     54   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
     55   if (obj.is_null()) {
     56     delete this;
     57   } else {
     58     // The java side will destroy |this|
     59     Java_WebContentsObserverAndroid_detachFromWebContents(env, obj.obj());
     60   }
     61 }
     62 
     63 void WebContentsObserverAndroid::RenderProcessGone(
     64     base::TerminationStatus termination_status) {
     65   JNIEnv* env = AttachCurrentThread();
     66   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
     67   if (obj.is_null())
     68     return;
     69   jboolean was_oom_protected =
     70       termination_status == base::TERMINATION_STATUS_OOM_PROTECTED;
     71   Java_WebContentsObserverAndroid_renderProcessGone(
     72       env, obj.obj(), was_oom_protected);
     73 }
     74 
     75 void WebContentsObserverAndroid::DidStartLoading(
     76     RenderViewHost* render_view_host) {
     77   JNIEnv* env = AttachCurrentThread();
     78   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
     79   if (obj.is_null())
     80     return;
     81   ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
     82       env, web_contents()->GetVisibleURL().spec()));
     83   Java_WebContentsObserverAndroid_didStartLoading(
     84       env, obj.obj(), jstring_url.obj());
     85 }
     86 
     87 void WebContentsObserverAndroid::DidStopLoading(
     88     RenderViewHost* render_view_host) {
     89   JNIEnv* env = AttachCurrentThread();
     90   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
     91   if (obj.is_null())
     92     return;
     93   ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
     94       env, web_contents()->GetLastCommittedURL().spec()));
     95   Java_WebContentsObserverAndroid_didStopLoading(
     96       env, obj.obj(), jstring_url.obj());
     97 }
     98 
     99 void WebContentsObserverAndroid::DidFailProvisionalLoad(
    100     int64 frame_id,
    101     const base::string16& frame_unique_name,
    102     bool is_main_frame,
    103     const GURL& validated_url,
    104     int error_code,
    105     const base::string16& error_description,
    106     RenderViewHost* render_view_host) {
    107   DidFailLoadInternal(
    108         true, is_main_frame, error_code, error_description, validated_url);
    109 }
    110 
    111 void WebContentsObserverAndroid::DidFailLoad(
    112     int64 frame_id,
    113     const GURL& validated_url,
    114     bool is_main_frame,
    115     int error_code,
    116     const base::string16& error_description,
    117     RenderViewHost* render_view_host) {
    118   DidFailLoadInternal(
    119         false, is_main_frame, error_code, error_description, validated_url);
    120 }
    121 
    122 void WebContentsObserverAndroid::DidNavigateMainFrame(
    123     const LoadCommittedDetails& details,
    124     const FrameNavigateParams& params) {
    125   JNIEnv* env = AttachCurrentThread();
    126   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    127   if (obj.is_null())
    128     return;
    129   ScopedJavaLocalRef<jstring> jstring_url(
    130       ConvertUTF8ToJavaString(env, params.url.spec()));
    131   ScopedJavaLocalRef<jstring> jstring_base_url(
    132       ConvertUTF8ToJavaString(env, params.base_url.spec()));
    133 
    134   // See http://crbug.com/251330 for why it's determined this way.
    135   url::Replacements<char> replacements;
    136   replacements.ClearRef();
    137   bool urls_same_ignoring_fragment =
    138       params.url.ReplaceComponents(replacements) ==
    139       details.previous_url.ReplaceComponents(replacements);
    140 
    141   // is_fragment_navigation is indicative of the intent of this variable.
    142   // However, there isn't sufficient information here to determine whether this
    143   // is actually a fragment navigation, or a history API navigation to a URL
    144   // that would also be valid for a fragment navigation.
    145   bool is_fragment_navigation = urls_same_ignoring_fragment &&
    146       (details.type == NAVIGATION_TYPE_IN_PAGE || details.is_in_page);
    147   Java_WebContentsObserverAndroid_didNavigateMainFrame(
    148       env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
    149       details.is_navigation_to_different_page(), is_fragment_navigation);
    150 }
    151 
    152 void WebContentsObserverAndroid::DidNavigateAnyFrame(
    153     const LoadCommittedDetails& details,
    154     const FrameNavigateParams& params) {
    155   JNIEnv* env = AttachCurrentThread();
    156   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    157   if (obj.is_null())
    158     return;
    159   ScopedJavaLocalRef<jstring> jstring_url(
    160       ConvertUTF8ToJavaString(env, params.url.spec()));
    161   ScopedJavaLocalRef<jstring> jstring_base_url(
    162       ConvertUTF8ToJavaString(env, params.base_url.spec()));
    163   jboolean jboolean_is_reload =
    164       PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_RELOAD);
    165 
    166   Java_WebContentsObserverAndroid_didNavigateAnyFrame(
    167       env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
    168       jboolean_is_reload);
    169 }
    170 
    171 void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame(
    172       int64 frame_id,
    173       int64 parent_frame_id,
    174       bool is_main_frame,
    175       const GURL& validated_url,
    176       bool is_error_page,
    177       bool is_iframe_srcdoc,
    178       RenderViewHost* render_view_host) {
    179   JNIEnv* env = AttachCurrentThread();
    180   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    181   if (obj.is_null())
    182     return;
    183   ScopedJavaLocalRef<jstring> jstring_url(
    184       ConvertUTF8ToJavaString(env, validated_url.spec()));
    185   Java_WebContentsObserverAndroid_didStartProvisionalLoadForFrame(
    186       env, obj.obj(), frame_id, parent_frame_id, is_main_frame,
    187       jstring_url.obj(), is_error_page, is_iframe_srcdoc);
    188 }
    189 
    190 void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame(
    191       int64 frame_id,
    192       const base::string16& frame_unique_name,
    193       bool is_main_frame,
    194       const GURL& url,
    195       PageTransition transition_type,
    196       RenderViewHost* render_view_host) {
    197   JNIEnv* env = AttachCurrentThread();
    198   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    199   if (obj.is_null())
    200     return;
    201   ScopedJavaLocalRef<jstring> jstring_url(
    202       ConvertUTF8ToJavaString(env, url.spec()));
    203   Java_WebContentsObserverAndroid_didCommitProvisionalLoadForFrame(
    204       env, obj.obj(), frame_id, is_main_frame, jstring_url.obj(),
    205       transition_type);
    206 }
    207 
    208 void WebContentsObserverAndroid::DidFinishLoad(
    209     int64 frame_id,
    210     const GURL& validated_url,
    211     bool is_main_frame,
    212     RenderViewHost* render_view_host) {
    213   JNIEnv* env = AttachCurrentThread();
    214   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    215   if (obj.is_null())
    216     return;
    217 
    218   std::string url_string = validated_url.spec();
    219   NavigationEntry* entry =
    220     web_contents()->GetController().GetLastCommittedEntry();
    221   // Note that GetBaseURLForDataURL is only used by the Android WebView.
    222   if (entry && !entry->GetBaseURLForDataURL().is_empty())
    223     url_string = entry->GetBaseURLForDataURL().possibly_invalid_spec();
    224 
    225   ScopedJavaLocalRef<jstring> jstring_url(
    226       ConvertUTF8ToJavaString(env, url_string));
    227   Java_WebContentsObserverAndroid_didFinishLoad(
    228       env, obj.obj(), frame_id, jstring_url.obj(), is_main_frame);
    229 }
    230 
    231 void WebContentsObserverAndroid::DocumentLoadedInFrame(
    232     int64 frame_id,
    233     RenderViewHost* render_view_host) {
    234   JNIEnv* env = AttachCurrentThread();
    235   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    236   if (obj.is_null())
    237     return;
    238   Java_WebContentsObserverAndroid_documentLoadedInFrame(
    239       env, obj.obj(), frame_id);
    240 }
    241 
    242 void WebContentsObserverAndroid::NavigationEntryCommitted(
    243     const LoadCommittedDetails& load_details) {
    244   JNIEnv* env = AttachCurrentThread();
    245   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    246   if (obj.is_null())
    247     return;
    248   Java_WebContentsObserverAndroid_navigationEntryCommitted(env, obj.obj());
    249 }
    250 
    251 void WebContentsObserverAndroid::DidAttachInterstitialPage() {
    252   JNIEnv* env = AttachCurrentThread();
    253   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    254   if (obj.is_null())
    255     return;
    256   Java_WebContentsObserverAndroid_didAttachInterstitialPage(env, obj.obj());
    257 }
    258 
    259 void WebContentsObserverAndroid::DidDetachInterstitialPage() {
    260   JNIEnv* env = AttachCurrentThread();
    261   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    262   if (obj.is_null())
    263     return;
    264   Java_WebContentsObserverAndroid_didDetachInterstitialPage(env, obj.obj());
    265 }
    266 
    267 void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color) {
    268   JNIEnv* env = AttachCurrentThread();
    269   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    270   if (obj.is_null())
    271     return;
    272   Java_WebContentsObserverAndroid_didChangeThemeColor(env, obj.obj(), color);
    273 }
    274 
    275 void WebContentsObserverAndroid::DidFailLoadInternal(
    276     bool is_provisional_load,
    277     bool is_main_frame,
    278     int error_code,
    279     const base::string16& description,
    280     const GURL& url) {
    281   JNIEnv* env = AttachCurrentThread();
    282   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    283   if (obj.is_null())
    284     return;
    285   ScopedJavaLocalRef<jstring> jstring_error_description(
    286       ConvertUTF16ToJavaString(env, description));
    287   ScopedJavaLocalRef<jstring> jstring_url(
    288       ConvertUTF8ToJavaString(env, url.spec()));
    289 
    290   Java_WebContentsObserverAndroid_didFailLoad(
    291       env, obj.obj(),
    292       is_provisional_load,
    293       is_main_frame,
    294       error_code,
    295       jstring_error_description.obj(), jstring_url.obj());
    296 }
    297 
    298 void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() {
    299   JNIEnv* env = AttachCurrentThread();
    300   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
    301   if (obj.is_null())
    302     return;
    303   Java_WebContentsObserverAndroid_didFirstVisuallyNonEmptyPaint(
    304       env, obj.obj());
    305 }
    306 
    307 bool RegisterWebContentsObserverAndroid(JNIEnv* env) {
    308   return RegisterNativesImpl(env);
    309 }
    310 }  // namespace content
    311