diff options
author | leandrogracia@chromium.org <leandrogracia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-25 13:22:08 +0000 |
---|---|---|
committer | leandrogracia@chromium.org <leandrogracia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-25 13:22:08 +0000 |
commit | 975b42b0b184f93093dbb6067fb87b916e473939 (patch) | |
tree | 1f64091a2433837cb53af06b331a9329d132d010 | |
parent | b63fee8fed5490ac646d0249a3e4110620834379 (diff) | |
download | chromium_src-975b42b0b184f93093dbb6067fb87b916e473939.zip chromium_src-975b42b0b184f93093dbb6067fb87b916e473939.tar.gz chromium_src-975b42b0b184f93093dbb6067fb87b916e473939.tar.bz2 |
[Android] Introduce phone number detection.
For more context see: https://chromiumcodereview.appspot.com/10187020/
BUG=125390
TEST=phone_number_detector_unittest.cc
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=139019
Review URL: https://chromiumcodereview.appspot.com/10440021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139026 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | content/content_renderer.gypi | 7 | ||||
-rw-r--r-- | content/content_tests.gypi | 1 | ||||
-rw-r--r-- | content/renderer/android/DEPS | 3 | ||||
-rw-r--r-- | content/renderer/android/phone_number_detector.cc | 90 | ||||
-rw-r--r-- | content/renderer/android/phone_number_detector.h | 41 | ||||
-rw-r--r-- | content/renderer/android/phone_number_detector_unittest.cc | 74 | ||||
-rw-r--r-- | third_party/libphonenumber/libphonenumber.gyp | 1 |
7 files changed, 217 insertions, 0 deletions
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index b1a13de..74c7719 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -46,6 +46,8 @@ 'renderer/android/content_detector.h', 'renderer/android/email_detector.cc', 'renderer/android/email_detector.h', + 'renderer/android/phone_number_detector.cc', + 'renderer/android/phone_number_detector.h', 'renderer/active_notification_tracker.cc', 'renderer/active_notification_tracker.h', 'renderer/device_orientation_dispatcher.cc', @@ -268,6 +270,11 @@ '../base/allocator/allocator.gyp:allocator', ], }], + ['OS=="android"', { + 'dependencies': [ + '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber', + ], + }], # TODO(jrg): remove the OS=="android" section? # http://crbug.com/113172 # Understand better how media_stream_ is tied into Chromium. diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 65250f7..224c4f4 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -286,6 +286,7 @@ 'renderer/active_notification_tracker_unittest.cc', 'renderer/android/address_detector_unittest.cc', 'renderer/android/email_detector_unittest.cc', + 'renderer/android/phone_number_detector_unittest.cc', 'renderer/gpu/input_event_filter_unittest.cc', 'renderer/media/audio_message_filter_unittest.cc', 'renderer/media/capture_video_decoder_unittest.cc', diff --git a/content/renderer/android/DEPS b/content/renderer/android/DEPS new file mode 100644 index 0000000..bec0ab9 --- /dev/null +++ b/content/renderer/android/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+third_party/libphonenumber", # For phone number detection. +] diff --git a/content/renderer/android/phone_number_detector.cc b/content/renderer/android/phone_number_detector.cc new file mode 100644 index 0000000..30e0111 --- /dev/null +++ b/content/renderer/android/phone_number_detector.cc @@ -0,0 +1,90 @@ +// 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 "content/renderer/android/phone_number_detector.h" + +#include <algorithm> + +#include "base/utf_string_conversions.h" +#include "net/base/escape.h" +#include "third_party/libphonenumber/src/phonenumber_api.h" +#include "third_party/libphonenumber/src/phonenumbers/phonenumbermatch.h" +#include "third_party/libphonenumber/src/phonenumbers/phonenumbermatcher.h" +#include "third_party/libphonenumber/src/phonenumbers/region_code.h" + +using i18n::phonenumbers::PhoneNumberMatch; +using i18n::phonenumbers::PhoneNumberMatcher; +using i18n::phonenumbers::PhoneNumberUtil; +using i18n::phonenumbers::RegionCode; + +namespace { + +// Maximum number of characters to look around for phone number detection. +const size_t kMaximumTelephoneLength = 20; + +// Prefix used for telephone number intent URIs. +const char kPhoneNumberSchemaPrefix[] = "tel:"; + +} // anonymous namespace + +namespace content { + +PhoneNumberDetector::PhoneNumberDetector() + : region_code_(RegionCode::GetUnknown()) { +} + +// Region should be empty or an ISO 3166-1 alpha-2 country code. +PhoneNumberDetector::PhoneNumberDetector(const std::string& region) + : region_code_(region.empty() ? RegionCode::GetUnknown() + : StringToUpperASCII(region)) { +} + +PhoneNumberDetector::~PhoneNumberDetector() { +} + +size_t PhoneNumberDetector::GetMaximumContentLength() { + return kMaximumTelephoneLength; +} + +GURL PhoneNumberDetector::GetIntentURL(const std::string& content_text) { + if (content_text.empty()) + return GURL(); + + return GURL(kPhoneNumberSchemaPrefix + + net::EscapeQueryParamValue(content_text, true)); +} + +bool PhoneNumberDetector::FindContent(const string16::const_iterator& begin, + const string16::const_iterator& end, + size_t* start_pos, + size_t* end_pos, + std::string* content_text) { + string16 utf16_input = string16(begin, end); + std::string utf8_input = UTF16ToUTF8(utf16_input); + + PhoneNumberMatcher matcher(utf8_input, region_code_); + if (matcher.HasNext()) { + PhoneNumberMatch match; + matcher.Next(&match); + + PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance(); + phone_util->FormatNumberForMobileDialing(match.number(), region_code_, + false, /* with_formatting */ + content_text); + // If the number can't be dialed from the current region, the formatted + // string will be empty. + if (content_text->empty()) + return false; + + // Need to return start_pos and end_pos relative to a UTF16 encoding. + *start_pos = UTF8ToUTF16(utf8_input.substr(0, match.start())).length(); + *end_pos = *start_pos + UTF8ToUTF16(match.raw_string()).length(); + + return true; + } + + return false; +} + +} // namespace content diff --git a/content/renderer/android/phone_number_detector.h b/content/renderer/android/phone_number_detector.h new file mode 100644 index 0000000..fd13639 --- /dev/null +++ b/content/renderer/android/phone_number_detector.h @@ -0,0 +1,41 @@ +// 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. + +#ifndef CONTENT_RENDERER_ANDROID_PHONE_NUMBER_DETECTOR_H_ +#define CONTENT_RENDERER_ANDROID_PHONE_NUMBER_DETECTOR_H_ +#pragma once + +#include "content/renderer/android/content_detector.h" + +class PhoneNumberDetectorTest; + +namespace content { + +// Finds a telephone number in the given content text string. +class PhoneNumberDetector : public ContentDetector { + public: + PhoneNumberDetector(); + explicit PhoneNumberDetector(const std::string& region); + virtual ~PhoneNumberDetector(); + + private: + friend class ::PhoneNumberDetectorTest; + + // Implementation of ContentDetector. + virtual bool FindContent(const string16::const_iterator& begin, + const string16::const_iterator& end, + size_t* start_pos, + size_t* end_pos, + std::string* content_text) OVERRIDE; + virtual GURL GetIntentURL(const std::string& content_text) OVERRIDE; + virtual size_t GetMaximumContentLength() OVERRIDE; + + const std::string region_code_; + + DISALLOW_COPY_AND_ASSIGN(PhoneNumberDetector); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_ANDROID_PHONE_NUMBER_DETECTOR_H_ diff --git a/content/renderer/android/phone_number_detector_unittest.cc b/content/renderer/android/phone_number_detector_unittest.cc new file mode 100644 index 0000000..a0a01f1 --- /dev/null +++ b/content/renderer/android/phone_number_detector_unittest.cc @@ -0,0 +1,74 @@ +// 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 "content/renderer/android/phone_number_detector.h" + +#include "base/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" + +using content::PhoneNumberDetector; + +class PhoneNumberDetectorTest : public testing::Test { + public: + static std::string FindNumber(const std::string& content, + const std::string& region) { + string16 content_16 = UTF8ToUTF16(content); + string16 result_16; + size_t start, end; + PhoneNumberDetector detector(region); + std::string content_text; + if (detector.FindContent(content_16.begin(), content_16.end(), + &start, &end, &content_text)) + result_16 = content_16.substr(start, end - start); + return UTF16ToUTF8(result_16); + } + + static std::string FindAndFormatNumber(const std::string& content, + const std::string& region) { + string16 content_16 = UTF8ToUTF16(content); + string16 result_16; + size_t start, end; + PhoneNumberDetector detector(region); + std::string content_text; + detector.FindContent(content_16.begin(), content_16.end(), + &start, &end, &content_text); + return content_text; + } +}; + +TEST_F(PhoneNumberDetectorTest, FindNumber) { + // Tests cases with valid home numbers. + EXPECT_EQ("617-426-3000", FindNumber("hello 617-426-3000 blah", "us")); + EXPECT_EQ("", FindNumber("hello 617-426-3000 blah", "gb")); + EXPECT_EQ("020-7617-4426", FindNumber("<div>020-7617-4426</div>", "gb")); + EXPECT_EQ("", FindNumber("<div>020-7617-4426</div>", "fr")); + EXPECT_EQ("02.38.96.68.88", FindNumber("Tel:02.38.96.68.88", "fr")); + EXPECT_EQ("", FindNumber("Tel:02.38.96.68.88", "gb")); + EXPECT_EQ("1-800-866-2453", + FindNumber("You can call this number:1-800-866-2453 for more " + "information", "us")); + EXPECT_EQ("+1 203-925-4602", FindNumber("+1 203-925-4602", "us")); +} + +TEST_F(PhoneNumberDetectorTest, FindAndFormatNumber) { + EXPECT_EQ("+16174263000", + FindAndFormatNumber("hello 617-426-3000 blah", "us")); + EXPECT_EQ("", FindAndFormatNumber("hello 617-426-3000 blah", "gb")); + EXPECT_EQ("+442076174426", + FindAndFormatNumber("<div>020-7617-4426</div>", "gb")); + EXPECT_EQ("", FindAndFormatNumber("<div>020-7617-4426</div>", "fr")); + EXPECT_EQ("+33238966888", FindAndFormatNumber("Tel:02.38.96.68.88", "fr")); + EXPECT_EQ("+18008662453", + FindAndFormatNumber("You can call this number:1-800-866-2453 for" + "more information", "us")); + EXPECT_EQ("+12039254602", FindAndFormatNumber("+1 203-925-4602", "us")); + + // "+1 (650) 333-6000" using fullwidth UTF-8 characters. + EXPECT_EQ("+16503336000", FindAndFormatNumber( + "\xEF\xBC\x8B\xEF\xBC\x91\xE3\x80\x80\xEF\xBC\x88" + "\xEF\xBC\x96\xEF\xBC\x95\xEF\xBC\x90\xEF\xBC\x89" + "\xE3\x80\x80\xEF\xBC\x93\xEF\xBC\x93\xEF\xBC\x93" + "\xE3\x83\xBC\xEF\xBC\x96\xEF\xBC\x90\xEF\xBC\x90" + "\xEF\xBC\x90", "us")); +} diff --git a/third_party/libphonenumber/libphonenumber.gyp b/third_party/libphonenumber/libphonenumber.gyp index 16f21dc..0741fd9 100644 --- a/third_party/libphonenumber/libphonenumber.gyp +++ b/third_party/libphonenumber/libphonenumber.gyp @@ -58,6 +58,7 @@ 'direct_dependent_settings': { 'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)/protoc_out/third_party/libphonenumber', + 'src', ], }, 'variables': { |