com.vaadin.server.WebBrowser.java Source code

Java tutorial

Introduction

Here is the source code for com.vaadin.server.WebBrowser.java

Source

/*
 * Copyright 2000-2018 Vaadin Ltd.
 *
 * 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 com.vaadin.server;

import java.io.Serializable;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import com.vaadin.shared.VBrowserDetails;

/**
 * Class that provides information about the web browser the user is using.
 * Provides information such as browser name and version, screen resolution and
 * IP address.
 *
 * @author Vaadin Ltd.
 */
public class WebBrowser implements Serializable {

    private int screenHeight = -1;
    private int screenWidth = -1;
    private String browserApplication = null;
    private Locale locale;
    private String address;
    private boolean secureConnection;
    private int timezoneOffset = 0;
    private int rawTimezoneOffset = 0;
    private int dstSavings;
    private boolean dstInEffect;
    private String timeZoneId;
    private boolean touchDevice;

    private VBrowserDetails browserDetails;
    private long clientServerTimeDelta;

    /**
     * Gets the height of the screen in pixels. This is the full screen
     * resolution and not the height available for the application.
     *
     * @return the height of the screen in pixels.
     */
    public int getScreenHeight() {
        return screenHeight;
    }

    /**
     * Gets the width of the screen in pixels. This is the full screen
     * resolution and not the width available for the application.
     *
     * @return the width of the screen in pixels.
     */
    public int getScreenWidth() {
        return screenWidth;
    }

    /**
     * Get the browser user-agent string.
     *
     * @return The raw browser userAgent string
     */
    public String getBrowserApplication() {
        return browserApplication;
    }

    /**
     * Gets the IP-address of the web browser. If the application is running
     * inside a portlet, this method will return null.
     *
     * @return IP-address in 1.12.123.123 -format
     */
    public String getAddress() {
        return address;
    }

    /** Get the default locate of the browser. */
    public Locale getLocale() {
        return locale;
    }

    /** Is the connection made using HTTPS? */
    public boolean isSecureConnection() {
        return secureConnection;
    }

    /**
     * Tests whether the user is using Firefox.
     *
     * @return true if the user is using Firefox, false if the user is not using
     *         Firefox or if no information on the browser is present
     */
    public boolean isFirefox() {
        if (browserDetails == null) {
            return false;
        }

        return browserDetails.isFirefox();
    }

    /**
     * Tests whether the user is using Internet Explorer.
     *
     * @return true if the user is using Internet Explorer, false if the user is
     *         not using Internet Explorer or if no information on the browser
     *         is present
     */
    public boolean isIE() {
        if (browserDetails == null) {
            return false;
        }

        return browserDetails.isIE();
    }

    /**
     * Tests whether the user is using Edge.
     *
     * @since 7.5.3
     * @return true if the user is using Edge, false if the user is not using
     *         Edge or if no information on the browser is present
     */
    public boolean isEdge() {
        if (browserDetails == null) {
            return false;
        }

        return browserDetails.isEdge();
    }

    /**
     * Tests whether the user is using Safari. Note that Chrome on iOS is not
     * detected as Safari but as Chrome although the underlying browser engine
     * is the same.
     *
     * @return true if the user is using Safari, false if the user is not using
     *         Safari or if no information on the browser is present
     */
    public boolean isSafari() {
        if (browserDetails == null) {
            return false;
        }

        return browserDetails.isSafari();
    }

    /**
     * Tests whether the user is using Opera.
     *
     * @return true if the user is using Opera, false if the user is not using
     *         Opera or if no information on the browser is present
     */
    public boolean isOpera() {
        if (browserDetails == null) {
            return false;
        }

        return browserDetails.isOpera();
    }

    /**
     * Tests whether the user is using Chrome.
     *
     * @return true if the user is using Chrome, false if the user is not using
     *         Chrome or if no information on the browser is present
     */
    public boolean isChrome() {
        if (browserDetails == null) {
            return false;
        }

        return browserDetails.isChrome();
    }

    /**
     * Tests whether the user is using Chrome Frame.
     *
     * @return true if the user is using Chrome Frame, false if the user is not
     *         using Chrome or if no information on the browser is present
     */
    public boolean isChromeFrame() {
        if (browserDetails == null) {
            return false;
        }

        return browserDetails.isChromeFrame();
    }

    /**
     * Tests whether the user's browser is Chrome Frame capable.
     *
     * @return true if the user can use Chrome Frame, false if the user can not
     *         or if no information on the browser is present
     */
    public boolean isChromeFrameCapable() {
        if (browserDetails == null) {
            return false;
        }

        return browserDetails.isChromeFrameCapable();
    }

    /**
     * Gets the major version of the browser the user is using.
     *
     * <p>
     * Note that Internet Explorer in IE7 compatibility mode might return 8 in
     * some cases even though it should return 7.
     * </p>
     *
     * @return The major version of the browser or -1 if not known.
     */
    public int getBrowserMajorVersion() {
        if (browserDetails == null) {
            return -1;
        }

        return browserDetails.getBrowserMajorVersion();
    }

    /**
     * Gets the minor version of the browser the user is using.
     *
     * @see #getBrowserMajorVersion()
     *
     * @return The minor version of the browser or -1 if not known.
     */
    public int getBrowserMinorVersion() {
        if (browserDetails == null) {
            return -1;
        }

        return browserDetails.getBrowserMinorVersion();
    }

    /**
     * Gets the complete browser version as string. The version is given by the
     * browser through the user agent string and usually consists of
     * dot-separated numbers. Note that the string may contain characters other
     * than dots and digits.
     *
     * @return the complete browser version or {@code null} if unknown
     * @since 8.4
     */
    public String getBrowserVersion() {
        return browserDetails != null ? browserDetails.getBrowserVersion() : null;
    }

    /**
     * Tests whether the user is using Linux.
     *
     * @return true if the user is using Linux, false if the user is not using
     *         Linux or if no information on the browser is present
     */
    public boolean isLinux() {
        return browserDetails.isLinux();
    }

    /**
     * Tests whether the user is using Mac OS X.
     *
     * @return true if the user is using Mac OS X, false if the user is not
     *         using Mac OS X or if no information on the browser is present
     */
    public boolean isMacOSX() {
        return browserDetails.isMacOSX();
    }

    /**
     * Tests whether the user is using Windows.
     *
     * @return true if the user is using Windows, false if the user is not using
     *         Windows or if no information on the browser is present
     */
    public boolean isWindows() {
        return browserDetails.isWindows();
    }

    /**
     * Tests whether the user is using Windows Phone.
     *
     * @return true if the user is using Windows Phone, false if the user is not
     *         using Windows Phone or if no information on the browser is
     *         present
     * @since 7.3.2
     */
    public boolean isWindowsPhone() {
        return browserDetails.isWindowsPhone();
    }

    /**
     * Tests if the browser is run on Android.
     *
     * @return true if run on Android false if the user is not using Android or
     *         if no information on the browser is present
     */
    public boolean isAndroid() {
        return browserDetails.isAndroid();
    }

    /**
     * Tests if the browser is run in iOS.
     *
     * @return true if run in iOS false if the user is not using iOS or if no
     *         information on the browser is present
     */
    public boolean isIOS() {
        return browserDetails.isIOS();
    }

    /**
     * Tests if the browser is run on IPhone.
     *
     * @return true if run on IPhone false if the user is not using IPhone or if
     *         no information on the browser is present
     * @since 7.3.3
     */
    public boolean isIPhone() {
        return browserDetails.isIPhone();
    }

    /**
     * Tests if the browser is run on IPad.
     *
     * @return true if run on IPad false if the user is not using IPad or if no
     *         information on the browser is present
     * @since 7.3.3
     */
    public boolean isIPad() {
        return browserDetails.isIPad();
    }

