d6ac2b57创建于 2012年9月21日历史提交
// Copyright (c) 2012 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/android/chrome_web_contents_delegate_android.h"

#include "base/android/jni_android.h"
#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/ui/find_bar/find_match_rects_details.h"
#include "chrome/browser/ui/find_bar/find_notification_details.h"
#include "chrome/browser/ui/find_bar/find_tab_helper.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_creator.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/file_chooser_params.h"
#include "jni/ChromeWebContentsDelegateAndroid_jni.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/rect_f.h"

using base::android::AttachCurrentThread;
using base::android::GetClass;
using base::android::ScopedJavaLocalRef;
using content::FileChooserParams;
using content::WebContents;

namespace {

// Convenience method to create Android rects.
// RectType should be either gfx::Rect or gfx::RectF.
template <typename RectType>
ScopedJavaLocalRef<jobject> CreateAndroidRect(
    JNIEnv* env,
    const ScopedJavaLocalRef<jclass>& clazz,
    const jmethodID& constructor,
    const RectType& rect) {

  ScopedJavaLocalRef<jobject> rect_object(
      env,
      env->NewObject(clazz.obj(),
                     constructor,
                     rect.x(),
                     rect.y(),
                     rect.right(),
                     rect.bottom()));

  DCHECK(!rect_object.is_null());
  return rect_object;
}

}  // anonymous namespace

namespace chrome {
namespace android {

ChromeWebContentsDelegateAndroid::ChromeWebContentsDelegateAndroid(JNIEnv* env,
                                                                   jobject obj)
    : WebContentsDelegateAndroid(env, obj) {
}

ChromeWebContentsDelegateAndroid::~ChromeWebContentsDelegateAndroid() {
  notification_registrar_.RemoveAll();
}

// Register native methods.
bool RegisterChromeWebContentsDelegateAndroid(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

void ChromeWebContentsDelegateAndroid::RunFileChooser(
    WebContents* web_contents,
    const FileChooserParams& params) {
  FileSelectHelper::RunFileChooser(web_contents, params);
}

void ChromeWebContentsDelegateAndroid::CloseContents(
    WebContents* web_contents) {
  // Prevent dangling registrations assigned to closed web contents.
  if (notification_registrar_.IsRegistered(this,
      chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
      content::Source<WebContents>(web_contents))) {
    notification_registrar_.Remove(this,
        chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
        content::Source<WebContents>(web_contents));
  }

  WebContentsDelegateAndroid::CloseContents(web_contents);
}

void ChromeWebContentsDelegateAndroid::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_FIND_RESULT_AVAILABLE:
      OnFindResultAvailable(
          content::Source<WebContents>(source).ptr(),
          content::Details<FindNotificationDetails>(details).ptr());
      break;
    default:
      NOTREACHED() << "Unexpected notification: " << type;
      break;
  }
}

void ChromeWebContentsDelegateAndroid::FindReply(
    WebContents* web_contents,
    int request_id,
    int number_of_matches,
    const gfx::Rect& selection_rect,
    int active_match_ordinal,
    bool final_update) {
  if (!notification_registrar_.IsRegistered(this,
      chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
      content::Source<WebContents>(web_contents))) {
    notification_registrar_.Add(this,
        chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
        content::Source<WebContents>(web_contents));
  }

  TabContents* tab_contents = TabContents::FromWebContents(web_contents);
  tab_contents->find_tab_helper()->HandleFindReply(request_id,
                                                   number_of_matches,
                                                   selection_rect,
                                                   active_match_ordinal,
                                                   final_update);
}

void ChromeWebContentsDelegateAndroid::OnFindResultAvailable(
    WebContents* web_contents,
    const FindNotificationDetails* find_result) {
  JNIEnv* env = AttachCurrentThread();
  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
  if (obj.is_null())
    return;

  // Create the selection rect.
  ScopedJavaLocalRef<jclass> rect_clazz =
      GetClass(env, "android/graphics/Rect");

  jmethodID rect_constructor =
      GetMethodID(env, rect_clazz, "<init>", "(IIII)V");

  ScopedJavaLocalRef<jobject> selection_rect = CreateAndroidRect(
      env, rect_clazz, rect_constructor, find_result->selection_rect());

  // Create the details object.
  ScopedJavaLocalRef<jclass> details_clazz =
      GetClass(env, "org/chromium/chrome/browser/FindNotificationDetails");

  jmethodID details_constructor = GetMethodID(env, details_clazz, "<init>",
                                              "(ILandroid/graphics/Rect;IZ)V");

  ScopedJavaLocalRef<jobject> details_object(
      env,
      env->NewObject(details_clazz.obj(),
                     details_constructor,
                     find_result->number_of_matches(),
                     selection_rect.obj(),
                     find_result->active_match_ordinal(),
                     find_result->final_update()));
  DCHECK(!details_object.is_null());

  Java_ChromeWebContentsDelegateAndroid_onFindResultAvailable(
      env,
      obj.obj(),
      details_object.obj());
}

void ChromeWebContentsDelegateAndroid::FindMatchRectsReply(
    WebContents* web_contents,
    int version,
    const std::vector<gfx::RectF>& rects,
    const gfx::RectF& active_rect) {
  FindMatchRectsDetails match_rects(version, rects, active_rect);
  content::NotificationService::current()->Notify(
      chrome::NOTIFICATION_FIND_MATCH_RECTS_AVAILABLE,
      content::Source<WebContents>(web_contents),
      content::Details<FindMatchRectsDetails>(&match_rects));

  JNIEnv* env = AttachCurrentThread();
  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
  if (obj.is_null())
    return;

  // Create the rects.
  ScopedJavaLocalRef<jclass> rect_clazz =
      GetClass(env, "android/graphics/RectF");

  jmethodID rect_constructor =
      GetMethodID(env, rect_clazz, "<init>", "(FFFF)V");

  ScopedJavaLocalRef<jobjectArray> jrects(env, env->NewObjectArray(
      match_rects.rects().size(), rect_clazz.obj(), NULL));

  for (size_t i = 0; i < match_rects.rects().size(); ++i) {
    env->SetObjectArrayElement(
        jrects.obj(), i,
        CreateAndroidRect(env,
                          rect_clazz,
                          rect_constructor,
                          match_rects.rects()[i]).obj());
  }

  ScopedJavaLocalRef<jobject> jactive_rect = CreateAndroidRect(
      env, rect_clazz, rect_constructor, match_rects.active_rect());

  // Create the details object.
  ScopedJavaLocalRef<jclass> details_clazz =
      GetClass(env, "org/chromium/chrome/browser/FindMatchRectsDetails");

  jmethodID details_constructor = GetMethodID(env, details_clazz, "<init>",
      "(I[Landroid/graphics/RectF;Landroid/graphics/RectF;)V");

  ScopedJavaLocalRef<jobject> details_object(
      env,
      env->NewObject(details_clazz.obj(),
                     details_constructor,
                     match_rects.version(),
                     jrects.obj(),
                     jactive_rect.obj()));
  DCHECK(!details_object.is_null());

  Java_ChromeWebContentsDelegateAndroid_onFindMatchRectsAvailable(
      env,
      obj.obj(),
      details_object.obj());
}

content::JavaScriptDialogCreator*
ChromeWebContentsDelegateAndroid::GetJavaScriptDialogCreator() {
  return GetJavaScriptDialogCreatorInstance();
}

}  // namespace android
}  // namespace chrome