/**
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.waveprotocol.wave.client.common.util;
import com.google.gwt.core.client.GWT;
import org.waveprotocol.wave.model.util.Box;
import com.google.common.annotations.VisibleForTesting;
/**
* Class to contain run-time checks of a user-agent's capabilities.
*
*
*/
@VisibleForTesting
public class UserAgentRuntimeProperties {
private static final UserAgentRuntimeProperties INSTANCE = createInstance();
private static UserAgentRuntimeProperties createInstance() {
return GWT.isScript() ? new UserAgentRuntimeProperties(getNativeUserAgent())
: new UserAgentRuntimeProperties("");
}
@VisibleForTesting
public static UserAgentRuntimeProperties get() {
return INSTANCE;
}
private final String userAgent;
private final int version;
private final boolean isMac;
private final boolean isWin;
private final boolean isLinux;
private final boolean isIe7;
private final boolean isIe8;
private final boolean isChrome;
@VisibleForTesting
public UserAgentRuntimeProperties(String userAgent) {
this.userAgent = userAgent;
this.version = calculateVersion(userAgent);
this.isMac = calculateIsMac(userAgent);
this.isWin = calculateIsWin(userAgent);
this.isLinux = calculateIsLinux(userAgent);
this.isIe7 = calculateIe7(userAgent);
this.isIe8 = calculateIe8(userAgent);
this.isChrome = calculateIsChrome(userAgent);
}
@VisibleForTesting
public String getUserAgent() {
return userAgent;
}
@VisibleForTesting
public boolean isMac() {
return isMac;
}
@VisibleForTesting
public boolean isWin() {
return isWin;
}
@VisibleForTesting
public boolean isLinux() {
return isLinux;
}
@VisibleForTesting
public boolean isIe7() {
return isIe7;
}
@VisibleForTesting
public boolean isIe8(){
return isIe8;
}
@VisibleForTesting
public boolean isChrome() {
return isChrome;
}
/**
* @return whether the current user agent version is at least the one given by
* the method parameters.
*/
@VisibleForTesting
public boolean isAtLeastVersion(int major, int minor) {
return version >= (major * 1000 + minor);
}
/**
* Do not use this for program logic - for debugging only. For program logic,
* instead use {@link #isAtLeastVersion(int, int)}
*/
@VisibleForTesting
public int getMajorVer() {
return version / 1000;
}
/**
* Do not use this for program logic - for debugging only. For program logic,
* instead use {@link #isAtLeastVersion(int, int)}
*/
@VisibleForTesting
public int getMinorVer() {
return version % 1000;
}
private static native String getNativeUserAgent() /*-{
return navigator.userAgent;
}-*/;
private static boolean calculateIe7(String userAgent) {
return userAgent.indexOf(" MSIE 7.") != -1;
}
private static boolean calculateIe8(String userAgent) {
return userAgent.indexOf(" MSIE 8.") != -1;
}
private static boolean calculateIsMac(String userAgent) {
return userAgent.indexOf("Mac") != -1;
}
private static boolean calculateIsWin(String userAgent) {
return userAgent.indexOf("Windows") != -1;
}
private static boolean calculateIsLinux(String userAgent) {
return userAgent.indexOf("Linux") != -1;
}
private static boolean calculateIsChrome(String userAgent) {
return userAgent.indexOf("Chrome") != -1;
}
private static int calculateVersion(String userAgent) {
if (userAgent == null || userAgent.isEmpty()) {
return -1;
}
// TODO(user): Make this work after regex deps are fixed and don't break static rendering
//
// String regexps[] = {"firefox.([0-9]+).([0-9]+)",
// "webkit.([0-9]+).([0-9]+)",
// "msie.([0-9]+).([0-9]+)",
// "minefield.([0-9]+).([0-9]+)"};
// TODO(user): Don't use "firefox" and "minefield", check Gecko rv.
String names[] = {"firefox", "webkit", "msie", "minefield"};
for (String name : names) {
int v = calculateVersion(name, userAgent);
if (v >= 0) {
return v;
}
}
return -1;
}
// /**
// * Matches a browser-specific regular expression against the user agent to
// * obtain a version number.
// *
// * @param regexp The browser-specific regular expression to use
// * @param userAgent The user agent string to check
// * @return A version number or -1 if unknown
// */
/**
* Matches a browser-specific name against the user agent to obtain a version
* number.
*
* @param name The browser-specific name to use
* @param userAgent The user agent string to check
* @return A version number or -1 if unknown
*/
private static int calculateVersion(String name, String userAgent) {
int index = userAgent.toLowerCase().indexOf(name);
if (index == -1) {
return -1;
}
Box<Integer> output = Box.create();
index += name.length() + 1;
if ((index = consumeDigit(index, userAgent, output)) == -1) {
return -1;
}
int major = output.boxed;
index++;
if ((index = consumeDigit(index, userAgent, output)) == -1) {
return -1;
}
int minor = output.boxed;
return major * 1000 + minor;
// TODO(user): Make this work after regex deps are fixed and don't break static rendering
//
// RegExp pattern = RegExp.compile(regexp);
// MatchResult result = pattern.exec(userAgent.toLowerCase());
// if (result != null && result.getGroupCount() == 3) {
// int major = Integer.parseInt(result.getGroup(1));
// int minor = Integer.parseInt(result.getGroup(2));
// return major * 1000 + minor;
// }
// return -1;
}
private static int consumeDigit(int index, String str, Box<Integer> output) {
StringBuilder nb = new StringBuilder();
char c;
while (index < str.length() && Character.isDigit( (c = str.charAt(index)) )) {
nb.append(c);
index++;
}
if (nb.length() == 0) {
return -1;
}
try {
output.boxed = Integer.parseInt(nb.toString());
return index;
} catch (NumberFormatException e) {
return -1;
}
}
}