    /**
     * Tests if the browser is run on ChromeOS (e.g. a Chromebook).
     *
     * @return true if run on ChromeOS false if the user is not using ChromeOS
     *         or if no information on the browser is present
     * @since 8.1.1
     */
    public boolean isChromeOS() {
        return browserDetails.isChromeOS();
    }

    /**
     * Returns the browser-reported TimeZone offset in milliseconds from GMT.
     * This includes possible daylight saving adjustments, to figure out which
     * TimeZone the user actually might be in, see
     * {@link #getRawTimezoneOffset()}.
     *
     * @see WebBrowser#getRawTimezoneOffset()
     * @return timezone offset in milliseconds, 0 if not available
     */
    public int getTimezoneOffset() {
        return timezoneOffset;
    }

    /**
     * Returns the TimeZone Id (like "Europe/Helsinki") provided by the browser
     * (if the browser supports this feature).
     *
     * @return the TimeZone Id if provided by the browser, null otherwise.
     * @see <a href=
     *      "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat/resolvedOptions">Intl.DateTimeFormat.prototype.resolvedOptions()</a>
     * @since 8.2
     */
    public String getTimeZoneId() {
        return timeZoneId;
    }

    /**
     * Returns the browser-reported TimeZone offset in milliseconds from GMT
     * ignoring possible daylight saving adjustments that may be in effect in
     * the browser.
     * <p>
     * You can use this to figure out which TimeZones the user could actually be
     * in by calling {@link TimeZone#getAvailableIDs(int)}.
     * </p>
     * <p>
     * If {@link #getRawTimezoneOffset()} and {@link #getTimezoneOffset()}
     * returns the same value, the browser is either in a zone that does not
     * currently have daylight saving time, or in a zone that never has daylight
     * saving time.
     * </p>
     *
     * @return timezone offset in milliseconds excluding DST, 0 if not available
     */
    public int getRawTimezoneOffset() {
        return rawTimezoneOffset;
    }

    /**
     * Returns the offset in milliseconds between the browser's GMT TimeZone and
     * DST.
     *
     * @return the number of milliseconds that the TimeZone shifts when DST is
     *         in effect
     */
    public int getDSTSavings() {
        return dstSavings;
    }

    /**
     * Returns whether daylight saving time (DST) is currently in effect in the
     * region of the browser or not.
     *
     * @return true if the browser resides at a location that currently is in
     *         DST
     */
    public boolean isDSTInEffect() {
        return dstInEffect;
    }

    /**
     * Returns the current date and time of the browser. This will not be
     * entirely accurate due to varying network latencies, but should provide a
     * close-enough value for most cases. Also note that the returned Date
     * object uses servers default time zone, not the clients.
     * <p>
     * To get the actual date and time shown in the end users computer, you can
     * do something like:
     *
     * <pre>
     * WebBrowser browser = ...;
     * SimpleTimeZone timeZone = new SimpleTimeZone(browser.getTimezoneOffset(), "Fake client time zone");
     * DateFormat format = DateFormat.getDateTimeInstance();
     * format.setTimeZone(timeZone);
     * myLabel.setValue(format.format(browser.getCurrentDate()));
     * </pre>
     *
     * @return the current date and time of the browser.
     * @see #isDSTInEffect()
     * @see #getDSTSavings()
     * @see #getTimezoneOffset()
     */
    public Date getCurrentDate() {
        return new Date(new Date().getTime() + clientServerTimeDelta);
    }

    /**
     * @return true if the browser is detected to support touch events
     */
    public boolean isTouchDevice() {
        return touchDevice;
    }

