Commit ba0affc5 authored by Conley Owens's avatar Conley Owens Committed by Commit Bot

physicalweb: Remove share feature

Just one more step in Removing the Physical Web from Chrome.

BUG=826540

Change-Id: I6d413b2d0b3257a9d38a86ab09eb82ff0f42f127
Reviewed-on: https://chromium-review.googlesource.com/988804Reviewed-by: default avatarMatt Reynolds <mattreynolds@chromium.org>
Reviewed-by: default avatarTommy Nyquist <nyquist@chromium.org>
Reviewed-by: default avatarColin Blundell <blundell@chromium.org>
Reviewed-by: default avatarBernhard Bauer <bauerb@chromium.org>
Commit-Queue: Conley Owens <cco3@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548118}
parent 7e57b2d6
......@@ -755,33 +755,6 @@ by a child template that "extends" this file.
<service android:name="org.chromium.chrome.browser.physicalweb.NearbyMessageIntentService"
android:exported="false" />
<!-- This activity is to expose the PhysicalWeb Share option via the generic Android share action. -->
<activity
android:name="org.chromium.chrome.browser.physicalweb.PhysicalWebShareActivity"
android:icon="@drawable/physical_web_notification_large"
android:label="@string/physical_web_share_activity_title"
android:enabled="false"
android:excludeFromRecents="true"
android:noHistory="true"
android:theme="@android:style/Theme.NoDisplay"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<!-- This activity is to expose the PhysicalWeb Share option via the generic Android share action. -->
<activity
android:name="org.chromium.chrome.browser.physicalweb.PhysicalWebShareEntryActivity"
android:label="@string/physical_web_share_entry_title"
android:excludeFromRecents="true"
android:noHistory="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" >
</activity>
<!-- Activities for Browser Actions -->
<activity android:name="org.chromium.chrome.browser.browseractions.BrowserActionActivity"
android:theme="@style/FullscreenTransparentActivityTheme"
......@@ -799,12 +772,6 @@ by a child template that "extends" this file.
android:exported="false">
</service>
<!-- Service for Broadcasting a Physical Web URL -->
<service
android:name="org.chromium.chrome.browser.physicalweb.PhysicalWebBroadcastService"
android:exported="false">
</service>
<!-- Service for decoding images in a sandboxed process. -->
<service
android:description="@string/decoder_description"
......
// Copyright 2017 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.
package org.chromium.chrome.browser.physicalweb;
import android.annotation.TargetApi;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.IBinder;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder;
import org.chromium.chrome.browser.notifications.NotificationBuilderFactory;
import org.chromium.chrome.browser.notifications.NotificationConstants;
import org.chromium.chrome.browser.notifications.NotificationManagerProxy;
import org.chromium.chrome.browser.notifications.NotificationManagerProxyImpl;
import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
import org.chromium.chrome.browser.util.IntentUtils;
/**
* Broadcasts Physical Web URLs via Bluetooth Low Energy (BLE).
*
* This background service will start when the user activates the Physical Web Sharing item in the
* sharing chooser intent. If the URL received from the triggering Tab is validated
* by the Physical Web Service then it will encode the URL into an Eddystone URL and
* broadcast the URL through BLE.
*
* To notify and provide the user with the ability to terminate broadcasting
* a persistent notification with a cancel button will be created. This cancel button will stop the
* service and will be the only way for the user to stop the service.
*
* If the user terminates Chrome or the OS shuts down this service mid-broadcasting, when the
* service gets restarted it will restart broadcasting as well by gathering the URL from
* shared preferences. This will create a seamless experience to the user by behaving as
* though broadcasting is not connected to the Chrome application.
*
* bluetooth.le.AdvertiseCallback and bluetooth.BluetoothAdapter require API level 21.
* This will only be run on M and above.
**/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class PhysicalWebBroadcastService extends Service {
public static final String DISPLAY_URL_KEY = "display_url";
public static final String PREVIOUS_BROADCAST_URL_KEY = "previousUrl";
private static final String STOP_SERVICE =
"org.chromium.chrome.browser.physicalweb.stop_service";
private static final String TAG = "PhysicalWebSharing";
private static final int BLUETOOTH_ADAPTER_DEFAULT_STATE = -1;
private boolean mStartedByRestart;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
int state = IntentUtils.safeGetIntExtra(
intent, BluetoothAdapter.EXTRA_STATE, BLUETOOTH_ADAPTER_DEFAULT_STATE);
if (state == BluetoothAdapter.STATE_OFF) {
stopSelf();
}
} else if (STOP_SERVICE.equals(action)) {
stopSelf();
} else {
Log.e(TAG, "Unrecognized Broadcast Received");
}
}
};
/**
* Starts the PhysicalWebBroadcastService.
*/
public static void startBroadcastService(String url) {
Context context = ContextUtils.getApplicationContext();
Intent intent = new Intent(context, PhysicalWebBroadcastService.class);
intent.putExtra(DISPLAY_URL_KEY, url);
context.startService(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String displayUrl = fetchDisplayUrl(intent);
// This should never happen.
if (displayUrl == null) {
Log.e(TAG, "Given null display URL");
stopSelf();
return START_STICKY;
}
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(STOP_SERVICE);
registerReceiver(mBroadcastReceiver, filter);
// TODO(iankc): implement broadcasting, Url Shortener.
createBroadcastNotification(displayUrl);
return START_STICKY;
}
@Override
public void onDestroy() {
unregisterReceiver(mBroadcastReceiver);
disableUrlBroadcasting();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private String fetchDisplayUrl(Intent intent) {
mStartedByRestart = intent == null;
if (mStartedByRestart) {
SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
return sharedPrefs.getString(PREVIOUS_BROADCAST_URL_KEY, null);
}
String displayUrl = intent.getStringExtra(DISPLAY_URL_KEY);
ContextUtils.getAppSharedPreferences()
.edit()
.putString(PREVIOUS_BROADCAST_URL_KEY, displayUrl)
.apply();
return displayUrl;
}
/**
* Surfaces a notification to the user that the Physical Web is broadcasting.
* The notification specifies the URL that is being broadcast. It cannot be swiped away,
* but broadcasting can be terminated with the stop button on the notification.
*/
private void createBroadcastNotification(String displayUrl) {
Context context = getApplicationContext();
PendingIntent stopPendingIntent = PendingIntent.getBroadcast(
context, 0, new Intent(STOP_SERVICE), PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManagerProxy notificationManager = new NotificationManagerProxyImpl(
(NotificationManager) getSystemService(NOTIFICATION_SERVICE));
ChromeNotificationBuilder notificationBuilder =
NotificationBuilderFactory
.createChromeNotificationBuilder(
true /* preferCompat */, ChannelDefinitions.CHANNEL_ID_BROWSER)
.setSmallIcon(R.drawable.ic_image_white_24dp)
.setContentTitle(getString(R.string.physical_web_broadcast_notification))
.setContentText(displayUrl)
.setOngoing(true)
.addAction(android.R.drawable.ic_menu_close_clear_cancel,
getString(R.string.physical_web_stop_broadcast), stopPendingIntent);
notificationManager.notify(
NotificationConstants.NOTIFICATION_ID_PHYSICAL_WEB, notificationBuilder.build());
NotificationUmaTracker.getInstance().onNotificationShown(
NotificationUmaTracker.PHYSICAL_WEB, ChannelDefinitions.CHANNEL_ID_BROWSER);
}
/** Turns off URL broadcasting. */
private void disableUrlBroadcasting() {
NotificationManagerProxy notificationManager = new NotificationManagerProxyImpl(
(NotificationManager) getSystemService(NOTIFICATION_SERVICE));
notificationManager.cancel(NotificationConstants.NOTIFICATION_ID_PHYSICAL_WEB);
}
private native byte[] nativeEncodeUrl(String url);
}
// Copyright 2017 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.
package org.chromium.chrome.browser.physicalweb;
import android.content.Intent;
import android.os.Build;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.share.ShareActivity;
/**
* A simple activity that allows Chrome to start the physical web sharing service.
*/
public class PhysicalWebShareActivity extends ShareActivity {
@Override
protected void handleShareAction(ChromeActivity triggeringActivity) {
String url = triggeringActivity.getActivityTab().getUrl();
if (!PhysicalWeb.sharingIsOptedIn()) {
// This shows an interstitial for the user to opt-in for sending URL to Google.
Intent intent = new Intent(this, PhysicalWebShareEntryActivity.class);
intent.putExtra(PhysicalWebShareEntryActivity.SHARING_ENTRY_URL, url);
triggeringActivity.startActivity(intent);
return;
}
PhysicalWebBroadcastService.startBroadcastService(url);
}
/**
* Returns whether we should show this sharing option in the share sheet.
* Pre-conditions for Physical Web Sharing to be enabled:
* Device has hardware BLE advertising capabilities.
* Device had Bluetooth on.
* Device is Marshmallow or above.
* Device has sharing feature enabled.
* @return {@code true} if the feature should be enabled.
*/
public static boolean featureIsAvailable() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;
return PhysicalWeb.hasBleAdvertiseCapability() && PhysicalWeb.bluetoothIsEnabled()
&& PhysicalWeb.sharingIsEnabled();
}
}
// Copyright 2017 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.
package org.chromium.chrome.browser.physicalweb;
import android.app.Activity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import org.chromium.chrome.R;
/**
* Activity used to interact with user before starting Physical Web Sharing.
* TODO(iankc): add Bluetooth checks handling.
*/
public class PhysicalWebShareEntryActivity extends Activity {
public static final String SHARING_ENTRY_URL = "physical_web.entry.url";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if (extras == null) {
finish();
return;
}
final String url = extras.getString(SHARING_ENTRY_URL);
if (url == null) {
finish();
return;
}
new AlertDialog.Builder(this, R.style.AlertDialogTheme)
.setTitle(R.string.physical_web_share_entry_title)
.setMessage(R.string.physical_web_share_entry_message)
.setPositiveButton(R.string.continue_button,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
PhysicalWeb.setSharingOptedIn();
PhysicalWebBroadcastService.startBroadcastService(url);
finish();
}
})
.setNegativeButton(R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setIcon(android.R.drawable.ic_dialog_info)
.setCancelable(false)
.show();
}
}
\ No newline at end of file
......@@ -14,7 +14,6 @@ import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.browser.UrlConstants;
import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
import org.chromium.chrome.browser.physicalweb.PhysicalWebShareActivity;
import org.chromium.chrome.browser.printing.PrintShareActivity;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.util.ChromeFileProvider;
......@@ -73,9 +72,6 @@ public class ShareMenuActionHandler {
if (PrintShareActivity.featureIsAvailable(currentTab)) {
classesToEnable.add(PrintShareActivity.class);
}
if (PhysicalWebShareActivity.featureIsAvailable()) {
classesToEnable.add(PhysicalWebShareActivity.class);
}
if (!classesToEnable.isEmpty()) {
OptionalShareTargetsManager.enableOptionalShareActivities(activity, classesToEnable,
......
......@@ -2992,21 +2992,6 @@ You must have Bluetooth and Location turned on in order to use the Physical Web.
<message name="IDS_PHYSICAL_WEB_LAUNCH_BUTTON" desc="The label for a button that opens a list of nearby URLs">
See what’s nearby
</message>
<message name="IDS_PHYSICAL_WEB_SHARE_ACTIVITY_TITLE" desc="Title of the Physical Web Share activity that will appear in the Android share dialog.">
Physical Web
</message>
<message name="IDS_PHYSICAL_WEB_SHARE_ENTRY_TITLE" desc="Label of the Physical Web Share Entry Activity.">
Physical Web Sharing
</message>
<message name="IDS_PHYSICAL_WEB_SHARE_ENTRY_MESSAGE" desc="This is the message the is shown in the alert box to notify that the Physical Web Share Feature sends a URL to Google Servers.">
This service needs to anonymously send this website address to Google servers for verification.
</message>
<message name="IDS_PHYSICAL_WEB_BROADCAST_NOTIFICATION" desc="The message that will be displayed when a Physical Web URL is broadcasted successfully.">
Website is broadcasting
</message>
<message name="IDS_PHYSICAL_WEB_STOP_BROADCAST" desc="The label for the button within a notification that stops a Physical Web broadcast.">
Stop
</message>
<!-- WebUsb Picker UI strings -->
<message name="IDS_USB_CHOOSER_DIALOG_PROMPT" desc="The text that is used to introduce the USB chooser dialog to the user.">
......
......@@ -938,10 +938,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/physicalweb/NearbySubscription.java",
"java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java",
"java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBleClient.java",
"java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBroadcastService.java",
"java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java",
"java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebShareActivity.java",
"java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebShareEntryActivity.java",
"java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java",
"java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java",
"java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java",
......
......@@ -1681,7 +1681,6 @@ jumbo_split_static_library("browser") {
"//components/password_manager/core/common",
"//components/password_manager/sync/browser",
"//components/payments/core",
"//components/physical_web/eddystone",
"//components/policy:generated",
"//components/policy/content/",
"//components/policy/core/browser",
......@@ -2101,8 +2100,6 @@ jumbo_split_static_library("browser") {
"android/password_ui_view_android.h",
"android/payments/service_worker_payment_app_bridge.cc",
"android/photo_picker_sandbox_bridge.cc",
"android/physical_web/eddystone_encoder_bridge.cc",
"android/physical_web/eddystone_encoder_bridge.h",
"android/physical_web/physical_web_data_source_android.cc",
"android/physical_web/physical_web_data_source_android.h",
"android/policy/policy_auditor.cc",
......@@ -4382,7 +4379,6 @@ if (is_android) {
"../android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogDelegate.java",
"../android/java/src/org/chromium/chrome/browser/permissions/PermissionUmaUtil.java",
"../android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java",
"../android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBroadcastService.java",
"../android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java",
"../android/java/src/org/chromium/chrome/browser/policy/PolicyAuditor.java",
"../android/java/src/org/chromium/chrome/browser/preferences/LocationSettings.java",
......
// Copyright 2017 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/physical_web/eddystone_encoder_bridge.h"
#include <vector>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "components/physical_web/eddystone/eddystone_encoder.h"
#include "jni/PhysicalWebBroadcastService_jni.h"
static base::android::ScopedJavaLocalRef<jbyteArray>
JNI_PhysicalWebBroadcastService_EncodeUrl(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
const base::android::JavaParamRef<jstring>& j_url) {
/*
* Exception preparation for illegal arguments.
*/
jclass exception_class = env->FindClass("java/lang/IllegalArgumentException");
/*
* Input Sanitization
*/
if (j_url.is_null()) {
env->ThrowNew(exception_class, "URL is null.");
return NULL;
}
std::string c_url;
base::android::ConvertJavaStringToUTF8(env, j_url, &c_url);
std::vector<uint8_t> encoded_url;
int encode_message = physical_web::EncodeUrl(c_url, &encoded_url);
if (encode_message < 0) {
std::string err_message = "Error in Eddystone Encoding. Error Code: ";
err_message += std::to_string(encode_message);
env->ThrowNew(exception_class, err_message.c_str());
return NULL;
}
return base::android::ToJavaByteArray(env, encoded_url.data(),
encoded_url.size());
}
// Functions For Testing
base::android::ScopedJavaLocalRef<jbyteArray> EncodeUrlForTesting(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
const base::android::JavaParamRef<jstring>& j_url) {
return JNI_PhysicalWebBroadcastService_EncodeUrl(env, jcaller, j_url);
}
// Copyright 2017 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/physical_web/eddystone_encoder_bridge.h"
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using base::android::ToJavaByteArray;
class EddystoneEncoderBridgeTest : public testing::Test {
public:
EddystoneEncoderBridgeTest() {}
~EddystoneEncoderBridgeTest() override {}
void SetUp() override { env_ = base::android::AttachCurrentThread(); }
void TearDown() override {}
JNIEnv* Env();
jstring JavaString(const std::string& value);
bool ScopedJavaLocalRefJByteArrayEquals(JNIEnv* env,
ScopedJavaLocalRef<jbyteArray> a,
ScopedJavaLocalRef<jbyteArray> b);
private:
JNIEnv* env_;
};
JNIEnv* EddystoneEncoderBridgeTest::Env() {
return env_;
}
jstring EddystoneEncoderBridgeTest::JavaString(const std::string& value) {
return base::android::ConvertUTF8ToJavaString(Env(), value).Release();
}
bool EddystoneEncoderBridgeTest::ScopedJavaLocalRefJByteArrayEquals(
JNIEnv* env,
ScopedJavaLocalRef<jbyteArray> a,
ScopedJavaLocalRef<jbyteArray> b) {
jbyteArray a_byte_array = a.obj();
jbyteArray b_byte_array = b.obj();
int a_len = env->GetArrayLength(a_byte_array);
if (a_len != env->GetArrayLength(b_byte_array)) {
return false;
}
jbyte* a_elems = env->GetByteArrayElements(a_byte_array, NULL);
jbyte* b_elems = env->GetByteArrayElements(b_byte_array, NULL);
bool cmp = memcmp(a_elems, b_elems, a_len) == 0;
env->ReleaseByteArrayElements(a_byte_array, a_elems, JNI_ABORT);
env->ReleaseByteArrayElements(b_byte_array, b_elems, JNI_ABORT);
return cmp;
}
TEST_F(EddystoneEncoderBridgeTest, TestNullUrl) {
ScopedJavaLocalRef<jbyteArray> actual =
EncodeUrlForTesting(Env(), JavaParamRef<jobject>(nullptr),
JavaParamRef<jstring>(Env(), nullptr));
EXPECT_TRUE(Env()->ExceptionCheck());
}
TEST_F(EddystoneEncoderBridgeTest, TestInvalidUrl) {
std::string url = "Wrong!";
ScopedJavaLocalRef<jbyteArray> actual =
EncodeUrlForTesting(Env(), JavaParamRef<jobject>(nullptr),
JavaParamRef<jstring>(Env(), JavaString(url)));
EXPECT_TRUE(Env()->ExceptionCheck());
}
TEST_F(EddystoneEncoderBridgeTest, TestValidUrl) {
std::string url = "https://www.example.com/";
uint8_t expected_array[] = {0x01, // "https://www."
0x65, 0x78, 0x61, 0x6d,
0x70, 0x6c, 0x65, // "example"
0x00};
size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
ScopedJavaLocalRef<jbyteArray> expected =
ToJavaByteArray(Env(), &expected_array[0], expected_array_length);
ScopedJavaLocalRef<jbyteArray> actual =
EncodeUrlForTesting(Env(), JavaParamRef<jobject>(nullptr),
JavaParamRef<jstring>(Env(), JavaString(url)));
EXPECT_TRUE(ScopedJavaLocalRefJByteArrayEquals(Env(), expected, actual));
EXPECT_FALSE(Env()->ExceptionCheck());
}
......@@ -2241,7 +2241,6 @@ test("unit_tests") {
"../browser/android/oom_intervention/near_oom_monitor_unittest.cc",
"../browser/android/oom_intervention/oom_intervention_decider_unittest.cc",
"../browser/android/password_ui_view_android_unittest.cc",
"../browser/android/physical_web/eddystone_encoder_bridge_unittest.cc",
"../browser/android/physical_web/physical_web_data_source_android_unittest.cc",
"../browser/android/preferences/pref_service_bridge_unittest.cc",
"../browser/android/preferences/prefs_unittest.cc",
......
......@@ -122,7 +122,6 @@ test("components_unittests") {
"//components/password_manager/sync/browser:unit_tests",
"//components/payments/core:unit_tests",
"//components/physical_web/data_source:unit_tests",
"//components/physical_web/eddystone:unit_tests",
"//components/prefs:unit_tests",
"//components/previews/core:unit_tests",
"//components/proxy_config:unit_tests",
......
# Copyright 2017 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.
source_set("eddystone") {
sources = [
"eddystone_encoder.cc",
"eddystone_encoder.h",
]
deps = [
"//url",
]
}
source_set("unit_tests") {
testonly = true
sources = [
"eddystone_encoder_unittest.cc",
]
deps = [
":eddystone",
"//testing/gtest",
"//url",
]
}
// Copyright 2017 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 "components/physical_web/eddystone/eddystone_encoder.h"
#include <string>
#include <vector>
#include "url/gurl.h"
namespace {
const char* kPrefixes[] = {"http://www.", "https://www.", "http://",
"https://"};
const size_t kNumPrefixes = sizeof(kPrefixes) / sizeof(char*);
const char* kSuffixes[] = {".com/", ".org/", ".edu/", ".net/", ".info/",
".biz/", ".gov/", ".com", ".org", ".edu",
".net", ".info", ".biz", ".gov"};
const size_t kNumSuffixes = sizeof(kSuffixes) / sizeof(char*);
}
namespace physical_web {
size_t EncodeUrl(const std::string& url, std::vector<uint8_t>* encoded_url) {
/*
* Sanitize input.
*/
if (encoded_url == nullptr)
return kNullEncodedUrl;
if (url.empty())
return kEmptyUrl;
GURL gurl(url);
if (!gurl.is_valid())
return kInvalidUrl;
if (gurl.HostIsIPAddress() || !gurl.SchemeIsHTTPOrHTTPS())
return kInvalidFormat;
/*
* Necessary Declarations.
*/
const char* raw_url_position = url.c_str();
size_t prefix_lengths[kNumPrefixes];
size_t suffix_lengths[kNumSuffixes];
for (size_t i = 0; i < kNumPrefixes; i++) {
prefix_lengths[i] = strlen(kPrefixes[i]);
}
for (size_t i = 0; i < kNumSuffixes; i++) {
suffix_lengths[i] = strlen(kSuffixes[i]);
}
/*
* Handle prefix.
*/
for (size_t i = 0; i < kNumPrefixes; i++) {
size_t prefix_len = prefix_lengths[i];
if (strncmp(raw_url_position, kPrefixes[i], prefix_len) == 0) {
encoded_url->push_back(static_cast<uint8_t>(i));
raw_url_position += prefix_len;
break;
}
}
/*
* Handle suffixes.
*/
while (*raw_url_position) {
/* check for suffix match */
size_t i;
for (i = 0; i < kNumSuffixes; i++) {
size_t suffix_len = suffix_lengths[i];
if (strncmp(raw_url_position, kSuffixes[i], suffix_len) == 0) {
encoded_url->push_back(static_cast<uint8_t>(i));
raw_url_position += suffix_len;
break; /* from the for loop for checking against suffixes */
}
}
/* This is the default case where we've got an ordinary character which
* doesn't match a suffix. */
if (i == kNumSuffixes) {
encoded_url->push_back(*raw_url_position);
raw_url_position++;
}
}
return encoded_url->size();
}
}
// Copyright 2017 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 COMPONENTS_PHYSICAL_WEB_EDDYSTONE_EDDYSTONE_ENCODER_H_
#define COMPONENTS_PHYSICAL_WEB_EDDYSTONE_EDDYSTONE_ENCODER_H_
#include <string>
#include <vector>
namespace physical_web {
const size_t kEmptyUrl = static_cast<size_t>(-1);
const size_t kInvalidUrl = static_cast<size_t>(-2);
const size_t kInvalidFormat = static_cast<size_t>(-3);
const size_t kNullEncodedUrl = static_cast<size_t>(-4);
/*
* EncodeUrl takes a URL in the form of a std::string and
* a pointer to a uint8_t vector to populate with the eddystone
* encoding of the URL.
* Returns:
* kEmptyUrl If the URL parameter is empty.
* kInvalidUrl If the URL parameter is not a valid URL.
* kInvalidFormat If the URL parameter is not a standard HTTPS/HTTP URL.
* kNullEncodedUrl If the encoded_url vector is NULL.
* Length of encoded URL.
* Eddystone spec can be found here:
* https://github.com/google/eddystone/blob/master/protocol-specification.md
*/
size_t EncodeUrl(const std::string& url, std::vector<uint8_t>* encoded_url);
}
#endif // COMPONENTS_PHYSICAL_WEB_EDDYSTONE_EDDYSTONE_ENCODER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment