View Javadoc
1   /*
2    * Copyright 2012 Oracle Corporation. All Rights Reserved.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.fatwire.gst.foundation.mobile.mobiforge;
18  
19  import java.util.Enumeration;
20  import java.util.Locale;
21  
22  import javax.servlet.http.HttpServletRequest;
23  
24  import org.apache.commons.lang.StringUtils;
25  
26  import COM.FutureTense.Interfaces.ICS;
27  
28  import com.fatwire.gst.foundation.mobile.DeviceDetector;
29  import com.fatwire.gst.foundation.mobile.DeviceType;
30  
31  /**
32   * DeviceDecector making use of the MobiForce algorithm. This is a simple
33   * algorithm and takes care of most of the devices based on User-Agent header.
34   * </p> To override the User-Agent algorithm, you can add a parameter <tt>d</tt>
35   * with a value of <tt>mobile, tablet or desktop</tt>.
36   * 
37   * @author Dolf Dijkstra
38   * @since 25 jun. 2012
39   */
40  public class MobiForgeDeviceDetector implements DeviceDetector {
41      public static String DEVICE_VAR = "d";
42  
43      /*
44       * (non-Javadoc)
45       * 
46       * @see
47       * com.oracle.ateam.webcenter.sites.DeviceDetector#detectDeviceType(COM.
48       * FutureTense.Interfaces.ICS)
49       */
50      @Override
51      public DeviceType detectDeviceType(ICS ics) {
52          if ("desktop".equals(ics.GetVar(DEVICE_VAR)))
53              return DeviceType.DESKTOP;
54          if ("mobile".equals(ics.GetVar(DEVICE_VAR)))
55              return DeviceType.MOBILE;
56          if ("tablet".equals(ics.GetVar(DEVICE_VAR)))
57              return DeviceType.TABLET;
58  
59          @SuppressWarnings("deprecation")
60          HttpServletRequest request = ics.getIServlet().getServletRequest();
61          return detectDeviceType(request);
62      }
63  
64      protected DeviceType detectDeviceType(HttpServletRequest request) {
65          // UAProf detection
66          if (request.getHeader("x-wap-profile") != null || request.getHeader("Profile") != null) {
67              return DeviceType.MOBILE;
68          }
69  
70          if (StringUtils.isNotBlank(request.getHeader("Accept"))
71                  && request.getHeader("Accept").toLowerCase(Locale.US).indexOf("application/vnd.wap.xhtml+xml") > 0) {
72              return DeviceType.MOBILE;
73          }
74  
75          String userAgent = request.getHeader("User-Agent");
76          DeviceType type = detectDeviceType(userAgent);
77          // OperaMini special case
78          if (type == DeviceType.DESKTOP) {
79              @SuppressWarnings("rawtypes")
80              Enumeration headers = request.getHeaderNames();
81              while (headers.hasMoreElements()) {
82                  String header = (String) headers.nextElement();
83                  if (header.contains("OperaMini")) {
84                      return DeviceType.MOBILE;
85                  }
86  
87              }
88          }
89          return type;
90  
91      }
92  
93      protected DeviceType detectDeviceType(String ua) {
94          if (StringUtils.isBlank(ua) || ua.length() < 5)
95              return DeviceType.DESKTOP;
96          String userAgent = ua.toLowerCase(Locale.US);
97  
98          String mobile_ua = userAgent.substring(0, 4);
99          for (String prefix : KNOWN_MOBILE_USER_AGENT_PREFIXES) {
100             if (prefix.equals(mobile_ua))
101                 return DeviceType.MOBILE;
102         }
103 
104         // UserAgent keyword detection for Mobile and Tablet devices
105 
106         for (String keyword : KNOWN_MOBILE_USER_AGENT_KEYWORDS) {
107             if (userAgent.contains(keyword)) {
108                 return DeviceType.MOBILE;
109             }
110         }
111         for (String keyword : KNOWN_TABLET_USER_AGENT_KEYWORDS) {
112             if (userAgent.contains(keyword)) {
113                 return DeviceType.TABLET;
114             }
115         }
116         // Android special case
117         if (userAgent.contains("android") && userAgent.contains("mobile")) {
118             return DeviceType.MOBILE;
119         } else if (userAgent.contains("android") && !userAgent.contains("mobile")) {
120             return DeviceType.TABLET;
121         }
122         return DeviceType.DESKTOP;// default to desktop
123     }
124 
125     private static final String[] KNOWN_MOBILE_USER_AGENT_PREFIXES = new String[] { "w3c ", "w3c-", "acs-", "alav",
126             "alca", "amoi", "audi", "avan", "benq", "bird", "blac", "blaz", "brew", "cell", "cldc", "cmd-", "dang",
127             "doco", "eric", "hipt", "htc_", "inno", "ipaq", "ipod", "jigs", "kddi", "keji", "leno", "lg-c", "lg-d",
128             "lg-g", "lge-", "lg/u", "maui", "maxo", "midp", "mits", "mmef", "mobi", "mot-", "moto", "mwbp", "nec-",
129             "newt", "noki", "palm", "pana", "pant", "phil", "play", "port", "prox", "qwap", "sage", "sams", "sany",
130             "sch-", "sec-", "send", "seri", "sgh-", "shar", "sie-", "siem", "smal", "smar", "sony", "sph-", "symb",
131             "t-mo", "teli", "tim-", "tosh", "tsm-", "upg1", "upsi", "vk-v", "voda", "wap-", "wapa", "wapi", "wapp",
132             "wapr", "webc", "winw", "winw", "xda ", "xda-" };
133     private static final String[] KNOWN_MOBILE_USER_AGENT_KEYWORDS = new String[] { "blackberry", "webos", "ipod",
134             "lge vx", "midp", "maemo", "mmp", "netfront", "hiptop", "nintendo DS", "novarra", "openweb", "opera mobi",
135             "opera mini", "palm", "psp", "phone", "smartphone", "symbian", "up.browser", "up.link", "wap", "windows ce" };
136 
137     private static final String[] KNOWN_TABLET_USER_AGENT_KEYWORDS = new String[] { "ipad", "playbook", "hp-tablet" };
138 
139 }