// Copyright 2016 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.Intent;
import android.content.res.Resources;
import android.os.Build;
import android.text.Html;
import android.text.util.Linkify;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ContextUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.BasicNativePage;
import org.chromium.chrome.browser.UrlConstants;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.components.location.LocationUtils;
import java.util.HashSet;
import java.util.Set;
/**
* Provides diagnostic information about the Physical Web feature.
*/
public class PhysicalWebDiagnosticsPage extends BasicNativePage {
private String mSuccessColor;
private String mFailureColor;
private String mIndeterminateColor;
private View mPageView;
private Button mLaunchButton;
private TextView mDiagnosticsText;
/**
* Create a new instance of the Physical Web diagnostics page.
* @param activity The activity to get context and manage fragments.
* @param tab The tab to load urls.
*/
public PhysicalWebDiagnosticsPage(Activity activity, Tab tab) {
super(activity, tab);
}
@Override
protected void initialize(final Activity activity, Tab tab) {
Resources resources = activity.getResources();
mSuccessColor = colorToHexValue(ApiCompatibilityUtils.getColor(resources,
R.color.physical_web_diags_success_color));
mFailureColor = colorToHexValue(ApiCompatibilityUtils.getColor(resources,
R.color.physical_web_diags_failure_color));
mIndeterminateColor = colorToHexValue(ApiCompatibilityUtils.getColor(resources,
R.color.physical_web_diags_indeterminate_color));
LayoutInflater inflater = LayoutInflater.from(activity);
mPageView = inflater.inflate(R.layout.physical_web_diagnostics, null);
mLaunchButton = (Button) mPageView.findViewById(R.id.physical_web_launch);
mLaunchButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
activity.startActivity(createListUrlsIntent());
}
});
mDiagnosticsText = (TextView) mPageView.findViewById(R.id.physical_web_diagnostics_text);
mDiagnosticsText.setAutoLinkMask(Linkify.WEB_URLS);
mDiagnosticsText.setText(Html.fromHtml(createDiagnosticsReportHtml()));
}
@Override
public String getTitle() {
return "Physical Web Diagnostics";
}
@Override
public String getHost() {
return UrlConstants.PHYSICAL_WEB_HOST;
}
@Override
public View getView() {
return mPageView;
}
private void appendResult(StringBuilder sb, boolean success, String successMessage,
String failureMessage) {
int successValue = (success ? Utils.RESULT_SUCCESS : Utils.RESULT_FAILURE);
appendResult(sb, successValue, successMessage, failureMessage, null);
}
private void appendResult(StringBuilder sb, int successValue, String successMessage,
String failureMessage, String indeterminateMessage) {
String color;
String message;
switch (successValue) {
case Utils.RESULT_SUCCESS:
color = mSuccessColor;
message = successMessage;
break;
case Utils.RESULT_FAILURE:
color = mFailureColor;
message = failureMessage;
break;
case Utils.RESULT_INDETERMINATE:
color = mIndeterminateColor;
message = indeterminateMessage;
break;
default:
return;
}
sb.append(String.format("<font color=\"%s\">%s</font><br/>", color, message));
}
private void appendPrerequisitesReport(StringBuilder sb) {
boolean isSdkVersionCorrect = isSdkVersionCorrect();
boolean isDataConnectionActive = Utils.isDataConnectionActive();
int bluetoothStatus = Utils.getBluetoothEnabledStatus();
LocationUtils locationUtils = LocationUtils.getInstance();
boolean isLocationServicesEnabled = locationUtils.isSystemLocationSettingEnabled();
boolean isLocationPermissionGranted = locationUtils.hasAndroidLocationPermission();
boolean isPreferenceEnabled = PhysicalWeb.isPhysicalWebPreferenceEnabled();
boolean isOnboarding = PhysicalWeb.isOnboarding();
int prerequisitesResult = Utils.RESULT_SUCCESS;
if (!isSdkVersionCorrect
|| !isDataConnectionActive
|| bluetoothStatus == Utils.RESULT_FAILURE
|| !isLocationServicesEnabled
|| !isLocationPermissionGranted
|| !isPreferenceEnabled) {
prerequisitesResult = Utils.RESULT_FAILURE;
} else if (bluetoothStatus == Utils.RESULT_INDETERMINATE) {
prerequisitesResult = Utils.RESULT_INDETERMINATE;
}
sb.append("<h2>Status</h2>");
sb.append("Physical Web is ");
appendResult(sb, prerequisitesResult != Utils.RESULT_FAILURE, "ON", "OFF");
sb.append("<h2>Prerequisites</h2>");
sb.append("Android SDK version: ");
appendResult(sb, isSdkVersionCorrect, "Compatible", "Incompatible");
sb.append("Data connection: ");
appendResult(sb, isDataConnectionActive, "Connected", "Not connected");
sb.append("Location services: ");
appendResult(sb, isLocationServicesEnabled, "Enabled", "Disabled");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
sb.append("Location app permission: ");
appendResult(sb, isLocationPermissionGranted, "Granted", "Not granted");
}
sb.append("Physical Web privacy settings: ");
String preferenceDisabledMessage = (isOnboarding ? "Default (off)" : "Off");
appendResult(sb, isPreferenceEnabled, "On", preferenceDisabledMessage);
sb.append("Bluetooth: ");
appendResult(sb, bluetoothStatus, "Enabled", "Disabled", "Unknown");
// Append instructions for how to verify Bluetooth is enabled when we are unable to check
// programmatically.
if (bluetoothStatus == Utils.RESULT_INDETERMINATE) {
sb.append("<br/>To verify Bluetooth is enabled on this device, check that the "
+ "Bluetooth icon is shown in the status bar.");
}
}
private void appendUrlManagerReport(StringBuilder sb) {
UrlManager urlManager = UrlManager.getInstance();
Set<String> nearbyUrls = new HashSet<>(urlManager.getNearbyUrls());
Set<String> resolvedUrls = new HashSet<>(urlManager.getResolvedUrls());
Set<String> union = new HashSet<>(nearbyUrls);
union.addAll(resolvedUrls);
sb.append("<h2>Nearby web pages</h2>");
if (union.isEmpty()) {
sb.append("No nearby web pages found<br/>");
} else {
for (String url : union) {
boolean isNearby = nearbyUrls.contains(url);
boolean isResolved = resolvedUrls.contains(url);
sb.append(url);
if (!isNearby) {
sb.append(" : LOST");
} else if (!isResolved) {
sb.append(" : UNRESOLVED");
}
sb.append("<br/>");
}
}
}
private String createDiagnosticsReportHtml() {
StringBuilder sb = new StringBuilder();
appendPrerequisitesReport(sb);
sb.append("<br/>");
appendUrlManagerReport(sb);
return sb.toString();
}
private boolean isSdkVersionCorrect() {
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT);
}
private static Intent createListUrlsIntent() {
return new Intent(ContextUtils.getApplicationContext(), ListUrlsActivity.class)
.putExtra(ListUrlsActivity.REFERER_KEY, ListUrlsActivity.DIAGNOSTICS_REFERER);
}
private static String colorToHexValue(int color) {
return "#" + Integer.toHexString(color & 0x00ffffff);
}
}