package org.vaadin.tori; import java.io.IOException; import java.io.PrintWriter; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.log4j.Logger; import com.vaadin.server.RequestHandler; import com.vaadin.server.UnsupportedBrowserHandler; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinResponse; import com.vaadin.server.VaadinSession; import com.vaadin.server.WebBrowser; public class UnsupportedDeviceHandler implements RequestHandler { private static final long serialVersionUID = 522576372014293512L; private static final Pattern IOS_REGEX = Pattern .compile("iPhone OS ([0-9]+)_"); private static final Pattern ANDROID_REGEX = Pattern .compile("Android ([0-9]+)\\.([0-9]+)\\.[0-9]+;"); private static final int FIRST_SUPPORTED_VERSION_IOS = 6; private static final int LAST_UNSUPPORTED_ANDROID_MAJOR_VERSION = 2; private static final int LAST_UNSUPPORTED_ANDROID_MINOR_VERSION = 3; @Override public boolean handleRequest(final VaadinSession session, final VaadinRequest request, final VaadinResponse response) throws IOException { @SuppressWarnings("deprecation") final WebBrowser browser = session.getBrowser(); final String browserUserAgent = browser.getBrowserApplication(); if (isUnsupportedDevice(browserUserAgent) && !userHasChosenToDisregardWarning(request)) { displayUnsupportedDevicePage(request, response); return true; // we handled this, done. } // pass to next handler return false; } private static boolean userHasChosenToDisregardWarning( final VaadinRequest request) { final String cookieHeader = request.getHeader("Cookie"); final boolean disregarding = cookieHeader != null && cookieHeader .contains(UnsupportedBrowserHandler.FORCE_LOAD_COOKIE); if (disregarding) { getLogger().debug("User has chosen to disregard any warnings"); } return disregarding; } private static void displayUnsupportedDevicePage( final VaadinRequest request, final VaadinResponse response) throws IOException { getLogger().debug("outputting unsupported page."); final PrintWriter page = response.getWriter(); // @formatter:off page.write("<html><body>" + "<p style='font-size: bigger; font-weight: bold'>I'm sorry, you seem to be using an unsupported device.</p>" + "<p>We've done our best to optimize Tori the best we can for every device, " + "but our tests have shown that your device would have a suboptimal viewing " + "experience. You're free to try it out still, but we really recommend to" + "try again with a more powerful device.</p>" + "<p>However, if you still want to try it out, " + "<a onclick=\"document.cookie='" + UnsupportedBrowserHandler.FORCE_LOAD_COOKIE + "';window.location.reload();return false;\" href=\"#\">just click here</a> " + "and let's hope for the best!.</p>"+ "</body></html>"); // @formatter:on page.close(); } private static boolean isUnsupportedDevice(final String browserUserAgent) { if (browserUserAgent != null && !browserUserAgent.isEmpty()) { return isUnsupportedAppleDevice(browserUserAgent) || isUnsupportedAndroidDevice(browserUserAgent); } else { return false; } } private static boolean isUnsupportedAndroidDevice( final String browserUserAgent) { final Matcher matcher = ANDROID_REGEX.matcher(browserUserAgent); if (matcher.find()) { try { final String androidMajorVersionString = matcher.group(1); final int androidMajorVersion = Integer .parseInt(androidMajorVersionString); final String androidMinorVersionString = matcher.group(2); final int androidMinorVersion = Integer .parseInt(androidMinorVersionString); return androidMajorVersion <= LAST_UNSUPPORTED_ANDROID_MAJOR_VERSION && androidMinorVersion <= LAST_UNSUPPORTED_ANDROID_MINOR_VERSION; } catch (final NumberFormatException e) { getLogger() .info("Device seems to be Android, but the version numbering is weird"); return false; } } else { getLogger().debug("Device isn't running Android"); return false; } } private static boolean isUnsupportedAppleDevice( final String browserUserAgent) { final Matcher matcher = IOS_REGEX.matcher(browserUserAgent); if (matcher.find()) { try { final String iosMajorVersionString = matcher.group(1); final int iosMajorVersion = Integer .parseInt(iosMajorVersionString); final boolean isUnsupported = iosMajorVersion < FIRST_SUPPORTED_VERSION_IOS; getLogger().debug( "Is device unsupported? " + isUnsupported + ", ios version" + iosMajorVersion); return isUnsupported; } catch (final NumberFormatException e) { getLogger().info( "Device seems to be an iOS device, but platform " + "version is weird: " + browserUserAgent); return false; } } else { getLogger().debug("Device isn't running iOS"); return false; } } private static Logger getLogger() { return Logger.getLogger(UnsupportedDeviceHandler.class); } }