Home | History | Annotate | Download | only in web_contents
      1 // Copyright 2013 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/web_contents/web_contents_android.h"
      6 
      7 #include "base/android/jni_android.h"
      8 #include "base/android/jni_string.h"
      9 #include "base/command_line.h"
     10 #include "base/json/json_writer.h"
     11 #include "base/logging.h"
     12 #include "content/browser/android/interstitial_page_delegate_android.h"
     13 #include "content/browser/frame_host/interstitial_page_impl.h"
     14 #include "content/browser/media/android/browser_media_player_manager.h"
     15 #include "content/browser/media/media_web_contents_observer.h"
     16 #include "content/browser/renderer_host/render_view_host_impl.h"
     17 #include "content/browser/web_contents/web_contents_impl.h"
     18 #include "content/common/frame_messages.h"
     19 #include "content/common/input_messages.h"
     20 #include "content/common/view_messages.h"
     21 #include "content/public/browser/browser_context.h"
     22 #include "content/public/browser/browser_thread.h"
     23 #include "content/public/browser/web_contents.h"
     24 #include "content/public/common/content_switches.h"
     25 #include "jni/WebContentsImpl_jni.h"
     26 
     27 using base::android::AttachCurrentThread;
     28 using base::android::ConvertJavaStringToUTF8;
     29 using base::android::ConvertJavaStringToUTF16;
     30 using base::android::ConvertUTF8ToJavaString;
     31 using base::android::ScopedJavaGlobalRef;
     32 
     33 namespace {
     34 
     35 void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
     36                               const base::Value* result) {
     37   JNIEnv* env = base::android::AttachCurrentThread();
     38   std::string json;
     39   base::JSONWriter::Write(result, &json);
     40   ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
     41   content::Java_WebContentsImpl_onEvaluateJavaScriptResult(
     42       env, j_json.obj(), callback.obj());
     43 }
     44 
     45 }  // namespace
     46 
     47 namespace content {
     48 
     49 // static
     50 WebContents* WebContents::FromJavaWebContents(
     51     jobject jweb_contents_android) {
     52   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     53   if (!jweb_contents_android)
     54     return NULL;
     55 
     56   WebContentsAndroid* web_contents_android =
     57       reinterpret_cast<WebContentsAndroid*>(
     58           Java_WebContentsImpl_getNativePointer(AttachCurrentThread(),
     59                                                 jweb_contents_android));
     60   if (!web_contents_android)
     61     return NULL;
     62   return web_contents_android->web_contents();
     63 }
     64 
     65 // static
     66 bool WebContentsAndroid::Register(JNIEnv* env) {
     67   return RegisterNativesImpl(env);
     68 }
     69 
     70 WebContentsAndroid::WebContentsAndroid(WebContents* web_contents)
     71     : web_contents_(web_contents),
     72       navigation_controller_(&(web_contents->GetController())) {
     73   JNIEnv* env = AttachCurrentThread();
     74   obj_.Reset(env,
     75              Java_WebContentsImpl_create(
     76                  env,
     77                  reinterpret_cast<intptr_t>(this),
     78                  navigation_controller_.GetJavaObject().obj()).obj());
     79 }
     80 
     81 WebContentsAndroid::~WebContentsAndroid() {
     82   Java_WebContentsImpl_destroy(AttachCurrentThread(), obj_.obj());
     83 }
     84 
     85 base::android::ScopedJavaLocalRef<jobject>
     86 WebContentsAndroid::GetJavaObject() {
     87   return base::android::ScopedJavaLocalRef<jobject>(obj_);
     88 }
     89 
     90 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetTitle(
     91     JNIEnv* env, jobject obj) const {
     92   return base::android::ConvertUTF16ToJavaString(env,
     93                                                  web_contents_->GetTitle());
     94 }
     95 
     96 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetVisibleURL(
     97     JNIEnv* env, jobject obj) const {
     98   return base::android::ConvertUTF8ToJavaString(
     99       env, web_contents_->GetVisibleURL().spec());
    100 }
    101 
    102 void WebContentsAndroid::Stop(JNIEnv* env, jobject obj) {
    103   web_contents_->Stop();
    104 }
    105 
    106 void WebContentsAndroid::InsertCSS(
    107     JNIEnv* env, jobject jobj, jstring jcss) {
    108   web_contents_->InsertCSS(base::android::ConvertJavaStringToUTF8(env, jcss));
    109 }
    110 
    111 RenderWidgetHostViewAndroid*
    112     WebContentsAndroid::GetRenderWidgetHostViewAndroid() {
    113   RenderWidgetHostView* rwhv = NULL;
    114   rwhv = web_contents_->GetRenderWidgetHostView();
    115   if (web_contents_->ShowingInterstitialPage()) {
    116     rwhv = static_cast<InterstitialPageImpl*>(
    117         web_contents_->GetInterstitialPage())->
    118             GetRenderViewHost()->GetView();
    119   }
    120   return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
    121 }
    122 
    123 jint WebContentsAndroid::GetBackgroundColor(JNIEnv* env, jobject obj) {
    124   RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
    125   if (!rwhva)
    126     return SK_ColorWHITE;
    127   return rwhva->GetCachedBackgroundColor();
    128 }
    129 
    130 ScopedJavaLocalRef<jstring> WebContentsAndroid::GetURL(JNIEnv* env,
    131                                                        jobject obj) const {
    132   return ConvertUTF8ToJavaString(env, web_contents_->GetURL().spec());
    133 }
    134 
    135 jboolean WebContentsAndroid::IsIncognito(JNIEnv* env, jobject obj) {
    136   return web_contents_->GetBrowserContext()->IsOffTheRecord();
    137 }
    138 
    139 void WebContentsAndroid::ResumeResponseDeferredAtStart(JNIEnv* env,
    140                                                        jobject obj) {
    141   static_cast<WebContentsImpl*>(web_contents_)->ResumeResponseDeferredAtStart();
    142 }
    143 
    144 void WebContentsAndroid::SetHasPendingNavigationTransitionForTesting(
    145     JNIEnv* env,
    146     jobject obj) {
    147   CommandLine::ForCurrentProcess()->AppendSwitch(
    148       switches::kEnableExperimentalWebPlatformFeatures);
    149   RenderFrameHost* frame =
    150       static_cast<WebContentsImpl*>(web_contents_)->GetMainFrame();
    151   BrowserThread::PostTask(
    152       BrowserThread::IO,
    153       FROM_HERE,
    154       base::Bind(&TransitionRequestManager::AddPendingTransitionRequestData,
    155                  base::Unretained(TransitionRequestManager::GetInstance()),
    156                  frame->GetProcess()->GetID(),
    157                  frame->GetRoutingID(),
    158                  "*",
    159                  "",
    160                  ""));
    161 }
    162 
    163 void WebContentsAndroid::SetupTransitionView(JNIEnv* env,
    164                                              jobject jobj,
    165                                              jstring markup) {
    166   web_contents_->GetMainFrame()->Send(new FrameMsg_SetupTransitionView(
    167       web_contents_->GetMainFrame()->GetRoutingID(),
    168       ConvertJavaStringToUTF8(env, markup)));
    169 }
    170 
    171 void WebContentsAndroid::BeginExitTransition(JNIEnv* env,
    172                                              jobject jobj,
    173                                              jstring css_selector) {
    174   web_contents_->GetMainFrame()->Send(new FrameMsg_BeginExitTransition(
    175       web_contents_->GetMainFrame()->GetRoutingID(),
    176       ConvertJavaStringToUTF8(env, css_selector)));
    177 }
    178 
    179 void WebContentsAndroid::OnHide(JNIEnv* env, jobject obj) {
    180   web_contents_->WasHidden();
    181 }
    182 
    183 void WebContentsAndroid::OnShow(JNIEnv* env, jobject obj) {
    184   web_contents_->WasShown();
    185 }
    186 
    187 void WebContentsAndroid::ReleaseMediaPlayers(JNIEnv* env, jobject jobj) {
    188 #if defined(ENABLE_BROWSER_CDMS)
    189   RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
    190       web_contents_->GetRenderViewHost());
    191   if (!rvhi || !rvhi->GetMainFrame())
    192     return;
    193 
    194   BrowserMediaPlayerManager* manager =
    195       rvhi->media_web_contents_observer()->GetMediaPlayerManager(
    196           rvhi->GetMainFrame());
    197   if (manager)
    198     manager->ReleaseAllMediaPlayers();
    199 #endif // defined(ENABLE_BROWSER_CDMS)
    200 }
    201 
    202 void WebContentsAndroid::AddStyleSheetByURL(
    203     JNIEnv* env,
    204     jobject obj,
    205     jstring url) {
    206   web_contents_->GetMainFrame()->Send(new FrameMsg_AddStyleSheetByURL(
    207       web_contents_->GetMainFrame()->GetRoutingID(),
    208       ConvertJavaStringToUTF8(env, url)));
    209 }
    210 
    211 void WebContentsAndroid::ShowInterstitialPage(
    212     JNIEnv* env,
    213     jobject obj,
    214     jstring jurl,
    215     jlong delegate_ptr) {
    216   GURL url(base::android::ConvertJavaStringToUTF8(env, jurl));
    217   InterstitialPageDelegateAndroid* delegate =
    218       reinterpret_cast<InterstitialPageDelegateAndroid*>(delegate_ptr);
    219   InterstitialPage* interstitial = InterstitialPage::Create(
    220       web_contents_, false, url, delegate);
    221   delegate->set_interstitial_page(interstitial);
    222   interstitial->Show();
    223 }
    224 
    225 jboolean WebContentsAndroid::IsShowingInterstitialPage(JNIEnv* env,
    226                                                         jobject obj) {
    227   return web_contents_->ShowingInterstitialPage();
    228 }
    229 
    230 jboolean WebContentsAndroid::IsRenderWidgetHostViewReady(
    231     JNIEnv* env,
    232     jobject obj) {
    233   RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
    234   return view && view->HasValidFrame();
    235 }
    236 
    237 void WebContentsAndroid::ExitFullscreen(JNIEnv* env, jobject obj) {
    238   RenderViewHost* host = web_contents_->GetRenderViewHost();
    239   if (!host)
    240     return;
    241   host->ExitFullscreen();
    242 }
    243 
    244 void WebContentsAndroid::UpdateTopControlsState(
    245     JNIEnv* env,
    246     jobject obj,
    247     bool enable_hiding,
    248     bool enable_showing,
    249     bool animate) {
    250   RenderViewHost* host = web_contents_->GetRenderViewHost();
    251   if (!host)
    252     return;
    253   host->Send(new ViewMsg_UpdateTopControlsState(host->GetRoutingID(),
    254                                                 enable_hiding,
    255                                                 enable_showing,
    256                                                 animate));
    257 }
    258 
    259 void WebContentsAndroid::ShowImeIfNeeded(JNIEnv* env, jobject obj) {
    260   RenderViewHost* host = web_contents_->GetRenderViewHost();
    261   if (!host)
    262     return;
    263   host->Send(new ViewMsg_ShowImeIfNeeded(host->GetRoutingID()));
    264 }
    265 
    266 void WebContentsAndroid::ScrollFocusedEditableNodeIntoView(
    267     JNIEnv* env,
    268     jobject obj) {
    269   RenderViewHost* host = web_contents_->GetRenderViewHost();
    270   if (!host)
    271     return;
    272   host->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect(
    273       host->GetRoutingID(), gfx::Rect()));
    274 }
    275 
    276 void WebContentsAndroid::SelectWordAroundCaret(JNIEnv* env, jobject obj) {
    277   RenderViewHost* host = web_contents_->GetRenderViewHost();
    278   if (!host)
    279     return;
    280   host->SelectWordAroundCaret();
    281 }
    282 
    283 bool WebContentsAndroid::WillHandleDeferAfterResponseStarted() {
    284   JNIEnv* env = AttachCurrentThread();
    285   return Java_WebContentsImpl_willHandleDeferAfterResponseStarted(env,
    286                                                                   obj_.obj());
    287 }
    288 
    289 void WebContentsAndroid::DidDeferAfterResponseStarted(
    290     const TransitionLayerData& transition_data) {
    291   JNIEnv* env = AttachCurrentThread();
    292   std::vector<GURL> entering_stylesheets;
    293   std::string transition_color;
    294   if (transition_data.response_headers) {
    295     TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
    296         transition_data.response_headers,
    297         entering_stylesheets,
    298         transition_data.request_url);
    299 
    300     transition_data.response_headers->EnumerateHeader(
    301         NULL, "X-Transition-Entering-Color", &transition_color);
    302   }
    303 
    304   ScopedJavaLocalRef<jstring> jstring_markup(
    305       ConvertUTF8ToJavaString(env, transition_data.markup));
    306 
    307   ScopedJavaLocalRef<jstring> jstring_css_selector(
    308       ConvertUTF8ToJavaString(env, transition_data.css_selector));
    309 
    310   ScopedJavaLocalRef<jstring> jstring_transition_color(
    311       ConvertUTF8ToJavaString(env, transition_color));
    312 
    313   Java_WebContentsImpl_didDeferAfterResponseStarted(
    314       env,
    315       obj_.obj(),
    316       jstring_markup.obj(),
    317       jstring_css_selector.obj(),
    318       jstring_transition_color.obj());
    319 
    320   std::vector<GURL>::const_iterator iter = entering_stylesheets.begin();
    321   for (; iter != entering_stylesheets.end(); ++iter) {
    322     ScopedJavaLocalRef<jstring> jstring_url(
    323         ConvertUTF8ToJavaString(env, iter->spec()));
    324     Java_WebContentsImpl_addEnteringStylesheetToTransition(
    325         env, obj_.obj(), jstring_url.obj());
    326   }
    327 }
    328 
    329 void WebContentsAndroid::DidStartNavigationTransitionForFrame(int64 frame_id) {
    330   JNIEnv* env = AttachCurrentThread();
    331   Java_WebContentsImpl_didStartNavigationTransitionForFrame(
    332       env, obj_.obj(), frame_id);
    333 }
    334 
    335 void WebContentsAndroid::EvaluateJavaScript(JNIEnv* env,
    336                                             jobject obj,
    337                                             jstring script,
    338                                             jobject callback) {
    339   RenderViewHost* rvh = web_contents_->GetRenderViewHost();
    340   DCHECK(rvh);
    341 
    342   if (!rvh->IsRenderViewLive()) {
    343     if (!static_cast<WebContentsImpl*>(web_contents_)->
    344         CreateRenderViewForInitialEmptyDocument()) {
    345       LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript";
    346       return;
    347     }
    348   }
    349 
    350   if (!callback) {
    351     // No callback requested.
    352     web_contents_->GetMainFrame()->ExecuteJavaScript(
    353         ConvertJavaStringToUTF16(env, script));
    354     return;
    355   }
    356 
    357   // Secure the Java callback in a scoped object and give ownership of it to the
    358   // base::Callback.
    359   ScopedJavaGlobalRef<jobject> j_callback;
    360   j_callback.Reset(env, callback);
    361   content::RenderFrameHost::JavaScriptResultCallback js_callback =
    362       base::Bind(&JavaScriptResultCallback, j_callback);
    363 
    364   web_contents_->GetMainFrame()->ExecuteJavaScript(
    365       ConvertJavaStringToUTF16(env, script), js_callback);
    366 }
    367 
    368 }  // namespace content
    369