    /**
     * For internal use by VaadinServlet/VaadinPortlet only. Updates all
     * properties in the class according to the given information.
     *
     * @param sw
     *            Screen width
     * @param sh
     *            Screen height
     * @param tzo
     *            TimeZone offset in minutes from GMT
     * @param rtzo
     *            raw TimeZone offset in minutes from GMT (w/o DST adjustment)
     * @param dstSavings
     *            the difference between the raw TimeZone and DST in minutes
     * @param dstInEffect
     *            is DST currently active in the region or not?
     * @param curDate
     *            the current date in milliseconds since the epoch
     * @param touchDevice
     */
    void updateClientSideDetails(String sw, String sh, String tzo, String rtzo, String dstSavings,
            String dstInEffect, String tzId, String curDate, boolean touchDevice) {
        if (sw != null) {
            try {
                screenHeight = Integer.parseInt(sh);
                screenWidth = Integer.parseInt(sw);
            } catch (final NumberFormatException e) {
                screenHeight = screenWidth = -1;
            }
        }
        if (tzo != null) {
            try {
                // browser->java conversion: min->ms, reverse sign
                timezoneOffset = -Integer.parseInt(tzo) * 60 * 1000;
            } catch (final NumberFormatException e) {
                timezoneOffset = 0; // default gmt+0
            }
        }
        if (rtzo != null) {
            try {
                // browser->java conversion: min->ms, reverse sign
                rawTimezoneOffset = -Integer.parseInt(rtzo) * 60 * 1000;
            } catch (final NumberFormatException e) {
                rawTimezoneOffset = 0; // default gmt+0
            }
        }
        if (dstSavings != null) {
            try {
                // browser->java conversion: min->ms
                this.dstSavings = Integer.parseInt(dstSavings) * 60 * 1000;
            } catch (final NumberFormatException e) {
                this.dstSavings = 0; // default no savings
            }
        }
        if (dstInEffect != null) {
            this.dstInEffect = Boolean.parseBoolean(dstInEffect);
        }
        if (tzId == null || "undefined".equals(tzId)) {
            timeZoneId = null;
        } else {
            timeZoneId = tzId;
        }
        if (curDate != null) {
            try {
                long curTime = Long.parseLong(curDate);
                clientServerTimeDelta = curTime - new Date().getTime();
            } catch (final NumberFormatException e) {
                clientServerTimeDelta = 0;
            }
        }
        this.touchDevice = touchDevice;

    }

    /**
     * For internal use by VaadinServlet/VaadinPortlet only. Updates all
     * properties in the class according to the given information.
     *
     * @param request
     *            the Vaadin request to read the information from
     */
    public void updateRequestDetails(VaadinRequest request) {
        locale = request.getLocale();
        address = request.getRemoteAddr();
        secureConnection = request.isSecure();
        // Headers are case insensitive according to the specification but are
        // case sensitive in Weblogic portal...
        String agent = request.getHeader("User-Agent");

        if (agent != null) {
            browserApplication = agent;
            browserDetails = new VBrowserDetails(agent);
        }

        if (request.getParameter("v-sw") != null) {
            updateClientSideDetails(request.getParameter("v-sw"), request.getParameter("v-sh"),
                    request.getParameter("v-tzo"), request.getParameter("v-rtzo"), request.getParameter("v-dstd"),
                    request.getParameter("v-dston"), request.getParameter("v-tzid"),
                    request.getParameter("v-curdate"), request.getParameter("v-td") != null);
        }
    }

    /**
     * Checks if the browser is so old that it simply won't work with a Vaadin
     * application. Can be used to redirect to an alternative page, show
     * alternative content or similar.
     *
     * When this method returns true chances are very high that the browser
     * won't work and it does not make sense to direct the user to the Vaadin
     * application.
     *
     * @return true if the browser won't work, false if not the browser is
     *         supported or might work
     */
    public boolean isTooOldToFunctionProperly() {
        if (browserDetails == null) {
            // Don't know, so assume it will work
            return false;
        }

        return browserDetails.isTooOldToFunctionProperly();
    }

    /**
     * Checks if the browser supports ECMAScript 6, based on the user agent.
     *
     * @return <code>true</code> if the browser supports ES6, <code>false</code>
     *         otherwise.
     * @since 8.1
     */
    public boolean isEs6Supported() {
        if (browserDetails == null) {
            // Don't know, so assume no
            return false;
        }
        return browserDetails.isEs6Supported();

    }
}