/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (c) Alkacon Software GmbH (http://www.alkacon.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* For further information about Alkacon Software, please see the
* company website: http://www.alkacon.com
*
* For further information about OpenCms, please see the
* project website: http://www.opencms.org
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.opencms.jsp.util;
import org.opencms.util.CmsRequestUtil;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
/**
* This class provides the detection for different devices, so that the
* <code><cms:device type="..."></code>-Tag can detect which device sends the HTTP request.<p>
*
* @since 8.0.0
*/
public class CmsJspDeviceSelector implements I_CmsJspDeviceSelector {
/** Constant for console detection. */
public static final String C_CONSOLE = "console";
/** Constant for desktop detection. */
public static final String C_DESKTOP = "desktop";
/** Constant for mobile detection. */
public static final String C_MOBILE = "mobile";
/** A Smartphone name constant. */
public static final String DEVICE_ANDROID = "android";
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_ARCHOS = "archos";
/** A Smartphone name constant. */
public static final String DEVICE_BB = "blackberry";
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_BREW = "brew";
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_DANGER = "danger";
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_HIPTOP = "hiptop";
/** A Smartphone name constant. */
public static final String DEVICE_IEMOBILE = "iemobile";
/** A Smartphone name constant. */
public static final String DEVICE_IPHONE = "iphone";
/** A Smartphone name constant. */
public static final String DEVICE_IPOD = "ipod";
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_MIDP = "midp"; //a mobile Java technology
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_NINTENDO = "nintendo";
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_NINTENDO_DS = "nitro";
/** A Smartphone name constant. */
public static final String DEVICE_PALM = "palm";
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_PDA = "pda"; //some devices report themselves as PDAs
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_PLAYSTATION = "playstation";
/** A Smartphone name constant. */
public static final String DEVICE_S60 = "series60";
/** A Smartphone name constant. */
public static final String DEVICE_S70 = "series70";
/** A Smartphone name constant. */
public static final String DEVICE_S80 = "series80";
/** A Smartphone name constant. */
public static final String DEVICE_S90 = "series90";
/** A Smartphone name constant. */
public static final String DEVICE_SYMBIAN = "symbian";
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_WII = "wii";
/** A Smartphone name constant. */
public static final String DEVICE_WIN_MOBILE = "windows ce";
/** A Smartphone name constant. */
public static final String DEVICE_WINDOWS = "windows";
/** Constant for other random devices and mobile browsers. */
public static final String DEVICE_XBOX = "xbox";
/** A Smartphone name constant. */
public static final String ENGINE_BLAZER = "blazer"; //Old Palm
/** Constant for other random devices and mobile browsers. */
public static final String ENGINE_NETFRONT = "netfront"; //Common embedded OS browser
/** Constant for other random devices and mobile browsers. */
public static final String ENGINE_OPEN_WEB = "openweb"; //Transcoding by OpenWave server
/** Constant for other random devices and mobile browsers. */
public static final String ENGINE_OPERA = "opera"; //Popular browser
/** A Smartphone name constant. */
public static final String ENGINE_PIE = "wm5 pie"; //An old Windows Mobile
/** Constant for other random devices and mobile browsers. */
public static final String ENGINE_UP_BROWSER = "up.browser"; //common on some phones
/** A Smartphone name constant. */
public static final String ENGINE_WEBKIT = "webkit";
/** A Smartphone name constant. */
public static final String ENGINE_XIINO = "xiino"; //Another old Palm
/** Constant for other random devices and mobile browsers. */
public static final String LINUX = "linux";
/** Constant for other random devices and mobile browsers. */
public static final String MAEMO = "maemo";
/** Constant for other random devices and mobile browsers. */
public static final String MAEMO_TABLET = "tablet";
/** Constant for other random devices and mobile browsers. */
public static final String MANU_ERICSSON = "ericsson";
/** Constant for other random devices and mobile browsers. */
public static final String MANU_SAMSUNG1 = "sec-sgh";
/** Constant for other random devices and mobile browsers. */
public static final String MANU_SONY = "sony";
/** Constant for other random devices and mobile browsers. */
public static final String MANU_SONY_ERICSSON = "sonyericsson";
/** Constant for other random devices and mobile browsers. */
public static final String MINI = "mini"; //Some mobile browsers put "mini" in their names.
/** Constant for other random devices and mobile browsers. */
public static final String MOBI = "mobi"; //Some mobile browsers put "mobi" in their user agent strings.
/** Constant for other random devices and mobile browsers. */
public static final String MOBILE = "mobile"; //Some mobile browsers put "mobile" in their user agent strings.
/** Constant for other random devices and mobile browsers. */
public static final String MYLO_COM2 = "com2"; //for Sony Mylo also
/** Constant for other random devices and mobile browsers. */
public static final String QT_EMBEDDED = "qt embedded"; //for Sony Mylo
/** Constant for other random devices and mobile browsers. */
public static final String SVC_DOCOMO = "docomo";
/** Constant for other random devices and mobile browsers. */
public static final String SVC_KDDI = "kddi";
/** Constant for other random devices and mobile browsers. */
public static final String SVC_VODAFONE = "vodafone";
/** Constant for other random devices and mobile browsers. */
public static final String UPLINK = "up.link";
/** A Smartphone name constant. */
public static final String VND_RIM = "vnd.rim"; //Detectable when BB devices emulate IE or Firefox
/** Constant for mobile-specific content. */
public static final String VND_WAP = "vnd.wap";
/** Constant for mobile-specific content. */
public static final String WML = "wml";
/** Accept HTTP request header. */
protected String m_httpAccept = "";
/** User-Agent HTTP request header. */
protected String m_userAgent = "";
/**
* @see org.opencms.jsp.util.I_CmsJspDeviceSelector#getDeviceType(javax.servlet.http.HttpServletRequest)
*/
public String getDeviceType(HttpServletRequest req) {
init(req.getHeader(CmsRequestUtil.HEADER_USER_AGENT), req.getHeader(CmsRequestUtil.HEADER_ACCEPT));
if (detectMobileQuick()) {
return C_MOBILE;
} else if (detectGameConsole()) {
return C_CONSOLE;
} else {
return C_DESKTOP;
}
}
/**
* @see org.opencms.jsp.util.I_CmsJspDeviceSelector#getDeviceTypes()
*/
public List<String> getDeviceTypes() {
String[] devices = {C_MOBILE, C_CONSOLE, C_DESKTOP};
return Arrays.asList(devices);
}
/**
* Return the lower case <code>HTTP_ACCEPT</code>.<p>
*
* @return the HTTP HEADER Accept information
*/
public String getHttpAccept() {
return m_httpAccept;
}
/**
* Return the lower case <code>HTTP_USER_AGENT</code>.<p>
*
* @return the user agent
*/
public String getUserAgent() {
return m_userAgent;
}
/**
* Initialize the userAgent and httpAccept variables.<p>
*
* @param userAgent the User-Agent header
* @param httpAccept the Accept header
*/
public void init(String userAgent, String httpAccept) {
if (userAgent != null) {
this.m_userAgent = userAgent.toLowerCase();
}
if (httpAccept != null) {
this.m_httpAccept = httpAccept.toLowerCase();
}
}
/**
* Detects if the current device is an Android OS-based device.<p>
*
* @return <code>true</code> if the device is an Android, <code>false</code> otherwise
*/
protected boolean detectAndroid() {
if (m_userAgent.indexOf(DEVICE_ANDROID) != -1) {
return true;
}
return false;
}
/**
* Detects if the current device is an Android OS-based device and
* the browser is based on WebKit.<p>
*
* @return <code>true</code> if the device is an Android OS-based, <code>false</code> otherwise
*/
protected boolean detectAndroidWebKit() {
if (detectAndroid() && detectWebkit()) {
return true;
}
return false;
}
/**
* Detects if the current device is an Archos media player/Internet tablet.<p>
*
* @return <code>true</code> if the current device is an Archos media player/Internet tablet, <code>false</code> otherwise
*/
protected boolean detectArchos() {
if (m_userAgent.indexOf(DEVICE_ARCHOS) != -1) {
return true;
}
return false;
}
/**
* Detects if the current browser is a BlackBerry of some sort.<p>
*
* @return <code>true</code> if the current browser is a BlackBerry of some sort, <code>false</code> otherwise
*/
protected boolean detectBlackBerry() {
if ((m_userAgent.indexOf(DEVICE_BB) != -1) || (m_httpAccept.indexOf(VND_RIM) != -1)) {
return true;
}
return false;
}
/**
* Detects whether the device is a Brew-powered device.<p>
*
* @return <code>true</code> if the device is a Brew-powered device, <code>false</code> otherwise
*/
protected boolean detectBrewDevice() {
if (m_userAgent.indexOf(DEVICE_BREW) != -1) {
return true;
}
return false;
}
/**
* Detects the Danger Hiptop device.<p>
*
* @return <code>true</code> if the device is a Danger Hiptop device, <code>false</code> otherwise
*/
protected boolean detectDangerHiptop() {
if ((m_userAgent.indexOf(DEVICE_DANGER) != -1) || (m_userAgent.indexOf(DEVICE_HIPTOP) != -1)) {
return true;
}
return false;
}
/**
* Detects if the current device is an Internet-capable game console.<p>
*
* @return <code>true</code> if the device is an Internet-capable game console, <code>false</code> otherwise
*/
protected boolean detectGameConsole() {
if (detectSonyPlaystation() || detectNintendo() || detectXbox()) {
return true;
}
return false;
}
/**
* Detects if the current device is an iPhone.<p>
*
* @return <code>true</code> if the device is an iPhone, <code>false</code> otherwise
*/
protected boolean detectIphone() {
// The iPod touch says it's an iPhone! So let's disambiguate.
if ((m_userAgent.indexOf(DEVICE_IPHONE) != -1) && !detectIpod()) {
return true;
}
return false;
}
/**
* Detects if the current device is an iPhone or iPod Touch.<p>
*
* @return <code>true</code> if the device is an iPhone or iPod Touch, <code>false</code> otherwise
*/
protected boolean detectIphoneOrIpod() {
//We repeat the searches here because some iPods may report themselves as an iPhone, which would be okay.
if ((m_userAgent.indexOf(DEVICE_IPHONE) != -1) || (m_userAgent.indexOf(DEVICE_IPOD) != -1)) {
return true;
}
return false;
}
/**
* Detects if the current device is an iPod Touch.<p>
*
* @return <code>true</code> if the device is an iPod Touch, <code>false</code> otherwise
*/
protected boolean detectIpod() {
if (m_userAgent.indexOf(DEVICE_IPOD) != -1) {
return true;
}
return false;
}
/**
* Detects if the current device is on one of the Maemo-based Nokia Internet Tablets.<p>
*
* @return <code>true</code> if the current device is on one of the Maemo-based Nokia Internet Tablets, <code>false</code> otherwise
*/
protected boolean detectMaemoTablet() {
if (m_userAgent.indexOf(MAEMO) != -1) {
return true;
}
return false;
}
/**
* Detects if the current device supports MIDP, a mobile Java technology.<p>
*
* @return <code>true</code> if the current device supports MIDP, a mobile Java technology, <code>false</code> otherwise
*/
protected boolean detectMidpCapable() {
if ((m_userAgent.indexOf(DEVICE_MIDP) != -1) || (m_httpAccept.indexOf(DEVICE_MIDP) != -1)) {
return true;
}
return false;
}
/**
* The longer and more thorough way to detect for a mobile device.<p>
*
* Will probably detect most feature phones,
* smartphone-class devices, Internet Tablets,
* Internet-enabled game consoles, etc.
* This ought to catch a lot of the more obscure and older devices, also --
* but no promises on thoroughness!<p>
*
* @return <code>true</code> if the current device is a mobile, a tablet or a gameconsole, <code>false</code> otherwise
*/
protected boolean detectMobileLong() {
if (detectMobileQuick() || detectMaemoTablet() || detectGameConsole()) {
return true;
}
return false;
}
/**
* The quick way to detect for a mobile device.<p>
*
* Will probably detect most recent/current mid-tier Feature Phones
* as well as smartphone-class devices.<p>
*
* @return <code>true</code> if the device is mobile, <code>false</code> otherwise
*/
protected boolean detectMobileQuick() {
if (detectIphone()) {
return true;
}
//Ordered roughly by market share, WAP/XML > Brew > Smartphone.
if (detectWapWml()) {
return true;
}
// if (detectBrewDevice()) {
// Updated by AHand
if (detectOperaMobile()) {
return true;
}
// }
if (m_userAgent.indexOf(ENGINE_UP_BROWSER) != -1) {
if (m_userAgent.indexOf(ENGINE_OPEN_WEB) != -1) {
return true;
}
}
// if (m_userAgent.indexOf(DEVICE_MIDP) != -1) {
if (detectSmartphone()) {
return true;
}
// }
if (detectDangerHiptop()) {
if (detectMidpCapable()) {
return true;
}
}
if (m_userAgent.indexOf(DEVICE_PDA) != -1) {
if (m_userAgent.indexOf(MOBILE) != -1) {
return true;
}
}
//detect older phones from certain manufacturers and operators.
if (m_userAgent.indexOf(UPLINK) != -1) {
if (m_userAgent.indexOf(MANU_SONY_ERICSSON) != -1) {
return true;
}
}
if (m_userAgent.indexOf(MANU_ERICSSON) != -1) {
if (m_userAgent.indexOf(MANU_SAMSUNG1) != -1) {
return true;
}
}
if (m_userAgent.indexOf(SVC_DOCOMO) != -1) {
if (m_userAgent.indexOf(SVC_KDDI) != -1) {
return true;
}
}
if (m_userAgent.indexOf(SVC_VODAFONE) != -1) {
return false;
}
return false;
}
/**
* Detects if the current device is a Nintendo game device.<p>
*
* @return <code>true</code> if the device is a Nintendo game, <code>false</code> otherwise
*/
protected boolean detectNintendo() {
if ((m_userAgent.indexOf(DEVICE_NINTENDO) != -1)
|| (m_userAgent.indexOf(DEVICE_WII) != -1)
|| (m_userAgent.indexOf(DEVICE_NINTENDO_DS) != -1)) {
return true;
}
return false;
}
/**
* Detects Opera Mobile or Opera Mini.<p>
*
* @return <code>true</code> if the browser is a Opera Mobile or Opera Mini, <code>false</code> otherwise
*/
protected boolean detectOperaMobile() {
if ((m_userAgent.indexOf(ENGINE_OPERA) != -1)
&& ((m_userAgent.indexOf(MINI) != -1) || (m_userAgent.indexOf(MOBI) != -1))) {
return true;
}
return false;
}
/**
* Detects if the current browser is on a PalmOS device.<p>
*
* @return <code>true</code> if the current browser is on a PalmOS device, <code>false</code> otherwise
*/
protected boolean detectPalmOS() {
//Most devices nowadays report as 'Palm', but some older ones reported as Blazer or Xiino.
if ((m_userAgent.indexOf(DEVICE_PALM) != -1)
|| (m_userAgent.indexOf(ENGINE_BLAZER) != -1)
|| (m_userAgent.indexOf(ENGINE_XIINO) != -1)) {
return true;
}
return false;
}
/**
* Detects if the current browser is the S60 Open Source Browser.<p>
*
* @return <code>true</code> if the current browser is the S60 Open Source Browser, <code>false</code> otherwise
*/
protected boolean detectS60OssBrowser() {
//First, test for WebKit, then make sure it's either Symbian or S60.
if (detectWebkit() && ((m_userAgent.indexOf(DEVICE_SYMBIAN) != -1) || (m_userAgent.indexOf(DEVICE_S60) != -1))) {
return true;
}
return false;
}
/**
* Check to see whether the device is any device in the 'smartphone' category.<p>
*
* @return <code>true</code> if the device is any device in the 'smartphone', <code>false</code> otherwise
*/
protected boolean detectSmartphone() {
return (detectIphoneOrIpod()
|| detectS60OssBrowser()
|| detectSymbianOS()
|| detectWindowsMobile()
|| detectBlackBerry()
|| detectPalmOS() || detectAndroid());
}
/**
* Detects if the current browser is a Sony Mylo device.<p>
*
* @return <code>true</code> if the current device is a Sony Mylo device, <code>false</code> otherwise
*/
protected boolean detectSonyMylo() {
if ((m_userAgent.indexOf(MANU_SONY) != -1)
&& ((m_userAgent.indexOf(QT_EMBEDDED) != -1) || (m_userAgent.indexOf(MYLO_COM2) != -1))) {
return true;
}
return false;
}
/**
* Detects if the current device is a Sony Playstation.<p>
*
* @return <code>true</code> if the device is a Sony Playstation, <code>false</code> otherwise
*/
protected boolean detectSonyPlaystation() {
if (m_userAgent.indexOf(DEVICE_PLAYSTATION) != -1) {
return true;
}
return false;
}
/**
*
* Detects if the current device is any Symbian OS-based device,
* including older S60, Series 70, Series 80, Series 90, and UIQ,
* or other browsers running on these devices.<p>
*
* @return <code>true</code> if the current device is any Symbian OS-based device, <code>false</code> otherwise
*/
protected boolean detectSymbianOS() {
if ((m_userAgent.indexOf(DEVICE_SYMBIAN) != -1)
|| (m_userAgent.indexOf(DEVICE_S60) != -1)
|| (m_userAgent.indexOf(DEVICE_S70) != -1)
|| (m_userAgent.indexOf(DEVICE_S80) != -1)
|| (m_userAgent.indexOf(DEVICE_S90) != -1)) {
return true;
}
return false;
}
/**
* The quick way to detect for a tier of devices.<p>
*
* This method detects for devices which can
* display iPhone-optimized web content.
* Includes iPhone, iPod Touch, Android, etc.<p>
*
* @return <code>true</code> if the current device from the iPhone tier, <code>false</code> otherwise
*/
protected boolean detectTierIphone() {
if (detectIphoneOrIpod() || detectAndroid() || detectAndroidWebKit()) {
return true;
}
return false;
}
/**
* The quick way to detect for a tier of devices.<p>
*
* This method detects for all other types of phones,
* but excludes the iPhone and Smartphone Tier devices.<p>
*
* @return <code>true<code> if the current device is mobile but not a iPhone and not a smartphone, <code>false</code> otherwise
*/
protected boolean detectTierOtherPhones() {
if (detectMobileQuick() && (!detectTierIphone()) && (!detectTierSmartphones())) {
return true;
}
return false;
}
/**
* The quick way to detect for a tier of devices.<p>
*
* This method detects for all smartphones, but
* excludes the iPhone Tier devices.<p>
*
* @return <code>true</code> if the current device is a smartphone but not a iPhone, <code>false</code> otherwise
*/
protected boolean detectTierSmartphones() {
if (detectSmartphone() && (!detectTierIphone())) {
return true;
}
return false;
}
/**
* Detects whether the device supports WAP or WML.<p>
*
* @return <code>true</code> if the device supports WAP or WML, <code>false</code> otherwise
*/
protected boolean detectWapWml() {
if ((m_httpAccept.indexOf(VND_WAP) != -1) || (m_httpAccept.indexOf(WML) != -1)) {
return true;
}
return false;
}
/**
* Detects if the current browser is based on WebKit.<p>
*
* @return <code>true</code> if the current browser is based on WebKit, <code>false</code> otherwise
*/
protected boolean detectWebkit() {
if (m_userAgent.indexOf(ENGINE_WEBKIT) != -1) {
return true;
}
return false;
}
/**
* Detects if the current browser is a Windows Mobile device.<p>
*
* @return <code>true</code> if the current browser is a Windows Mobile device, <code>flase</code> otherwise
*/
protected boolean detectWindowsMobile() {
//Most devices use 'Windows CE', but some report 'iemobile'
// and some older ones report as 'PIE' for Pocket IE.
if ((m_userAgent.indexOf(DEVICE_WIN_MOBILE) != -1)
|| (m_userAgent.indexOf(DEVICE_IEMOBILE) != -1)
|| (m_userAgent.indexOf(ENGINE_PIE) != -1)
|| (detectWapWml() && (m_userAgent.indexOf(DEVICE_WINDOWS) != -1))) {
return true;
}
return false;
}
/**
* Detects if the current device is a Microsoft Xbox.<p>
*
* @return <code>true</code> if the device is a Microsoft Xbox, <code>false</code> otherwise
*/
protected boolean detectXbox() {
if (m_userAgent.indexOf(DEVICE_XBOX) != -1) {
return true;
}
return false;
}
}