From b56a729e3adb1aa957ffab6ed1a5238da3558bb4 Mon Sep 17 00:00:00 2001 From: Demian Katz <demian.katz@villanova.edu> Date: Thu, 3 Dec 2015 09:20:35 -0500 Subject: [PATCH] Fixed submodule mess. --- vendor/ahand/mobileesp | 1 - .../Sub-Classed Page Technique/MDetectPage.cs | 1632 ++++++++++++++++ .../MDetect_Test.aspx | 16 + .../MDetect_Test.aspx.cs | 29 + .../UserControl Technique/MDetectControl.cs | 1647 +++++++++++++++++ .../MobileDetectControl.ascx | 1 + .../MobileDetectControl.ascx.cs | 34 + .../MobileDetectControl.ascx.designer.cs | 18 + .../MobileDetectTestPage.aspx | 17 + .../MobileDetectTestPage.aspx.cs | 17 + .../MobileDetectTestPage.aspx.designer.cs | 34 + vendor/ahand/mobileesp/Cpp/mdetect.h | 1312 +++++++++++++ vendor/ahand/mobileesp/Java/UAgentInfo.java | 1305 +++++++++++++ vendor/ahand/mobileesp/JavaScript/mdetect.js | 1160 ++++++++++++ vendor/ahand/mobileesp/LICENSE | 202 ++ ...MobileESP UA Test Strings - UA Strings.csv | 139 ++ .../MobileESP UA Test Strings.xlsx | Bin 0 -> 41819 bytes vendor/ahand/mobileesp/PHP/mdetect.php | 1287 +++++++++++++ vendor/ahand/mobileesp/Python/mdetect.py | 1023 ++++++++++ vendor/ahand/mobileesp/README.md | 91 + vendor/ahand/mobileesp/composer.json | 24 + vendor/autoload.php | 2 +- .../src/Selenium2Driver.php | 0 vendor/composer/autoload_psr4.php | 2 +- vendor/composer/autoload_real.php | 8 +- vendor/composer/installed.json | 642 +++---- .../lib/WebDriver/Service/CurlService.php | 0 .../Service/CurlServiceInterface.php | 0 .../lib/WebDriver/ServiceFactory.php | 0 29 files changed, 10315 insertions(+), 328 deletions(-) delete mode 160000 vendor/ahand/mobileesp create mode 100755 vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetectPage.cs create mode 100755 vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetect_Test.aspx create mode 100755 vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetect_Test.aspx.cs create mode 100755 vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MDetectControl.cs create mode 100755 vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx create mode 100755 vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx.cs create mode 100755 vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx.designer.cs create mode 100755 vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx create mode 100755 vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx.cs create mode 100755 vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx.designer.cs create mode 100755 vendor/ahand/mobileesp/Cpp/mdetect.h create mode 100755 vendor/ahand/mobileesp/Java/UAgentInfo.java create mode 100755 vendor/ahand/mobileesp/JavaScript/mdetect.js create mode 100644 vendor/ahand/mobileesp/LICENSE create mode 100644 vendor/ahand/mobileesp/MobileESP_UA-Test-Strings/MobileESP UA Test Strings - UA Strings.csv create mode 100644 vendor/ahand/mobileesp/MobileESP_UA-Test-Strings/MobileESP UA Test Strings.xlsx create mode 100755 vendor/ahand/mobileesp/PHP/mdetect.php create mode 100755 vendor/ahand/mobileesp/Python/mdetect.py create mode 100644 vendor/ahand/mobileesp/README.md create mode 100644 vendor/ahand/mobileesp/composer.json mode change 100644 => 100755 vendor/behat/mink-selenium2-driver/src/Selenium2Driver.php mode change 100644 => 100755 vendor/instaclick/php-webdriver/lib/WebDriver/Service/CurlService.php mode change 100644 => 100755 vendor/instaclick/php-webdriver/lib/WebDriver/Service/CurlServiceInterface.php mode change 100644 => 100755 vendor/instaclick/php-webdriver/lib/WebDriver/ServiceFactory.php diff --git a/vendor/ahand/mobileesp b/vendor/ahand/mobileesp deleted file mode 160000 index 098bc79938f..00000000000 --- a/vendor/ahand/mobileesp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 098bc79938fceec7bbb298456ed1aba6271a0bac diff --git a/vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetectPage.cs b/vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetectPage.cs new file mode 100755 index 00000000000..581b428bedb --- /dev/null +++ b/vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetectPage.cs @@ -0,0 +1,1632 @@ +/* ******************************************* +// Copyright 2010-2015, Anthony Hand +// +// +// File version 2015.05.13 (May 13, 2015) +// Updates: +// - Moved MobileESP to GitHub. https://github.com/ahand/mobileesp +// - Opera Mobile/Mini browser has the same UA string on multiple platforms and doesn't differentiate phone vs. tablet. +// - Removed DetectOperaAndroidPhone(). This method is no longer reliable. +// - Removed DetectOperaAndroidTablet(). This method is no longer reliable. +// - Added support for Windows Phone 10: variable and DetectWindowsPhone10() +// - Updated DetectWindowsPhone() to include WP10. +// - Added support for Firefox OS. +// - A variable plus DetectFirefoxOS(), DetectFirefoxOSPhone(), DetectFirefoxOSTablet() +// - NOTE: Firefox doesn't add UA tokens to definitively identify Firefox OS vs. their browsers on other mobile platforms. +// - Added support for Sailfish OS. Not enough info to add a tablet detection method at this time. +// - A variable plus DetectSailfish(), DetectSailfishPhone() +// - Added support for Ubuntu Mobile OS. +// - DetectUbuntu(), DetectUbuntuPhone(), DetectUbuntuTablet() +// - Added support for 2 smart TV OSes. They lack browsers but do have WebViews for use by HTML apps. +// - One variable for Samsung Tizen TVs, plus DetectTizenTV() +// - One variable for LG WebOS TVs, plus DetectWebOSTV() +// - Added DetectTizen(). Tests for “mobile†to disambiguate from Samsung Smart TVs. +// - Removed variables for obsolete devices: deviceHtcFlyer, deviceXoom. +// - Updated DetectAndroid(). No longer has a special test case for the HTC Flyer tablet. +// - Updated DetectAndroidPhone(). +// - Updated internal detection code for Android. +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android and reports here if relevant. +// - Updated DetectAndroidTablet(). +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android to exclude it from here. +// - DetectMeego(): Changed definition for this method. Now detects any Meego OS device, not just phones. +// - DetectMeegoPhone(): NEW. For Meego phones. Ought to detect Opera browsers on Meego, as well. +// - DetectTierIphone(): Added support for phones running Sailfish, Ubuntu and Firefox Mobile. +// - DetectTierTablet(): Added support for tablets running Ubuntu and Firefox Mobile. +// - DetectSmartphone(): Added support for Meego phones. +// - Caught this library up to the PHP, JavaScript and Java versions. Updates include: +// - Added support for Bada: a variable and DetectBada(). This detects any Bada OS device, but (almost) all are phones. +// - Refactored the Windows Phone delegate-related properties and features. Now fires for any Windows Phone, not just WP7. +// - The event fires now when DetectWindowsPhone() is true. +// - Added support for Windows Phone 8: DetectWindowsPhone8(). +// - Updated DetectWindowsMobile(). Excludes any Windows Phone device, not just WP7. +// - Added support for BlackBerry 10 OS phones: DetectBlackBerry10Phone(). +// - Updated DetectSonyMylo(). +// - Updated DetectSmartphone() to sync with the other libraries. +// - Updated DetectTierIphone() to sync with the other libraries. +// - OnInit(EventArgs e): Fixed the user agent and httpaccept init logic. +// - Refactored the detection logic in DetectMobileQuick() and DetectMobileLong(). +// - Moved a few detection tests for older browsers to Long. +// +// +// +// LICENSE INFORMATION +// 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. +// +// +// ABOUT THIS PROJECT +// Project Owner: Anthony Hand +// Email: anthony.hand@gmail.com +// Web Site: http://www.mobileesp.com +// Source Files: https://github.com/ahand/mobileesp +// +// Versions of this code are available for: +// PHP, JavaScript, Java, ASP.NET (C#), and Ruby +// +// ******************************************* +*/ + + +using System; +using System.Collections.Generic; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +/// <summary> +/// Subclass this page to inherit the built-in mobile device detection. +/// </summary> +public class MDetectPage : System.Web.UI.Page +{ + + private string useragent = ""; + private string httpaccept = ""; + + #region Fields - Detection Argument Values + + //standardized values for detection arguments. + private const string dargsIphone = "iphone"; + private const string dargsIpod = "ipod"; + private const string dargsIpad = "ipad"; + private const string dargsIphoneOrIpod = "iphoneoripod"; + private const string dargsIos = "ios"; + private const string dargsAndroid = "android"; + private const string dargsAndroidPhone = "androidphone"; + private const string dargsAndroidTablet = "androidtablet"; + private const string dargsGoogleTV = "googletv"; + private const string dargsWebKit = "webkit"; + private const string dargsSymbianOS = "symbianos"; + private const string dargsS60 = "series60"; + private const string dargsWindowsPhone = "windowsphone"; + private const string dargsWindowsMobile = "windowsmobile"; + private const string dargsBlackBerry = "blackberry"; + private const string dargsBlackBerryWebkit = "blackberrywebkit"; + private const string dargsPalmOS = "palmos"; + private const string dargsPalmWebOS = "webos"; + private const string dargsWebOSTablet = "webostablet"; + private const string dargsSmartphone = "smartphone"; + private const string dargsBrewDevice = "brew"; + private const string dargsDangerHiptop = "dangerhiptop"; + private const string dargsOperaMobile = "operamobile"; + private const string dargsWapWml = "wapwml"; + private const string dargsKindle = "kindle"; + private const string dargsMobileQuick = "mobilequick"; + private const string dargsTierTablet = "tiertablet"; + private const string dargsTierIphone = "tieriphone"; + private const string dargsTierRichCss = "tierrichcss"; + private const string dargsTierOtherPhones = "tierotherphones"; + + #endregion Fields - Detection Argument Values + + #region Fields - User Agent Keyword Values + + private const string engineWebKit = "WEBKIT"; + private const string deviceIphone = "IPHONE"; + private const string deviceIpod = "IPOD"; + private const string deviceIpad = "IPAD"; + private const string deviceMacPpc = "MACINTOSH"; //Used for disambiguation + + private const string deviceAndroid = "ANDROID"; + private const string deviceGoogleTV = "GOOGLETV"; + + private const string deviceNuvifone = "NUVIFONE"; //Garmin Nuvifone + private const string deviceBada = "BADA"; //Samsung's Bada OS + private const string deviceTizen = "TIZEN"; //Tizen OS + private const string deviceMeego = "MEEGO"; //Meego OS + private const string deviceSailfish = "SAILFISH"; //Sailfish OS + private const string deviceUbuntu = "UBUNTU"; //Ubuntu Mobile OS + + private const string deviceSymbian = "SYMBIAN"; + private const string deviceS60 = "SERIES60"; + private const string deviceS70 = "SERIES70"; + private const string deviceS80 = "SERIES80"; + private const string deviceS90 = "SERIES90"; + + private const string deviceWinPhone7 = "WINDOWS PHONE OS 7"; + private const string deviceWinPhone8 = "WINDOWS PHONE 8"; + private const string deviceWinPhone10 = "WINDOWS PHONE 10"; + private const string deviceWinMob = "WINDOWS CE"; + private const string deviceWindows = "WINDOWS"; + private const string deviceIeMob = "IEMOBILE"; + private const string devicePpc = "PPC"; //Stands for PocketPC + private const string enginePie = "WM5 PIE"; //An old Windows Mobile browser + + private const string deviceBB = "BLACKBERRY"; + private const string deviceBB10 = "BB10"; //For the new BB 10 OS + private const string vndRIM = "VND.RIM"; //Detectable when BB devices emulate IE or Firefox + private const string deviceBBStorm = "BLACKBERRY95"; //Storm 1 and 2 + private const string deviceBBBold = "BLACKBERRY97"; //Bold 97x0 (non-touch) + private const string deviceBBBoldTouch = "BLACKBERRY 99"; //Bold 99x0 (touchscreen) + private const string deviceBBTour = "BLACKBERRY96"; //Tour + private const string deviceBBCurve = "BLACKBERRY89"; //Curve2 + private const string deviceBBCurveTouch = "BLACKBERRY 938"; //Curve Touch 9380 + private const string deviceBBTorch = "BLACKBERRY 98"; //Torch + private const string deviceBBPlaybook = "PLAYBOOK"; //PlayBook tablet + + private const string devicePalm = "PALM"; + private const string deviceWebOS = "WEBOS"; //For Palm devices + private const string deviceWebOStv = "WEB0S"; //For LG TVs + private const string deviceWebOShp = "HPWOS"; //For HP's line of WebOS devices + + private const string engineBlazer = "BLAZER"; //Old Palm + private const string engineXiino = "XIINO"; //Another old Palm + + private const string deviceKindle = "KINDLE"; //Amazon Kindle, eInk one + private const string engineSilk = "SILK"; //Amazon's accelerated Silk browser for Kindle Fire + + //Initialize private strings for mobile-specific content. + private const string vndwap = "VND.WAP"; + private const string wml = "WML"; + + //Initialize private strings for other random devices and mobile browsers. + private const string deviceTablet = "TABLET"; //Generic term for slate and tablet devices + private const string deviceBrew = "BREW"; + private const string deviceDanger = "DANGER"; + private const string deviceHiptop = "HIPTOP"; + private const string devicePlaystation = "PLAYSTATION"; + private const string devicePlaystationVita = "VITA"; + private const string deviceNintendoDs = "NITRO"; + private const string deviceNintendo = "NINTENDO"; + private const string deviceWii = "WII"; + private const string deviceXbox = "XBOX"; + private const string deviceArchos = "ARCHOS"; + + private const string engineFirefox = "FIREFOX"; //For Firefox OS + private const string engineOpera = "OPERA"; //Popular browser + private const string engineNetfront = "NETFRONT"; //Common embedded OS browser + private const string engineUpBrowser = "UP.BROWSER"; //common on some phones + private const string engineOpenWeb = "OPENWEB"; //Transcoding by OpenWave server + private const string deviceMidp = "MIDP"; //a mobile Java technology + private const string uplink = "UP.LINK"; + private const string engineTelecaQ = "TELECA Q"; //a modern feature phone browser + + private const string devicePda = "PDA"; //some devices report themselves as PDAs + private const string mini = "MINI"; //Some mobile browsers put "mini" in their names. + private const string mobile = "MOBILE"; //Some mobile browsers put "mobile" in their user agent private strings. + private const string mobi = "MOBI"; //Some mobile browsers put "mobi" in their user agent private strings. + + //Smart TV strings + private const string smartTV1 = "SMART-TV"; //Samsung Tizen smart TVs + private const string smartTV2 = "SMARTTV"; //LG WebOS smart TVs + + //Use Maemo, Tablet, and Linux to test for Nokia"s Internet Tablets. + private const string maemo = "MAEMO"; + private const string linux = "LINUX"; + private const string qtembedded = "QT EMBEDDED"; //for Sony Mylo + private const string mylocom2 = "COM2"; //for Sony Mylo also + + //In some UserAgents, the only clue is the manufacturer. + private const string manuSonyEricsson = "SONYERICSSON"; + private const string manuericsson = "ERICSSON"; + private const string manuSamsung1 = "SEC-SGH"; + private const string manuSony = "SONY"; + private const string manuHtc = "HTC"; //Popular Android and WinMo manufacturer + + //In some UserAgents, the only clue is the operator. + private const string svcDocomo = "DOCOMO"; + private const string svcKddi = "KDDI"; + private const string svcVodafone = "VODAFONE"; + + //Disambiguation strings. + private const string disUpdate = "UPDATE"; //pda vs. update + + #endregion Fields - User Agent Keyword Values + + /// <summary> + /// To instantiate a WebPage sub-class with built-in + /// mobile device detection delegates and events. + /// </summary> + public MDetectPage() + { + + } + + /// <summary> + /// To run the device detection methods andd fire + /// any existing OnDetectXXX events. + /// </summary> + public void FireEvents() + { + if (useragent == "" && httpaccept == "") + { + useragent = (Request.ServerVariables["HTTP_USER_AGENT"] ?? "").ToUpper(); + httpaccept = (Request.ServerVariables["HTTP_ACCEPT"] ?? "").ToUpper(); + } + + #region Event Fire Methods + + MDetectArgs mda = null; + if (this.DetectIpod()) + { + mda = new MDetectArgs(dargsIpod); + if (this.OnDetectIpod != null) + { + this.OnDetectIpod(this, mda); + } + } + if (this.DetectIpad()) + { + mda = new MDetectArgs(dargsIpad); + if (this.OnDetectIpad != null) + { + this.OnDetectIpad(this, mda); + } + } + if (this.DetectIphone()) + { + mda = new MDetectArgs(dargsIphone); + if (this.OnDetectIphone != null) + { + this.OnDetectIphone(this, mda); + } + } + if (this.DetectIphoneOrIpod()) + { + mda = new MDetectArgs(dargsIphoneOrIpod); + if (this.OnDetectDetectIPhoneOrIpod != null) + { + this.OnDetectDetectIPhoneOrIpod(this, mda); + } + } + if (this.DetectIos()) + { + mda = new MDetectArgs(dargsIos); + if (this.OnDetectIos != null) + { + this.OnDetectIos(this, mda); + } + } + if (this.DetectAndroid()) + { + mda = new MDetectArgs(dargsAndroid); + if (this.OnDetectAndroid != null) + { + this.OnDetectAndroid(this, mda); + } + } + if (this.DetectAndroidPhone()) + { + mda = new MDetectArgs(dargsAndroidPhone); + if (this.OnDetectAndroidPhone != null) + { + this.OnDetectAndroidPhone(this, mda); + } + } + if (this.DetectAndroidTablet()) + { + mda = new MDetectArgs(dargsAndroidTablet); + if (this.OnDetectAndroidTablet != null) + { + this.OnDetectAndroidTablet(this, mda); + } + } + if (this.DetectGoogleTV()) + { + mda = new MDetectArgs(dargsGoogleTV); + if (this.OnDetectGoogleTV != null) + { + this.OnDetectGoogleTV(this, mda); + } + } + if (this.DetectWebkit()) + { + mda = new MDetectArgs(dargsWebKit); + if (this.OnDetectWebkit != null) + { + this.OnDetectWebkit(this, mda); + } + } + if (this.DetectS60OssBrowser()) + { + mda = new MDetectArgs(dargsS60); + if (this.OnDetectS60OssBrowser != null) + { + this.OnDetectS60OssBrowser(this, mda); + } + } + if (this.DetectSymbianOS()) + { + mda = new MDetectArgs(dargsSymbianOS); + if (this.OnDetectSymbianOS != null) + { + this.OnDetectSymbianOS(this, mda); + } + } + if (this.DetectWindowsPhone()) + { + mda = new MDetectArgs(dargsWindowsPhone); + if (this.OnDetectWindowsPhone != null) + { + this.OnDetectWindowsPhone(this, mda); + } + } + if (this.DetectWindowsMobile()) + { + mda = new MDetectArgs(dargsWindowsMobile); + if (this.OnDetectWindowsMobile != null) + { + this.OnDetectWindowsMobile(this, mda); + } + } + if (this.DetectBlackBerry()) + { + mda = new MDetectArgs(dargsBlackBerryWebkit); + if (this.OnDetectBlackBerry != null) + { + this.OnDetectBlackBerry(this, mda); + } + } + if (this.DetectBlackBerryWebKit()) + { + mda = new MDetectArgs(dargsBlackBerryWebkit); + if (this.OnDetectBlackBerryWebkit != null) + { + this.OnDetectBlackBerryWebkit(this, mda); + } + } + if (this.DetectPalmOS()) + { + mda = new MDetectArgs(dargsPalmOS); + if (this.OnDetectPalmOS != null) + { + this.OnDetectPalmOS(this, mda); + } + } + if (this.DetectPalmWebOS()) + { + mda = new MDetectArgs(dargsPalmWebOS); + if (this.OnDetectPalmWebOS != null) + { + this.OnDetectPalmWebOS(this, mda); + } + } + if (this.DetectWebOSTablet()) + { + mda = new MDetectArgs(dargsWebOSTablet); + if (this.OnDetectWebOSTablet != null) + { + this.OnDetectWebOSTablet(this, mda); + } + } + if (this.DetectSmartphone()) + { + mda = new MDetectArgs(dargsSmartphone); + if (this.OnDetectSmartphone != null) + { + this.OnDetectSmartphone(this, mda); + } + } + if (this.DetectBrewDevice()) + { + mda = new MDetectArgs(dargsBrewDevice); + if (this.OnDetectBrewDevice != null) + { + this.OnDetectBrewDevice(this, mda); + } + } + if (this.DetectDangerHiptop()) + { + mda = new MDetectArgs(dargsDangerHiptop); + if (this.OnDetectDangerHiptop != null) + { + this.OnDetectDangerHiptop(this, mda); + } + } + if (this.DetectOperaMobile()) + { + mda = new MDetectArgs(dargsOperaMobile); + if (this.OnDetectOperaMobile != null) + { + this.OnDetectOperaMobile(this, mda); + } + } + if (this.DetectWapWml()) + { + mda = new MDetectArgs(dargsWapWml); + if (this.OnDetectWapWml != null) + { + this.OnDetectWapWml(this, mda); + } + } + if (this.DetectKindle()) + { + mda = new MDetectArgs(dargsKindle); + if (this.OnDetectKindle != null) + { + this.OnDetectKindle(this, mda); + } + } + if (this.DetectMobileQuick()) + { + mda = new MDetectArgs(dargsMobileQuick); + if (this.OnDetectMobileQuick != null) + { + this.OnDetectMobileQuick(this, mda); + } + } + if (this.DetectTierTablet()) + { + mda = new MDetectArgs(dargsTierTablet); + if (this.OnDetectTierTablet != null) + { + this.OnDetectTierTablet(this, mda); + } + } + if (this.DetectTierIphone()) + { + mda = new MDetectArgs(dargsTierIphone); + if (this.OnDetectTierIphone != null) + { + this.OnDetectTierIphone(this, mda); + } + } + if (this.DetectTierRichCss()) + { + mda = new MDetectArgs(dargsTierRichCss); + if (this.OnDetectTierRichCss != null) + { + this.OnDetectTierRichCss(this, mda); + } + } + if (this.DetectTierOtherPhones()) + { + mda = new MDetectArgs(dargsTierOtherPhones); + if (this.OnDetectTierOtherPhones != null) + { + this.OnDetectTierOtherPhones(this, mda); + } + } + + #endregion Event Fire Methods + + } + + public class MDetectArgs : EventArgs + { + public MDetectArgs(string type) + { + this.Type = type; + } + + public readonly string Type; + } + + #region Mobile Device Detection Methods + + //************************** + // Detects if the current device is an iPod Touch. + public bool DetectIpod() + { + if (useragent.IndexOf(deviceIpod)!= -1) + return true; + else + return false; + } + + //Ipod delegate + public delegate void DetectIpodHandler(object page, MDetectArgs args); + public event DetectIpodHandler OnDetectIpod; + + + //************************** + // Detects if the current device is an iPad tablet. + public bool DetectIpad() + { + if (useragent.IndexOf(deviceIpad) != -1 && DetectWebkit()) + return true; + else + return false; + } + + //Ipod delegate + public delegate void DetectIpadHandler(object page, MDetectArgs args); + public event DetectIpadHandler OnDetectIpad; + + + //************************** + // Detects if the current device is an iPhone. + public bool DetectIphone() + { + if (useragent.IndexOf(deviceIphone)!= -1) + { + //The iPad and iPod touch say they're an iPhone! So let's disambiguate. + if (DetectIpad() || DetectIpod()) + { + return false; + } + else + return true; + } + else + return false; + } + //IPhone delegate + public delegate void DetectIphoneHandler(object page, MDetectArgs args); + public event DetectIphoneHandler OnDetectIphone; + + //************************** + // Detects if the current device is an iPhone or iPod Touch. + public bool DetectIphoneOrIpod() + { + //We repeat the searches here because some iPods may report themselves as an iPhone, which would be okay. + if (useragent.IndexOf(deviceIphone)!= -1 || + useragent.IndexOf(deviceIpod)!= -1) + return true; + else + return false; + } + //IPhoneOrIpod delegate + public delegate void DetectIPhoneOrIpodHandler(object page, MDetectArgs args); + public event DetectIPhoneOrIpodHandler OnDetectDetectIPhoneOrIpod; + + //************************** + // Detects *any* iOS device: iPhone, iPod Touch, iPad. + public bool DetectIos() + { + if (DetectIphoneOrIpod() || DetectIpad()) + return true; + else + return false; + } + + //Ios delegate + public delegate void DetectIosHandler(object page, MDetectArgs args); + public event DetectIosHandler OnDetectIos; + + + //************************** + // Detects *any* Android OS-based device: phone, tablet, and multi-media player. + // Also detects Google TV. + public bool DetectAndroid() + { + if ((useragent.IndexOf(deviceAndroid) != -1) || + DetectGoogleTV()) + return true; + + return false; + } + //Android delegate + public delegate void DetectAndroidHandler(object page, MDetectArgs args); + public event DetectAndroidHandler OnDetectAndroid; + + //************************** + // Detects if the current device is a (small-ish) Android OS-based device + // used for calling and/or multi-media (like a Samsung Galaxy Player). + // Google says these devices will have 'Android' AND 'mobile' in user agent. + // Ignores tablets (Honeycomb and later). + public bool DetectAndroidPhone() + { + //First, let's make sure we're on an Android device. + if (!DetectAndroid()) + return false; + + //If it's Android and has 'mobile' in it, Google says it's a phone. + if (useragent.IndexOf(mobile) != -1) + return true; + + //Special check for Android devices with Opera Mobile/Mini. They should report here. + if (DetectOperaMobile()) + return true; + + return false; + } + + //Android Phone delegate + public delegate void DetectAndroidPhoneHandler(object page, MDetectArgs args); + public event DetectAndroidPhoneHandler OnDetectAndroidPhone; + + //************************** + // Detects if the current device is a (self-reported) Android tablet. + // Google says these devices will have 'Android' and NOT 'mobile' in their user agent. + public bool DetectAndroidTablet() + { + //First, let's make sure we're on an Android device. + if (!DetectAndroid()) + return false; + + //Special check for Android devices with Opera Mobile/Mini. They should NOT report here. + if (DetectOperaMobile()) + return false; + + //Otherwise, if it's Android and does NOT have 'mobile' in it, Google says it's a tablet. + if (useragent.IndexOf(mobile) > -1) + return false; + else + return true; + } + + //Android Tablet delegate + public delegate void DetectAndroidTabletHandler(object page, MDetectArgs args); + public event DetectAndroidTabletHandler OnDetectAndroidTablet; + + //************************** + // Detects if the current device is a GoogleTV device. + public bool DetectGoogleTV() + { + if (useragent.IndexOf(deviceGoogleTV) != -1) + return true; + else + return false; + } + //GoogleTV delegate + public delegate void DetectGoogleTVHandler(object page, MDetectArgs args); + public event DetectGoogleTVHandler OnDetectGoogleTV; + + //************************** + // Detects if the current device is an Android OS-based device and + // the browser is based on WebKit. + public bool DetectAndroidWebKit() + { + if (DetectAndroid() && DetectWebkit()) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is based on WebKit. + public bool DetectWebkit() + { + if (useragent.IndexOf(engineWebKit)!= -1) + return true; + else + return false; + } + + //Webkit delegate + public delegate void DetectWebkitHandler(object page, MDetectArgs args); + public event DetectWebkitHandler OnDetectWebkit; + + //************************** + // Detects if the current browser is the Nokia S60 Open Source Browser. + public bool DetectS60OssBrowser() + { + //First, test for WebKit, then make sure it's either Symbian or S60. + if (DetectWebkit()) + { + if (useragent.IndexOf(deviceSymbian)!= -1 || + useragent.IndexOf(deviceS60)!= -1) + { + return true; + } + else + return false; + } + else + return false; + } + + //S60OssBrowser delegate + public delegate void DetectS60OssBrowserHandler(object page, MDetectArgs args); + public event DetectS60OssBrowserHandler OnDetectS60OssBrowser; + + //************************** + // 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. + public bool DetectSymbianOS() + { + if (useragent.IndexOf(deviceSymbian)!= -1 || + useragent.IndexOf(deviceS60)!= -1 || + useragent.IndexOf(deviceS70)!= -1 || + useragent.IndexOf(deviceS80)!= -1 || + useragent.IndexOf(deviceS90)!= -1) + return true; + else + return false; + } + + //SymbianOS delegate + public delegate void DetectSymbianOSHandler(object page, MDetectArgs args); + public event DetectSymbianOSHandler OnDetectSymbianOS; + + //************************** + // Detects if the current browser is a + // Windows Phone 7, 8, or 10 device. + public bool DetectWindowsPhone() + { + if (DetectWindowsPhone7() || + DetectWindowsPhone8() || + DetectWindowsPhone10()) + return true; + + return false; + } + + //WindowsPhone delegate + public delegate void DetectWindowsPhoneHandler(object page, MDetectArgs args); + public event DetectWindowsPhoneHandler OnDetectWindowsPhone; + + //************************** + // Detects if the current browser is a + // Windows Phone 7 device. + public bool DetectWindowsPhone7() + { + if (useragent.IndexOf(deviceWinPhone7) != -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a + // Windows Phone 8 device. + public bool DetectWindowsPhone8() + { + if (useragent.IndexOf(deviceWinPhone8) != -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a + // Windows Phone 10 device. + public bool DetectWindowsPhone10() + { + if (useragent.IndexOf(deviceWinPhone10) != -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a Windows Mobile device. + // Excludes Windows Phone devices. + // Focuses on Windows Mobile 6.xx and earlier. + public bool DetectWindowsMobile() + { + //Exclude new Windows Phone. + if (DetectWindowsPhone()) + return false; + //Most devices use 'Windows CE', but some report 'iemobile' + // and some older ones report as 'PIE' for Pocket IE. + if (useragent.IndexOf(deviceWinMob)!= -1 || + useragent.IndexOf(deviceIeMob)!= -1 || + useragent.IndexOf(enginePie) != -1) + return true; + //Test for Windows Mobile PPC but not old Macintosh PowerPC. + if (useragent.IndexOf(devicePpc) != -1 && + !(useragent.IndexOf(deviceMacPpc) != -1)) + return true; + //Test for certain Windwos Mobile-based HTC devices. + if (useragent.IndexOf(manuHtc) != -1 && + useragent.IndexOf(deviceWindows) != -1) + return true; + if (DetectWapWml() == true && + useragent.IndexOf(deviceWindows)!= -1) + return true; + else + return false; + } + + //WindowsMobile delegate + public delegate void DetectWindowsMobileHandler(object page, MDetectArgs args); + public event DetectWindowsMobileHandler OnDetectWindowsMobile; + + //************************** + // Detects if the current browser is any BlackBerry device. + // Includes the PlayBook. + public bool DetectBlackBerry() + { + if ((useragent.IndexOf(deviceBB)!= -1) || + (httpaccept.IndexOf(vndRIM)!= -1)) + return true; + else + return false; + } + //BlackBerry delegate + public delegate void DetectBlackBerryHandler(object page, MDetectArgs args); + public event DetectBlackBerryHandler OnDetectBlackBerry; + + + //************************** + // Detects if the current browser is a BlackBerry 10 OS phone. + // Excludes tablets. + public bool DetectBlackBerry10Phone() + { + if (useragent.IndexOf(deviceBB10) != -1 && + useragent.IndexOf(mobile) != -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is on a BlackBerry tablet device. + // Example: PlayBook + public bool DetectBlackBerryTablet() + { + if (useragent.IndexOf(deviceBBPlaybook) != -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a BlackBerry device AND uses a + // WebKit-based browser. These are signatures for the new BlackBerry OS 6. + // Examples: Torch. Includes the Playbook. + public bool DetectBlackBerryWebKit() + { + if (DetectBlackBerry() && DetectWebkit()) + return true; + else + return false; + } + //BlackBerry Webkit delegate + public delegate void DetectBlackBerryWebkitHandler(object page, MDetectArgs args); + public event DetectBlackBerryWebkitHandler OnDetectBlackBerryWebkit; + + + //************************** + // Detects if the current browser is a BlackBerry Touch + // device, such as the Storm, Torch, and Bold Touch. Excludes the Playbook. + public bool DetectBlackBerryTouch() + { + if (DetectBlackBerry() && + (useragent.IndexOf(deviceBBStorm) != -1 || + useragent.IndexOf(deviceBBTorch) != -1 || + useragent.IndexOf(deviceBBBoldTouch) != -1 || + useragent.IndexOf(deviceBBCurveTouch) != -1)) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a BlackBerry device AND + // has a more capable recent browser. Excludes the Playbook. + // Examples, Storm, Bold, Tour, Curve2 + // Excludes the new BlackBerry OS 6 and 7 browser!! + public bool DetectBlackBerryHigh() + { + //Disambiguate for BlackBerry OS 6 or 7 (WebKit) browser + if (DetectBlackBerryWebKit()) + return false; + if (DetectBlackBerry()) + { + if (DetectBlackBerryTouch() || + useragent.IndexOf(deviceBBBold) != -1 || + useragent.IndexOf(deviceBBTour) != -1 || + useragent.IndexOf(deviceBBCurve) != -1) + return true; + else + return false; + } + else + return false; + } + + //************************** + // Detects if the current browser is a BlackBerry device AND + // has an older, less capable browser. + // Examples: Pearl, 8800, Curve1. + public bool DetectBlackBerryLow() + { + if (DetectBlackBerry()) + { + //Assume that if it's not in the High tier, then it's Low. + if (DetectBlackBerryHigh() || DetectBlackBerryWebKit()) + return false; + else + return true; + } + else + return false; + } + + //************************** + // Detects if the current browser is on a PalmOS device. + public bool DetectPalmOS() + { + //Most devices nowadays report as 'Palm', but some older ones reported as Blazer or Xiino. + if (useragent.IndexOf(devicePalm) != -1 || + useragent.IndexOf(engineBlazer) != -1 || + useragent.IndexOf(engineXiino) != -1) + { + //Make sure it's not WebOS first + if (DetectPalmWebOS() == true) + return false; + else + return true; + } + else + return false; + } + //PalmOS delegate + public delegate void DetectPalmOSHandler(object page, MDetectArgs args); + public event DetectPalmOSHandler OnDetectPalmOS; + + + //************************** + // Detects if the current browser is on a Palm device + // running the new WebOS. + public bool DetectPalmWebOS() + { + if (useragent.IndexOf(deviceWebOS) != -1) + return true; + else + return false; + } + + //PalmWebOS delegate + public delegate void DetectPalmWebOSHandler(object page, MDetectArgs args); + public event DetectPalmWebOSHandler OnDetectPalmWebOS; + + + //************************** + // Detects if the current browser is on an HP tablet running WebOS. + public bool DetectWebOSTablet() + { + if (useragent.IndexOf(deviceWebOShp) != -1 && + useragent.IndexOf(deviceTablet) != -1) + { + return true; + } + else + return false; + } + //WebOS tablet delegate + public delegate void DetectWebOSTabletHandler(object page, MDetectArgs args); + public event DetectWebOSTabletHandler OnDetectWebOSTablet; + + + //************************** + // Detects if the current browser is on a WebOS smart TV. + public bool DetectWebOSTV() + { + if (useragent.IndexOf(deviceWebOStv) != -1 && + useragent.IndexOf(smartTV2) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects if the current browser is Opera Mobile or Mini. + public bool DetectOperaMobile() + { + if (useragent.IndexOf(engineOpera)!= -1) + { + if ((useragent.IndexOf(mini)!= -1) || + (useragent.IndexOf(mobi)!= -1)) + { + return true; + } + else + return false; + } + else + return false; + } + + //Opera Mobile delegate + public delegate void DetectOperaMobileHandler(object page, MDetectArgs args); + public event DetectOperaMobileHandler OnDetectOperaMobile; + + //************************** + // Detects if the current browser is a + // Garmin Nuvifone. + public bool DetectGarminNuvifone() + { + if (useragent.IndexOf(deviceNuvifone) != -1) + return true; + else + return false; + } + + //************************** + // Detects a device running the Bada OS from Samsung. + public bool DetectBada() + { + if (useragent.IndexOf(deviceBada) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects a device running the Tizen smartphone OS. + public bool DetectTizen() + { + if (useragent.IndexOf(deviceTizen) != -1 && + useragent.IndexOf(mobile) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects if the current browser is on a Tizen smart TV. + public bool DetectTizenTV() + { + if (useragent.IndexOf(deviceTizen) != -1 && + useragent.IndexOf(smartTV1) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects a device running the Meego OS. + public bool DetectMeego() + { + if (useragent.IndexOf(deviceMeego) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects a phone running the Meego OS. + public bool DetectMeegoPhone() + { + if (useragent.IndexOf(deviceMeego) != -1 && + useragent.IndexOf(mobile) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects a mobile device (probably) running the Firefox OS. + public bool DetectFirefoxOS() + { + if (DetectFirefoxOSPhone() || DetectFirefoxOSTablet()) + return true; + + return false; + } + + //************************** + // Detects a phone (probably) running the Firefox OS. + public bool DetectFirefoxOSPhone() + { + //First, let's make sure we're NOT on another major mobile OS. + if (DetectIos() || + DetectAndroid() || + DetectSailfish()) + return false; + + if ((useragent.IndexOf(engineFirefox) != -1) && + (useragent.IndexOf(mobile) != -1)) + return true; + + return false; + } + + //************************** + // Detects a tablet (probably) running the Firefox OS. + public bool DetectFirefoxOSTablet() + { + //First, let's make sure we're NOT on another major mobile OS. + if (DetectIos() || + DetectAndroid() || + DetectSailfish()) + return false; + + if ((useragent.IndexOf(engineFirefox) != -1) && + (useragent.IndexOf(deviceTablet) != -1)) + return true; + + return false; + } + + //************************** + // Detects a device running the Sailfish OS. + public bool DetectSailfish() + { + if (useragent.IndexOf(deviceSailfish) != -1) + return true; + else + return false; + } + + //************************** + // Detects a phone running the Sailfish OS. + public bool DetectSailfishPhone() + { + if (DetectSailfish() && + (useragent.IndexOf(mobile) != -1)) + return true; + + return false; + } + + //************************** + // Detects a mobile device running the Ubuntu Mobile OS. + public bool DetectUbuntu() + { + if (DetectUbuntuPhone() || DetectUbuntuTablet()) + return true; + + return false; + } + + //************************** + // Detects a phone running the Ubuntu Mobile OS. + public bool DetectUbuntuPhone() + { + if ((useragent.IndexOf(deviceUbuntu) != -1) && + (useragent.IndexOf(mobile) != -1)) + return true; + + return false; + } + + //************************** + // Detects a tablet running the Ubuntu Mobile OS. + public bool DetectUbuntuTablet() + { + if ((useragent.IndexOf(deviceUbuntu) != -1) && + (useragent.IndexOf(deviceTablet) != -1)) + return true; + + return false; + } + + + //************************** + // Detects whether the device is a Brew-powered device. + public bool DetectBrewDevice() + { + if (useragent.IndexOf(deviceBrew)!= -1) + return true; + else + return false; + } + + //BrewDevice delegate + public delegate void DetectBrewDeviceHandler(object page, MDetectArgs args); + public event DetectBrewDeviceHandler OnDetectBrewDevice; + + //************************** + // Detects the Danger Hiptop device. + public bool DetectDangerHiptop() + { + if (useragent.IndexOf(deviceDanger)!= -1 || + useragent.IndexOf(deviceHiptop)!= -1) + return true; + else + return false; + } + //DangerHiptop delegate + public delegate void DetectDangerHiptopHandler(object page, MDetectArgs args); + public event DetectDangerHiptopHandler OnDetectDangerHiptop; + + //************************** + // Detects whether the device supports WAP or WML. + public bool DetectWapWml() + { + if (httpaccept.IndexOf(vndwap)!= -1 || + httpaccept.IndexOf(wml)!= -1) + return true; + else + return false; + } + //WapWml delegate + public delegate void DetectWapWmlHandler(object page, MDetectArgs args); + public event DetectWapWmlHandler OnDetectWapWml; + + + //************************** + // Detects if the current device is an Amazon Kindle (eInk devices only). + // Note: For the Kindle Fire, use the normal Android methods. + public bool DetectKindle() + { + if (useragent.IndexOf(deviceKindle) != -1 && + !DetectAndroid()) + return true; + else + return false; + } + + //Kindle delegate + public delegate void DetectKindleHandler(object page, MDetectArgs args); + public event DetectKindleHandler OnDetectKindle; + + + //************************** + // Detects if the current Amazon device is using the Silk Browser. + // Note: Typically used by the the Kindle Fire. + public bool DetectAmazonSilk() + { + if (useragent.IndexOf(engineSilk) != -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a Sony Playstation. + public bool DetectSonyPlaystation() + { + if (useragent.IndexOf(devicePlaystation)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a handheld gaming device with + // a touchscreen and modern iPhone-class browser. Includes the Playstation Vita. + public bool DetectGamingHandheld() + { + if (useragent.IndexOf(devicePlaystation)!= -1 && + useragent.IndexOf(devicePlaystationVita)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a Nintendo game device. + public bool DetectNintendo() + { + if (useragent.IndexOf(deviceNintendo)!= -1 || + useragent.IndexOf(deviceWii)!= -1 || + useragent.IndexOf(deviceNintendoDs)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a Microsoft Xbox. + public bool DetectXbox() + { + if (useragent.IndexOf(deviceXbox)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is an Internet-capable game console. + public bool DetectGameConsole() + { + if (DetectSonyPlaystation()) + return true; + else if (DetectNintendo()) + return true; + else if (DetectXbox()) + return true; + else + return false; + } + + //************************** + // Detects if the current device supports MIDP, a mobile Java technology. + public bool DetectMidpCapable() + { + if (useragent.IndexOf(deviceMidp)!= -1 || + httpaccept.IndexOf(deviceMidp)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is on one of the Maemo-based Nokia Internet Tablets. + public bool DetectMaemoTablet() + { + if (useragent.IndexOf(maemo)!= -1) + return true; + //For Nokia N810, must be Linux + Tablet, or else it could be something else. + else if (useragent.IndexOf(linux)!= -1 && + useragent.IndexOf(deviceTablet) != -1 && + !DetectWebOSTablet() && + !DetectAndroid()) + return true; + else + return false; + } + + //************************** + // Detects if the current device is an Archos media player/Internet tablet. + public bool DetectArchos() + { + if (useragent.IndexOf(deviceArchos)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a Sony Mylo device. + public bool DetectSonyMylo() + { + if ((useragent.IndexOf(manuSony)!= -1) && + ((useragent.IndexOf(qtembedded)!= -1) || + (useragent.IndexOf(mylocom2)!= -1))) + return true; + + return false; + } + + //***************************** + // Device Classes + //***************************** + + //************************** + // Check to see whether the device is any device + // in the 'smartphone' category. + // Note: It's better to use DetectTierIphone() for modern touchscreen devices. + public bool DetectSmartphone() + { + if (DetectTierIphone() || + DetectS60OssBrowser() || + DetectSymbianOS() || + DetectWindowsMobile() || + DetectBlackBerry() || + DetectMeegoPhone() || + DetectPalmOS()) + return true; + else + return false; + } + + //DetectSmartphone delegate + public delegate void DetectSmartphoneHandler(object page, MDetectArgs args); + public event DetectSmartphoneHandler OnDetectSmartphone; + + //************************** + // Detects if the current device is a mobile device. + // This method catches most of the popular modern devices. + // Excludes Apple iPads and other modern tablets. + public bool DetectMobileQuick() + { + //Let's exclude tablets + if (DetectTierTablet()) + return false; + + //Most mobile browsing is done on smartphones + if (DetectSmartphone()) + return true; + + //Catch-all for many mobile devices + if (useragent.IndexOf(mobile) != -1) + return true; + + if (DetectOperaMobile()) + return true; + + //We also look for Kindle devices + if (DetectKindle() || + DetectAmazonSilk()) + return true; + + if (DetectWapWml() || + DetectMidpCapable() || + DetectBrewDevice()) + return true; + + if ((useragent.IndexOf(engineNetfront) != -1) || + (useragent.IndexOf(engineUpBrowser) != -1)) + return true; + + return false; + } + + //DetectMobileQuick delegate + public delegate void DetectMobileQuickHandler(object page, MDetectArgs args); + public event DetectMobileQuickHandler OnDetectMobileQuick; + + + //************************** + // The longer and more thorough way to detect for a mobile device. + // 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! + public bool DetectMobileLong() + { + if (DetectMobileQuick()) + return true; + + if (DetectGameConsole()) + return true; + + if (DetectDangerHiptop() || + DetectMaemoTablet() || + DetectSonyMylo() || + DetectArchos()) + return true; + + if ((useragent.IndexOf(devicePda) != -1) && + (useragent.IndexOf(disUpdate) != -1)) + return true; + + //Detect older phones from certain manufacturers and operators. + if ((useragent.IndexOf(uplink) != -1) || + (useragent.IndexOf(engineOpenWeb) != -1) || + (useragent.IndexOf(manuSamsung1) != -1) || + (useragent.IndexOf(manuSonyEricsson) != -1) || + (useragent.IndexOf(manuericsson) != -1) || + (useragent.IndexOf(svcDocomo) != -1) || + (useragent.IndexOf(svcKddi) != -1) || + (useragent.IndexOf(svcVodafone) != -1)) + return true; + + return false; + } + + + + //***************************** + // For Mobile Web Site Design + //***************************** + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for the new generation of + // HTML 5 capable, larger screen tablets. + // Includes iPad, Android (e.g., Xoom), BB Playbook, WebOS, etc. + public bool DetectTierTablet() + { + if (DetectIpad() + || DetectAndroidTablet() + || DetectBlackBerryTablet() + || DetectFirefoxOSTablet() + || DetectUbuntuTablet() + || DetectWebOSTablet()) + return true; + else + return false; + } + + //DetectTierTablet delegate + public delegate void DetectTierTabletHandler(object page, MDetectArgs args); + public event DetectTierTabletHandler OnDetectTierTablet; + + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for devices which can + // display iPhone-optimized web content. + // Includes iPhone, iPod Touch, Android, Windows Phone, BB10, Playstation Vita, etc. + public bool DetectTierIphone() + { + if (DetectIphoneOrIpod() || + DetectAndroidPhone() || + DetectWindowsPhone() || + DetectBlackBerry10Phone() || + DetectPalmWebOS() || + DetectBada() || + DetectTizen() || + DetectFirefoxOSPhone() || + DetectSailfishPhone() || + DetectUbuntuPhone() || + DetectGamingHandheld()) + return true; + else + return false; + } + + //DetectTierIphone delegate + public delegate void DetectTierIphoneHandler(object page, MDetectArgs args); + public event DetectTierIphoneHandler OnDetectTierIphone; + + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for devices which are likely to be capable + // of viewing CSS content optimized for the iPhone, + // but may not necessarily support JavaScript. + // Excludes all iPhone Tier devices. + public bool DetectTierRichCss() + { + if (DetectMobileQuick()) + { + //Exclude iPhone Tier and e-Ink Kindle devices + if (DetectTierIphone() || DetectKindle()) + return false; + + if (DetectWebkit() || + DetectS60OssBrowser()) + return true; + + //Note: 'High' BlackBerry devices ONLY + if (DetectBlackBerryHigh() == true) + return true; + + //Older Windows 'Mobile' isn't good enough for iPhone Tier. + if (DetectWindowsMobile() == true) + return true; + if (useragent.IndexOf(engineTelecaQ) != -1) + return true; + + else + return false; + } + else + return false; + } + + //DetectTierRichCss delegate + public delegate void DetectTierRichCssHandler(object page, MDetectArgs args); + public event DetectTierRichCssHandler OnDetectTierRichCss; + + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for all other types of phones, + // but excludes the iPhone and Smartphone Tier devices. + public bool DetectTierOtherPhones() + { + if (DetectMobileLong() == true) + { + //Exclude devices in the other 2 categories + if (DetectTierIphone() || + DetectTierRichCss()) + return false; + else + return true; + } + else + return false; + } + + //DetectTierOtherPhones delegate + public delegate void DetectTierOtherPhonesHandler(object page, MDetectArgs args); + public event DetectTierOtherPhonesHandler OnDetectTierOtherPhones; + + //*************************************************************** + #endregion + + //Instead of overriding OnInit(), you can override InitializeCulture() + // so that detection can happen earlier in page's lifecycle, if necessary. + protected override void OnInit(EventArgs e) + { + base.OnInit(e); + + if (useragent == "" && httpaccept == "") + { + useragent = (Request.ServerVariables["HTTP_USER_AGENT"] ?? "").ToUpper(); + httpaccept = (Request.ServerVariables["HTTP_ACCEPT"] ?? "").ToUpper(); + } + } +} diff --git a/vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetect_Test.aspx b/vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetect_Test.aspx new file mode 100755 index 00000000000..e33e4b200cc --- /dev/null +++ b/vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetect_Test.aspx @@ -0,0 +1,16 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeFile="MDetect_Test.aspx.cs" Inherits="MDetect_Test" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <div> + + </div> + </form> +</body> +</html> diff --git a/vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetect_Test.aspx.cs b/vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetect_Test.aspx.cs new file mode 100755 index 00000000000..bb18dc25fa9 --- /dev/null +++ b/vendor/ahand/mobileesp/ASP_NET/Sub-Classed Page Technique/MDetect_Test.aspx.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +public partial class MDetect_Test : MDetectPage +{ + protected void Page_Load(object sender, EventArgs e) + { + this.FireEvents(); + } + + protected override void OnInit(EventArgs e) + { + base.OnInit(e); + + //As a test, let's listen for any WebKit-based device. + OnDetectWebkit += new DetectWebkitHandler(MDetect_Test_OnDetectWebkit); + } + + void MDetect_Test_OnDetectWebkit(object page, MDetectPage.MDetectArgs args) + { + //Write the Type value from the argument to the web page. + Response.Write("<b>This browser is " + args.Type + "</b>"); + } + +} diff --git a/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MDetectControl.cs b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MDetectControl.cs new file mode 100755 index 00000000000..edc93b4f41f --- /dev/null +++ b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MDetectControl.cs @@ -0,0 +1,1647 @@ +/* ******************************************* +// Copyright 2010-2015, Anthony Hand +// +// +// File version 2015.05.13 (May 13, 2015) +// Updates: +// - Moved MobileESP to GitHub. https://github.com/ahand/mobileesp +// - Opera Mobile/Mini browser has the same UA string on multiple platforms and doesn't differentiate phone vs. tablet. +// - Removed DetectOperaAndroidPhone(). This method is no longer reliable. +// - Removed DetectOperaAndroidTablet(). This method is no longer reliable. +// - Added support for Windows Phone 10: variable and DetectWindowsPhone10() +// - Updated DetectWindowsPhone() to include WP10. +// - Added support for Firefox OS. +// - A variable plus DetectFirefoxOS(), DetectFirefoxOSPhone(), DetectFirefoxOSTablet() +// - NOTE: Firefox doesn't add UA tokens to definitively identify Firefox OS vs. their browsers on other mobile platforms. +// - Added support for Sailfish OS. Not enough info to add a tablet detection method at this time. +// - A variable plus DetectSailfish(), DetectSailfishPhone() +// - Added support for Ubuntu Mobile OS. +// - DetectUbuntu(), DetectUbuntuPhone(), DetectUbuntuTablet() +// - Added support for 2 smart TV OSes. They lack browsers but do have WebViews for use by HTML apps. +// - One variable for Samsung Tizen TVs, plus DetectTizenTV() +// - One variable for LG WebOS TVs, plus DetectWebOSTV() +// - Added DetectTizen(). Tests for “mobile†to disambiguate from Samsung Smart TVs. +// - Removed variables for obsolete devices: deviceHtcFlyer, deviceXoom. +// - Updated DetectAndroid(). No longer has a special test case for the HTC Flyer tablet. +// - Updated DetectAndroidPhone(). +// - Updated internal detection code for Android. +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android and reports here if relevant. +// - Updated DetectAndroidTablet(). +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android to exclude it from here. +// - DetectMeego(): Changed definition for this method. Now detects any Meego OS device, not just phones. +// - DetectMeegoPhone(): NEW. For Meego phones. Ought to detect Opera browsers on Meego, as well. +// - DetectTierIphone(): Added support for phones running Sailfish, Ubuntu and Firefox Mobile. +// - DetectTierTablet(): Added support for tablets running Ubuntu and Firefox Mobile. +// - DetectSmartphone(): Added support for Meego phones. +// - Caught this library up to the PHP, JavaScript and Java versions. Updates include: +// - Added support for Bada: a variable and DetectBada(). This detects any Bada OS device, but (almost) all are phones. +// - Refactored the Windows Phone delegate-related properties and features. Now fires for any Windows Phone, not just WP7. +// - The event fires now when DetectWindowsPhone() is true. +// - Added support for Windows Phone 8: DetectWindowsPhone8(). +// - Updated DetectWindowsMobile(). Excludes any Windows Phone device, not just WP7. +// - Added support for BlackBerry 10 OS phones: DetectBlackBerry10Phone(). +// - Updated DetectSonyMylo(). +// - Updated DetectSmartphone() to sync with the other libraries. +// - Updated DetectTierIphone() to sync with the other libraries. +// - OnInit(EventArgs e): Fixed the user agent and httpaccept init logic. +// - Refactored the detection logic in DetectMobileQuick() and DetectMobileLong(). +// - Moved a few detection tests for older browsers to Long. +// +// +// +// LICENSE INFORMATION +// 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. +// +// +// ABOUT THIS PROJECT +// Project Owner: Anthony Hand +// Email: anthony.hand@gmail.com +// Web Site: http://www.mobileesp.com +// Source Files: https://github.com/ahand/mobileesp +// +// Versions of this code are available for: +// PHP, JavaScript, Java, ASP.NET (C#), and Ruby +// +// ******************************************* +*/ + + +using System; +using System.Collections.Generic; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +/// <summary> +/// Subclass this control to inherit the built-in mobile device detection. +/// </summary> +public class MDetectControl : System.Web.UI.UserControl +{ + + private string useragent = ""; + private string httpaccept = ""; + + #region Fields - Detection Argument Values + + //standardized values for detection arguments. + private const string dargsIphone = "iphone"; + private const string dargsIpod = "ipod"; + private const string dargsIpad = "ipad"; + private const string dargsIphoneOrIpod = "iphoneoripod"; + private const string dargsIos = "ios"; + private const string dargsAndroid = "android"; + private const string dargsAndroidPhone = "androidphone"; + private const string dargsAndroidTablet = "androidtablet"; + private const string dargsGoogleTV = "googletv"; + private const string dargsWebKit = "webkit"; + private const string dargsSymbianOS = "symbianos"; + private const string dargsS60 = "series60"; + private const string dargsWindowsPhone = "windowsphone"; + private const string dargsWindowsMobile = "windowsmobile"; + private const string dargsBlackBerry = "blackberry"; + private const string dargsBlackBerryWebkit = "blackberrywebkit"; + private const string dargsPalmOS = "palmos"; + private const string dargsPalmWebOS = "webos"; + private const string dargsWebOSTablet = "webostablet"; + private const string dargsSmartphone = "smartphone"; + private const string dargsBrewDevice = "brew"; + private const string dargsDangerHiptop = "dangerhiptop"; + private const string dargsOperaMobile = "operamobile"; + private const string dargsWapWml = "wapwml"; + private const string dargsKindle = "kindle"; + private const string dargsMobileQuick = "mobilequick"; + private const string dargsTierTablet = "tiertablet"; + private const string dargsTierIphone = "tieriphone"; + private const string dargsTierRichCss = "tierrichcss"; + private const string dargsTierOtherPhones = "tierotherphones"; + + #endregion Fields - Detection Argument Values + + #region Fields - User Agent Keyword Values + + private const string engineWebKit = "WEBKIT"; + private const string deviceIphone = "IPHONE"; + private const string deviceIpod = "IPOD"; + private const string deviceIpad = "IPAD"; + private const string deviceMacPpc = "MACINTOSH"; //Used for disambiguation + + private const string deviceAndroid = "ANDROID"; + private const string deviceGoogleTV = "GOOGLETV"; + + private const string deviceNuvifone = "NUVIFONE"; //Garmin Nuvifone + private const string deviceBada = "BADA"; //Samsung's Bada OS + private const string deviceTizen = "TIZEN"; //Tizen OS + private const string deviceMeego = "MEEGO"; //Meego OS + private const string deviceSailfish = "SAILFISH"; //Sailfish OS + private const string deviceUbuntu = "UBUNTU"; //Ubuntu Mobile OS + + private const string deviceSymbian = "SYMBIAN"; + private const string deviceS60 = "SERIES60"; + private const string deviceS70 = "SERIES70"; + private const string deviceS80 = "SERIES80"; + private const string deviceS90 = "SERIES90"; + + private const string deviceWinPhone7 = "WINDOWS PHONE OS 7"; + private const string deviceWinPhone8 = "WINDOWS PHONE 8"; + private const string deviceWinPhone10 = "WINDOWS PHONE 10"; + private const string deviceWinMob = "WINDOWS CE"; + private const string deviceWindows = "WINDOWS"; + private const string deviceIeMob = "IEMOBILE"; + private const string devicePpc = "PPC"; //Stands for PocketPC + private const string enginePie = "WM5 PIE"; //An old Windows Mobile browser + + private const string deviceBB = "BLACKBERRY"; + private const string deviceBB10 = "BB10"; //For the new BB 10 OS + private const string vndRIM = "VND.RIM"; //Detectable when BB devices emulate IE or Firefox + private const string deviceBBStorm = "BLACKBERRY95"; //Storm 1 and 2 + private const string deviceBBBold = "BLACKBERRY97"; //Bold 97x0 (non-touch) + private const string deviceBBBoldTouch = "BLACKBERRY 99"; //Bold 99x0 (touchscreen) + private const string deviceBBTour = "BLACKBERRY96"; //Tour + private const string deviceBBCurve = "BLACKBERRY89"; //Curve2 + private const string deviceBBCurveTouch = "BLACKBERRY 938"; //Curve Touch 9380 + private const string deviceBBTorch = "BLACKBERRY 98"; //Torch + private const string deviceBBPlaybook = "PLAYBOOK"; //PlayBook tablet + + private const string devicePalm = "PALM"; + private const string deviceWebOS = "WEBOS"; //For Palm devices + private const string deviceWebOStv = "WEB0S"; //For LG TVs + private const string deviceWebOShp = "HPWOS"; //For HP's line of WebOS devices + + private const string engineBlazer = "BLAZER"; //Old Palm + private const string engineXiino = "XIINO"; //Another old Palm + + private const string deviceKindle = "KINDLE"; //Amazon Kindle, eInk one + private const string engineSilk = "SILK"; //Amazon's accelerated Silk browser for Kindle Fire + + //Initialize private strings for mobile-specific content. + private const string vndwap = "VND.WAP"; + private const string wml = "WML"; + + //Initialize private strings for other random devices and mobile browsers. + private const string deviceTablet = "TABLET"; //Generic term for slate and tablet devices + private const string deviceBrew = "BREW"; + private const string deviceDanger = "DANGER"; + private const string deviceHiptop = "HIPTOP"; + private const string devicePlaystation = "PLAYSTATION"; + private const string devicePlaystationVita = "VITA"; + private const string deviceNintendoDs = "NITRO"; + private const string deviceNintendo = "NINTENDO"; + private const string deviceWii = "WII"; + private const string deviceXbox = "XBOX"; + private const string deviceArchos = "ARCHOS"; + + private const string engineFirefox = "FIREFOX"; //For Firefox OS + private const string engineOpera = "OPERA"; //Popular browser + private const string engineNetfront = "NETFRONT"; //Common embedded OS browser + private const string engineUpBrowser = "UP.BROWSER"; //common on some phones + private const string engineOpenWeb = "OPENWEB"; //Transcoding by OpenWave server + private const string deviceMidp = "MIDP"; //a mobile Java technology + private const string uplink = "UP.LINK"; + private const string engineTelecaQ = "TELECA Q"; //a modern feature phone browser + + private const string devicePda = "PDA"; //some devices report themselves as PDAs + private const string mini = "MINI"; //Some mobile browsers put "mini" in their names. + private const string mobile = "MOBILE"; //Some mobile browsers put "mobile" in their user agent private strings. + private const string mobi = "MOBI"; //Some mobile browsers put "mobi" in their user agent private strings. + + //Smart TV strings + private const string smartTV1 = "SMART-TV"; //Samsung Tizen smart TVs + private const string smartTV2 = "SMARTTV"; //LG WebOS smart TVs + + //Use Maemo, Tablet, and Linux to test for Nokia"s Internet Tablets. + private const string maemo = "MAEMO"; + private const string linux = "LINUX"; + private const string qtembedded = "QT EMBEDDED"; //for Sony Mylo + private const string mylocom2 = "COM2"; //for Sony Mylo also + + //In some UserAgents, the only clue is the manufacturer. + private const string manuSonyEricsson = "SONYERICSSON"; + private const string manuericsson = "ERICSSON"; + private const string manuSamsung1 = "SEC-SGH"; + private const string manuSony = "SONY"; + private const string manuHtc = "HTC"; //Popular Android and WinMo manufacturer + + //In some UserAgents, the only clue is the operator. + private const string svcDocomo = "DOCOMO"; + private const string svcKddi = "KDDI"; + private const string svcVodafone = "VODAFONE"; + + //Disambiguation strings. + private const string disUpdate = "UPDATE"; //pda vs. update + + #endregion Fields - User Agent Keyword Values + + + /// <summary> + /// To instantiate a WebPage sub-class with built-in + /// mobile device detection delegates and events. + /// </summary> + public MDetectControl() + { + + } + + /// <summary> + /// To run the device detection methods andd fire + /// any existing OnDetectXXX events. + /// </summary> + public void FireEvents() + { + if (useragent == "" && httpaccept == "") + { + useragent = (Request.ServerVariables["HTTP_USER_AGENT"] ?? "").ToUpper(); + httpaccept = (Request.ServerVariables["HTTP_ACCEPT"] ?? "").ToUpper(); + } + + #region Event Fire Methods + + MDetectArgs mda = null; + if (this.DetectIpod()) + { + mda = new MDetectArgs(dargsIpod); + if (this.OnDetectIpod != null) + { + this.OnDetectIpod(this, mda); + } + } + if (this.DetectIpad()) + { + mda = new MDetectArgs(dargsIpad); + if (this.OnDetectIpad != null) + { + this.OnDetectIpad(this, mda); + } + } + if (this.DetectIphone()) + { + mda = new MDetectArgs(dargsIphone); + if (this.OnDetectIphone != null) + { + this.OnDetectIphone(this, mda); + } + } + if (this.DetectIphoneOrIpod()) + { + mda = new MDetectArgs(dargsIphoneOrIpod); + if (this.OnDetectDetectIPhoneOrIpod != null) + { + this.OnDetectDetectIPhoneOrIpod(this, mda); + } + } + if (this.DetectIos()) + { + mda = new MDetectArgs(dargsIos); + if (this.OnDetectIos != null) + { + this.OnDetectIos(this, mda); + } + } + if (this.DetectAndroid()) + { + mda = new MDetectArgs(dargsAndroid); + if (this.OnDetectAndroid != null) + { + this.OnDetectAndroid(this, mda); + } + } + if (this.DetectAndroidPhone()) + { + mda = new MDetectArgs(dargsAndroidPhone); + if (this.OnDetectAndroidPhone != null) + { + this.OnDetectAndroidPhone(this, mda); + } + } + if (this.DetectAndroidTablet()) + { + mda = new MDetectArgs(dargsAndroidTablet); + if (this.OnDetectAndroidTablet != null) + { + this.OnDetectAndroidTablet(this, mda); + } + } + if (this.DetectGoogleTV()) + { + mda = new MDetectArgs(dargsGoogleTV); + if (this.OnDetectGoogleTV != null) + { + this.OnDetectGoogleTV(this, mda); + } + } + if (this.DetectWebkit()) + { + mda = new MDetectArgs(dargsWebKit); + if (this.OnDetectWebkit != null) + { + this.OnDetectWebkit(this, mda); + } + } + if (this.DetectS60OssBrowser()) + { + mda = new MDetectArgs(dargsS60); + if (this.OnDetectS60OssBrowser != null) + { + this.OnDetectS60OssBrowser(this, mda); + } + } + if (this.DetectSymbianOS()) + { + mda = new MDetectArgs(dargsSymbianOS); + if (this.OnDetectSymbianOS != null) + { + this.OnDetectSymbianOS(this, mda); + } + } + if (this.DetectWindowsPhone()) + { + mda = new MDetectArgs(dargsWindowsPhone); + if (this.OnDetectWindowsPhone != null) + { + this.OnDetectWindowsPhone(this, mda); + } + } + if (this.DetectWindowsMobile()) + { + mda = new MDetectArgs(dargsWindowsMobile); + if (this.OnDetectWindowsMobile != null) + { + this.OnDetectWindowsMobile(this, mda); + } + } + if (this.DetectBlackBerry()) + { + mda = new MDetectArgs(dargsBlackBerry); + if (this.OnDetectBlackBerry != null) + { + this.OnDetectBlackBerry(this, mda); + } + } + if (this.DetectBlackBerryWebKit()) + { + mda = new MDetectArgs(dargsBlackBerryWebkit); + if (this.OnDetectBlackBerryWebkit != null) + { + this.OnDetectBlackBerryWebkit(this, mda); + } + } + if (this.DetectPalmOS()) + { + mda = new MDetectArgs(dargsPalmOS); + if (this.OnDetectPalmOS != null) + { + this.OnDetectPalmOS(this, mda); + } + } + if (this.DetectPalmWebOS()) + { + mda = new MDetectArgs(dargsPalmWebOS); + if (this.OnDetectPalmWebOS != null) + { + this.OnDetectPalmWebOS(this, mda); + } + } + if (this.DetectWebOSTablet()) + { + mda = new MDetectArgs(dargsWebOSTablet); + if (this.OnDetectWebOSTablet != null) + { + this.OnDetectWebOSTablet(this, mda); + } + } + if (this.DetectSmartphone()) + { + mda = new MDetectArgs(dargsSmartphone); + if (this.OnDetectSmartphone != null) + { + this.OnDetectSmartphone(this, mda); + } + } + if (this.DetectBrewDevice()) + { + mda = new MDetectArgs(dargsBrewDevice); + if (this.OnDetectBrewDevice != null) + { + this.OnDetectBrewDevice(this, mda); + } + } + if (this.DetectDangerHiptop()) + { + mda = new MDetectArgs(dargsDangerHiptop); + if (this.OnDetectDangerHiptop != null) + { + this.OnDetectDangerHiptop(this, mda); + } + } + if (this.DetectOperaMobile()) + { + mda = new MDetectArgs(dargsOperaMobile); + if (this.OnDetectOperaMobile != null) + { + this.OnDetectOperaMobile(this, mda); + } + } + if (this.DetectWapWml()) + { + mda = new MDetectArgs(dargsWapWml); + if (this.OnDetectWapWml != null) + { + this.OnDetectWapWml(this, mda); + } + } + if (this.DetectKindle()) + { + mda = new MDetectArgs(dargsKindle); + if (this.OnDetectKindle != null) + { + this.OnDetectKindle(this, mda); + } + } + if (this.DetectMobileQuick()) + { + mda = new MDetectArgs(dargsMobileQuick); + if (this.OnDetectMobileQuick != null) + { + this.OnDetectMobileQuick(this, mda); + } + } + if (this.DetectTierTablet()) + { + mda = new MDetectArgs(dargsTierTablet); + if (this.OnDetectTierTablet != null) + { + this.OnDetectTierTablet(this, mda); + } + } + if (this.DetectTierIphone()) + { + mda = new MDetectArgs(dargsTierIphone); + if (this.OnDetectTierIphone != null) + { + this.OnDetectTierIphone(this, mda); + } + } + if (this.DetectTierRichCss()) + { + mda = new MDetectArgs(dargsTierRichCss); + if (this.OnDetectTierRichCss != null) + { + this.OnDetectTierRichCss(this, mda); + } + } + if (this.DetectTierOtherPhones()) + { + mda = new MDetectArgs(dargsTierOtherPhones); + if (this.OnDetectTierOtherPhones != null) + { + this.OnDetectTierOtherPhones(this, mda); + } + } + + #endregion Event Fire Methods + + } + + public class MDetectArgs : EventArgs + { + public MDetectArgs(string type) + { + this.Type = type; + } + + public readonly string Type; + } + + #region Mobile Device Detection Methods + + + //***************************** + // Start device detection + //***************************** + + //************************** + // Detects if the current device is an iPhone. + public bool DetectIphone() + { + if (useragent.IndexOf(deviceIphone)!= -1) + { + //The iPad and iPod touch say they're an iPhone! So let's disambiguate. + if (DetectIpad() || DetectIpod()) + { + return false; + } + else + return true; + } + else + return false; + } + //IPhone delegate + public delegate void DetectIphoneHandler(object page, MDetectArgs args); + public event DetectIphoneHandler OnDetectIphone; + + + //************************** + // Detects if the current device is an iPod Touch. + public bool DetectIpod() + { + if (useragent.IndexOf(deviceIpod)!= -1) + return true; + else + return false; + } + + //Ipod delegate + public delegate void DetectIpodHandler(object page, MDetectArgs args); + public event DetectIpodHandler OnDetectIpod; + + + //************************** + // Detects if the current device is an iPad tablet. + public bool DetectIpad() + { + if (useragent.IndexOf(deviceIpad) != -1 && DetectWebkit()) + return true; + else + return false; + } + + //Ipod delegate + public delegate void DetectIpadHandler(object page, MDetectArgs args); + public event DetectIpadHandler OnDetectIpad; + + + //************************** + // Detects if the current device is an iPhone or iPod Touch. + public bool DetectIphoneOrIpod() + { + //We repeat the searches here because some iPods may report themselves as an iPhone, which would be okay. + if (useragent.IndexOf(deviceIphone)!= -1 || + useragent.IndexOf(deviceIpod)!= -1) + return true; + else + return false; + } + //IPhoneOrIpod delegate + public delegate void DetectIPhoneOrIpodHandler(object page, MDetectArgs args); + public event DetectIPhoneOrIpodHandler OnDetectDetectIPhoneOrIpod; + + //************************** + // Detects *any* iOS device: iPhone, iPod Touch, iPad. + public bool DetectIos() + { + if (DetectIphoneOrIpod() || DetectIpad()) + return true; + else + return false; + } + + //Ios delegate + public delegate void DetectIosHandler(object page, MDetectArgs args); + public event DetectIosHandler OnDetectIos; + + + //************************** + // Detects *any* Android OS-based device: phone, tablet, and multi-media player. + // Also detects Google TV. + public bool DetectAndroid() + { + if ((useragent.IndexOf(deviceAndroid) != -1) || + DetectGoogleTV()) + return true; + + return false; + } + //Android delegate + public delegate void DetectAndroidHandler(object page, MDetectArgs args); + public event DetectAndroidHandler OnDetectAndroid; + + //************************** + // Detects if the current device is a (small-ish) Android OS-based device + // used for calling and/or multi-media (like a Samsung Galaxy Player). + // Google says these devices will have 'Android' AND 'mobile' in user agent. + // Ignores tablets (Honeycomb and later). + public bool DetectAndroidPhone() + { + //First, let's make sure we're on an Android device. + if (!DetectAndroid()) + return false; + + //If it's Android and has 'mobile' in it, Google says it's a phone. + if (useragent.IndexOf(mobile) != -1) + return true; + + //Special check for Android devices with Opera Mobile/Mini. They should report here. + if (DetectOperaMobile()) + return true; + + return false; + } + + //Android Phone delegate + public delegate void DetectAndroidPhoneHandler(object page, MDetectArgs args); + public event DetectAndroidPhoneHandler OnDetectAndroidPhone; + + //************************** + // Detects if the current device is a (self-reported) Android tablet. + // Google says these devices will have 'Android' and NOT 'mobile' in their user agent. + public bool DetectAndroidTablet() + { + //First, let's make sure we're on an Android device. + if (!DetectAndroid()) + return false; + + //Special check for Android devices with Opera Mobile/Mini. They should NOT report here. + if (DetectOperaMobile()) + return false; + + //Otherwise, if it's Android and does NOT have 'mobile' in it, Google says it's a tablet. + if (useragent.IndexOf(mobile) > -1) + return false; + else + return true; + } + + //Android Tablet delegate + public delegate void DetectAndroidTabletHandler(object page, MDetectArgs args); + public event DetectAndroidTabletHandler OnDetectAndroidTablet; + + //************************** + // Detects if the current device is a GoogleTV device. + public bool DetectGoogleTV() + { + if (useragent.IndexOf(deviceGoogleTV) != -1) + return true; + else + return false; + } + + //GoogleTV delegate + public delegate void DetectGoogleTVHandler(object page, MDetectArgs args); + public event DetectGoogleTVHandler OnDetectGoogleTV; + + //************************** + // Detects if the current device is an Android OS-based device and + // the browser is based on WebKit. + public bool DetectAndroidWebKit() + { + if (DetectAndroid() && DetectWebkit()) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is based on WebKit. + public bool DetectWebkit() + { + if (useragent.IndexOf(engineWebKit)!= -1) + return true; + else + return false; + } + + //Webkit delegate + public delegate void DetectWebkitHandler(object page, MDetectArgs args); + public event DetectWebkitHandler OnDetectWebkit; + + //************************** + // Detects if the current browser is the Nokia S60 Open Source Browser. + public bool DetectS60OssBrowser() + { + //First, test for WebKit, then make sure it's either Symbian or S60. + if (DetectWebkit()) + { + if (useragent.IndexOf(deviceSymbian)!= -1 || + useragent.IndexOf(deviceS60)!= -1) + { + return true; + } + else + return false; + } + else + return false; + } + + //S60OssBrowser delegate + public delegate void DetectS60OssBrowserHandler(object page, MDetectArgs args); + public event DetectS60OssBrowserHandler OnDetectS60OssBrowser; + + //************************** + // 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. + public bool DetectSymbianOS() + { + if (useragent.IndexOf(deviceSymbian)!= -1 || + useragent.IndexOf(deviceS60)!= -1 || + useragent.IndexOf(deviceS70)!= -1 || + useragent.IndexOf(deviceS80)!= -1 || + useragent.IndexOf(deviceS90)!= -1) + return true; + else + return false; + } + + //SymbianOS delegate + public delegate void DetectSymbianOSHandler(object page, MDetectArgs args); + public event DetectSymbianOSHandler OnDetectSymbianOS; + + + //************************** + // Detects if the current browser is a + // Windows Phone 7, 8, or 10 device. + public bool DetectWindowsPhone() + { + if (DetectWindowsPhone7() || + DetectWindowsPhone8() || + DetectWindowsPhone10()) + return true; + + return false; + } + + //WindowsPhone delegate + public delegate void DetectWindowsPhoneHandler(object page, MDetectArgs args); + public event DetectWindowsPhoneHandler OnDetectWindowsPhone; + + //************************** + // Detects if the current browser is a + // Windows Phone 7 device. + public bool DetectWindowsPhone7() + { + if (useragent.IndexOf(deviceWinPhone7) != -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a + // Windows Phone 8 device. + public bool DetectWindowsPhone8() + { + if (useragent.IndexOf(deviceWinPhone8) != -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a + // Windows Phone 10 device. + public bool DetectWindowsPhone10() + { + if (useragent.IndexOf(deviceWinPhone10) != -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a Windows Mobile device. + // Excludes Windows Phone devices. + // Focuses on Windows Mobile 6.xx and earlier. + public bool DetectWindowsMobile() + { + //Exclude new Windows Phone. + if (DetectWindowsPhone()) + return false; + //Most devices use 'Windows CE', but some report 'iemobile' + // and some older ones report as 'PIE' for Pocket IE. + if (useragent.IndexOf(deviceWinMob)!= -1 || + useragent.IndexOf(deviceIeMob)!= -1 || + useragent.IndexOf(enginePie) != -1) + return true; + //Test for Windows Mobile PPC but not old Macintosh PowerPC. + if (useragent.IndexOf(devicePpc) != -1 && + !(useragent.IndexOf(deviceMacPpc) != -1)) + return true; + //Test for certain Windwos Mobile-based HTC devices. + if (useragent.IndexOf(manuHtc) != -1 && + useragent.IndexOf(deviceWindows) != -1) + return true; + if (DetectWapWml() == true && + useragent.IndexOf(deviceWindows)!= -1) + return true; + else + return false; + } + + //WindowsMobile delegate + public delegate void DetectWindowsMobileHandler(object page, MDetectArgs args); + public event DetectWindowsMobileHandler OnDetectWindowsMobile; + + //************************** + // Detects if the current browser is any BlackBerry device. + // Includes the PlayBook. + public bool DetectBlackBerry() + { + if (useragent.IndexOf(deviceBB)!= -1) + return true; + if (httpaccept.IndexOf(vndRIM)!= -1) + return true; + else + return false; + } + //BlackBerry delegate + public delegate void DetectBlackBerryHandler(object page, MDetectArgs args); + public event DetectBlackBerryHandler OnDetectBlackBerry; + + //************************** + // Detects if the current browser is a BlackBerry 10 OS phone. + // Excludes tablets. + public bool DetectBlackBerry10Phone() + { + if (useragent.IndexOf(deviceBB10) != -1 && + useragent.IndexOf(mobile) != -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is on a BlackBerry tablet device. + // Example: PlayBook + public bool DetectBlackBerryTablet() + { + if (useragent.IndexOf(deviceBBPlaybook) != -1) + return true; + else + return false; + } + + + //************************** + // Detects if the current browser is a BlackBerry device AND uses a + // WebKit-based browser. These are signatures for the new BlackBerry OS 6. + // Examples: Torch. Includes the Playbook. + public bool DetectBlackBerryWebKit() + { + if (DetectBlackBerry() && DetectWebkit()) + return true; + else + return false; + } + //BlackBerry Webkit delegate + public delegate void DetectBlackBerryWebkitHandler(object page, MDetectArgs args); + public event DetectBlackBerryWebkitHandler OnDetectBlackBerryWebkit; + + + //************************** + // Detects if the current browser is a BlackBerry Touch + // device, such as the Storm, Torch, and Bold Touch. Excludes the Playbook. + public bool DetectBlackBerryTouch() + { + if (DetectBlackBerry() && + (useragent.IndexOf(deviceBBStorm) != -1 || + useragent.IndexOf(deviceBBTorch) != -1 || + useragent.IndexOf(deviceBBBoldTouch) != -1 || + useragent.IndexOf(deviceBBCurveTouch) != -1)) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a BlackBerry device AND + // has a more capable recent browser. Excludes the Playbook. + // Excludes the new BlackBerry OS 6 and 7 browser!! + public bool DetectBlackBerryHigh() + { + //Disambiguate for BlackBerry OS 6 or 7 (WebKit) browser + if (DetectBlackBerryWebKit()) + return false; + if (DetectBlackBerry()) + { + if (DetectBlackBerryTouch() || + useragent.IndexOf(deviceBBBold) != -1 || + useragent.IndexOf(deviceBBTour) != -1 || + useragent.IndexOf(deviceBBCurve) != -1) + return true; + else + return false; + } + else + return false; + } + + //************************** + // Detects if the current browser is a BlackBerry device AND + // has an older, less capable browser. + // Examples: Pearl, 8800, Curve1. + public bool DetectBlackBerryLow() + { + if (DetectBlackBerry()) + { + //Assume that if it's not in the High tier, then it's Low. + if (DetectBlackBerryHigh() || DetectBlackBerryWebKit()) + return false; + else + return true; + } + else + return false; + } + + + //************************** + // Detects if the current browser is on a PalmOS device. + public bool DetectPalmOS() + { + //Most devices nowadays report as 'Palm', but some older ones reported as Blazer or Xiino. + if (useragent.IndexOf(devicePalm) != -1 || + useragent.IndexOf(engineBlazer) != -1 || + useragent.IndexOf(engineXiino) != -1) + { + //Make sure it's not WebOS first + if (DetectPalmWebOS() == true) + return false; + else + return true; + } + else + return false; + } + //PalmOS delegate + public delegate void DetectPalmOSHandler(object page, MDetectArgs args); + public event DetectPalmOSHandler OnDetectPalmOS; + + + //************************** + // Detects if the current browser is on a Palm device + // running the new WebOS. + public bool DetectPalmWebOS() + { + if (useragent.IndexOf(deviceWebOS) != -1) + return true; + else + return false; + } + + //PalmWebOS delegate + public delegate void DetectPalmWebOSHandler(object page, MDetectArgs args); + public event DetectPalmWebOSHandler OnDetectPalmWebOS; + + + //************************** + // Detects if the current browser is on an HP tablet running WebOS. + public bool DetectWebOSTablet() + { + if (useragent.IndexOf(deviceWebOShp) != -1 && + useragent.IndexOf(deviceTablet) != -1) + { + return true; + } + else + return false; + } + //WebOS tablet delegate + public delegate void DetectWebOSTabletHandler(object page, MDetectArgs args); + public event DetectWebOSTabletHandler OnDetectWebOSTablet; + + + //************************** + // Detects if the current browser is on a WebOS smart TV. + public bool DetectWebOSTV() + { + if (useragent.IndexOf(deviceWebOStv) != -1 && + useragent.IndexOf(smartTV2) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects if the current browser is Opera Mobile or Mini. + public bool DetectOperaMobile() + { + if (useragent.IndexOf(engineOpera)!= -1) + { + if ((useragent.IndexOf(mini)!= -1) || + (useragent.IndexOf(mobi)!= -1)) + { + return true; + } + else + return false; + } + else + return false; + } + + //Opera Mobile delegate + public delegate void DetectOperaMobileHandler(object page, MDetectArgs args); + public event DetectOperaMobileHandler OnDetectOperaMobile; + + + //************************** + // Detects if the current browser is a + // Garmin Nuvifone. + public bool DetectGarminNuvifone() + { + if (useragent.IndexOf(deviceNuvifone) != -1) + return true; + else + return false; + } + + //************************** + // Detects a device running the Bada OS from Samsung. + public bool DetectBada() + { + if (useragent.IndexOf(deviceBada) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects a device running the Tizen smartphone OS. + public bool DetectTizen() + { + if (useragent.IndexOf(deviceTizen) != -1 && + useragent.IndexOf(mobile) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects if the current browser is on a Tizen smart TV. + public bool DetectTizenTV() + { + if (useragent.IndexOf(deviceTizen) != -1 && + useragent.IndexOf(smartTV1) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects a device running the Meego OS. + public bool DetectMeego() + { + if (useragent.IndexOf(deviceMeego) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects a phone running the Meego OS. + public bool DetectMeegoPhone() + { + if (useragent.IndexOf(deviceMeego) != -1 && + useragent.IndexOf(mobile) != -1) + { + return true; + } + else + return false; + } + + //************************** + // Detects a mobile device (probably) running the Firefox OS. + public bool DetectFirefoxOS() + { + if (DetectFirefoxOSPhone() || DetectFirefoxOSTablet()) + return true; + + return false; + } + + //************************** + // Detects a phone (probably) running the Firefox OS. + public bool DetectFirefoxOSPhone() + { + //First, let's make sure we're NOT on another major mobile OS. + if (DetectIos() || + DetectAndroid() || + DetectSailfish()) + return false; + + if ((useragent.IndexOf(engineFirefox) != -1) && + (useragent.IndexOf(mobile) != -1)) + return true; + + return false; + } + + //************************** + // Detects a tablet (probably) running the Firefox OS. + public bool DetectFirefoxOSTablet() + { + //First, let's make sure we're NOT on another major mobile OS. + if (DetectIos() || + DetectAndroid() || + DetectSailfish()) + return false; + + if ((useragent.IndexOf(engineFirefox) != -1) && + (useragent.IndexOf(deviceTablet) != -1)) + return true; + + return false; + } + + //************************** + // Detects a device running the Sailfish OS. + public bool DetectSailfish() + { + if (useragent.IndexOf(deviceSailfish) != -1) + return true; + else + return false; + } + + //************************** + // Detects a phone running the Sailfish OS. + public bool DetectSailfishPhone() + { + if (DetectSailfish() && + (useragent.IndexOf(mobile) != -1)) + return true; + + return false; + } + + //************************** + // Detects a mobile device running the Ubuntu Mobile OS. + public bool DetectUbuntu() + { + if (DetectUbuntuPhone() || DetectUbuntuTablet()) + return true; + + return false; + } + + //************************** + // Detects a phone running the Ubuntu Mobile OS. + public bool DetectUbuntuPhone() + { + if ((useragent.IndexOf(deviceUbuntu) != -1) && + (useragent.IndexOf(mobile) != -1)) + return true; + + return false; + } + + //************************** + // Detects a tablet running the Ubuntu Mobile OS. + public bool DetectUbuntuTablet() + { + if ((useragent.IndexOf(deviceUbuntu) != -1) && + (useragent.IndexOf(deviceTablet) != -1)) + return true; + + return false; + } + + //************************** + // Detects whether the device is a Brew-powered device. + public bool DetectBrewDevice() + { + if (useragent.IndexOf(deviceBrew)!= -1) + return true; + else + return false; + } + + //BrewDevice delegate + public delegate void DetectBrewDeviceHandler(object page, MDetectArgs args); + public event DetectBrewDeviceHandler OnDetectBrewDevice; + + //************************** + // Detects the Danger Hiptop device. + public bool DetectDangerHiptop() + { + if (useragent.IndexOf(deviceDanger)!= -1 || + useragent.IndexOf(deviceHiptop)!= -1) + return true; + else + return false; + } + //DangerHiptop delegate + public delegate void DetectDangerHiptopHandler(object page, MDetectArgs args); + public event DetectDangerHiptopHandler OnDetectDangerHiptop; + + //************************** + // Detects whether the device supports WAP or WML. + public bool DetectWapWml() + { + if (httpaccept.IndexOf(vndwap)!= -1 || + httpaccept.IndexOf(wml)!= -1) + return true; + else + return false; + } + //WapWml delegate + public delegate void DetectWapWmlHandler(object page, MDetectArgs args); + public event DetectWapWmlHandler OnDetectWapWml; + + + //************************** + // Detects if the current device is an Amazon Kindle (eInk devices only). + // Note: For the Kindle Fire, use the normal Android methods. + public bool DetectKindle() + { + if (useragent.IndexOf(deviceKindle) != -1 && + !DetectAndroid()) + return true; + else + return false; + } + + //Kindle delegate + public delegate void DetectKindleHandler(object page, MDetectArgs args); + public event DetectKindleHandler OnDetectKindle; + + + //************************** + // Detects if the current Amazon device is using the Silk Browser. + // Note: Typically used by the the Kindle Fire. + public bool DetectAmazonSilk() + { + if (useragent.IndexOf(engineSilk) != -1) + return true; + else + return false; + } + + + //************************** + // Detects if the current device is a Sony Playstation. + public bool DetectSonyPlaystation() + { + if (useragent.IndexOf(devicePlaystation)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a handheld gaming device with + // a touchscreen and modern iPhone-class browser. Includes the Playstation Vita. + public bool DetectGamingHandheld() + { + if (useragent.IndexOf(devicePlaystation)!= -1 && + useragent.IndexOf(devicePlaystationVita)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a Nintendo game device. + public bool DetectNintendo() + { + if (useragent.IndexOf(deviceNintendo)!= -1 || + useragent.IndexOf(deviceWii)!= -1 || + useragent.IndexOf(deviceNintendoDs)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a Microsoft Xbox. + public bool DetectXbox() + { + if (useragent.IndexOf(deviceXbox)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is an Internet-capable game console. + public bool DetectGameConsole() + { + if (DetectSonyPlaystation()) + return true; + else if (DetectNintendo()) + return true; + else if (DetectXbox()) + return true; + else + return false; + } + + //************************** + // Detects if the current device supports MIDP, a mobile Java technology. + public bool DetectMidpCapable() + { + if (useragent.IndexOf(deviceMidp)!= -1 || + httpaccept.IndexOf(deviceMidp)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current device is on one of the Maemo-based Nokia Internet Tablets. + public bool DetectMaemoTablet() + { + if (useragent.IndexOf(maemo) != -1) + return true; + //For Nokia N810, must be Linux + Tablet, or else it could be something else. + else if (useragent.IndexOf(linux) != -1 && + useragent.IndexOf(deviceTablet) != -1 && + !DetectWebOSTablet() && + !DetectAndroid()) + return true; + else + return false; + } + + //************************** + // Detects if the current device is an Archos media player/Internet tablet. + public bool DetectArchos() + { + if (useragent.IndexOf(deviceArchos)!= -1) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a Sony Mylo device. + public bool DetectSonyMylo() + { + if ((useragent.IndexOf(manuSony)!= -1) && + ((useragent.IndexOf(qtembedded)!= -1) || + (useragent.IndexOf(mylocom2)!= -1))) + return true; + + return false; + } + + + + //***************************** + // Device Classes + //***************************** + + //************************** + // Check to see whether the device is any device + // in the 'smartphone' category. + // Note: It's better to use DetectTierIphone() for modern touchscreen devices. + public bool DetectSmartphone() + { + if (DetectTierIphone() || + DetectS60OssBrowser() || + DetectSymbianOS() || + DetectWindowsMobile() || + DetectBlackBerry() || + DetectMeegoPhone() || + DetectPalmOS()) + return true; + else + return false; + } + + //DetectSmartphone delegate + public delegate void DetectSmartphoneHandler(object page, MDetectArgs args); + public event DetectSmartphoneHandler OnDetectSmartphone; + + //************************** + // Detects if the current device is a mobile device. + // This method catches most of the popular modern devices. + // Excludes Apple iPads and other modern tablets. + public bool DetectMobileQuick() + { + //Let's exclude tablets + if (DetectTierTablet()) + return false; + + //Most mobile browsing is done on smartphones + if (DetectSmartphone()) + return true; + + //Catch-all for many mobile devices + if (useragent.IndexOf(mobile) != -1) + return true; + + if (DetectOperaMobile()) + return true; + + //We also look for Kindle devices + if (DetectKindle() || + DetectAmazonSilk()) + return true; + + if (DetectWapWml() || + DetectMidpCapable() || + DetectBrewDevice()) + return true; + + if ((useragent.IndexOf(engineNetfront) != -1) || + (useragent.IndexOf(engineUpBrowser) != -1)) + return true; + + return false; + } + + //DetectMobileQuick delegate + public delegate void DetectMobileQuickHandler(object page, MDetectArgs args); + public event DetectMobileQuickHandler OnDetectMobileQuick; + + + //************************** + // The longer and more thorough way to detect for a mobile device. + // 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! + public bool DetectMobileLong() + { + if (DetectMobileQuick()) + return true; + + if (DetectGameConsole()) + return true; + + if (DetectDangerHiptop() || + DetectMaemoTablet() || + DetectSonyMylo() || + DetectArchos()) + return true; + + if ((useragent.IndexOf(devicePda) != -1) && + (useragent.IndexOf(disUpdate) != -1)) + return true; + + //Detect older phones from certain manufacturers and operators. + if ((useragent.IndexOf(uplink) != -1) || + (useragent.IndexOf(engineOpenWeb) != -1) || + (useragent.IndexOf(manuSamsung1) != -1) || + (useragent.IndexOf(manuSonyEricsson) != -1) || + (useragent.IndexOf(manuericsson) != -1) || + (useragent.IndexOf(svcDocomo) != -1) || + (useragent.IndexOf(svcKddi) != -1) || + (useragent.IndexOf(svcVodafone) != -1)) + return true; + + return false; + } + + + + //***************************** + // For Mobile Web Site Design + //***************************** + + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for the new generation of + // HTML 5 capable, larger screen tablets. + // Includes iPad, Android (e.g., Xoom), BB Playbook, WebOS, etc. + public bool DetectTierTablet() + { + if (DetectIpad() + || DetectAndroidTablet() + || DetectBlackBerryTablet() + || DetectFirefoxOSTablet() + || DetectUbuntuTablet() + || DetectWebOSTablet()) + return true; + else + return false; + } + + //DetectTierTablet delegate + public delegate void DetectTierTabletHandler(object page, MDetectArgs args); + public event DetectTierTabletHandler OnDetectTierTablet; + + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for devices which can + // display iPhone-optimized web content. + // Includes iPhone, iPod Touch, Android, Windows Phone, BB10, Playstation Vita, etc. + public bool DetectTierIphone() + { + if (DetectIphoneOrIpod() || + DetectAndroidPhone() || + DetectWindowsPhone() || + DetectBlackBerry10Phone() || + DetectPalmWebOS() || + DetectBada() || + DetectTizen() || + DetectFirefoxOSPhone() || + DetectSailfishPhone() || + DetectUbuntuPhone() || + DetectGamingHandheld()) + return true; + else + return false; + } + + //DetectTierIphone delegate + public delegate void DetectTierIphoneHandler(object page, MDetectArgs args); + public event DetectTierIphoneHandler OnDetectTierIphone; + + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for devices which are likely to be capable + // of viewing CSS content optimized for the iPhone, + // but may not necessarily support JavaScript. + // Excludes all iPhone Tier devices. + public bool DetectTierRichCss() + { + if (DetectMobileQuick()) + { + //Exclude iPhone Tier and e-Ink Kindle devices + if (DetectTierIphone() || DetectKindle()) + return false; + + if (DetectWebkit() || + DetectS60OssBrowser()) + return true; + + //Note: 'High' BlackBerry devices ONLY + if (DetectBlackBerryHigh() == true) + return true; + + //Older Windows 'Mobile' isn't good enough for iPhone Tier. + if (DetectWindowsMobile() == true) + return true; + if (useragent.IndexOf(engineTelecaQ) != -1) + return true; + + else + return false; + } + else + return false; + } + + //DetectTierRichCss delegate + public delegate void DetectTierRichCssHandler(object page, MDetectArgs args); + public event DetectTierRichCssHandler OnDetectTierRichCss; + + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for all other types of phones, + // but excludes the iPhone and Smartphone Tier devices. + public bool DetectTierOtherPhones() + { + if (DetectMobileLong() == true) + { + //Exclude devices in the other 2 categories + if (DetectTierIphone() || + DetectTierRichCss()) + return false; + else + return true; + } + else + return false; + } + + //DetectTierOtherPhones delegate + public delegate void DetectTierOtherPhonesHandler(object page, MDetectArgs args); + public event DetectTierOtherPhonesHandler OnDetectTierOtherPhones; + + //*************************************************************** + #endregion + + //Instead of overriding OnInit(), you can override InitializeCulture() + // so that detection can happen earlier in page's lifecycle, if necessary. + protected override void OnInit(EventArgs e) + { + base.OnInit(e); + + if (useragent == "" && httpaccept == "") + { + useragent = (Request.ServerVariables["HTTP_USER_AGENT"] ?? "").ToUpper(); + httpaccept = (Request.ServerVariables["HTTP_ACCEPT"] ?? "").ToUpper(); + } + + } +} diff --git a/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx new file mode 100755 index 00000000000..a0b14adbe9d --- /dev/null +++ b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx @@ -0,0 +1 @@ +<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MobileDetectControl.ascx.cs" Inherits="WebApplication1.MobileDetect.MobileDetectControl" %> diff --git a/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx.cs b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx.cs new file mode 100755 index 00000000000..42ae4319a9a --- /dev/null +++ b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace WebApplication1.MobileDetect +{ + public partial class MobileDetectControl : MDetectControl + { + protected void Page_Load(object sender, EventArgs e) + { + this.FireEvents(); + } + + + protected override void OnInit(EventArgs e) + { + base.OnInit(e); + + //As a test, let's listen for any WebKit-based device. + OnDetectWebkit += new DetectWebkitHandler(MobileDetectControl_OnDetectWebkit); + + } + + void MobileDetectControl_OnDetectWebkit(object page, MDetectControl.MDetectArgs args) + { + //Write the Type value from the argument to the web page. + Response.Write("<b>This browser is " + args.Type + "</b>"); + + } + } +} \ No newline at end of file diff --git a/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx.designer.cs b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx.designer.cs new file mode 100755 index 00000000000..2b700c811dc --- /dev/null +++ b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectControl.ascx.designer.cs @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:2.0.50727.42 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace WebApplication1.MobileDetect +{ + + + public partial class MobileDetectControl + { + } +} diff --git a/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx new file mode 100755 index 00000000000..54c01cb221e --- /dev/null +++ b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx @@ -0,0 +1,17 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="MobileDetectTestPage.aspx.cs" Inherits="WebApplication1.MobileDetect.MobileDetectTestPage" %> +<%@ Register TagPrefix="mdc" TagName="MobileDetect" Src="MobileDetectControl.ascx" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" > +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <div> + <mdc:MobileDetect id="MDC" runat="server"></mdc:MobileDetect> + </div> + </form> +</body> +</html> diff --git a/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx.cs b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx.cs new file mode 100755 index 00000000000..c65d3c883e1 --- /dev/null +++ b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace WebApplication1.MobileDetect +{ + public partial class MobileDetectTestPage : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + + } + } +} diff --git a/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx.designer.cs b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx.designer.cs new file mode 100755 index 00000000000..d7d2426ac27 --- /dev/null +++ b/vendor/ahand/mobileesp/ASP_NET/UserControl Technique/MobileDetectTestPage.aspx.designer.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:2.0.50727.3607 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace WebApplication1.MobileDetect { + + + public partial class MobileDetectTestPage { + + /// <summary> + /// form1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + + /// <summary> + /// MDC control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::WebApplication1.MobileDetect.MobileDetectControl MDC; + } +} diff --git a/vendor/ahand/mobileesp/Cpp/mdetect.h b/vendor/ahand/mobileesp/Cpp/mdetect.h new file mode 100755 index 00000000000..92f22fefc21 --- /dev/null +++ b/vendor/ahand/mobileesp/Cpp/mdetect.h @@ -0,0 +1,1312 @@ +/* ******************************************* +// Copyright 2010-2015, Anthony Hand +// +// +// File version 2015.05.13 (May 13, 2015) +// Updates: +// - Moved MobileESP to GitHub. https://github.com/ahand/mobileesp +// - Opera Mobile/Mini browser has the same UA string on multiple platforms and doesn't differentiate phone vs. tablet. +// - Removed DetectOperaAndroidPhone(). This method is no longer reliable. +// - Removed DetectOperaAndroidTablet(). This method is no longer reliable. +// - Added support for Windows Phone 10: variable and DetectWindowsPhone10() +// - Updated DetectWindowsPhone() to include WP10. +// - Added support for Firefox OS. +// - A variable plus DetectFirefoxOS(), DetectFirefoxOSPhone(), DetectFirefoxOSTablet() +// - NOTE: Firefox doesn't add UA tokens to definitively identify Firefox OS vs. their browsers on other mobile platforms. +// - Added support for Sailfish OS. Not enough info to add a tablet detection method at this time. +// - A variable plus DetectSailfish(), DetectSailfishPhone() +// - Added support for Ubuntu Mobile OS. +// - DetectUbuntu(), DetectUbuntuPhone(), DetectUbuntuTablet() +// - Added support for 2 smart TV OSes. They lack browsers but do have WebViews for use by HTML apps. +// - One variable for Samsung Tizen TVs, plus DetectTizenTV() +// - One variable for LG WebOS TVs, plus DetectWebOSTV() +// - Updated DetectTizen(). Now tests for “mobile†to disambiguate from Samsung Smart TVs +// - Removed variables for obsolete devices: deviceHtcFlyer, deviceXoom. +// - Updated DetectAndroid(). No longer has a special test case for the HTC Flyer tablet. +// - Updated DetectAndroidPhone(). +// - Updated internal detection code for Android. +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android and reports here if relevant. +// - Updated DetectAndroidTablet(). +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android to exclude it from here. +// - DetectMeego(): Changed definition for this method. Now detects any Meego OS device, not just phones. +// - DetectMeegoPhone(): NEW. For Meego phones. Ought to detect Opera browsers on Meego, as well. +// - DetectTierIphone(): Added support for phones running Sailfish, Ubuntu and Firefox Mobile. +// - DetectTierTablet(): Added support for tablets running Ubuntu and Firefox Mobile. +// - DetectSmartphone(): Added support for Meego phones. +// - Removed the variable for Obigo, an embedded browser. The browser is on old devices. +// - Couldn’t find info on current Obigo embedded browser user agent strings. +// - Refactored the detection logic in DetectMobileQuick() and DetectMobileLong(). +// - Moved a few detection tests for older browsers to Long. +// +// +// +// File version 2014.01.24 (January 24, 2014) +// Updates: +// - Ported to C++ by Kiran T. Based on the PHP library. +// +// +// +// LICENSE INFORMATION +// 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. +// +// +// ABOUT THIS PROJECT +// Project Owner: Anthony Hand +// Email: anthony.hand@gmail.com +// Web Site: http://www.mobileesp.com +// Source Files: https://github.com/ahand/mobileesp +// +// Versions of this code are available for: +// PHP, JavaScript, Java, ASP.NET (C#), C++, and Ruby +// +// ******************************************* +*/ +#ifndef MDETECT_H +#define MDETECT_H + +#include <string> +#include <algorithm> + +using namespace std; + +namespace MobileESP +{ + //Initialize some initial smartphone string variables. + const string engineWebKit = "webkit"; + + const string deviceIphone = "iphone"; + const string deviceIpod = "ipod"; + const string deviceIpad = "ipad"; + const string deviceMacPpc = "macintosh"; //Used for disambiguation + + const string deviceAndroid = "android"; + const string deviceGoogleTV = "googletv"; + const string deviceHtcFlyer = "htc_flyer"; //HTC Flyer + + const string deviceWinPhone7 = "windows phone os 7"; + const string deviceWinPhone8 = "windows phone 8"; + const string deviceWinPhone10 = "windows phone 10"; + const string deviceWinMob = "windows ce"; + const string deviceWindows = "windows"; + const string deviceIeMob = "iemobile"; + const string devicePpc = "ppc"; //Stands for PocketPC + const string enginePie = "wm5 pie"; //An old Windows Mobile + + const string deviceBB = "blackberry"; + const string deviceBB10 = "bb10"; //For the new BB 10 OS + const string vndRIM = "vnd.rim"; //Detectable when BB devices emulate IE or Firefox + const string deviceBBStorm = "blackberry95"; //Storm 1 and 2 + const string deviceBBBold = "blackberry97"; //Bold 97x0 (non-touch) + const string deviceBBBoldTouch = "blackberry 99"; //Bold 99x0 (touchscreen) + const string deviceBBTour = "blackberry96"; //Tour + const string deviceBBCurve = "blackberry89"; //Curve2 + const string deviceBBCurveTouch = "blackberry 938"; //Curve Touch + const string deviceBBTorch = "blackberry 98"; //Torch + const string deviceBBPlaybook = "playbook"; //PlayBook tablet + + const string deviceSymbian = "symbian"; + const string deviceS60 = "series60"; + const string deviceS70 = "series70"; + const string deviceS80 = "series80"; + const string deviceS90 = "series90"; + + const string devicePalm = "palm"; + const string deviceWebOS = "webos"; //For Palm devices + const string deviceWebOStv = "web0s"; //For LG TVs + const string deviceWebOShp = "hpwos"; //For HP's line of WebOS devices + + const string engineBlazer = "blazer"; //Old Palm browser + const string engineXiino = "xiino"; //Another old Palm + + const string deviceNuvifone = "nuvifone"; //Garmin Nuvifone + const string deviceBada = "bada"; //Samsung's Bada OS + const string deviceTizen = "tizen"; //Tizen OS + const string deviceMeego = "meego"; //Meego OS + const string deviceSailfish = "sailfish"; //Sailfish OS + const string deviceUbuntu = "ubuntu"; //Ubuntu Mobile OS + + const string deviceKindle = "kindle"; //Amazon Kindle, eInk one + const string engineSilk = "silk-accelerated"; //Amazon's accelerated Silk browser for Kindle Fire + + //Initialize variables for mobile-specific content. + const string vndwap = "vnd.wap"; + const string wml = "wml"; + + //Initialize variables for other random devices and mobile browsers. + const string deviceTablet = "tablet"; //Generic term for slate and tablet devices + const string deviceBrew = "brew"; + const string deviceDanger = "danger"; + const string deviceHiptop = "hiptop"; + const string devicePlaystation = "playstation"; + const string devicePlaystationVita = "vita"; + const string deviceNintendoDs = "nitro"; + const string deviceNintendo = "nintendo"; + const string deviceWii = "wii"; + const string deviceXbox = "xbox"; + const string deviceArchos = "archos"; + + const string engineFirefox = "firefox"; //For Firefox OS + const string engineOpera = "opera"; //Popular browser + const string engineNetfront = "netfront"; //Common embedded OS browser + const string engineUpBrowser = "up.browser"; //common on some phones + const string engineOpenWeb = "openweb"; //Transcoding by OpenWave server + const string deviceMidp = "midp"; //a mobile Java technology + const string uplink = "up.link"; + const string engineTelecaQ = "teleca q"; //a modern feature phone browser + + const string devicePda = "pda"; //some devices report themselves as PDAs + const string mini = "mini"; //Some mobile browsers put 'mini' in their names. + const string mobile = "mobile"; //Some mobile browsers put 'mobile' in their user agent strings. + const string mobi = "mobi"; //Some mobile browsers put 'mobi' in their user agent strings. + + //Smart TV strings + const string smartTV1 = "smart-tv"; //Samsung Tizen smart TVs + const string smartTV2 = "smarttv"; //LG WebOS smart TVs + + //Use Maemo, Tablet, and Linux to test for Nokia's Internet Tablets. + const string maemo = "maemo"; + const string llinux = "linux"; + const string qtembedded = "qt embedded"; //for Sony Mylo and others + const string mylocom2 = "com2"; //for Sony Mylo also + + //In some UserAgents, the only clue is the manufacturer. + const string manuSonyEricsson = "sonyericsson"; + const string manuericsson = "ericsson"; + const string manuSamsung1 = "sec-sgh"; + const string manuSony = "sony"; + const string manuHtc = "htc"; + + //In some UserAgents, the only clue is the operator. + const string svcDocomo = "docomo"; + const string svcKddi = "kddi"; + const string svcVodafone = "vodafone"; + + //Disambiguation strings. + const string disUpdate = "update"; //pda vs. update + +//************************** +// The uagent_info class encapsulates information about +// a browser's connection to your web site. +// You can use it to find out whether the browser asking for +// your site's content is probably running on a mobile device. +// The methods were written so you can be as granular as you want. +// For example, enquiring whether it's as specific as an iPod Touch or +// as general as a smartphone class device. +// The object's methods return 1 for true, or 0 for false. +class uagent_info +{ +private: + string useragent; + string httpaccept; + //Let's store values for quickly accessing the same info multiple times. InitCompleted + bool initCompleted; //Stores whether we're currently initializing the most popular functions. + bool isWebkit; //Stores the result of DetectWebkit() + bool isMobilePhone; //Stores the result of DetectMobileQuick() + bool isIphone; //Stores the result of DetectIphone() + bool isAndroid; //Stores the result of DetectAndroid() + bool isAndroidPhone; //Stores the result of DetectAndroidPhone() + bool isTierTablet; //Stores the result of DetectTierTablet() + bool isTierIphone; //Stores the result of DetectTierIphone() + bool isTierRichCss; //Stores the result of DetectTierRichCss() + bool isTierGenericMobile; //Stores the result of DetectTierOtherPhones() + + //************************** + // Initialize Key Stored Values. + void InitDeviceScan() + { + //Save these properties to speed processing + isWebkit = DetectWebkit(); + isIphone = DetectIphone(); + isAndroid = DetectAndroid(); + isAndroidPhone = DetectAndroidPhone(); + + //These tiers are the most useful for web development + isTierTablet = DetectTierTablet(); //Do first + isTierIphone = DetectTierIphone(); //Do second + isMobilePhone = DetectMobileQuick(); //Do third + + //Optional: Comment these out if you NEVER use them. + isTierRichCss = DetectTierRichCss(); + isTierGenericMobile = DetectTierOtherPhones(); + + initCompleted = true; + } + +public: + + //************************** + //The constructor. + uagent_info(const string &user_agent,const string &accept): + useragent(user_agent), + httpaccept(accept), + initCompleted(false), + isWebkit(false), + isMobilePhone(false), + isIphone(false), + isAndroid(false), + isAndroidPhone(false), + isTierTablet(false), + isTierIphone(false), + isTierRichCss(false), + isTierGenericMobile(false) + { + std::transform(useragent.begin(), useragent.end(),useragent.begin(), ::tolower); + std::transform(httpaccept.begin(), httpaccept.end(),httpaccept.begin(), ::tolower); + + //Let's initialize some values to save cycles later. + InitDeviceScan(); + } + + + + //************************** + //Returns the contents of the User Agent value, in lower case. + string Get_Uagent() + { + return useragent; + } + + //************************** + //Returns the contents of the HTTP Accept value, in lower case. + string Get_HttpAccept() + { + return httpaccept; + } + + + //************************** + // Detects if the current device is an iPhone. + bool DetectIphone() + { + if (initCompleted == true || + isIphone == true) + return isIphone; + + if (useragent.find( MobileESP::deviceIphone) != std::string::npos) + { + //The iPad and iPod Touch say they're an iPhone. So let's disambiguate. + if (DetectIpad() == true || + DetectIpod() == true) + return false; + //Yay! It's an iPhone! + else + return true; + } + else + return false; + } + + //************************** + // Detects if the current device is an iPod Touch. + bool DetectIpod() + { + if (useragent.find( MobileESP::deviceIpod) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if the current device is an iPad tablet. + bool DetectIpad() + { + if (useragent.find( MobileESP::deviceIpad) != std::string::npos && + DetectWebkit() == true) + return true; + else + return false; + } + + //************************** + // Detects if the current device is an iPhone or iPod Touch. + bool DetectIphoneOrIpod() + { + //We repeat the searches here because some iPods may report themselves as an iPhone, which would be okay. + if (DetectIphone() == true || + DetectIpod() == true) + return true; + else + return false; + } + + //************************** + // Detects *any* iOS device: iPhone, iPod Touch, iPad. + bool DetectIos() + { + if ((DetectIphoneOrIpod() == true) || + (DetectIpad() == true)) + return true; + else + return false; + } + + + //************************** + // Detects *any* Android OS-based device: phone, tablet, and multi-media player. + // Also detects Google TV. + bool DetectAndroid() + { + if (initCompleted == true || + isAndroid == true) + return isAndroid; + + if ((useragent.find( MobileESP::deviceAndroid) != std::string::npos) + || (DetectGoogleTV() == true)) + return true; + + return false; + } + + //************************** + // Detects if the current device is a (small-ish) Android OS-based device + // used for calling and/or multi-media (like a Samsung Galaxy Player). + // Google says these devices will have 'Android' AND 'mobile' in user agent. + // Ignores tablets (Honeycomb and later). + bool DetectAndroidPhone() + { + if (initCompleted == true || + isAndroidPhone == true) + return isAndroidPhone; + + //First, let's make sure we're on an Android device. + if (DetectAndroid() == false) + return false; + + //If it's Android and has 'mobile' in it, Google says it's a phone. + if (useragent.find( MobileESP::mobile) != std::string::npos) + return true; + + //Special check for Android devices with Opera Mobile/Mini. They should report here. + if ((DetectOperaMobile() == true)) + return true; + + return false; + } + + //************************** + // Detects if the current device is a (self-reported) Android tablet. + // Google says these devices will have 'Android' and NOT 'mobile' in their user agent. + bool DetectAndroidTablet() + { + //First, let's make sure we're on an Android device. + if (DetectAndroid() == false) + return false; + + //Special check for Android devices with Opera Mobile/Mini. They should NOT report here. + if (DetectOperaMobile() == true) + return false; + + //Otherwise, if it's Android and does NOT have 'mobile' in it, Google says it's a tablet. + if (useragent.find( MobileESP::mobile) != std::string::npos) + return false; + + return true; + } + + //************************** + // Detects if the current device is an Android OS-based device and + // the browser is based on WebKit. + bool DetectAndroidWebKit() + { + if ((DetectAndroid() == true) && + (DetectWebkit() == true)) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a GoogleTV. + bool DetectGoogleTV() + { + if (useragent.find( MobileESP::deviceGoogleTV) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is based on WebKit. + bool DetectWebkit() + { + if (initCompleted == true || + isWebkit == true) + return isWebkit; + + if (useragent.find( MobileESP::engineWebKit) != std::string::npos) + return true; + else + return false; + } + + + //************************** + // Detects if the current browser is a + // Windows Phone 7, 8, or 10 device. + bool DetectWindowsPhone() + { + if ((DetectWindowsPhone7() == true) + || (DetectWindowsPhone8() == true) + || (DetectWindowsPhone10() == true)) + return true; + else + return false; + } + + //************************** + // Detects a Windows Phone 7 device (in mobile browsing mode). + bool DetectWindowsPhone7() + { + if (useragent.find( MobileESP::deviceWinPhone7) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects a Windows Phone 8 device (in mobile browsing mode). + bool DetectWindowsPhone8() + { + if (useragent.find( MobileESP::deviceWinPhone8) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects a Windows Phone 10 device (in mobile browsing mode). + bool DetectWindowsPhone10() + { + if (useragent.find( MobileESP::deviceWinPhone10) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a Windows Mobile device. + // Excludes Windows Phone 7 and later devices. + // Focuses on Windows Mobile 6.xx and earlier. + bool DetectWindowsMobile() + { + if (DetectWindowsPhone() == true) + return false; + + //Most devices use 'Windows CE', but some report 'iemobile' + // and some older ones report as 'PIE' for Pocket IE. + if (useragent.find( MobileESP::deviceWinMob) != std::string::npos || + useragent.find( MobileESP::deviceIeMob) != std::string::npos || + useragent.find( MobileESP::enginePie) != std::string::npos) + return true; + //Test for Windows Mobile PPC but not old Macintosh PowerPC. + if (useragent.find( MobileESP::devicePpc) != std::string::npos + && !(useragent.find( MobileESP::deviceMacPpc) > 1)) + return true; + //Test for certain Windwos Mobile-based HTC devices. + if (useragent.find( MobileESP::manuHtc) != std::string::npos && + useragent.find( MobileESP::deviceWindows) != std::string::npos) + return true; + if (DetectWapWml() == true && + useragent.find( MobileESP::deviceWindows) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is any BlackBerry device. + // Includes BB10 OS, but excludes the PlayBook. + bool DetectBlackBerry() + { + if ((useragent.find( MobileESP::deviceBB) != std::string::npos) || + (httpaccept.find( MobileESP::vndRIM) != std::string::npos)) + return true; + if (DetectBlackBerry10Phone() == true) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a BlackBerry 10 OS phone. + // Excludes tablets. + bool DetectBlackBerry10Phone() + { + if ((useragent.find( MobileESP::deviceBB10) != std::string::npos) && + (useragent.find( MobileESP::mobile) != std::string::npos)) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is on a BlackBerry tablet device. + // Examples: PlayBook + bool DetectBlackBerryTablet() + { + if ((useragent.find( MobileESP::deviceBBPlaybook) != std::string::npos)) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a BlackBerry phone device AND uses a + // WebKit-based browser. These are signatures for the new BlackBerry OS 6. + // Examples: Torch. Includes the Playbook. + bool DetectBlackBerryWebKit() + { + if ((DetectBlackBerry() == true) && + (DetectWebkit() == true)) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a BlackBerry Touch phone device with + // a large screen, such as the Storm, Torch, and Bold Touch. Excludes the Playbook. + bool DetectBlackBerryTouch() + { + if ((useragent.find( MobileESP::deviceBBStorm) != std::string::npos) || + (useragent.find( MobileESP::deviceBBTorch) != std::string::npos) || + (useragent.find( MobileESP::deviceBBBoldTouch) != std::string::npos) || + (useragent.find( MobileESP::deviceBBCurveTouch) != std::string::npos)) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a BlackBerry OS 5 device AND + // has a more capable recent browser. Excludes the Playbook. + // Examples, Storm, Bold, Tour, Curve2 + // Excludes the new BlackBerry OS 6 and 7 browser!! + bool DetectBlackBerryHigh() + { + //Disambiguate for BlackBerry OS 6 or 7 (WebKit) browser + if (DetectBlackBerryWebKit() == true) + return false; + if (DetectBlackBerry() == true) + { + if ((DetectBlackBerryTouch() == true) || + useragent.find( MobileESP::deviceBBBold) != std::string::npos || + useragent.find( MobileESP::deviceBBTour) != std::string::npos || + useragent.find( MobileESP::deviceBBCurve) != std::string::npos) + { + return true; + } + else + return false; + } + else + return false; + } + + //************************** + // Detects if the current browser is a BlackBerry device AND + // has an older, less capable browser. + // Examples: Pearl, 8800, Curve1. + bool DetectBlackBerryLow() + { + if (DetectBlackBerry() == true) + { + //Assume that if it's not in the High tier, then it's Low. + if ((DetectBlackBerryHigh() == true) || + (DetectBlackBerryWebKit() == true)) + return false; + else + return true; + } + else + return false; + } + + + //************************** + // Detects if the current browser is the Nokia S60 Open Source Browser. + bool DetectS60OssBrowser() + { + //First, test for WebKit, then make sure it's either Symbian or S60. + if (DetectWebkit() == true) + { + if (useragent.find( MobileESP::deviceSymbian) != std::string::npos || + useragent.find( MobileESP::deviceS60) != std::string::npos) + { + return true; + } + else + return false; + } + else + 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. + bool DetectSymbianOS() + { + if (useragent.find( MobileESP::deviceSymbian) != std::string::npos || + useragent.find( MobileESP::deviceS60) != std::string::npos || + useragent.find( MobileESP::deviceS70) != std::string::npos || + useragent.find( MobileESP::deviceS80) != std::string::npos || + useragent.find( MobileESP::deviceS90) != std::string::npos) + return true; + else + return false; + } + + + //************************** + // Detects if the current browser is on a PalmOS device. + bool DetectPalmOS() + { + //Make sure it's not WebOS first + if (DetectPalmWebOS() == true) + return false; + + //Most devices nowadays report as 'Palm', but some older ones reported as Blazer or Xiino. + if (useragent.find( MobileESP::devicePalm) != std::string::npos || + useragent.find( MobileESP::engineBlazer) != std::string::npos || + useragent.find( MobileESP::engineXiino) != std::string::npos) + return true; + else + return false; + } + + + //************************** + // Detects if the current browser is on a Palm device + // running the new WebOS. + bool DetectPalmWebOS() + { + if (useragent.find( MobileESP::deviceWebOS) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is on an HP tablet running WebOS. + bool DetectWebOSTablet() + { + if ((useragent.find( MobileESP::deviceWebOShp) != std::string::npos) + && (useragent.find( MobileESP::deviceTablet) != std::string::npos)) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is on a WebOS smart TV. + bool DetectWebOSTV() + { + if ((useragent.find( MobileESP::deviceWebOStv) != std::string::npos) + && (useragent.find( MobileESP::smartTV2) != std::string::npos)) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is Opera Mobile or Mini. + bool DetectOperaMobile() + { + if (useragent.find( MobileESP::engineOpera) != std::string::npos) + { + if ((useragent.find( MobileESP::mini) != std::string::npos) || + (useragent.find( MobileESP::mobi) != std::string::npos)) + return true; + else + return false; + } + else + return false; + } + + //************************** + // Detects if the current device is an Amazon Kindle (eInk devices only). + // Note: For the Kindle Fire, use the normal Android methods. + bool DetectKindle() + { + if (useragent.find( MobileESP::deviceKindle) != std::string::npos && + DetectAndroid() == false) + return true; + else + return false; + } + + //************************** + // Detects if the current Amazon device has turned on the Silk accelerated browsing feature. + // Note: Typically used by the the Kindle Fire. + bool DetectAmazonSilk() + { + if (useragent.find( MobileESP::engineSilk) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if a Garmin Nuvifone device. + bool DetectGarminNuvifone() + { + if (useragent.find( MobileESP::deviceNuvifone) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects a device running the Bada smartphone OS from Samsung. + bool DetectBada() + { + if (useragent.find( MobileESP::deviceBada) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects a device running the Tizen smartphone OS. + bool DetectTizen() + { + if ((useragent.find( MobileESP::deviceTizen) != std::string::npos) + && (useragent.find( MobileESP::mobile) != std::string::npos)) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is on a Tizen smart TV. + bool DetectTizenTV() + { + if ((useragent.find( MobileESP::deviceTizen) != std::string::npos) + && (useragent.find( MobileESP::smartTV1) != std::string::npos)) + return true; + else + return false; + } + + //************************** + // Detects a device running the Meego OS. + bool DetectMeego() + { + if (useragent.find( MobileESP::deviceMeego) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects a phone running the Meego OS. + bool DetectMeegoPhone() + { + if ((useragent.find( MobileESP::deviceMeego) != std::string::npos) + && (useragent.find( MobileESP::mobi) != std::string::npos)) + return true; + else + return false; + } + + //************************** + // Detects a mobile device (probably) running the Firefox OS. + bool DetectFirefoxOS() + { + if ((DetectFirefoxOSPhone() == true) || DetectFirefoxOSTablet()) + return true; + + return false; + } + + //************************** + // Detects a phone (probably) running the Firefox OS. + bool DetectFirefoxOSPhone() + { + //First, let's make sure we're NOT on another major mobile OS. + if (DetectIos() || + DetectAndroid() || + DetectSailfish()) + return false; + + if ((useragent.find( MobileESP::engineFirefox) != std::string::npos) && + (useragent.find( MobileESP::mobile) != std::string::npos)) + return true; + + return false; + } + + //************************** + // Detects a tablet (probably) running the Firefox OS. + bool DetectFirefoxOSTablet() + { + //First, let's make sure we're NOT on another major mobile OS. + if (DetectIos() || + DetectAndroid() || + DetectSailfish()) + return false; + + if ((useragent.find( MobileESP::engineFirefox) != std::string::npos) && + (useragent.find( MobileESP::deviceTablet) != std::string::npos)) + return true; + + return false; + } + + //************************** + // Detects a device running the Sailfish OS. + bool DetectSailfish() + { + if (useragent.find( MobileESP::deviceSailfish) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects a phone running the Sailfish OS. + bool DetectSailfishPhone() + { + if ((DetectSailfish() == true) && + (useragent.find( MobileESP::mobile) != std::string::npos)) + return true; + + return false; + } + + //************************** + // Detects a mobile device running the Ubuntu Mobile OS. + bool DetectUbuntu() + { + if ((DetectUbuntuPhone() == true) || DetectUbuntuTablet() == true) + return true; + + return false; + } + + //************************** + // Detects a phone running the Ubuntu Mobile OS. + bool DetectUbuntuPhone() + { + if ((useragent.find( MobileESP::deviceUbuntu) != std::string::npos) && + (useragent.find( MobileESP::mobile) != std::string::npos)) + return true; + + return false; + } + + //************************** + // Detects a tablet running the Ubuntu Mobile OS. + bool DetectUbuntuTablet() + { + if ((useragent.find( MobileESP::deviceUbuntu) != std::string::npos) && + (useragent.find( MobileESP::deviceTablet) != std::string::npos)) + return true; + + return false; + } + + //************************** + // Detects the Danger Hiptop device. + bool DetectDangerHiptop() + { + if (useragent.find( MobileESP::deviceDanger) != std::string::npos || + useragent.find( MobileESP::deviceHiptop) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if the current browser is a Sony Mylo device. + bool DetectSonyMylo() + { + if ((useragent.find( MobileESP::manuSony) != std::string::npos) && + ((useragent.find( MobileESP::qtembedded) != std::string::npos) || + (useragent.find( MobileESP::mylocom2) != std::string::npos))) + return true; + else + return false; + } + + //************************** + // Detects if the current device is on one of the Maemo-based Nokia Internet Tablets. + bool DetectMaemoTablet() + { + if (useragent.find( MobileESP::maemo) != std::string::npos) + return true; + //For Nokia N810, must be Linux + Tablet, or else it could be something else. + if ((useragent.find( MobileESP::llinux) != std::string::npos) + && (useragent.find( MobileESP::deviceTablet) != std::string::npos) + && (DetectWebOSTablet() == false) + && (DetectAndroid() == false)) + return true; + else + return false; + } + + //************************** + // Detects if the current device is an Archos media player/Internet tablet. + bool DetectArchos() + { + if (useragent.find( MobileESP::deviceArchos) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if the current device is an Internet-capable game console. + // Includes many handheld consoles. + bool DetectGameConsole() + { + if ((DetectSonyPlaystation() == true) || + (DetectNintendo() == true) || + (DetectXbox() == true)) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a Sony Playstation. + bool DetectSonyPlaystation() + { + if (useragent.find( MobileESP::devicePlaystation) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a handheld gaming device with + // a touchscreen and modern iPhone-class browser. Includes the Playstation Vita. + bool DetectGamingHandheld() + { + if ((useragent.find( MobileESP::devicePlaystation) != std::string::npos) && + (useragent.find( MobileESP::devicePlaystationVita) != std::string::npos)) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a Nintendo game device. + bool DetectNintendo() + { + if (useragent.find( MobileESP::deviceNintendo) != std::string::npos || + useragent.find( MobileESP::deviceWii) != std::string::npos || + useragent.find( MobileESP::deviceNintendoDs) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if the current device is a Microsoft Xbox. + bool DetectXbox() + { + if (useragent.find( MobileESP::deviceXbox) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects whether the device is a Brew-powered device. + bool DetectBrewDevice() + { + if (useragent.find( MobileESP::deviceBrew) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects whether the device supports WAP or WML. + bool DetectWapWml() + { + if (httpaccept.find( MobileESP::vndwap) != std::string::npos || + httpaccept.find( MobileESP::wml) != std::string::npos) + return true; + else + return false; + } + + //************************** + // Detects if the current device supports MIDP, a mobile Java technology. + bool DetectMidpCapable() + { + if (useragent.find( MobileESP::deviceMidp) != std::string::npos || + httpaccept.find( MobileESP::deviceMidp) != std::string::npos) + return true; + else + return false; + } + + + + //***************************** + // Device Classes + //***************************** + + //************************** + // Check to see whether the device is *any* 'smartphone'. + // Note: It's better to use DetectTierIphone() for modern touchscreen devices. + bool DetectSmartphone() + { + //Exclude duplicates from TierIphone + if ((DetectTierIphone() == true) + || (DetectS60OssBrowser() == true) + || (DetectSymbianOS() == true) + || (DetectWindowsMobile() == true) + || (DetectBlackBerry() == true) + || (DetectMeegoPhone() == true) + || (DetectPalmWebOS() == true)) + return true; + else + return false; + } + + //************************** + // The quick way to detect for a mobile device. + // Will probably detect most recent/current mid-tier Feature Phones + // as well as smartphone-class devices. Excludes Apple iPads and other modern tablets. + bool DetectMobileQuick() + { + if (initCompleted == true || + isMobilePhone == true) + return isMobilePhone; + + //Let's exclude tablets + if (isTierTablet == true) + return false; + + //Most mobile browsing is done on smartphones + if (DetectSmartphone() == true) + return true; + + //Catch-all for many mobile devices + if (useragent.find( MobileESP::mobile) != std::string::npos) + return true; + + if (DetectOperaMobile() == true) + return true; + + //We also look for Kindle devices + if (DetectKindle() == true || + DetectAmazonSilk() == true) + return true; + + if ((DetectWapWml() == true) + || (DetectMidpCapable() == true) + || (DetectBrewDevice() == true)) + return true; + + if ((useragent.find( MobileESP::engineNetfront) != std::string::npos) + || (useragent.find( MobileESP::engineUpBrowser) != std::string::npos)) + return true; + + else + return false; + } + + //************************** + // The longer and more thorough way to detect for a mobile device. + // 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! + bool DetectMobileLong() + { + if (DetectMobileQuick() == true) + return true; + if (DetectGameConsole() == true) + return true; + + if ((DetectDangerHiptop() == true) + || (DetectMaemoTablet() == true) + || (DetectSonyMylo() == true) + || (DetectArchos() == true)) + return true; + + if ((useragent.find( MobileESP::devicePda) != std::string::npos) && + !(useragent.find( MobileESP::disUpdate) != std::string::npos)) + return true; + + //Detect older phones from certain manufacturers and operators. + if ((useragent.find( MobileESP::uplink) != std::string::npos) + || (useragent.find( MobileESP::engineOpenWeb) != std::string::npos) + || (useragent.find( MobileESP::manuSamsung1) != std::string::npos) + || (useragent.find( MobileESP::manuSonyEricsson) != std::string::npos) + || (useragent.find( MobileESP::manuericsson) != std::string::npos) + || (useragent.find( MobileESP::svcDocomo) != std::string::npos) + || (useragent.find( MobileESP::svcKddi) != std::string::npos) + || (useragent.find( MobileESP::svcVodafone) != std::string::npos)) + return true; + + return false; + } + + + //***************************** + // For Mobile Web Site Design + //***************************** + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for the new generation of + // HTML 5 capable, larger screen tablets. + // Includes iPad, Android (e.g., Xoom), BB Playbook, WebOS, etc. + bool DetectTierTablet() + { + if (initCompleted == true || + isTierTablet == true) + return isTierTablet; + + if ((DetectIpad() == true) + || (DetectAndroidTablet() == true) + || (DetectBlackBerryTablet() == true) + || (DetectFirefoxOSTablet() == true) + || (DetectUbuntuTablet() == true) + || (DetectWebOSTablet() == true)) + return true; + else + return false; + } + + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for devices which can + // display iPhone-optimized web content. + // Includes iPhone, iPod Touch, Android, Windows Phone 7 and 8, BB10, WebOS, Playstation Vita, etc. + bool DetectTierIphone() + { + if (initCompleted == true || + isTierIphone == true) + return isTierIphone; + + if ((DetectIphoneOrIpod() == true) + || (DetectAndroidPhone() == true) + || (DetectWindowsPhone() == true) + || (DetectBlackBerry10Phone() == true) + || (DetectPalmWebOS() == true) + || (DetectBada() == true) + || (DetectTizen() == true) + || (DetectFirefoxOSPhone() == true) + || (DetectSailfishPhone() == true) + || (DetectUbuntuPhone() == true) + || (DetectGamingHandheld() == true)) + return true; + + //Note: BB10 phone is in the previous paragraph + if ((DetectBlackBerryWebKit() == true) && + (DetectBlackBerryTouch() == true)) + return true; + + else + return false; + } + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for devices which are likely to be capable + // of viewing CSS content optimized for the iPhone, + // but may not necessarily support JavaScript. + // Excludes all iPhone Tier devices. + bool DetectTierRichCss() + { + if (initCompleted == true || + isTierRichCss == true) + return isTierRichCss; + + if (DetectMobileQuick() == true) + { + //Exclude iPhone Tier and e-Ink Kindle devices + if ((DetectTierIphone() == true) || + (DetectKindle() == true)) + return false; + + //The following devices are explicitly ok. + if (DetectWebkit() == true) //Any WebKit + return true; + if (DetectS60OssBrowser() == true) + return true; + + //Note: 'High' BlackBerry devices ONLY + if (DetectBlackBerryHigh() == true) + return true; + + //Older Windows 'Mobile' isn't good enough for iPhone Tier. + if (DetectWindowsMobile() == true) + return true; + if (useragent.find( MobileESP::engineTelecaQ) != std::string::npos) + return true; + + //default + else + return false; + } + else + return false; + } + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for all other types of phones, + // but excludes the iPhone and RichCSS Tier devices. + bool DetectTierOtherPhones() + { + if (initCompleted == true || + isTierGenericMobile == true) + return isTierGenericMobile; + + //Exclude devices in the other 2 categories + if ((DetectMobileLong() == true) + && (DetectTierIphone() == false) + && (DetectTierRichCss() == false)) + return true; + else + return false; + } +}; + +} + +/* Example code * +#include <iostream> +#include "mdetect.h" + +int main(int argc, char** argv) +{ + int ret = 0; + if(argc < 3) { + std::cout << "Usage is mdetect [user agent string] [Accept string]" << std::endl; + } else { + MobileESP::uagent_info usageInfo(argv[1],argv[2]); + if(true == usageInfo.DetectMobileQuick()) { + std::cout << "Passed in user agent is from a mobile browser" << std::endl; + } else { + std::cout << "Passed in user agent is *NOT* from a mobile browser" << std::endl; + } + } + return ret; +} + +*/ +#endif //MDETECT_H diff --git a/vendor/ahand/mobileesp/Java/UAgentInfo.java b/vendor/ahand/mobileesp/Java/UAgentInfo.java new file mode 100755 index 00000000000..e4dd0f7f361 --- /dev/null +++ b/vendor/ahand/mobileesp/Java/UAgentInfo.java @@ -0,0 +1,1305 @@ +/* ******************************************* +// Copyright 2010-2015, Anthony Hand +// +// +// File version 2015.05.13 (May 13, 2015) +// Updates: +// - Moved MobileESP to GitHub. https://github.com/ahand/mobileesp +// - Opera Mobile/Mini browser has the same UA string on multiple platforms and doesn't differentiate phone vs. tablet. +// - Removed DetectOperaAndroidPhone(). This method is no longer reliable. +// - Removed DetectOperaAndroidTablet(). This method is no longer reliable. +// - Added support for Windows Phone 10: variable and DetectWindowsPhone10() +// - Updated DetectWindowsPhone() to include WP10. +// - Added support for Firefox OS. +// - A variable plus DetectFirefoxOS(), DetectFirefoxOSPhone(), DetectFirefoxOSTablet() +// - NOTE: Firefox doesn't add UA tokens to definitively identify Firefox OS vs. their browsers on other mobile platforms. +// - Added support for Sailfish OS. Not enough info to add a tablet detection method at this time. +// - A variable plus DetectSailfish(), DetectSailfishPhone() +// - Added support for Ubuntu Mobile OS. +// - DetectUbuntu(), DetectUbuntuPhone(), DetectUbuntuTablet() +// - Added support for 2 smart TV OSes. They lack browsers but do have WebViews for use by HTML apps. +// - One variable for Samsung Tizen TVs, plus DetectTizenTV() +// - One variable for LG WebOS TVs, plus DetectWebOSTV() +// - Updated DetectTizen(). Now tests for "mobile" to disambiguate from Samsung Smart TVs +// - Removed variables for obsolete devices: deviceHtcFlyer, deviceXoom. +// - Updated DetectAndroid(). No longer has a special test case for the HTC Flyer tablet. +// - Updated DetectAndroidPhone(). +// - Updated internal detection code for Android. +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android and reports here if relevant. +// - Updated DetectAndroidTablet(). +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android to exclude it from here. +// - DetectMeego(): Changed definition for this method. Now detects any Meego OS device, not just phones. +// - DetectMeegoPhone(): NEW. For Meego phones. Ought to detect Opera browsers on Meego, as well. +// - DetectTierIphone(): Added support for phones running Sailfish, Ubuntu and Firefox Mobile. +// - DetectTierTablet(): Added support for tablets running Ubuntu and Firefox Mobile. +// - DetectSmartphone(): Added support for Meego phones. +// - Refactored the detection logic in DetectMobileQuick() and DetectMobileLong(). +// - Moved a few detection tests for older browsers to Long. +// +// +// +// LICENSE INFORMATION +// 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. +// +// +// ABOUT THIS PROJECT +// Project Owner: Anthony Hand +// Email: anthony.hand@gmail.com +// Web Site: http://www.mobileesp.com +// Source Files: https://github.com/ahand/mobileesp +// +// Versions of this code are available for: +// PHP, JavaScript, Java, ASP.NET (C#), and Ruby +// +// ******************************************* + */ +package com.handinteractive.mobile; + +/** + * The DetectSmartPhone class encapsulates information about + * a browser's connection to your web site. + * You can use it to find out whether the browser asking for + * your site's content is probably running on a mobile device. + * The methods were written so you can be as granular as you want. + * For example, enquiring whether it's as specific as an iPod Touch or + * as general as a smartphone class device. + * The object's methods return true, or false. + */ +public class UAgentInfo { + // User-Agent and Accept HTTP request headers + + private String userAgent = ""; + private String httpAccept = ""; + + // Let's store values for quickly accessing the same info multiple times. + public boolean initCompleted = false; + public boolean isWebkit = false; //Stores the result of DetectWebkit() + public boolean isMobilePhone = false; //Stores the result of DetectMobileQuick() + public boolean isIphone = false; //Stores the result of DetectIphone() + public boolean isAndroid = false; //Stores the result of DetectAndroid() + public boolean isAndroidPhone = false; //Stores the result of DetectAndroidPhone() + public boolean isTierTablet = false; //Stores the result of DetectTierTablet() + public boolean isTierIphone = false; //Stores the result of DetectTierIphone() + public boolean isTierRichCss = false; //Stores the result of DetectTierRichCss() + public boolean isTierGenericMobile = false; //Stores the result of DetectTierOtherPhones() + + // Initialize some initial smartphone string variables. + public static final String engineWebKit = "webkit"; + + public static final String deviceIphone = "iphone"; + public static final String deviceIpod = "ipod"; + public static final String deviceIpad = "ipad"; + public static final String deviceMacPpc = "macintosh"; //Used for disambiguation + + public static final String deviceAndroid = "android"; + public static final String deviceGoogleTV = "googletv"; + + public static final String deviceWinPhone7 = "windows phone os 7"; + public static final String deviceWinPhone8 = "windows phone 8"; + public static final String deviceWinPhone10 = "windows phone 10"; + public static final String deviceWinMob = "windows ce"; + public static final String deviceWindows = "windows"; + public static final String deviceIeMob = "iemobile"; + public static final String devicePpc = "ppc"; //Stands for PocketPC + public static final String enginePie = "wm5 pie"; //An old Windows Mobile + + public static final String deviceBB = "blackberry"; + public static final String deviceBB10 = "bb10"; //For the new BB 10 OS + public static final String vndRIM = "vnd.rim"; //Detectable when BB devices emulate IE or Firefox + public static final String deviceBBStorm = "blackberry95"; //Storm 1 and 2 + public static final String deviceBBBold = "blackberry97"; //Bold 97x0 (non-touch) + public static final String deviceBBBoldTouch = "blackberry 99"; //Bold 99x0 (touchscreen) + public static final String deviceBBTour = "blackberry96"; //Tour + public static final String deviceBBCurve = "blackberry89"; //Curve 2 + public static final String deviceBBCurveTouch = "blackberry 938"; //Curve Touch 9380 + public static final String deviceBBTorch = "blackberry 98"; //Torch + public static final String deviceBBPlaybook = "playbook"; //PlayBook tablet + + public static final String deviceSymbian = "symbian"; + public static final String deviceS60 = "series60"; + public static final String deviceS70 = "series70"; + public static final String deviceS80 = "series80"; + public static final String deviceS90 = "series90"; + + public static final String devicePalm = "palm"; + public static final String deviceWebOS = "webos"; //For Palm devices + public static final String deviceWebOStv = "web0s"; //For LG TVs + public static final String deviceWebOShp = "hpwos"; //For HP's line of WebOS devices + + public static final String deviceNuvifone = "nuvifone"; //Garmin Nuvifone + public static final String deviceBada = "bada"; //Samsung's Bada OS + public static final String deviceTizen = "tizen"; //Tizen OS + public static final String deviceMeego = "meego"; //Meego OS + public static final String deviceSailfish = "sailfish"; //Sailfish OS + public static final String deviceUbuntu = "ubuntu"; //Ubuntu Mobile OS + + public static final String deviceKindle = "kindle"; //Amazon Kindle, eInk one + public static final String engineSilk = "silk-accelerated"; //Amazon's accelerated Silk browser for Kindle Fire + + public static final String engineBlazer = "blazer"; //Old Palm + public static final String engineXiino = "xiino"; //Another old Palm + + //Initialize variables for mobile-specific content. + public static final String vndwap = "vnd.wap"; + public static final String wml = "wml"; + + //Initialize variables for other random devices and mobile browsers. + public static final String deviceTablet = "tablet"; //Generic term for slate and tablet devices + public static final String deviceBrew = "brew"; + public static final String deviceDanger = "danger"; + public static final String deviceHiptop = "hiptop"; + public static final String devicePlaystation = "playstation"; + public static final String devicePlaystationVita = "vita"; + public static final String deviceNintendoDs = "nitro"; + public static final String deviceNintendo = "nintendo"; + public static final String deviceWii = "wii"; + public static final String deviceXbox = "xbox"; + public static final String deviceArchos = "archos"; + + public static final String engineFirefox = "firefox"; //For Firefox OS + public static final String engineOpera = "opera"; //Popular browser + public static final String engineNetfront = "netfront"; //Common embedded OS browser + public static final String engineUpBrowser = "up.browser"; //common on some phones + public static final String engineOpenWeb = "openweb"; //Transcoding by OpenWave server + public static final String deviceMidp = "midp"; //a mobile Java technology + public static final String uplink = "up.link"; + public static final String engineTelecaQ = "teleca q"; //a modern feature phone browser + public static final String devicePda = "pda"; //some devices report themselves as PDAs + public static final String mini = "mini"; //Some mobile browsers put "mini" in their names. + public static final String mobile = "mobile"; //Some mobile browsers put "mobile" in their user agent strings. + public static final String mobi = "mobi"; //Some mobile browsers put "mobi" in their user agent strings. + + //Smart TV strings + public static final String smartTV1 = "smart-tv"; //Samsung Tizen smart TVs + public static final String smartTV2 = "smarttv"; //LG WebOS smart TVs + + //Use Maemo, Tablet, and Linux to test for Nokia"s Internet Tablets. + public static final String maemo = "maemo"; + public static final String linux = "linux"; + public static final String qtembedded = "qt embedded"; //for Sony Mylo + public static final String mylocom2 = "com2"; //for Sony Mylo also + + //In some UserAgents, the only clue is the manufacturer. + public static final String manuSonyEricsson = "sonyericsson"; + public static final String manuericsson = "ericsson"; + public static final String manuSamsung1 = "sec-sgh"; + public static final String manuSony = "sony"; + public static final String manuHtc = "htc"; //Popular Android and WinMo manufacturer + + //In some UserAgents, the only clue is the operator. + public static final String svcDocomo = "docomo"; + public static final String svcKddi = "kddi"; + public static final String svcVodafone = "vodafone"; + + //Disambiguation strings. + public static final String disUpdate = "update"; //pda vs. update + + + /** + * Initialize the userAgent and httpAccept variables + * + * @param userAgent the User-Agent header + * @param httpAccept the Accept header + */ + public UAgentInfo(String userAgent, String httpAccept) { + if (userAgent != null) { + this.userAgent = userAgent.toLowerCase(); + } + if (httpAccept != null) { + this.httpAccept = httpAccept.toLowerCase(); + } + + //Intialize key stored values. + initDeviceScan(); + } + + /** + * Return the lower case HTTP_USER_AGENT + * @return userAgent + */ + public String getUserAgent() { + return userAgent; + } + + /** + * Return the lower case HTTP_ACCEPT + * @return httpAccept + */ + public String getHttpAccept() { + return httpAccept; + } + + /** + * Return whether the device is an Iphone or iPod Touch + * @return isIphone + */ + public boolean getIsIphone() { + return isIphone; + } + + /** + * Return whether the device is in the Tablet Tier. + * @return isTierTablet + */ + public boolean getIsTierTablet() { + return isTierTablet; + } + + /** + * Return whether the device is in the Iphone Tier. + * @return isTierIphone + */ + public boolean getIsTierIphone() { + return isTierIphone; + } + + /** + * Return whether the device is in the 'Rich CSS' tier of mobile devices. + * @return isTierRichCss + */ + public boolean getIsTierRichCss() { + return isTierRichCss; + } + + /** + * Return whether the device is a generic, less-capable mobile device. + * @return isTierGenericMobile + */ + public boolean getIsTierGenericMobile() { + return isTierGenericMobile; + } + + /** + * Initialize Key Stored Values. + */ + public void initDeviceScan() { + //Save these properties to speed processing + this.isWebkit = detectWebkit(); + this.isIphone = detectIphone(); + this.isAndroid = detectAndroid(); + this.isAndroidPhone = detectAndroidPhone(); + + //Generally, these tiers are the most useful for web development + this.isMobilePhone = detectMobileQuick(); + this.isTierTablet = detectTierTablet(); + this.isTierIphone = detectTierIphone(); + + //Optional: Comment these out if you NEVER use them + this.isTierRichCss = detectTierRichCss(); + this.isTierGenericMobile = detectTierOtherPhones(); + + this.initCompleted = true; + } + + /** + * Detects if the current device is an iPhone. + * @return detection of an iPhone + */ + public boolean detectIphone() { + // The iPad and iPod touch say they're an iPhone! So let's disambiguate. + if (userAgent.indexOf(deviceIphone) != -1 && + !detectIpad() && + !detectIpod()) { + return true; + } + return false; + } + + /** + * Detects if the current device is an iPod Touch. + * @return detection of an iPod Touch + */ + public boolean detectIpod() { + if (userAgent.indexOf(deviceIpod) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current device is an iPad tablet. + * @return detection of an iPad + */ + public boolean detectIpad() { + if (userAgent.indexOf(deviceIpad) != -1 + && detectWebkit()) { + return true; + } + return false; + } + + /** + * Detects if the current device is an iPhone or iPod Touch. + * @return detection of an iPhone or iPod Touch + */ + public boolean detectIphoneOrIpod() { + //We repeat the searches here because some iPods may report themselves as an iPhone, which would be okay. + if (userAgent.indexOf(deviceIphone) != -1 + || userAgent.indexOf(deviceIpod) != -1) { + return true; + } + return false; + } + + /** + * Detects *any* iOS device: iPhone, iPod Touch, iPad. + * @return detection of an Apple iOS device + */ + public boolean detectIos() { + if (detectIphoneOrIpod() || detectIpad()) { + return true; + } + return false; + } + + + /** + * Detects *any* Android OS-based device: phone, tablet, and multi-media player. + * Also detects Google TV. + * @return detection of an Android device + */ + public boolean detectAndroid() { + if ((userAgent.indexOf(deviceAndroid) != -1) || + detectGoogleTV()) + return true; + + return false; + } + + /** + * Detects if the current device is a (small-ish) Android OS-based device + * used for calling and/or multi-media (like a Samsung Galaxy Player). + * Google says these devices will have 'Android' AND 'mobile' in user agent. + * Ignores tablets (Honeycomb and later). + * @return detection of an Android phone + */ + public boolean detectAndroidPhone() { + //First, let's make sure we're on an Android device. + if (!detectAndroid()) + return false; + + //If it's Android and has 'mobile' in it, Google says it's a phone. + if (userAgent.indexOf(mobile) != -1) + return true; + + //Special check for Android devices with Opera Mobile/Mini. They should report here. + if (detectOperaMobile()) + return true; + + return false; + } + + /** + * Detects if the current device is a (self-reported) Android tablet. + * Google says these devices will have 'Android' and NOT 'mobile' in their user agent. + * @return detection of an Android tablet + */ + public boolean detectAndroidTablet() { + //First, let's make sure we're on an Android device. + if (!detectAndroid()) + return false; + + //Special check for Android devices with Opera Mobile/Mini. They should NOT report here. + if (detectOperaMobile()) + return false; + + //Otherwise, if it's Android and does NOT have 'mobile' in it, Google says it's a tablet. + if ((userAgent.indexOf(mobile) > -1)) + return false; + else + return true; + } + + /** + * Detects if the current device is an Android OS-based device and + * the browser is based on WebKit. + * @return detection of an Android WebKit browser + */ + public boolean detectAndroidWebKit() { + if (detectAndroid() && detectWebkit()) { + return true; + } + return false; + } + + /** + * Detects if the current device is a GoogleTV. + * @return detection of GoogleTV + */ + public boolean detectGoogleTV() { + if (userAgent.indexOf(deviceGoogleTV) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is based on WebKit. + * @return detection of a WebKit browser + */ + public boolean detectWebkit() { + if (userAgent.indexOf(engineWebKit) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is the Symbian S60 Open Source Browser. + * @return detection of Symbian S60 Browser + */ + public boolean detectS60OssBrowser() { + //First, test for WebKit, then make sure it's either Symbian or S60. + if (detectWebkit() + && (userAgent.indexOf(deviceSymbian) != -1 + || userAgent.indexOf(deviceS60) != -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. + * @return detection of SymbianOS + */ + public boolean detectSymbianOS() { + if (userAgent.indexOf(deviceSymbian) != -1 + || userAgent.indexOf(deviceS60) != -1 + || userAgent.indexOf(deviceS70) != -1 + || userAgent.indexOf(deviceS80) != -1 + || userAgent.indexOf(deviceS90) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is a Windows Phone 7.x, 8, or 10 device + * @return detection of Windows Phone 7.x OR 8 + */ + public boolean detectWindowsPhone() { + if (detectWindowsPhone7() + || detectWindowsPhone8() + || detectWindowsPhone10()) { + return true; + } + return false; + } + + /** + * Detects a Windows Phone 7 device (in mobile browsing mode). + * @return detection of Windows Phone 7 + */ + public boolean detectWindowsPhone7() { + if (userAgent.indexOf(deviceWinPhone7) != -1) { + return true; + } + return false; + } + + /** + * Detects a Windows Phone 8 device (in mobile browsing mode). + * @return detection of Windows Phone 8 + */ + public boolean detectWindowsPhone8() { + if (userAgent.indexOf(deviceWinPhone8) != -1) { + return true; + } + return false; + } + + /** + * Detects a Windows Phone 10 device (in mobile browsing mode). + * @return detection of Windows Phone 10 + */ + public boolean detectWindowsPhone10() { + if (userAgent.indexOf(deviceWinPhone10) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is a Windows Mobile device. + * Excludes Windows Phone 7.x and 8 devices. + * Focuses on Windows Mobile 6.xx and earlier. + * @return detection of Windows Mobile + */ + public boolean detectWindowsMobile() { + if (detectWindowsPhone()) { + return false; + } + //Most devices use 'Windows CE', but some report 'iemobile' + // and some older ones report as 'PIE' for Pocket IE. + // We also look for instances of HTC and Windows for many of their WinMo devices. + if (userAgent.indexOf(deviceWinMob) != -1 + || userAgent.indexOf(deviceWinMob) != -1 + || userAgent.indexOf(deviceIeMob) != -1 + || userAgent.indexOf(enginePie) != -1 + || (userAgent.indexOf(manuHtc) != -1 && userAgent.indexOf(deviceWindows) != -1) + || (detectWapWml() && userAgent.indexOf(deviceWindows) != -1)) { + return true; + } + + //Test for Windows Mobile PPC but not old Macintosh PowerPC. + if (userAgent.indexOf(devicePpc) != -1 && + !(userAgent.indexOf(deviceMacPpc) != -1)) + return true; + + return false; + } + + /** + * Detects if the current browser is any BlackBerry. + * Includes BB10 OS, but excludes the PlayBook. + * @return detection of Blackberry + */ + public boolean detectBlackBerry() { + if (userAgent.indexOf(deviceBB) != -1 || + httpAccept.indexOf(vndRIM) != -1) + return true; + + if (detectBlackBerry10Phone()) + return true; + + return false; + } + + /** + * Detects if the current browser is a BlackBerry 10 OS phone. + * Excludes tablets. + * @return detection of a Blackberry 10 device + */ + public boolean detectBlackBerry10Phone() { + if (userAgent.indexOf(deviceBB10) != -1 && + userAgent.indexOf(mobile) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is on a BlackBerry tablet device. + * Example: PlayBook + * @return detection of a Blackberry Tablet + */ + public boolean detectBlackBerryTablet() { + if (userAgent.indexOf(deviceBBPlaybook) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is a BlackBerry device AND uses a + * WebKit-based browser. These are signatures for the new BlackBerry OS 6. + * Examples: Torch. Includes the Playbook. + * @return detection of a Blackberry device with WebKit browser + */ + public boolean detectBlackBerryWebKit() { + if (detectBlackBerry() && + userAgent.indexOf(engineWebKit) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is a BlackBerry Touch + * device, such as the Storm, Torch, and Bold Touch. Excludes the Playbook. + * @return detection of a Blackberry touchscreen device + */ + public boolean detectBlackBerryTouch() { + if (detectBlackBerry() && + (userAgent.indexOf(deviceBBStorm) != -1 || + userAgent.indexOf(deviceBBTorch) != -1 || + userAgent.indexOf(deviceBBBoldTouch) != -1 || + userAgent.indexOf(deviceBBCurveTouch) != -1 )) { + return true; + } + return false; + } + + /** + * Detects if the current browser is a BlackBerry device AND + * has a more capable recent browser. Excludes the Playbook. + * Examples, Storm, Bold, Tour, Curve2 + * Excludes the new BlackBerry OS 6 and 7 browser!! + * @return detection of a Blackberry device with a better browser + */ + public boolean detectBlackBerryHigh() { + //Disambiguate for BlackBerry OS 6 or 7 (WebKit) browser + if (detectBlackBerryWebKit()) + return false; + if (detectBlackBerry()) { + if (detectBlackBerryTouch() + || userAgent.indexOf(deviceBBBold) != -1 + || userAgent.indexOf(deviceBBTour) != -1 + || userAgent.indexOf(deviceBBCurve) != -1) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + /** + * Detects if the current browser is a BlackBerry device AND + * has an older, less capable browser. + * Examples: Pearl, 8800, Curve1 + * @return detection of a Blackberry device with a poorer browser + */ + public boolean detectBlackBerryLow() { + if (detectBlackBerry()) { + //Assume that if it's not in the High tier, then it's Low + if (detectBlackBerryHigh() + || detectBlackBerryWebKit()) { + return false; + } else { + return true; + } + } else { + return false; + } + } + + /** + * Detects if the current browser is on a PalmOS device. + * @return detection of a PalmOS device + */ + public boolean detectPalmOS() { + //Most devices nowadays report as 'Palm', but some older ones reported as Blazer or Xiino. + if (userAgent.indexOf(devicePalm) != -1 + || userAgent.indexOf(engineBlazer) != -1 + || userAgent.indexOf(engineXiino) != -1) { + //Make sure it's not WebOS first + if (detectPalmWebOS()) { + return false; + } else { + return true; + } + } + return false; + } + + /** + * Detects if the current browser is on a Palm device + * running the new WebOS. + * @return detection of a Palm WebOS device + */ + public boolean detectPalmWebOS() { + if (userAgent.indexOf(deviceWebOS) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is on an HP tablet running WebOS. + * @return detection of an HP WebOS tablet + */ + public boolean detectWebOSTablet() { + if (userAgent.indexOf(deviceWebOShp) != -1 && + userAgent.indexOf(deviceTablet) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is on a WebOS smart TV. + * @return detection of a WebOS smart TV + */ + public boolean detectWebOSTV() { + if (userAgent.indexOf(deviceWebOStv) != -1 && + userAgent.indexOf(smartTV2) != -1) { + return true; + } + return false; + } + + /** + * Detects Opera Mobile or Opera Mini. + * @return detection of an Opera browser for a mobile device + */ + public boolean detectOperaMobile() { + if (userAgent.indexOf(engineOpera) != -1 + && (userAgent.indexOf(mini) != -1 + || userAgent.indexOf(mobi) != -1)) { + return true; + } + return false; + } + + /** + * Detects if the current device is an Amazon Kindle (eInk devices only). + * Note: For the Kindle Fire, use the normal Android methods. + * @return detection of a Kindle + */ + public boolean detectKindle() { + if (userAgent.indexOf(deviceKindle)!= -1 && + !detectAndroid()) { + return true; + } + return false; + } + + /** + * Detects if the current Amazon device is using the Silk Browser. + * Note: Typically used by the the Kindle Fire. + * @return detection of an Amazon Kindle Fire in Silk mode. + */ + public boolean detectAmazonSilk() { + if (userAgent.indexOf(engineSilk) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is a + * Garmin Nuvifone. + * @return detection of a Garmin Nuvifone + */ + public boolean detectGarminNuvifone() { + if (userAgent.indexOf(deviceNuvifone) != -1) { + return true; + } + return false; + } + + /** + * Detects a device running the Bada OS from Samsung. + * @return detection of a Bada device + */ + public boolean detectBada() { + if (userAgent.indexOf(deviceBada) != -1) { + return true; + } + return false; + } + + /** + * Detects a device running the Tizen smartphone OS. + * @return detection of a Tizen device + */ + public boolean detectTizen() { + if (userAgent.indexOf(deviceTizen) != -1 && + userAgent.indexOf(mobile) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is on a Tizen smart TV. + * @return detection of a Tizen smart TV + */ + public boolean detectTizenTV() { + if (userAgent.indexOf(deviceTizen) != -1 && + userAgent.indexOf(smartTV1) != -1) { + return true; + } + return false; + } + + /** + * Detects a device running the Meego OS. + * @return detection of a Meego device + */ + public boolean detectMeego() { + if (userAgent.indexOf(deviceMeego) != -1) { + return true; + } + return false; + } + + /** + * Detects a phone running the Meego OS. + * @return detection of a Meego phone + */ + public boolean detectMeegoPhone() { + if (userAgent.indexOf(deviceMeego) != -1 && + userAgent.indexOf(mobi) != -1) { + return true; + } + return false; + } + + /** + * Detects a mobile device (probably) running the Firefox OS. + * @return detection of a Firefox OS mobile device + */ + public boolean detectFirefoxOS() { + if (detectFirefoxOSPhone() || detectFirefoxOSTablet()) + return true; + + return false; + } + + /** + * Detects a phone (probably) running the Firefox OS. + * @return detection of a Firefox OS phone + */ + public boolean detectFirefoxOSPhone() { + //First, let's make sure we're NOT on another major mobile OS. + if (detectIos() + || detectAndroid() + || detectSailfish()) + return false; + + if ((userAgent.indexOf(engineFirefox) != -1) + && (userAgent.indexOf(mobile) != -1)) + return true; + + return false; + } + + /** + * Detects a tablet (probably) running the Firefox OS. + * @return detection of a Firefox OS tablet + */ + public boolean detectFirefoxOSTablet() { + //First, let's make sure we're NOT on another major mobile OS. + if (detectIos() + || detectAndroid() + || detectSailfish()) + return false; + + if ((userAgent.indexOf(engineFirefox) != -1) + && (userAgent.indexOf(deviceTablet) != -1)) + return true; + + return false; + } + + /** + * Detects a device running the Sailfish OS. + * @return detection of a Sailfish device + */ + public boolean detectSailfish() { + if (userAgent.indexOf(deviceSailfish) != -1) { + return true; + } + return false; + } + + /** + * Detects a phone running the Sailfish OS. + * @return detection of a Sailfish phone + */ + public boolean detectSailfishPhone() { + if (detectSailfish() && (userAgent.indexOf(mobile) != -1)) + return true; + + return false; + } + + /** + * Detects a mobile device running the Ubuntu Mobile OS. + * @return detection of an Ubuntu Mobile OS mobile device + */ + public boolean detectUbuntu() { + if (detectUbuntuPhone() || detectUbuntuTablet()) + return true; + + return false; + } + + /** + * Detects a phone running the Ubuntu Mobile OS. + * @return detection of an Ubuntu Mobile OS phone + */ + public boolean detectUbuntuPhone() { + if ((userAgent.indexOf(deviceUbuntu) != -1) + && (userAgent.indexOf(mobile) != -1)) + return true; + + return false; + } + + /** + * Detects a tablet running the Ubuntu Mobile OS. + * @return detection of an Ubuntu Mobile OS tablet + */ + public boolean detectUbuntuTablet() { + if ((userAgent.indexOf(deviceUbuntu) != -1) + && (userAgent.indexOf(deviceTablet) != -1)) + return true; + + return false; + } + + + /** + * Detects the Danger Hiptop device. + * @return detection of a Danger Hiptop + */ + public boolean detectDangerHiptop() { + if (userAgent.indexOf(deviceDanger) != -1 + || userAgent.indexOf(deviceHiptop) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current browser is a Sony Mylo device. + * @return detection of a Sony Mylo device + */ + public boolean detectSonyMylo() { + if (userAgent.indexOf(manuSony) != -1 + && (userAgent.indexOf(qtembedded) != -1 + || userAgent.indexOf(mylocom2) != -1)) { + return true; + } + return false; + } + + /** + * Detects if the current device is on one of the Maemo-based Nokia Internet Tablets. + * @return detection of a Maemo OS tablet + */ + public boolean detectMaemoTablet() { + if (userAgent.indexOf(maemo) != -1) { + return true; + } else if (userAgent.indexOf(linux) != -1 + && userAgent.indexOf(deviceTablet) != -1 + && !detectWebOSTablet() + && !detectAndroid()) { + return true; + } + return false; + } + + /** + * Detects if the current device is an Archos media player/Internet tablet. + * @return detection of an Archos media player + */ + public boolean detectArchos() { + if (userAgent.indexOf(deviceArchos) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current device is an Internet-capable game console. + * Includes many handheld consoles. + * @return detection of any Game Console + */ + public boolean detectGameConsole() { + if (detectSonyPlaystation() + || detectNintendo() + || detectXbox()) { + return true; + } + return false; + } + + /** + * Detects if the current device is a Sony Playstation. + * @return detection of Sony Playstation + */ + public boolean detectSonyPlaystation() { + if (userAgent.indexOf(devicePlaystation) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current device is a handheld gaming device with + * a touchscreen and modern iPhone-class browser. Includes the Playstation Vita. + * @return detection of a handheld gaming device + */ + public boolean detectGamingHandheld() { + if ((userAgent.indexOf(devicePlaystation) != -1) && + (userAgent.indexOf(devicePlaystationVita) != -1)) { + return true; + } + return false; + } + + /** + * Detects if the current device is a Nintendo game device. + * @return detection of Nintendo + */ + public boolean detectNintendo() { + if (userAgent.indexOf(deviceNintendo) != -1 + || userAgent.indexOf(deviceWii) != -1 + || userAgent.indexOf(deviceNintendoDs) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current device is a Microsoft Xbox. + * @return detection of Xbox + */ + public boolean detectXbox() { + if (userAgent.indexOf(deviceXbox) != -1) { + return true; + } + return false; + } + + /** + * Detects whether the device is a Brew-powered device. + * @return detection of a Brew device + */ + public boolean detectBrewDevice() { + if (userAgent.indexOf(deviceBrew) != -1) { + return true; + } + return false; + } + + /** + * Detects whether the device supports WAP or WML. + * @return detection of a WAP- or WML-capable device + */ + public boolean detectWapWml() { + if (httpAccept.indexOf(vndwap) != -1 + || httpAccept.indexOf(wml) != -1) { + return true; + } + return false; + } + + /** + * Detects if the current device supports MIDP, a mobile Java technology. + * @return detection of a MIDP mobile Java-capable device + */ + public boolean detectMidpCapable() { + if (userAgent.indexOf(deviceMidp) != -1 + || httpAccept.indexOf(deviceMidp) != -1) { + return true; + } + return false; + } + + + + //***************************** + // Device Classes + //***************************** + + /** + * Check to see whether the device is any device + * in the 'smartphone' category. + * @return detection of a general smartphone device + */ + public boolean detectSmartphone() { + //Exclude duplicates from TierIphone + return (detectTierIphone() + || detectS60OssBrowser() + || detectSymbianOS() + || detectWindowsMobile() + || detectBlackBerry() + || detectMeegoPhone() + || detectPalmOS()); + } + + /** + * Detects if the current device is a mobile device. + * This method catches most of the popular modern devices. + * Excludes Apple iPads and other modern tablets. + * @return detection of any mobile device using the quicker method + */ + public boolean detectMobileQuick() { + //Let's exclude tablets + if (isTierTablet) { + return false; + } + //Most mobile browsing is done on smartphones + if (detectSmartphone()) { + return true; + } + + //Catch-all for many mobile devices + if (userAgent.indexOf(mobile) != -1) { + return true; + } + + if (detectOperaMobile()) { + return true; + } + + //We also look for Kindle devices + if (detectKindle() + || detectAmazonSilk()) { + return true; + } + + if (detectWapWml() + || detectMidpCapable() + || detectBrewDevice()) { + return true; + } + + if ((userAgent.indexOf(engineNetfront) != -1) + || (userAgent.indexOf(engineUpBrowser) != -1)) { + return true; + } + + return false; + } + + /** + * The longer and more thorough way to detect for a mobile device. + * 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! + * @return detection of any mobile device using the more thorough method + */ + public boolean detectMobileLong() { + if (detectMobileQuick() + || detectGameConsole()) { + return true; + } + + if (detectDangerHiptop() + || detectMaemoTablet() + || detectSonyMylo() + || detectArchos()) { + return true; + } + + if ((userAgent.indexOf(devicePda) != -1) && + (userAgent.indexOf(disUpdate) < 0)) //no index found + { + return true; + } + + //Detect older phones from certain manufacturers and operators. + if ((userAgent.indexOf(uplink) != -1) + || (userAgent.indexOf(engineOpenWeb) != -1) + || (userAgent.indexOf(manuSamsung1) != -1) + || (userAgent.indexOf(manuSonyEricsson) != -1) + || (userAgent.indexOf(manuericsson) != -1) + || (userAgent.indexOf(svcDocomo) != -1) + || (userAgent.indexOf(svcKddi) != -1) + || (userAgent.indexOf(svcVodafone) != -1)) + { + return true; + } + + return false; + } + + //***************************** + // For Mobile Web Site Design + //***************************** + + /** + * The quick way to detect for a tier of devices. + * This method detects for the new generation of + * HTML 5 capable, larger screen tablets. + * Includes iPad, Android (e.g., Xoom), BB Playbook, WebOS, etc. + * @return detection of any device in the Tablet Tier + */ + public boolean detectTierTablet() { + if (detectIpad() + || detectAndroidTablet() + || detectBlackBerryTablet() + || detectFirefoxOSTablet() + || detectUbuntuTablet() + || detectWebOSTablet()) { + return true; + } + return false; + } + + /** + * The quick way to detect for a tier of devices. + * This method detects for devices which can + * display iPhone-optimized web content. + * Includes iPhone, iPod Touch, Android, Windows Phone 7 and 8, BB10, WebOS, Playstation Vita, etc. + * @return detection of any device in the iPhone/Android/Windows Phone/BlackBerry/WebOS Tier + */ + public boolean detectTierIphone() { + if (detectIphoneOrIpod() + || detectAndroidPhone() + || detectWindowsPhone() + || detectBlackBerry10Phone() + || (detectBlackBerryWebKit() + && detectBlackBerryTouch()) + || detectPalmWebOS() + || detectBada() + || detectTizen() + || detectFirefoxOSPhone() + || detectSailfishPhone() + || detectUbuntuPhone() + || detectGamingHandheld()) { + return true; + } + return false; + } + + /** + * The quick way to detect for a tier of devices. + * This method detects for devices which are likely to be capable + * of viewing CSS content optimized for the iPhone, + * but may not necessarily support JavaScript. + * Excludes all iPhone Tier devices. + * @return detection of any device in the 'Rich CSS' Tier + */ + public boolean detectTierRichCss() { + boolean result = false; + //The following devices are explicitly ok. + //Note: 'High' BlackBerry devices ONLY + if (detectMobileQuick()) { + + //Exclude iPhone Tier and e-Ink Kindle devices. + if (!detectTierIphone() && !detectKindle()) { + + //The following devices are explicitly ok. + //Note: 'High' BlackBerry devices ONLY + //Older Windows 'Mobile' isn't good enough for iPhone Tier. + if (detectWebkit() + || detectS60OssBrowser() + || detectBlackBerryHigh() + || detectWindowsMobile() + || userAgent.indexOf(engineTelecaQ) != -1) { + result= true; + } // if detectWebkit() + } //if !detectTierIphone() + } //if detectMobileQuick() + return result; + } + + /** + * The quick way to detect for a tier of devices. + * This method detects for all other types of phones, + * but excludes the iPhone and RichCSS Tier devices. + * @return detection of a mobile device in the less capable tier + */ + public boolean detectTierOtherPhones() { + //Exclude devices in the other 2 categories + if (detectMobileLong() + && !detectTierIphone() + && !detectTierRichCss()) { + return true; + } + return false; + } +} diff --git a/vendor/ahand/mobileesp/JavaScript/mdetect.js b/vendor/ahand/mobileesp/JavaScript/mdetect.js new file mode 100755 index 00000000000..d7a3a1360e3 --- /dev/null +++ b/vendor/ahand/mobileesp/JavaScript/mdetect.js @@ -0,0 +1,1160 @@ +/* ******************************************* +// Copyright 2010-2015, Anthony Hand +// +// BETA NOTICE +// Previous versions of the JavaScript code for MobileESP were 'regular' +// JavaScript. The strength of it was that it was really easy to code and use. +// Unfortunately, regular JavaScript means that all variables and functions +// are in the global namespace. There can be collisions with other code libraries +// which may have similar variable or function names. Collisions cause bugs as each +// library changes a variable's definition or functionality unexpectedly. +// As a result, we thought it wise to switch to an "object oriented" style of code. +// This 'literal notation' technique keeps all MobileESP variables and functions fully self-contained. +// It avoids potential for collisions with other JavaScript libraries. +// This technique allows the developer continued access to any desired function or property. +// +// Please send feedback to project founder Anthony Hand: anthony.hand@gmail.com +// +// +// File version 2015.05.13 (May 13, 2015) +// Updates: +// - Moved MobileESP to GitHub. https://github.com/ahand/mobileesp +// - Opera Mobile/Mini browser has the same UA string on multiple platforms and doesn't differentiate phone vs. tablet. +// - Removed DetectOperaAndroidPhone(). This method is no longer reliable. +// - Removed DetectOperaAndroidTablet(). This method is no longer reliable. +// - Added support for Windows Phone 10: variable and DetectWindowsPhone10() +// - Updated DetectWindowsPhone() to include WP10. +// - Added support for Firefox OS. +// - A variable plus DetectFirefoxOS(), DetectFirefoxOSPhone(), DetectFirefoxOSTablet() +// - NOTE: Firefox doesn't add UA tokens to definitively identify Firefox OS vs. their browsers on other mobile platforms. +// - Added support for Sailfish OS. Not enough info to add a tablet detection method at this time. +// - A variable plus DetectSailfish(), DetectSailfishPhone() +// - Added support for Ubuntu Mobile OS. +// - DetectUbuntu(), DetectUbuntuPhone(), DetectUbuntuTablet() +// - Added support for 2 smart TV OSes. They lack browsers but do have WebViews for use by HTML apps. +// - One variable for Samsung Tizen TVs, plus DetectTizenTV() +// - One variable for LG WebOS TVs, plus DetectWebOSTV() +// - Updated DetectTizen(). Now tests for “mobile†to disambiguate from Samsung Smart TVs +// - Removed variables for obsolete devices: deviceHtcFlyer, deviceXoom. +// - Updated DetectAndroid(). No longer has a special test case for the HTC Flyer tablet. +// - Updated DetectAndroidPhone(). +// - Updated internal detection code for Android. +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android and reports here if relevant. +// - Updated DetectAndroidTablet(). +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android to exclude it from here. +// - DetectMeego(): Changed definition for this method. Now detects any Meego OS device, not just phones. +// - DetectMeegoPhone(): NEW. For Meego phones. Ought to detect Opera browsers on Meego, as well. +// - DetectTierIphone(): Added support for phones running Sailfish, Ubuntu and Firefox Mobile. +// - DetectTierTablet(): Added support for tablets running Ubuntu and Firefox Mobile. +// - DetectSmartphone(): Added support for Meego phones. +// - Reorganized DetectMobileQuick(). Moved the following to DetectMobileLong(): +// - DetectDangerHiptop(), DetectMaemoTablet(), DetectSonyMylo(), DetectArchos() +// +// +// +// LICENSE INFORMATION +// 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. +// +// +// ABOUT THIS PROJECT +// Project Owner: Anthony Hand +// Email: anthony.hand@gmail.com +// Web Site: http://www.mobileesp.com +// Source Files: https://github.com/ahand/mobileesp +// +// Versions of this code are available for: +// PHP, JavaScript, Java, ASP.NET (C#), Ruby and others +// +// +// WARNING: +// These JavaScript-based device detection features may ONLY work +// for the newest generation of smartphones, such as the iPhone, +// Android and Palm WebOS devices. +// These device detection features may NOT work for older smartphones +// which had poor support for JavaScript, including +// older BlackBerry, PalmOS, and Windows Mobile devices. +// Additionally, because JavaScript support is extremely poor among +// 'feature phones', these features may not work at all on such devices. +// For better results, consider using a server-based version of this code, +// such as Java, APS.NET, PHP, or Ruby. +// +// ******************************************* +*/ + + +var MobileEsp = { + + //GLOBALLY USEFUL VARIABLES + //Note: These values are set automatically during the Init function. + //Stores whether we're currently initializing the most popular functions. + initCompleted : false, + isWebkit : false, //Stores the result of DetectWebkit() + isMobilePhone : false, //Stores the result of DetectMobileQuick() + isIphone : false, //Stores the result of DetectIphone() + isAndroid : false, //Stores the result of DetectAndroid() + isAndroidPhone : false, //Stores the result of DetectAndroidPhone() + isTierTablet : false, //Stores the result of DetectTierTablet() + isTierIphone : false, //Stores the result of DetectTierIphone() + isTierRichCss : false, //Stores the result of DetectTierRichCss() + isTierGenericMobile : false, //Stores the result of DetectTierOtherPhones() + + //INTERNALLY USED DETECTION STRING VARIABLES + engineWebKit : 'webkit', + deviceIphone : 'iphone', + deviceIpod : 'ipod', + deviceIpad : 'ipad', + deviceMacPpc : 'macintosh', //Used for disambiguation + + deviceAndroid : 'android', + deviceGoogleTV : 'googletv', + + deviceWinPhone7 : 'windows phone os 7', + deviceWinPhone8 : 'windows phone 8', + deviceWinPhone10 : 'windows phone 10', + deviceWinMob : 'windows ce', + deviceWindows : 'windows', + deviceIeMob : 'iemobile', + devicePpc : 'ppc', //Stands for PocketPC + enginePie : 'wm5 pie', //An old Windows Mobile + + deviceBB : 'blackberry', + deviceBB10 : 'bb10', //For the new BB 10 OS + vndRIM : 'vnd.rim', //Detectable when BB devices emulate IE or Firefox + deviceBBStorm : 'blackberry95', //Storm 1 and 2 + deviceBBBold : 'blackberry97', //Bold 97x0 (non-touch) + deviceBBBoldTouch : 'blackberry 99', //Bold 99x0 (touchscreen) + deviceBBTour : 'blackberry96', //Tour + deviceBBCurve : 'blackberry89', //Curve 2 + deviceBBCurveTouch : 'blackberry 938', //Curve Touch 9380 + deviceBBTorch : 'blackberry 98', //Torch + deviceBBPlaybook : 'playbook', //PlayBook tablet + + deviceSymbian : 'symbian', + deviceSymbos : 'symbos', //Opera 10 on Symbian + deviceS60 : 'series60', + deviceS70 : 'series70', + deviceS80 : 'series80', + deviceS90 : 'series90', + + devicePalm : 'palm', + deviceWebOS : 'webos', //For Palm devices + deviceWebOStv : 'web0s', //For LG TVs + deviceWebOShp : 'hpwos', //For HP's line of WebOS devices + + deviceNuvifone : 'nuvifone', //Garmin Nuvifone + deviceBada : 'bada', //Samsung's Bada OS + deviceTizen : 'tizen', //Tizen OS + deviceMeego : 'meego', //Meego OS + deviceSailfish : 'sailfish', //Sailfish OS + deviceUbuntu : 'ubuntu', //Ubuntu Mobile OS + + deviceKindle : 'kindle', //Amazon eInk Kindle + engineSilk : 'silk-accelerated', //Amazon's accelerated Silk browser for Kindle Fire + + engineBlazer : 'blazer', //Old Palm browser + engineXiino : 'xiino', + + //Initialize variables for mobile-specific content. + vndwap : 'vnd.wap', + wml : 'wml', + + //Initialize variables for random devices and mobile browsers. + //Some of these may not support JavaScript + deviceTablet : 'tablet', + deviceBrew : 'brew', + deviceDanger : 'danger', + deviceHiptop : 'hiptop', + devicePlaystation : 'playstation', + devicePlaystationVita : 'vita', + deviceNintendoDs : 'nitro', + deviceNintendo : 'nintendo', + deviceWii : 'wii', + deviceXbox : 'xbox', + deviceArchos : 'archos', + + engineFirefox : 'firefox', //For Firefox OS + engineOpera : 'opera', //Popular browser + engineNetfront : 'netfront', //Common embedded OS browser + engineUpBrowser : 'up.browser', //common on some phones + deviceMidp : 'midp', //a mobile Java technology + uplink : 'up.link', + engineTelecaQ : 'teleca q', //a modern feature phone browser + engineObigo : 'obigo', //W 10 is a modern feature phone browser + + devicePda : 'pda', + mini : 'mini', //Some mobile browsers put 'mini' in their names + mobile : 'mobile', //Some mobile browsers put 'mobile' in their user agent strings + mobi : 'mobi', //Some mobile browsers put 'mobi' in their user agent strings + + //Smart TV strings + smartTV1 : 'smart-tv', //Samsung Tizen smart TVs + smartTV2 : 'smarttv', //LG WebOS smart TVs + + //Use Maemo, Tablet, and Linux to test for Nokia's Internet Tablets. + maemo : 'maemo', + linux : 'linux', + mylocom2 : 'sony/com', // for Sony Mylo 1 and 2 + + //In some UserAgents, the only clue is the manufacturer + manuSonyEricsson : 'sonyericsson', + manuericsson : 'ericsson', + manuSamsung1 : 'sec-sgh', + manuSony : 'sony', + manuHtc : 'htc', //Popular Android and WinMo manufacturer + + //In some UserAgents, the only clue is the operator + svcDocomo : 'docomo', + svcKddi : 'kddi', + svcVodafone : 'vodafone', + + //Disambiguation strings. + disUpdate : 'update', //pda vs. update + + //Holds the User Agent string value. + uagent : '', + + //Initializes key MobileEsp variables + InitDeviceScan : function() { + this.initCompleted = false; + + if (navigator && navigator.userAgent) + this.uagent = navigator.userAgent.toLowerCase(); + + //Save these properties to speed processing + this.isWebkit = this.DetectWebkit(); + this.isIphone = this.DetectIphone(); + this.isAndroid = this.DetectAndroid(); + this.isAndroidPhone = this.DetectAndroidPhone(); + + //Generally, these tiers are the most useful for web development + this.isMobilePhone = this.DetectMobileQuick(); + this.isTierIphone = this.DetectTierIphone(); + this.isTierTablet = this.DetectTierTablet(); + + //Optional: Comment these out if you NEVER use them + this.isTierRichCss = this.DetectTierRichCss(); + this.isTierGenericMobile = this.DetectTierOtherPhones(); + + this.initCompleted = true; + }, + + + //APPLE IOS + + //************************** + // Detects if the current device is an iPhone. + DetectIphone : function() { + if (this.initCompleted || this.isIphone) + return this.isIphone; + + if (this.uagent.search(this.deviceIphone) > -1) + { + //The iPad and iPod Touch say they're an iPhone! So let's disambiguate. + if (this.DetectIpad() || this.DetectIpod()) + return false; + //Yay! It's an iPhone! + else + return true; + } + else + return false; + }, + + //************************** + // Detects if the current device is an iPod Touch. + DetectIpod : function() { + if (this.uagent.search(this.deviceIpod) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current device is an iPhone or iPod Touch. + DetectIphoneOrIpod : function() { + //We repeat the searches here because some iPods + // may report themselves as an iPhone, which is ok. + if (this.DetectIphone() || this.DetectIpod()) + return true; + else + return false; + }, + + //************************** + // Detects if the current device is an iPad tablet. + DetectIpad : function() { + if (this.uagent.search(this.deviceIpad) > -1 && this.DetectWebkit()) + return true; + else + return false; + }, + + //************************** + // Detects *any* iOS device: iPhone, iPod Touch, iPad. + DetectIos : function() { + if (this.DetectIphoneOrIpod() || this.DetectIpad()) + return true; + else + return false; + }, + + + //ANDROID + + //************************** + // Detects *any* Android OS-based device: phone, tablet, and multi-media player. + // Also detects Google TV. + DetectAndroid : function() { + if (this.initCompleted || this.isAndroid) + return this.isAndroid; + + if ((this.uagent.search(this.deviceAndroid) > -1) || this.DetectGoogleTV()) + return true; + + return false; + }, + + //************************** + // Detects if the current device is a (small-ish) Android OS-based device + // used for calling and/or multi-media (like a Samsung Galaxy Player). + // Google says these devices will have 'Android' AND 'mobile' in user agent. + // Ignores tablets (Honeycomb and later). + DetectAndroidPhone : function() { + if (this.initCompleted || this.isAndroidPhone) + return this.isAndroidPhone; + + //First, let's make sure we're on an Android device. + if (!this.DetectAndroid()) + return false; + + //If it's Android and has 'mobile' in it, Google says it's a phone. + if (this.uagent.search(this.mobile) > -1) + return true; + + //Special check for Android phones with Opera Mobile. They should report here. + if (this.DetectOperaMobile()) + return true; + + return false; + }, + + //************************** + // Detects if the current device is a (self-reported) Android tablet. + // Google says these devices will have 'Android' and NOT 'mobile' in their user agent. + DetectAndroidTablet : function() { + //First, let's make sure we're on an Android device. + if (!this.DetectAndroid()) + return false; + + //Special check for Opera Android Phones. They should NOT report here. + if (this.DetectOperaMobile()) + return false; + + //Otherwise, if it's Android and does NOT have 'mobile' in it, Google says it's a tablet. + if (this.uagent.search(this.mobile) > -1) + return false; + else + return true; + }, + + //************************** + // Detects if the current device is an Android OS-based device and + // the browser is based on WebKit. + DetectAndroidWebKit : function() { + if (this.DetectAndroid() && this.DetectWebkit()) + return true; + else + return false; + }, + + //************************** + // Detects if the current device is a GoogleTV. + DetectGoogleTV : function() { + if (this.uagent.search(this.deviceGoogleTV) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is based on WebKit. + DetectWebkit : function() { + if (this.initCompleted || this.isWebkit) + return this.isWebkit; + + if (this.uagent.search(this.engineWebKit) > -1) + return true; + else + return false; + }, + + + //WINDOWS MOBILE AND PHONE + + // Detects if the current browser is a + // Windows Phone 7, 8, or 10 device. + DetectWindowsPhone : function() { + if (this.DetectWindowsPhone7() || + this.DetectWindowsPhone8() || + this.DetectWindowsPhone10()) + return true; + else + return false; + }, + + //************************** + // Detects a Windows Phone 7 device (in mobile browsing mode). + DetectWindowsPhone7 : function() { + if (this.uagent.search(this.deviceWinPhone7) > -1) + return true; + else + return false; + }, + + //************************** + // Detects a Windows Phone 8 device (in mobile browsing mode). + DetectWindowsPhone8 : function() { + if (this.uagent.search(this.deviceWinPhone8) > -1) + return true; + else + return false; + }, + + //************************** + // Detects a Windows Phone 10 device (in mobile browsing mode). + DetectWindowsPhone10 : function() { + if (this.uagent.search(this.deviceWinPhone10) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is a Windows Mobile device. + // Excludes Windows Phone 7 and later devices. + // Focuses on Windows Mobile 6.xx and earlier. + DetectWindowsMobile : function() { + if (this.DetectWindowsPhone()) + return false; + + //Most devices use 'Windows CE', but some report 'iemobile' + // and some older ones report as 'PIE' for Pocket IE. + if (this.uagent.search(this.deviceWinMob) > -1 || + this.uagent.search(this.deviceIeMob) > -1 || + this.uagent.search(this.enginePie) > -1) + return true; + //Test for Windows Mobile PPC but not old Macintosh PowerPC. + if ((this.uagent.search(this.devicePpc) > -1) && + !(this.uagent.search(this.deviceMacPpc) > -1)) + return true; + //Test for Windwos Mobile-based HTC devices. + if (this.uagent.search(this.manuHtc) > -1 && + this.uagent.search(this.deviceWindows) > -1) + return true; + else + return false; + }, + + + //BLACKBERRY + + //************************** + // Detects if the current browser is a BlackBerry of some sort. + // Includes BB10 OS, but excludes the PlayBook. + DetectBlackBerry : function() { + if ((this.uagent.search(this.deviceBB) > -1) || + (this.uagent.search(this.vndRIM) > -1)) + return true; + if (this.DetectBlackBerry10Phone()) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is a BlackBerry 10 OS phone. + // Excludes tablets. + DetectBlackBerry10Phone : function() { + if ((this.uagent.search(this.deviceBB10) > -1) && + (this.uagent.search(this.mobile) > -1)) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is on a BlackBerry tablet device. + // Example: PlayBook + DetectBlackBerryTablet : function() { + if (this.uagent.search(this.deviceBBPlaybook) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is a BlackBerry device AND uses a + // WebKit-based browser. These are signatures for the new BlackBerry OS 6. + // Examples: Torch. Includes the Playbook. + DetectBlackBerryWebKit : function() { + if (this.DetectBlackBerry() && + this.uagent.search(this.engineWebKit) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is a BlackBerry Touch + // device, such as the Storm, Torch, and Bold Touch. Excludes the Playbook. + DetectBlackBerryTouch : function() { + if (this.DetectBlackBerry() && + ((this.uagent.search(this.deviceBBStorm) > -1) || + (this.uagent.search(this.deviceBBTorch) > -1) || + (this.uagent.search(this.deviceBBBoldTouch) > -1) || + (this.uagent.search(this.deviceBBCurveTouch) > -1) )) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is a BlackBerry OS 5 device AND + // has a more capable recent browser. Excludes the Playbook. + // Examples, Storm, Bold, Tour, Curve2 + // Excludes the new BlackBerry OS 6 and 7 browser!! + DetectBlackBerryHigh : function() { + //Disambiguate for BlackBerry OS 6 or 7 (WebKit) browser + if (this.DetectBlackBerryWebKit()) + return false; + if ((this.DetectBlackBerry()) && + (this.DetectBlackBerryTouch() || + this.uagent.search(this.deviceBBBold) > -1 || + this.uagent.search(this.deviceBBTour) > -1 || + this.uagent.search(this.deviceBBCurve) > -1)) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is a BlackBerry device AND + // has an older, less capable browser. + // Examples: Pearl, 8800, Curve1. + DetectBlackBerryLow : function() { + if (this.DetectBlackBerry()) + { + //Assume that if it's not in the High tier or has WebKit, then it's Low. + if (this.DetectBlackBerryHigh() || this.DetectBlackBerryWebKit()) + return false; + else + return true; + } + else + return false; + }, + + + //SYMBIAN + + //************************** + // Detects if the current browser is the Nokia S60 Open Source Browser. + DetectS60OssBrowser : function() { + if (this.DetectWebkit()) + { + if ((this.uagent.search(this.deviceS60) > -1 || + this.uagent.search(this.deviceSymbian) > -1)) + return true; + else + return false; + } + else + 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. + DetectSymbianOS : function() { + if (this.uagent.search(this.deviceSymbian) > -1 || + this.uagent.search(this.deviceS60) > -1 || + ((this.uagent.search(this.deviceSymbos) > -1) && + (this.DetectOperaMobile)) || //Opera 10 + this.uagent.search(this.deviceS70) > -1 || + this.uagent.search(this.deviceS80) > -1 || + this.uagent.search(this.deviceS90) > -1) + return true; + else + return false; + }, + + + //WEBOS AND PALM + + //************************** + // Detects if the current browser is on a PalmOS device. + DetectPalmOS : function() { + //Make sure it's not WebOS first + if (this.DetectPalmWebOS()) + return false; + + //Most devices nowadays report as 'Palm', + // but some older ones reported as Blazer or Xiino. + if (this.uagent.search(this.devicePalm) > -1 || + this.uagent.search(this.engineBlazer) > -1 || + this.uagent.search(this.engineXiino) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is on a Palm device + // running the new WebOS. + DetectPalmWebOS : function() + { + if (this.uagent.search(this.deviceWebOS) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is on an HP tablet running WebOS. + DetectWebOSTablet : function() { + if (this.uagent.search(this.deviceWebOShp) > -1 && + this.uagent.search(this.deviceTablet) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is on a WebOS smart TV. + DetectWebOSTV : function() { + if (this.uagent.search(this.deviceWebOStv) > -1 && + this.uagent.search(this.smartTV2) > -1) + return true; + else + return false; + }, + + + //OPERA + + //************************** + // Detects if the current browser is Opera Mobile or Mini. + // Note: Older embedded Opera on mobile devices didn't follow these naming conventions. + // Like Archos media players, they will probably show up in DetectMobileQuick or -Long instead. + DetectOperaMobile : function() { + if ((this.uagent.search(this.engineOpera) > -1) && + ((this.uagent.search(this.mini) > -1 || + this.uagent.search(this.mobi) > -1))) + return true; + else + return false; + }, + + + //MISCELLANEOUS DEVICES + + //************************** + // Detects if the current device is an Amazon Kindle (eInk devices only). + // Note: For the Kindle Fire, use the normal Android methods. + DetectKindle : function() { + if (this.uagent.search(this.deviceKindle) > -1 && + !this.DetectAndroid()) + return true; + else + return false; + }, + + //************************** + // Detects if the current Amazon device has turned on the Silk accelerated browsing feature. + // Note: Typically used by the the Kindle Fire. + DetectAmazonSilk : function() { + if (this.uagent.search(this.engineSilk) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is a + // Garmin Nuvifone. + DetectGarminNuvifone : function() { + if (this.uagent.search(this.deviceNuvifone) > -1) + return true; + else + return false; + }, + + //************************** + // Detects a device running the Bada OS from Samsung. + DetectBada : function() { + if (this.uagent.search(this.deviceBada) > -1) + return true; + else + return false; + }, + + //************************** + // Detects a device running the Tizen smartphone OS. + DetectTizen : function() { + if (this.uagent.search(this.deviceTizen) > -1 && + this.uagent.search(this.mobile) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is on a Tizen smart TV. + DetectTizenTV : function() { + if (this.uagent.search(this.deviceTizen) > -1 && + this.uagent.search(this.smartTV1) > -1) + return true; + else + return false; + }, + + //************************** + // Detects a device running the Meego OS. + DetectMeego : function() { + if (this.uagent.search(this.deviceMeego) > -1) + return true; + else + return false; + }, + + //************************** + // Detects a phone running the Meego OS. + DetectMeegoPhone : function() { + if (this.uagent.search(this.deviceMeego) > -1 && + this.uagent.search(this.mobi) > -1) + return true; + else + return false; + }, + + //************************** + // Detects a mobile device (probably) running the Firefox OS. + DetectFirefoxOS : function() { + if (this.DetectFirefoxOSPhone() || this.DetectFirefoxOSTablet()) + return true; + else + return false; + }, + + //************************** + // Detects a phone (probably) running the Firefox OS. + DetectFirefoxOSPhone : function() { + //First, let's make sure we're NOT on another major mobile OS. + if (this.DetectIos() || + this.DetectAndroid() || + this.DetectSailfish()) + return false; + + if ((this.uagent.search(this.engineFirefox) > -1) && + (this.uagent.search(this.mobile) > -1)) + return true; + + return false; + }, + + //************************** + // Detects a tablet (probably) running the Firefox OS. + DetectFirefoxOSTablet : function() { + //First, let's make sure we're NOT on another major mobile OS. + if (this.DetectIos() || + this.DetectAndroid() || + this.DetectSailfish()) + return false; + + if ((this.uagent.search(this.engineFirefox) > -1) && + (this.uagent.search(this.deviceTablet) > -1)) + return true; + + return false; + }, + + //************************** + // Detects a device running the Sailfish OS. + DetectSailfish : function() { + if (this.uagent.search(this.deviceSailfish) > -1) + return true; + else + return false; + }, + + //************************** + // Detects a phone running the Sailfish OS. + DetectSailfishPhone : function() { + if (this.DetectSailfish() && (this.uagent.search(this.mobile) > -1)) + return true; + + return false; + }, + + + //************************** + // Detects a mobile device running the Ubuntu Mobile OS. + DetectUbuntu : function() { + if (this.DetectUbuntuPhone() || this.DetectUbuntuTablet()) + return true; + else + return false; + }, + + //************************** + // Detects a phone running the Ubuntu Mobile OS. + DetectUbuntuPhone : function() { + if ((this.uagent.search(this.deviceUbuntu) > -1) && + (this.uagent.search(this.mobile) > -1)) + return true; + + return false; + }, + + //************************** + // Detects a tablet running the Ubuntu Mobile OS. + DetectUbuntuTablet : function() { + if ((this.uagent.search(this.deviceUbuntu) > -1) && + (this.uagent.search(this.deviceTablet) > -1)) + return true; + + return false; + }, + + //************************** + // Detects the Danger Hiptop device. + DetectDangerHiptop : function() { + if (this.uagent.search(this.deviceDanger) > -1 || + this.uagent.search(this.deviceHiptop) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current browser is a Sony Mylo device. + DetectSonyMylo : function() { + if ((this.uagent.search(this.manuSony) > -1) && + ((this.uagent.search(this.qtembedded) > -1) || + (this.uagent.search(this.mylocom2) > -1))) + return true; + else + return false; + }, + + //************************** + // Detects if the current device is on one of + // the Maemo-based Nokia Internet Tablets. + DetectMaemoTablet : function() { + if (this.uagent.search(this.maemo) > -1) + return true; + //For Nokia N810, must be Linux + Tablet, or else it could be something else. + if ((this.uagent.search(this.linux) > -1) && + (this.uagent.search(this.deviceTablet) > -1) && + this.DetectWebOSTablet() && + !this.DetectAndroid()) + return true; + else + return false; + }, + + //************************** + // Detects if the current device is an Archos media player/Internet tablet. + DetectArchos : function() { + if (this.uagent.search(this.deviceArchos) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current device is an Internet-capable game console. + // Includes many handheld consoles. + DetectGameConsole : function() { + if (this.DetectSonyPlaystation() || + this.DetectNintendo() || + this.DetectXbox()) + return true; + else + return false; + }, + + //************************** + // Detects if the current device is a Sony Playstation. + DetectSonyPlaystation : function() { + if (this.uagent.search(this.devicePlaystation) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current device is a handheld gaming device with + // a touchscreen and modern iPhone-class browser. Includes the Playstation Vita. + DetectGamingHandheld : function() { + if ((this.uagent.search(this.devicePlaystation) > -1) && + (this.uagent.search(this.devicePlaystationVita) > -1)) + return true; + else + return false; + }, + + //************************** + // Detects if the current device is a Nintendo game device. + DetectNintendo : function() { + if (this.uagent.search(this.deviceNintendo) > -1 || + this.uagent.search(this.deviceWii) > -1 || + this.uagent.search(this.deviceNintendoDs) > -1) + return true; + else + return false; + }, + + //************************** + // Detects if the current device is a Microsoft Xbox. + DetectXbox : function() { + if (this.uagent.search(this.deviceXbox) > -1) + return true; + else + return false; + }, + + + //************************** + // Detects whether the device is a Brew-powered device. + // Note: Limited to older Brew-powered feature phones. + // Ignores newer Brew versions like MP. Refer to DetectMobileQuick(). + DetectBrewDevice : function() { + if (this.uagent.search(this.deviceBrew) > -1) + return true; + else + return false; + }, + + + // DEVICE CLASSES + + //************************** + // Check to see whether the device is *any* 'smartphone'. + // Note: It's better to use DetectTierIphone() for modern touchscreen devices. + DetectSmartphone : function() { + //Exclude duplicates from TierIphone + if (this.DetectTierIphone() || + this.DetectS60OssBrowser() || + this.DetectSymbianOS() || + this.DetectWindowsMobile() || + this.DetectBlackBerry() || + this.DetectMeegoPhone() || + this.DetectPalmOS()) + return true; + + //Otherwise, return false. + return false; + }, + + //************************** + // Detects if the current device is a mobile device. + // This method catches most of the popular modern devices. + // Excludes Apple iPads and other modern tablets. + DetectMobileQuick : function() { + if (this.initCompleted || this.isMobilePhone) + return this.isMobilePhone; + + //Let's exclude tablets. + if (this.DetectTierTablet()) + return false; + + //Most mobile browsing is done on smartphones + if (this.DetectSmartphone()) + return true; + + //Catch-all for many mobile devices + if (this.uagent.search(this.mobile) > -1) + return true; + + if (this.DetectOperaMobile()) + return true; + + //We also look for Kindle devices + if (this.DetectKindle() || + this.DetectAmazonSilk()) + return true; + + if (this.uagent.search(this.deviceMidp) > -1 || + this.DetectBrewDevice()) + return true; + + if ((this.uagent.search(this.engineObigo) > -1) || + (this.uagent.search(this.engineNetfront) > -1) || + (this.uagent.search(this.engineUpBrowser) > -1)) + return true; + + return false; + }, + + //************************** + // Detects in a more comprehensive way if the current device is a mobile device. + DetectMobileLong : function() { + if (this.DetectMobileQuick()) + return true; + if (this.DetectGameConsole()) + return true; + + if (this.DetectDangerHiptop() || + this.DetectMaemoTablet() || + this.DetectSonyMylo() || + this.DetectArchos()) + return true; + + if ((this.uagent.search(this.devicePda) > -1) && + !(this.uagent.search(this.disUpdate) > -1)) + return true; + + //Detect for certain very old devices with stupid useragent strings. + if ((this.uagent.search(this.manuSamsung1) > -1) || + (this.uagent.search(this.manuSonyEricsson) > -1) || + (this.uagent.search(this.manuericsson) > -1) || + (this.uagent.search(this.svcDocomo) > -1) || + (this.uagent.search(this.svcKddi) > -1) || + (this.uagent.search(this.svcVodafone) > -1)) + return true; + + return false; + }, + + //***************************** + // For Mobile Web Site Design + //***************************** + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for the new generation of + // HTML 5 capable, larger screen tablets. + // Includes iPad, Android (e.g., Xoom), BB Playbook, WebOS, etc. + DetectTierTablet : function() { + if (this.initCompleted || this.isTierTablet) + return this.isTierTablet; + + if (this.DetectIpad() || + this.DetectAndroidTablet() || + this.DetectBlackBerryTablet() || + this.DetectFirefoxOSTablet() || + this.DetectUbuntuTablet() || + this.DetectWebOSTablet()) + return true; + else + return false; + }, + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for devices which can + // display iPhone-optimized web content. + // Includes iPhone, iPod Touch, Android, Windows Phone 7 and 8, BB10, WebOS, Playstation Vita, etc. + DetectTierIphone : function() { + if (this.initCompleted || this.isTierIphone) + return this.isTierIphone; + + if (this.DetectIphoneOrIpod() || + this.DetectAndroidPhone() || + this.DetectWindowsPhone() || + this.DetectBlackBerry10Phone() || + this.DetectPalmWebOS() || + this.DetectBada() || + this.DetectTizen() || + this.DetectFirefoxOSPhone() || + this.DetectSailfishPhone() || + this.DetectUbuntuPhone() || + this.DetectGamingHandheld()) + return true; + + //Note: BB10 phone is in the previous paragraph + if (this.DetectBlackBerryWebKit() && this.DetectBlackBerryTouch()) + return true; + + else + return false; + }, + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for devices which are likely to be + // capable of viewing CSS content optimized for the iPhone, + // but may not necessarily support JavaScript. + // Excludes all iPhone Tier devices. + DetectTierRichCss : function() { + if (this.initCompleted || this.isTierRichCss) + return this.isTierRichCss; + + //Exclude iPhone and Tablet Tiers and e-Ink Kindle devices + if (this.DetectTierIphone() || + this.DetectKindle() || + this.DetectTierTablet()) + return false; + + //Exclude if not mobile + if (!this.DetectMobileQuick()) + return false; + + //If it's a mobile webkit browser on any other device, it's probably OK. + if (this.DetectWebkit()) + return true; + + //The following devices are also explicitly ok. + if (this.DetectS60OssBrowser() || + this.DetectBlackBerryHigh() || + this.DetectWindowsMobile() || + (this.uagent.search(this.engineTelecaQ) > -1)) + return true; + + else + return false; + }, + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for all other types of phones, + // but excludes the iPhone and RichCSS Tier devices. + // NOTE: This method probably won't work due to poor + // support for JavaScript among other devices. + DetectTierOtherPhones : function() { + if (this.initCompleted || this.isTierGenericMobile) + return this.isTierGenericMobile; + + //Exclude iPhone, Rich CSS and Tablet Tiers + if (this.DetectTierIphone() || + this.DetectTierRichCss() || + this.DetectTierTablet()) + return false; + + //Otherwise, if it's mobile, it's OK + if (this.DetectMobileLong()) + return true; + + else + return false; + } + +}; + +//Initialize the MobileEsp object +MobileEsp.InitDeviceScan(); + + + diff --git a/vendor/ahand/mobileesp/LICENSE b/vendor/ahand/mobileesp/LICENSE new file mode 100644 index 00000000000..8f71f43fee3 --- /dev/null +++ b/vendor/ahand/mobileesp/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. + diff --git a/vendor/ahand/mobileesp/MobileESP_UA-Test-Strings/MobileESP UA Test Strings - UA Strings.csv b/vendor/ahand/mobileesp/MobileESP_UA-Test-Strings/MobileESP UA Test Strings - UA Strings.csv new file mode 100644 index 00000000000..d1ce0ca1461 --- /dev/null +++ b/vendor/ahand/mobileesp/MobileESP_UA-Test-Strings/MobileESP UA Test Strings - UA Strings.csv @@ -0,0 +1,139 @@ +UA Type,Device OEM,Device Name,Device Platform,Browser,UA String,Matched Sub-Strings,MobileESP Detection Methods,MobileESP Priority,Comments,Markets Launched,Reference +tablet,Acer,Iconia A500,Andorid ,Android,"Mozilla/5.0 (Linux; U; Android 3.0.1; en-us; A500 Build/HRI66) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13","android, webkit","DetectAndroid(), DetectAndroidTablet(), DetectAndroidWebKit(), DetectWebKit()",High,Launched with Android 3.0 (Honeycomb),International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Amazon,Fire,Android,Kindle Silk,"Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Kindle Fire Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1","Android, mobile, webkit","DetectAndroid(), DetectAndroidPhone(), DetectAndroidWebKit(), DetectWebKit()",High,The Kindle Fire Android browser running in normal Android mode. MobileESP ignores the Kindle word here.,International,http://www.labnol.org/software/kindle-user-agent-string/20378/ +mobile,Amazon,Fire,Android,Kindle Silk,"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.1.0-80) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true",silk,DetectAmazonSilk(),High,The US for the Silk browser in accelerated mode on the Amazon Kindle Fire.,International,http://www.labnol.org/software/kindle-user-agent-string/20378/ +mobile,Barnes & Noble,Nook Simple Touch,Android,Android,"2.1 NOOK BNRV300---Mozilla/5.0 (Linux; U; Android 2.1; xx-xx; NOOK BNRV300 Build/ERD79) Apple WebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17","android, nook","DetectAndroid(), DetectAndroidPhone(), DetectAndroidWebKit(), DetectWebKit(), DetectNook()",Low,The Simple Touch is black and white but runs Android. ,, +tablet,Barnes & Noble,Nook,Android,Android,nook browser/1.0,nook,"DetectNook(), DetectMobileQuick()",Low,"This was the UA for the Nook 1.0 device. Support is added for detecting the ""Nook"" substring just in case the useragent doesn't report Android or the device is an older eInk one.",International,http://www.zytrax.com/tech/web/mobile_ids.html +tablet,Barnes & Noble,Nook Color,Android,Android,"Mozilla/5.0 (Linux; U; Android 2.3; xx-xx; BNTV250A Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Safari/533.1",android,"DetectAndroid(), DetectAndroidTablet(), DetectAndroidWebKit(), DetectWebKit()",High,"With this UA, the Nook Color reports itself as an Android Tablet. (The Nook Color was the Nook 2.0 device.)",International,http://www.zytrax.com/tech/web/mobile_ids.html +tablet,Google,Nexus 10,Android,Firefox,mozilla/5.0 (android; tablet; rv:37.0) gecko/37.0 firefox/37.0,android,"DetectAndrid(), DetectAndroidTablet()",Medium,"This will detect as a tablet because Firefox doesn't put ""mobile"" in the useragent. ",International,Through direct testing in May 2015. +tablet,Google,Nexus 10,Android,Opera,"mozilla/5.0 (linux; android 5.1.1; nexus 10 build/lmy47v) applewebkit/537.36 (khtml, like gecko) chrome/42.0.2311.107 safari/537.36 opr/29.0.1809.92117","android, webkit","DetectAndroid(), DetectWebKit()",Medium,"No token for ""tablet"". ",International,Through direct testing in May 2015. +tablet,Google,Nexus 10,Android,Opera Mini,opera/9.80 (android; opera mini/8.0.1807/36.1955; u; en) presto/2.12.423 version/12.16,"opera, mini","DetectOperaMobile(), DetectAndroid(), DetectMobileQuick()",Medium,"No token for ""tablet"". Scored 203 out of 555 at www.html5test.com",International,Through direct testing in May 2015. +mobile,HTC,Flyer - Desktop Mode,Android,Android,"mozilla/5.0 (macintosh; u; intel mac os x 10_6_3; htc_flyer_p512; en-us) applewebkit/533.16 (khtml, like gecko) version/5.0 safari/533.16",n/a,"DetectAndroid(), DetectAndroidPhone(), DetectAndroidWebKit(), DetectWebKit()",Low,"As of June 2012, special allowance is made for detecting the HTC Flyer in Desktop mode and identifying it as a phone. ",International,Copied from the HTC browser. Saved in Anthony's personal Gmail. +mobile,HTC,Flyer - Mobile Browsing Mode,Android,Android,"mozilla/5.0 (linux; u; android 2.3.4; en-us; htc_flyer_p512 build/grj22) applewebkit/533.1 (khtml, like gecko) version/4.0 mobile safari/533.1",android,"DetectAndroid(), DetectAndroidPhone(), DetectAndroidWebKit(), DetectWebKit()",Low,"As of June 2012, special allowance is made for detecting the HTC Flyer in Desktop mode and identifying it as a phone.",International,Copied from the HTC browser. Saved in Anthony's personal Gmail. +mobile,HTC,T-Mobile G1,Android,Android,"Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2","Android, mobile, webkit","DetectAndroid(), DetectAndroidPhone(), DetectAndroidWebKit(), DetectWebKit()",High,"The G1 was the first Android device on the US market (first in the world). It launched with Android 1.1, was later OTA updated to 1.5 (Cupcake).",USA,http://www.gtrifonov.com/2010/04/29/google-android-user-agent-strings-3/ +mobile,Motorola,DROID RAZR 4G,Android,Android,"Mozilla/5.0 (Linux; U; Android 2.3; xx-xx; DROID RAZR 4G Build/6.5.1-73_DHD-11_M1-29) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1","android, webkit","DetectAndroid(), DetectAndroidPhone(), DetectAndroidWebKit(), DetectWebKit()",Medium,A popular Android device on Verizon. ,USA,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=motorola_droid_razr_ver1 +tablet,Motorola,Xoom,Android,Android,"Mozilla/5.0 (Linux; U; Android 3.0.1; en-us; Xoom Build/HWI69) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",android,"DetectAndroid(), DetectAndroidTablet(), DetectAndroidWebKit(), DetectWebKit()",High,Launched with Android 3.0 (Honeycomb). The string varied slightly by culture/language and build.,International,http://www.zytrax.com/tech/web/mobile_ids.html +phone,Motorola,Moto X (2013),Android,Firefox,mozilla/5.0 (android; mobile; rv:37.0) gecko/37.0 firefox/37.0,"android, mobile","DetectAndroid(), DetectAndroidPhone()",Medium,,International,Through direct testing in May 2015. +phone,Motorola,Moto X (2013),Android,Opera,"mozilla/5.0 (linux; android 4.4.4; xt1053 build/kxa21.12-l1.29.1) applewebkit/537.36 (khtml, like gecko) chrome/42.0.2311.107 mobile safari/537.36 opr/29.0.1809.92117","android, mobile, webkit","DetectAndroid(), DetectAndroidPhone(), DetectWebKit()",Medium,"The new WebKit-based browser is more capable, so we don't count it as Opera Mobile.",International,Through direct testing in May 2015. +phone,Motorola,Moto X (2013),Android,Opera Mini,opera/9.80 (android; opera mini/8.0.1807/36.1955; u; en) presto/2.12.423 version/12.16,"opera, mini","DetectOperaMobile(), DetectAndroid(), DetectMobileQuick()",Medium,"No token for ""mobile."" ",International,Through direct testing in May 2015. +mobile,Samsung,Galaxy S 3,Android,Android,"mozilla/5.0 (linux; u; android 4.0.4; en-us; gt-i9300 build/imm76d) applewebkit/534.30 (khtml, like gecko) version/4.0 mobile safari/534.30","Android, mobile, webkit","DetectAndroid(), DetectAndroidPhone(), DetectAndroidWebKit(), DetectWebKit()",High,Samsung's 2012 flagship Android device. Sold worldwide.,International, +tablet,Sony,Tablet P,Android,Android,"Mozilla/5.0 (Linux; U; Android 3.2; de-de; Sony Tablet P Build/THMD01900) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",android,"DetectAndroid(), DetectAndroidTablet(), DetectAndroidWebKit(), DetectWebKit()",High,A dual-screen Android tablet.,International,http://www.zytrax.com/tech/web/mobile_ids.html +tablet,Sony,Tablet S,Android,Android,"Mozilla/5.0 (Linux; U; Android 3.2; en-gb; Sony Tablet S Build/THMD01900) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",android,"DetectAndroid(), DetectAndroidTablet(), DetectAndroidWebKit(), DetectWebKit()",High,"A 9.4"" Android tablet.",International,http://www.zytrax.com/tech/web/mobile_ids.html +tablet,Toshiba,AT100-100,Android,Android,"Mozilla/5.0 (Linux; U; Android 3.1; de-de; AT100 Build/HMJ37) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",Android,"DetectAndroid(), DetectAndroidTablet(), DetectAndroidWebKit(), DetectWebKit()",High,"A 10.1"" Android tablet",International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Samsung,GT-S5253,Bada,Dolfin,SAMSUNG-GT-S5253/1.0 Bada/1.0 AppleWebKit/533.1 Dolfin/2.0 Mobile NexPlayer/3.0 SMM-MMS/1.2.0 profile/MIDP-2.1 configuration/CLDC-1.1 OPN-B,"bada, mobile, midp, webkit","DetectBada(), DetectWebKit(), DetectMidpCapable()",Low,Bada is Samsung's proprietary Linux-based smartphone OS for non-USA markets. The Dolfin browser is quite good. This device is in the Bada 1.0 series.,International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=samsung_gt_s5253_ver1 +mobile,BlackBerry,9380 Curve Touch,BlackBerry,BlackBerry,"BlackBerry; U; BlackBerry 9380; xx-xx) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0.557 Mobile Safari/534.11+",blackberry 938,"DetectBlackBerry(), DetectBlackBerryTouch(), DetectBlackWebKit()",Low,"A touchscreen device for international markets with a large, iPhone-like screen.",International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=blackberry9380_ver1 +mobile,BlackBerry,Porsche Design P’9981,BlackBerry,BlackBerry,"BlackBerry; U; BlackBerry 9981; xx-xx) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0.579 Mobile Safari/534.11+","blackberry, webkit","DetectBlackBerry(), DetectBlackBerryTouch(), DetectBlackWebKit()",Low,This device is in the Bold Touch series. ,International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=blackberry9981_ver1 +mobile,BlackBerry,Style 9670,BlackBerry,BlackBerry,"BlackBerry; U; BlackBerry 9670; xx-xx) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.226 Mobile Safari/534.1+","blackberry, webkit","DetectBlackBerry(), DetectBlackWebKit()",Low,The device was launched on Sprint in late 2010.,USA,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=blackberry_9670_ver1 +mobile ,BlackBerry,Tour 9630,BlackBerry,BlackBerry,BlackBerry9630/4.7.1.40 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/126,blackberry96,"DetectBlackBerry(), DetectBlackHigh()",Low,"This device had a browser which could display CSS reasonably well, but didn't have much JS skills. High profile in late 2008.",International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=blackberry9630_ver1 +mobile,BlackBerry ,Bold (multiple models),BlackBerry,BlackBerry,BlackBerry9700/5.0.0.207 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/175,blackberry97,"DetectBlackBerry(), DetectBlackHigh()",Medium,"The Bold line is one of RIM's most popular models, with many variants. Note that touchscreen versions of the bold also register like this (as a non-touch device) due to the small screen. iPhone-style UIs would not work well.",International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=blackberry9700_ver1 +mobile,BlackBerry,Curve 2 8900,BlackBerry ,BlackBerry,BlackBerry8900/4.6.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/100,blackberry89,"DetectBlackBerry(), DetectBlackHigh()",Low,The device was high profile in the US esp. in 2008.,International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=blackberry8900_ver1 +mobile,BlackBerry,BB10 Developer Phone,BlackBerry 10,BlackBerry,"Mozilla/5.0 (BB10; touch) AppleWebKit/537.3+ (KHTML, like Gecko) Version/10.0.9.388 Mobile Safari/537.3+","bb10, webkit","DetectBlackBerry(), DetectBlackBerry10Phone(), DetectWebKit(), DetectIphoneTier(), DetectSmartphone()",Low,This is a test phone. The real devices going on sale will be High Priority.,International,http://devblog.blackberry.com/2012/08/blackberry-10-user-agent-string/ +mobile,BlackBerry,Pearl (8100),BlackBerry 4.2,BlackBerry,BlackBerry8100/4.5.0.108 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/214,blackberry,"DetectBlackBerry(), DetectBlackBerryLow()",Low,The first consumer-oriented BlackBerry device. Was a hit seller.,International,http://www.mobilerated.com/rim-blackberry-8100-pearl-specifications.html +mobile,BlackBerry,Storm 2,BlackBerry OS,BlackBerry,BlackBerry9550/5.0.0.320 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/105,blackberry95,"DetectBlackBerry(), DetectBlackBerryTouch(), DetectBlackBerryHigh()",High,"Lead the flagship all-touch line of devices, esp. Verizon, Nov. 2009.",USA & International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=blackberry9550_ver1 +mobile,BlackBerry,Torch (9800),BlackBerry OS,BlackBerry,"BlackBerry; U; BlackBerry 9800; xx-xx) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.135 Mobile Safari/534.1+",blackberry 98,"DetectBlackBerry(), DetectBlackBerryTouch(), DetectBlackWebKit()",High,Lead the touch BlackBerry device line at AT&T.,USA & International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=blackberry9800_ver1 +mobile,BlackBerry,Playbook,BlackBerry OS (QNX),BlackBerry,"Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML, like Gecko) Version/7.2.1.0 Safari/536.2+'",playbook,DetectBlackBerryTablet(),Medium,RIM's flagship tablet.,USA & International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=rim_playbook_android_ver1 +mobile,HTC,Freestyle (F5151),Brew,Obigo,"HTC-F5151/1.0 Mozilla/5.0 (BMP; U; en) AppleWebKit/530.8 (KHTML, like Gecko) OBIGO/W10 Safari/530.8",obigo,"DetectWebKit() , DetectMobileQuick()",Low,"This device is listed because it's a small but modern touchscreen feature phone. The modern Obigo W10 browser is based on WebKit, so it more capable than legacy Teleca or Obigo browsers.",International,http://developer.att.com/developer/device_detailSpec.jsp?id=6.3_v1_10800390 +mobile,Pantech,Link II ,Brew,Netfront,PantechP5000/JTUS06272011 BMP/1.0.2 DeviceId/141025 NetFront/4.1 OMC/1.5.3 Profile/MIDP-2.1 Configuration/CLDC-1.1,"midp, netfront","DetectMobileQuick(), DetectMidpCapable()",Low,"A feature phone on AT&T in 2012. Available worldwide, too. ",International, +desktop,Apple,Mac,Desktop,Safari,"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.18 (KHTML, like Gecko) Version/ 3.1.2 Safari/525.20.1",n/a,Unsupported,High,"A desktop or laptop running Mac OS. As with all ""desktop"" devices, should not be detected by MobileESP.",International,http://www.zytrax.com/tech/web/mobile_ids.html +game,Nintendo,3DS,Embedded,Opera,Mozilla/5.0 (Nintendo 3DS; U; ; de) Version/1.7455.EU,nintendo,"DetectNintendo(), DetectGameConsole()",Low,Anonther Nintendo handheld gaming device.,International,http://www.botsvsbrowsers.com/details/747492/index.html +game,Nintendo,DS,Embedded,Opera,Opera/9.00 (Nintendo DS; U; ; 1309-9; en),nintendo,"DetectNintendo(), DetectGameConsole()",Medium,There are tons of useragents for the Nintendo DS. This appears to be a reasonable choice for tracking. ,International,http://www.botsvsbrowsers.com/details/341766/index.html +game,Nintendo,DSi,Embedded,Opera,Nintendo DSi; Opera Mini/5.1.21965/20.2513; U; en,"nintendo, opera mini","DetectNintendo(), DetectGameConsole(), DetectOperaMobile()",Low,Anonther Nintendo handheld gaming device.,International,http://www.botsvsbrowsers.com/details/728961/index.html +game,Nintendo,Wii,Embedded,Opera,Opera/9.30 (Nintendo Wii; U; ; 2047-7; en),"nintendo, wii","DetectNintendo(), DetectGameConsole()",Medium,"Not high priority, but it is currently supported. Technically, this belongs in a TV Tier.",International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Cricket,A410,Feature Phone,Brew,Cricket-A410/1.0 Polaris/v6.17,n/a,Unsupported,Low - LMI,This Brew device was launched on the Cricket network in the US. Little is known about device. ,USA,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Danger,Hiptop,Feature Phone,Danger,Mozilla/5.0 (Danger hiptop 3.4; U; AvantGo 3.2),danger hiptop,DetectDangerHiptop(),Low,A popular feature phone around 2006.,USA,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,LG,enV3 (VX9200),Feature Phone,Teleca,Mozilla/5.0 (compatible; Teleca Q7; Brew 3.1.5; U; xx-xx) 320X240 LGE VX9200,"brew, teleca q","DetectMobileQuick(), DetectBrew(), DetectRichCss()",Low,"A popular feature phone, esp. on Verizon.",USA & International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=lg_vx9200_ver1 +mobile,LG,Chocolate (KG-800),Feature Phone,Teleca-Obigo,LG-KG800/V10e Obigo/WAP2.0 MIDP-2.0/CLDC-1.1,midp,DetectMidpCapable(),Low,A popular feature phone worldwide around 2008.,International,http://www.mobile-phone-specs.com/model/lg_kg800_ver1/ +mobile,Motorla,RAZR2 V9m,Feature Phone,Up,MOT-V9mm/00.62 UP.Browser/6.2.3.4.c.1.123 (GUI) MMP/2.0,up.browser,DetectMobileQuick(),Low,One of many devices using the Up Browser. ,International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Samsung,A737,Feature Phone,Brew,Mozilla/4.1 (U; BREW 3.1.5; en-US; Teleca/Q05A/INT),brew,DetectBrewDevice(),Medium,Should test positive for being a Brew device. It might work with a real phone due to the Accept properties (WML). Failed on 3/25/12.,USA,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Samsung,SPH-A620 VGA1000,Feature Phone,Obigo,Mozilla/4.0 (compatible; MSIE 6.0; j2me) ReqwirelessWeb/3.5,n/a,Unsupported,L - LMI,Not worth the effort to add support for this one obsolete device. Sold at Sprint.,USA,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Siemens,S55,Feature Phone,Embedded,ReqwirelessWeb/3.2 S55,n/a,Unsupported,L - LMP-D,A very old feature phone with a very small screen.,International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Various,Various,Feature Phones,Opera Mini,Opera/9.80 (J2ME/MIDP; Opera Mini/4.2.13221/25.623; U; en) Presto/2.5.25 Version/10.54,opera mini,DetectOperaMobile(),Medium,"Thought to be installed on various feature phones, including BlackBerries.",International,http://www.zytrax.com/tech/web/browser_ids.htm +mobile,Various,Various,Feature Phones,Opera Mini,Opera/9.80 (J2ME/MIDP; Opera Mini/5.1.21214/19.916; U; en) Presto/2.5.25,opera mini,DetectOperaMobile(),Medium,Thought to be installed on various feature phones.,International,http://www.zytrax.com/tech/web/browser_ids.htm +mobile,Various,Various,Feature Phones,Opera Mini,Opera/9.80 (J2ME/MIDP; Opera Mini/5.0.16823/1428; U; en) Presto/2.2.0,opera mini,DetectOperaMobile(),Medium,Thought to be installed on various feature phones.,International,http://www.zytrax.com/tech/web/browser_ids.htm +TV,Amazon,Fire TV,Fire OS,WebView,"Mozilla/5.0 (Linux; Android 4.2.2; AFTB Build/JDQ39) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.173 Mobile Safari/537.22 cordova-amazon-fireos/3.4.0 AmazonWebAppPlatform/3.4.0;2.0",amazonwebappplatform,"DetectFireTV() +DetectSmartTV()",Low,"Amazon's Fire TV doesn't have a standalone browser. Instead, apps can use a WebView to display HTML content. ",International,https://developer.amazon.com/public/solutions/devices/fire-tv/docs/user-agent-strings +mobile,Various,Various,Firefox OS,Firefox,Mozilla/5.0 (Mobile; rv:26.0) Gecko/26.0 Firefox/26.0,"firefox, mobile","DetectFirefoxOS(), DetectFirefoxOSPhone(), DetectTierIphone(), DetectSmartphone(), DetectMobileQuick()",Low,Potential new up and coming mobile OS. Need to exclude Android and iOS from check to disambiguate. ,International,https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference +tablet,Various,Various,Firefox OS,Firefox,Mozilla/5.0 (Tablet; rv:26.0) Gecko/26.0 Firefox/26.0,"firefox, tablet","DetectFirefoxOS(), DetectFirefoxOSTablet()",Low,Potential new up and coming mobile OS. ,International,https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference +tablet,Apple,iPad,iOS,Maxthon,"mozilla/5.0 (ipad; cpu os 7_0_2 llike mac os x) applewebkit/537.51.1 (khtml, like gecko) mobile/11a501a ","ipad, mobile, webkit","DetectTierTablet(), DetectWebkit(), DetectIpad(), DetectIos()",High,A popular browser in China now available worldwide. The Maxthon browser is available on iOS and Android devices. ,International,Screenshot from an iPad in October 2013. +tablet,Apple,iPad,iOS,Opera Coast,"Mozilla/5.0 (iPad; CPU OS 7_0_6 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Coast/2.0.5.71150 Mobile/11B651 Safari/7534.48.3","ipad, webkit","DetectTierTablet(), DetectWebkit(), DetectIpad(), DetectIos()",Low,"Because Opera Coast uses WebKit and tags the agent with ""iPad"", it will detect as if it's the default Apple browser. Opera Coast's iPhone browser similarly detects as iPhone. ",International,https://udger.com/resources/ua-list/browser-detail?browser=Coast +phone,Apple,iPhone,iOS,Opera Mini,"mozilla/5.0 (iphone; cpu iphone os 8_3 like mac os x) applewebkit/600.1.4 (khtml, like gecko) opios/10.0.1.90729 mobile/12f70 safari/9537.53","iphone, webkit","DetectIphone(), DetectIphoneOrIpod(), DetectIos(), DetectWebKit()",Low,"Because Opera Mini now has iPhone and WebKit tokens in the browser, it will be detected the same as the iPhone's native browser. ",International,Through direct testing in May 2015. +mobile,Apple,iPhone,iOS,Safari Mobile,"Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7","iphone, webkit","DetectIphone(), DetectIphoneOrIpod(), DetectIos(), DetectWebKit()",High,iOS v 4 on iPhone,International,http://www.zytrax.com/tech/web/browser_ids.htm +mobile,Apple,"iPod Touch +(Generation: Fall 2012)",iOS,Safari Mobile,"mozilla/5.0 (ipod; cpu iphone os 6_0 like mac os x) applewebkit/536.26 (khtml, like gecko) version/6.0 mobile/10a406 safari/8536.25","ipod, iphone, webkit","DetectIpod(), DetectIphoneOrIpod(), DetectIos(), DetectWebKit()",High,iOS v 6 on iPod Touch (Device launched Fall 2012),International,"UA string captured on a device in the Apple store, Oct. 2012." +tablet,Apple,iPad,iOS,Safari Mobile,"Mozilla/5.0 (iPad; U; CPU OS 4_3_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8G4 Safari/6533.18.5","ipad, webkit","DetectIpad(), DetectWebKit()",High,The Apple iPad running iOS version 4.,International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Apple,iPod Touch,iOS ,Safari Mobile,"Mozilla/5.0 (iPod; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7","ipod, iphone, webkit","DetectIpod(), DetectIphoneOrIpod(), DetectIos(), DetectWebKit()",High,iOS v 4 on iPod Touch,International,http://www.zytrax.com/tech/web/browser_ids.htm +mobile,Amazon,Kindle ,Kindle,Kindle (Monochrome),"Mozilla/5.0 (Linux; U; en-US) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) Version/4.0 Kindle/3.0 (screen 600×800; rotate)","kindle, webkit","DetectKindle(), DetectWebKit()",High,For the eInk monochrome devices only. ,International,http://www.labnol.org/software/kindle-user-agent-string/20378/ +mobile,Archos,605 WiFi,Linux,Opera,opera/9.02 (linux armv5tejl; u; archos; gogi; a605; en),archos,"DetectArchos(), DetectMobileQuick(), DetectTierOtherPhones()",n/a,An older 4.3 inch video & music player with an embedded browser. Released about 2007. ,International,"Screenshot from a friend who owns the device. Info & specs: +http://www.mobiletechreview.com/mediaplayers/Archos-605-wifi.htm" +mobile,Archos,7 Internet Media Tablet,Linux,Opera,opera/9.02 (linux armv71; u; archos; gogi; g61; version 1.7.22 (wmdrmpd: 10.1) ; en),archos,"DetectArchos(), DetectMobileQuick(), DetectTierOtherPhones()",n/a,An older 7 inch portable video & music player with an embedded browser. Released about 2009. ,International,"Screenshot from a friend who owns the device. Info & specs: +http://www.mobiletechreview.com/mediaplayers/Archos-7.htm" +mobile,Garmin ,Nüvifone G60,Linux,WebKit-based,"Mozilla/5.0 (Linux; U; arm; xx-xx, Nuvifone) AppleWebKit/523.13 (KHTML, like Gecko) Version/3.0 Mobile Safari/419.3 Qt Qtopia Iris/1.1.2","mobile, webkit","DetectGarminNuvifone(), DetectTierRichCss()",Low,"Because of its capable WebKit-based browser, this device was singled out for addition to the code. Released to AT&T in late 2009. Other Garmin phones based on Android ought to self-report as Android devices.",USA,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=garmin_nuviphone_ver1 +mobile,Sony,Mylo COM 1,Linux,Opera,Opera/8.02 (Qt embedded; Linux armv4ll; U) [ja] SONY/COM1,sony/com,"DetectSonyMylo(), DetectMobileLong()",Low,A poorly selling Internet tablet around 2007.,,http://www.osnews.com/thread?186230 +mobile,Sony,Mylo COM 2,Linux,Unknown (Netfront?),"Mozilla/5.0 (Linux, Sony/COM2/1.01 [en]; like Gecko/2007) Firefox/2",sony/com,"DetectSonyMylo(), DetectMobileLong()",Low,A poorly selling Internet tablet around 2007.,International,http://www.myuseragentstring.com/useragents/sony/sony_mylo_ver1/ +mobile,Nokia,N800,Maemo,Fennec (Mobile Firefox),Mozilla/5.0 (X11; U; Linux armv61; en-US; rv:1.9.1b2pre) Gecko/20081015 Fennec/1.0a1,n/a,Unsupported,Low - LMP-B,"Fennec was a beta on Maemo, more of an experiment.",International,http://www.zytrax.com/tech/web/browser_ids.htm +mobile,Nokia,N800,Maemo,Firefox,Mozilla/5.0 (X11; U; Linux armv6l; en-US; rv:1.9a6pre) Gecko/20070810 Firefox/3.0a1 Tablet browser 0.1.16 RX-34_2007SE_4.2007.38-2,"linux, tablet",DetectMaemoTablet(),Low,"On the Nokia N800, may have been the default browser.",International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Nokia,N900,Maemo,Firefox,Mozilla/5.0 (X11; U; Linux armv7l; en-GB; rv:1.9.2b6pre) Gecko/20100318 Firefox/3.5 Maemo Browser 1.7.4.7 RX-51 N900,maemo,DetectMaemoTablet(),Low,"Nokia's only Maemo phone. It was high visibility around 2010. Although the browser was decently capable, it's not worth putting in exception code to move it to the RichCSS Tier.",International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Nokia,N800,Maemo,Links,Links (2.1pre31; Linux 2.6.21-omap1 armv6l; x),n/a,Unsupported,L - LMP-B,UA for the Links browser for Nokia's Maemo platform.,International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Nokia,N800,Maemo,Midori,"Mozilla/5.0 (X11; U; Linux armv6l; en-us) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) midori",n/a,Unsupported,L - LMP-B,UA for the Midori browser for Maemo. Midori was released on a few other small devices. (Wikipedia),International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Nokia,N800,Maemo,Minimo,Mozilla/5.0 (X11; U; Linux armv6l; rv 1.8.1.5pre) Gecko/20070619 Minimo/0.020,n/a,Unsupported,Low - LMP-B,This was basically an experimental version of Firefox that was only minimally released for the Nokia N800. Predates Fennec.,International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Nokia,N800,Maemo,Prism,Mozilla/5.0 (X11; U; Linux armv6l; en-US; rv: 1.9.1a2pre) Gecko/20080813221937 Prism/0.9.1,n/a,Unsupported,L - LMP-B,UA for the Links browser for Nokia's Maemo platform.,International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Nokia,N800,Maemo,Tear,"Mozilla/5.0 (X11; U; Linux armv6l; en-us) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) tear",n/a,Unsupported,L - LMP-B,Beta for the Tear browser for Nokia's Maemo platform.,International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Nokia,"N9 +N950",Meego,Meego (Nokia),"Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13","meego, webkit, mobile","DetectMeego(), DetectMobileQuick(), DetectWebkit(), DetectTierRichCss()",Low,A device with limited sales and a deadend mobile OS. Both this device and the Nokia N950 shared the same useragent string. ,International,http://www.developer.nokia.com/Resources/Library/Web/#!nokia-browsers/nokia-browser-85-for-meego-12-harmattan/user-agent.html +mobile,Nokia,"N9 +N950",Meego,Opera,Opera/9.80 (Linux armv7l; Opera Mobi/1; MeeGo) Presto/2.11.355 Version/12.10,"meego, webkit, mobile","DetectMeego(), DetectMobileQuick(), DetectWebkit(), DetectTierRichCss()",Low,A device with limited sales and a deadend mobile OS. Both this device and the Nokia N950 shared the same useragent string. ,International,http://www.developer.nokia.com/Resources/Library/Web/#!nokia-browsers/nokia-browser-85-for-meego-12-harmattan/user-agent.html +mobile,Various,Various,Mobile Devices,Bolt,"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; BOLT/2.800) AppleWebKit/534.6 (KHTML, like Gecko) Version/5.0 Safari/534.6.3",n/a,Unsupported,Low - LMP-B,The Bolt mobile browser. Not sure if this is a generic UA for installed devices or also when white labeled.,International,http://www.zytrax.com/tech/web/mobile_ids.html#bolt +mobile,Palm,Centro,PalmOS,Blazer,Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Palmsource/Palm-D062; Blazer/4.5) 16;320X320,palm,DetectPalmWebOS(),Low,"Released in late 2007, this was the last significant PalmOS consumer device. It was a popular device in 2008. ",USA,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=palm_centro_ver1 +mobile,Palm,Various,PalmOS,Skysurf,Mozilla/4.74 [en] (X11; I; ProxiNet),n/a,Unsupported,L - LMP-B,"An archaic browser on a dead platform: ""Zero Grvaity's Skysurf, running under PalmOS 3.0""",International,http://www.zytrax.com/tech/web/mobile_ids.html +tablet,BlackBerry,PlayBook,PlayBook,PlayBook,"Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.7 Safari/534.11+",playbook,DetectBlackBerryTablet(),High,"The BlackBerry PlayBook tablet, launched 2011.",International,Sent by a MobileESP user based on his web site access logs +mobile,Sony,Playstation,Playstation,Playstation,Mozilla/5.0 (PLAYSTATION 3; 1.00),playstation,"DetectSonyPlaystation(), DetectGameConsole()",Medium,A Sony Playstation gaming console.,International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Sony,Playstation,Playstation,Playstation,"Mozilla/5.0 (PLAYSTATION 3 4.11) AppleWebKit/531.22.8 (KHTML, like Gecko)",playstation,"DetectSonyPlaystation(), DetectGameConsole(), DetectWebKit()",Low,Another version of a useragent for Sony Playstation gaming console.,International,http://www.hvz.baden-wuerttemberg.de/analysehvz/agent_201203.html +mobile,Sony,Playstation Portable,Playstation,Playstation,Mozilla/4.0 (PSP (PlayStation Portable); 2.00),playstation,"DetectSonyPlaystation(), DetectGameConsole()",Low,A handheld gaming console.,International,http://www.hvz.baden-wuerttemberg.de/analysehvz/agent_201203.html +mobile,Sony,Playstation Vita,Playstation,Playstation (Webkit),"Mozilla/5.0 (Playstation Vita 2.02) AppleWebKit/536.26 (KHTML, like Gecko) Silk/3.2","playstation, webkit","DetectSonyPlaystation(), DetectWebKit(), DetectGameConsole(), DetectPlayStationHandheld(), DetectTierIphone()",Medium,A handheld gaming console with an iPhone-class browser.,International,http://community.eu.playstation.com/t5/PS-Vita-General-Discussion/PS-vita-web-browser-a-few-details/td-p/14477729 +mobile,bSquare,bSquare,PocketPC,MS IE Mobile,Mozilla/4.0 (compatible; MSIE 5.5; Windows NT) (compatible; MSIE 5.5; Windows NT),n/a,Unsupported,Low - LMP - D,bSquare never sold their devices to consumers under their own label. This was the UA on reference hardware during early testing. ,None,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,HTC,Touch Pro,PocketPC,MS IE Mobile,XV6850 Opera/9.50 (Windows NT 5.1; U; en),n/a,Unsupported,Low - LMI,Not worth the effort to add support for this one obsolete device. The only unique element is the device ID (XV6850).,USA,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Sharp,Zarus SL-C750,PocketPC,MS IE Mobile,Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.18-rmk7-pxa3-embedix armv5tel; 480x640) Opera 6.0 [en],n/a,Unsupported,L - LMI,An old PocketPC-based Zarus PDA. May have been marketed outside of Japan.,Japan,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Various,Various,PocketPC,MS IE Mobile,Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; 240x320),windows ce,DetectWindowsMobile(),Low - OD,,International,http://www.zytrax.com/tech/web/browser_ids.htm +mobile,Various,Various,PocketPC,Opera Mobile,Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; PPC; 480x640) Opera 8.60 [en],"opera, windows ce","DetectOperaMobile(), DetectWindowsMobile()",Medium,Opera Mobile on Windows PocketPC devices.,International,http://www.zytrax.com/tech/web/browser_ids.htm +TV,ROku,various,Roku,WebView,Roku/DVP-5.2 (025.02E03197A),roku,"DetectRokuTV() +DetectSmartTV()",Low,"Roku doesn't have a standalone browser. Instead, apps can use a WebView to display HTML content. ",International,https://udger.com/resources/ua-list/device-detail?device=Smart+TV +mobile,Nokia,Nokia X3-02,S40,WAP Browser,Mozilla/5.0 (Series40; NokiaX3-02/06.00; Profile/MIDP-2.1 Configuration/CLDC-1.1) Gecko/20100401 S40OviBrowser/1.5.0.34.11,midp,DetectMobileQuick(),Medium,"Nokia still sells tons of S40-based feature phones around the world. Especially in developing countries, these devices are often used for accessing web sites. ",International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Jolla,Various,Sailfish,SailfishBrowser,Mozilla/5.0 (Maemo; Linux; U; Jolla; Sailfish; Mobile; rv:31.0) Gecko/31.0 Firefox/31.0 SailfishBrowser/1.0,"sailfish, mobile","DetectSailfish(), DetectSailfishPhone(), DetectTierIphone(), DetectSmartphone(), DetectMobileQuick()",Low,Potential new up and coming mobile OS.,International,https://together.jolla.com/question/81498/webservice-request-from-android-app-seems-to-be-overridden-with-user-agent-string-phandroidappl/ +tablet,Jolla,Various,Sailfish,SailfishBrowser,None available yet,TBD,TBD,Low,Potential new up and coming mobile OS. This Tablet method is speculative right now pending confirmation of useragent. ,International, +mobile,Nokia,Various,Symbian,Opera Mobile,Opera/9.80 (S60; SymbOS; Opera Mobi/499; U; ru) Presto/2.4.18 Version/10.00,"opera mobi, symbos","DetectOperaMobile(), DetectSymbianOS()",Medium,Opera Mobile 10.0 running on Nokia Symbian S60 devices.,International,http://www.zytrax.com/tech/web/browser_ids.htm +mobile,Nokia,Nokia 5800 XpressMusic,Symbian,OSS Browser,"Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0 Nokia5800d-1/21.0.025; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413","symbian, series60, webkit","DetectS60OssBrowser() +DetectSymbianOS(), DetectWebKit(), DetectTierRichCss()",Low,The OSS WebKit browser shipping on the new touch-based Nokia 5800 running S60 5th Edition.,International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Nokia,Nokia 701 (Belle Refresh),Symbian,OSS Browser,"Mozilla/5.0 (Symbian/3; Series60/5.3 Nokia701/111.020.0307; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.4.1.14 Mobile Safari/533.4 3gpp-gba","symbian, series60, webkit","DetectS60OssBrowser() +DetectSymbianOS(), DetectWebKit(), DetectTierRichCss()",Medium,"The OSS WebKit browser shipping on the 2010 Nokia 701 running Symbian^3 (the open sourced version of Symbian). ""Belle"" OS update.",International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Nokia,Nokia N8 (Anna Refresh),Symbian,OSS Browser,"Mozilla/5.0 (Symbian/3; Series60/5.2 NokiaN8-00/012.002; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.0 Mobile Safari/533.4 3gpp-gba","symbian, series60, webkit","DetectS60OssBrowser() +DetectSymbianOS(), DetectWebKit(), DetectTierRichCss()",Medium,"The OSS WebKit browser shipping on the 2010 flagship Nokia N8 running Symbian^3 (the open sourced version of Symbian). ""Anna"" OS update.",International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Nokia,S60 r3 Newer Devices,Symbian,OSS Browser,"Mozilla/5.0 (SymbianOS/9.1; U; [en]; Series60/3.0 NokiaE60/4.06.0) AppleWebKit/413 (KHTML, like Gecko) Safari/413","symbian, series60","DetectS60OssBrowser() +DetectSymbianOS(), DetectTierRichCss()",Low,"The ""new"" WebKit-based Open Source browser on later batches of Symbian r3 devices. 2006-07 era, probably. ",International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Nokia,S60 r3 Older Devices,Symbian,OSS Browser,"Mozilla/5.0 (SymbianOS/9.1; U; [en-us]) AppleWebKit/413 (KHTML, like Gecko) Safari/413",symbian,"DetectS60OssBrowser() +DetectSymbianOS(), DetectTierRichCss()",Low,"The ""new"" WebKit-based Open Source browser on the first batch or so of Symbian r3 devices. 2006-07 era, probably. ",International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Nokia,Nokia N73 (S60 r3),Symbian,S60 WAP Browser,NokiaN73-2/3.0-630.0.2 Series60/3.0 Profile/MIDP-2.0 Configuration/CLDC-1.1,symbian,DetectSymbianOS(),Low,This was for the original proprietary S60 WAP browser that was NOT based on WebKit. It shipped on many devices simultaneously with the newer OSS browser in S60 r3 before finally being killed. ,International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Various,Various,Symbian,Opera Mini,Opera/9.80 (Series 60; Opera Mini/6.1.26266/26.1069; U; en) Presto/2.8.119 Version/10.54,opera mini,DetectOperaMobile(),Medium,Version of Opera Mini for such Symbian devices as the Nokia E63.,International,http://www.handsetdetection.com/properties/tags/Nokia/E63/Opera%20Mini/6.1.26266 +mobile,Sony Ericsson,W960i,Symbian UIQ,Opera Mobile,SonyEricssonW960i/R100 Mozilla/4.0 (compatible; MSIE 6.0; Symbian OS; 701) Opera 8.65 [de],symbian,DetectSymbianOS(),Low,A poorly selling (but great) UIQ phone. One of Sony Ericsson's last UIQ devices.,International,http://www.mobile-phone-specs.com/model/sonyericsson_w960i_ver1/ +mobile,Samsung,TBD,Tizen,Tizen,"Mozilla/5.0 (SAMSUNG; SAMSUNG-GT-i9500/1.0; U; Tizen/1.0 like Android; en-us) AppleWebKit/534.46 (KHTML, like Gecko) SLP Browser/1.0 Mobile","tizen, mobile, webkit","DetectTizen(), +DetectWebKit(), +DetectTierIphone(), DetectSmartphone()",Low,Tizen is a new Linux-based smartphone platform being launched by Samsung and Intel. Browser capabilities are expected to be at least as good as Android's. ,International,"From a MobileESP community member, December 2012" +TV,Samsung,Various,Tizen TV,Browser,"Mozilla/5.0 (SMART-TV; Linux; Tizen 2.3) AppleWebkit/538.1 (KHTML, like Gecko) SamsungBrowser/1.0 TV Safari/538.1","tizen, smart-tv",DetectTizenTV(),Low,Samsung is committed to Tizen for its smart TV platform. ,International,http://developer.samsung.com/technical-doc/view.do?v=T000000203 +mobile,Various,Various,Ubuntu Mobile,Browser,Mozilla/5.0 (Linux; Ubuntu 14.04 like Android 4.4) AppleWebKit/537.36 Chromium/35.0.1870.2 Mobile Safari/537.36,"ubuntu, mobile","DetectUbuntu(), DetectUbuntuPhone(), DetectTierIphone(), DetectSmartphone(), DetectMobileQuick(), DetectWebkit()",Low,Potential new up and coming mobile OS.,International,https://plus.google.com/+SimosXenitellis/posts/hfnnDpgFEZA +tablet,Various,Various,Ubuntu Mobile,Browser,None available yet,"ubuntu, tablet","DetectUbuntu(), DetectUbuntuTablet(), DetectTierTablet()",Low,Potential new up and coming mobile OS. This Tablet method is speculative right now pending confirmation of useragent. ,International,http://daker.me/2013/11/ubuntu-touch-user-agent.html +tablet,HP,TouchPad,WebOS,WebOS,"Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.2; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/234.40.1 Safari/534.6 TouchPad/1.0",hpwos,DetectWebOSTablet(),High,HP WebOS-based TouchPad tablet,International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Palm,Pre,WebOS,WebOS (WebKit-based),"Mozilla/5.0 (webOS/1.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0",webos,DetectPalmWebOS(),Medium,The Palm Pre was the first WebOS device.,International,http://www.zytrax.com/tech/web/mobile_ids.html +TV,LG,Various,WebOS TV,Browser,"Mozilla/5.0 (Web0S; Linux/SmartTV) AppleWebKit/538.2 (KHTML, like Gecko) Large Screen WebAppManager Safari/538.2","webos, smarttv",DetectWebOSTV(),Low,LG is committed to WebOS for its smart TV platform. ,International,http://developer.lge.com/webOSTV/develop/web-app/webos-tv-platform/web-engine +desktop,Acer,Iconia W500,Windows,Internet Explorer,Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Tablet PC 2.0; MAAR; .NET4.0C),n/a,FALSE,High,"A tablet PC device probably launched with Windows 7. As with all ""desktop"" devices, should not be detected by MobileESP.",International,http://www.zytrax.com/tech/web/mobile_ids.html +game,Microsoft ,Xbox,Windows,Internet Explorer,Mozilla/5.0 (Windows NT 5.1; rv:6.0.2) xbox Gecko/20100101 Firefox/6.0.2,xbox,"DetectXbox(), DetectGameConsole()",Medium,A popular gaming console.,International,http://www.botsvsbrowsers.com/details/731405/index.html +mobile,Various,Various,Windows CE,Minimo,Mozilla/5.0 (Windows; U; Windows CE 5.1; rv:1.8.1a3) Gecko/20060610 Minimo/0.016,windows ce,"Unsupported +(Reports true for DetectWindowsMobile())",Low - LMP-B,This was basically an experimental version of Firefox that was only minimally released for WinCE PDAs. Predates Fennec.,International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,Various,Various,Windows CE,Opera Mobile,Opera/9.80 (Windows Mobile; WCE; Opera Mobi/WMD-50433; U; en) Presto/2.4.13 Version/10.00,opera,DetectOperaMobile(),Medium,Opera Mobile 10.0 running on Windows Mobile.,International,http://www.zytrax.com/tech/web/browser_ids.htm +mobile,Various,Various,"Windows CE +(PocketPC ?)",MS IE Mobile,Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11),"windows ce, iemobile",DetectWindowsMobile(),Low - OD,Such as Palm-branded PocketPC devices and the HTC Touch.,International,http://www.zytrax.com/tech/web/browser_ids.htm +mobile,Dell,Venue Pro,Windows Phone,MS IE Mobile,Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; DELL; Venue Pro),windows phone os 7,DetectWindowsPhone7(),High,"Dell Venue Pro, a Windows Phone 7 device",International,http://www.zytrax.com/tech/web/mobile_ids.html +mobile,HTC,8x,Windows Phone,Internet Explorer,Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; HTC; 0002),windows phone 8,"DetectWindowsPhone8(), DetectTierIphone(), DetectSmartphone()",High,HTC's flagship WP8 device for late 2012 and going into 2013.,USA & International,http://developer.att.com/developer/device_detailSpec.jsp?id=12600013 +mobile,Nokia,Lumia 900,Windows Phone,Internet Explorer,Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 900),windows phone os 7,"DetectWindowsPhone7(), DetectTierIphone(), DetectSmartphone()",High,Nokia's flagship WP7 device for 2012.,USA & International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Nokia,Lumia 920,Windows Phone,Internet Explorer,Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920),windows phone 8,"DetectWindowsPhone8(), DetectTierIphone(), DetectSmartphone()",High,Nokia's flagship WP8 device for late 2012 and going into 2013.,USA & International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Nokia,Lumia 800,Windows Phone ,Internet Explorer,"Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 800) +",windows phone os 7,"DetectWindowsPhone7(), DetectTierIphone(), DetectSmartphone()",Medium,"One of Nokia's first, best Windows Phone devices (2011).",International,http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices +mobile,Palm,Treo 800w,Windows PocketPC,Internet Explorer,"Treo800w/v0100 Mozilla/4.0 (compatible; MSIE 4.01; Windows CE, PPC; 320x320) (compatible; MSIE 6.0; Windows CE; IEMobile 7.11)",windows ce,DetectWindowsMobile(),Low,One of Palm's more successful Windows Mobile devices. Released in 2008.,International,http://www.tera-wurfl.com/explore/?action=wurfl_id&id=palm_treo800w_ver1 \ No newline at end of file diff --git a/vendor/ahand/mobileesp/MobileESP_UA-Test-Strings/MobileESP UA Test Strings.xlsx b/vendor/ahand/mobileesp/MobileESP_UA-Test-Strings/MobileESP UA Test Strings.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..85067cec24e0a195a553987c3cfd1163ddb73689 GIT binary patch literal 41819 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 U0s;Y{{C=Q;0|7DT{PFI80JMoMrvLx| literal 0 HcmV?d00001 diff --git a/vendor/ahand/mobileesp/PHP/mdetect.php b/vendor/ahand/mobileesp/PHP/mdetect.php new file mode 100755 index 00000000000..47810a45b0b --- /dev/null +++ b/vendor/ahand/mobileesp/PHP/mdetect.php @@ -0,0 +1,1287 @@ +<?php + +/* ******************************************* +// Copyright 2010-2015, Anthony Hand +// +// +// File version 2015.05.13 (May 13, 2015) +// Updates: +// - Moved MobileESP to GitHub. https://github.com/ahand/mobileesp +// - Opera Mobile/Mini browser has the same UA string on multiple platforms and doesn't differentiate phone vs. tablet. +// - Removed DetectOperaAndroidPhone(). This method is no longer reliable. +// - Removed DetectOperaAndroidTablet(). This method is no longer reliable. +// - Added support for Windows Phone 10: variable and DetectWindowsPhone10() +// - Updated DetectWindowsPhone() to include WP10. +// - Added support for Firefox OS. +// - A variable plus DetectFirefoxOS(), DetectFirefoxOSPhone(), DetectFirefoxOSTablet() +// - NOTE: Firefox doesn't add UA tokens to definitively identify Firefox OS vs. their browsers on other mobile platforms. +// - Added support for Sailfish OS. Not enough info to add a tablet detection method at this time. +// - A variable plus DetectSailfish(), DetectSailfishPhone() +// - Added support for Ubuntu Mobile OS. +// - DetectUbuntu(), DetectUbuntuPhone(), DetectUbuntuTablet() +// - Added support for 2 smart TV OSes. They lack browsers but do have WebViews for use by HTML apps. +// - One variable for Samsung Tizen TVs, plus DetectTizenTV() +// - One variable for LG WebOS TVs, plus DetectWebOSTV() +// - Updated DetectTizen(). Now tests for “mobile†to disambiguate from Samsung Smart TVs +// - Removed variables for obsolete devices: deviceHtcFlyer, deviceXoom. +// - Updated DetectAndroid(). No longer has a special test case for the HTC Flyer tablet. +// - Updated DetectAndroidPhone(). +// - Updated internal detection code for Android. +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android and reports here if relevant. +// - Updated DetectAndroidTablet(). +// - No longer has a special test case for the HTC Flyer tablet. +// - Checks against DetectOperaMobile() on Android to exclude it from here. +// - DetectMeego(): Changed definition for this method. Now detects any Meego OS device, not just phones. +// - DetectMeegoPhone(): NEW. For Meego phones. Ought to detect Opera browsers on Meego, as well. +// - DetectTierIphone(): Added support for phones running Sailfish, Ubuntu and Firefox Mobile. +// - DetectTierTablet(): Added support for tablets running Ubuntu and Firefox Mobile. +// - DetectSmartphone(): Added support for Meego phones. +// - Reorganized DetectMobileQuick(). Moved the following to DetectMobileLong(): +// - DetectDangerHiptop(), DetectMaemoTablet(), DetectSonyMylo(), DetectArchos() +// - Removed the variable for Obigo, an embedded browser. The browser is on old devices. +// - Couldn’t find info on current Obigo embedded browser user agent strings. +// +// +// +// LICENSE INFORMATION +// 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. +// +// +// ABOUT THIS PROJECT +// Project Owner: Anthony Hand +// Email: anthony.hand@gmail.com +// Web Site: http://www.mobileesp.com +// Source Files: https://github.com/ahand/mobileesp +// +// Versions of this code are available for: +// PHP, JavaScript, Java, ASP.NET (C#), and Ruby +// +// ******************************************* +*/ + + + +//************************** +// The uagent_info class encapsulates information about +// a browser's connection to your web site. +// You can use it to find out whether the browser asking for +// your site's content is probably running on a mobile device. +// The methods were written so you can be as granular as you want. +// For example, enquiring whether it's as specific as an iPod Touch or +// as general as a smartphone class device. +// The object's methods return 1 for true, or 0 for false. +class uagent_info +{ + var $useragent = ""; + var $httpaccept = ""; + + //standardized values for true and false. + var $true = 1; + var $false = 0; + + //Let's store values for quickly accessing the same info multiple times. InitCompleted + var $initCompleted = 0; //Stores whether we're currently initializing the most popular functions. + var $isWebkit = 0; //Stores the result of DetectWebkit() + var $isMobilePhone = 0; //Stores the result of DetectMobileQuick() + var $isIphone = 0; //Stores the result of DetectIphone() + var $isAndroid = 0; //Stores the result of DetectAndroid() + var $isAndroidPhone = 0; //Stores the result of DetectAndroidPhone() + var $isTierTablet = 0; //Stores the result of DetectTierTablet() + var $isTierIphone = 0; //Stores the result of DetectTierIphone() + var $isTierRichCss = 0; //Stores the result of DetectTierRichCss() + var $isTierGenericMobile = 0; //Stores the result of DetectTierOtherPhones() + + //Initialize some initial smartphone string variables. + var $engineWebKit = 'webkit'; + var $deviceIphone = 'iphone'; + var $deviceIpod = 'ipod'; + var $deviceIpad = 'ipad'; + var $deviceMacPpc = 'macintosh'; //Used for disambiguation + + var $deviceAndroid = 'android'; + var $deviceGoogleTV = 'googletv'; + + var $deviceWinPhone7 = 'windows phone os 7'; + var $deviceWinPhone8 = 'windows phone 8'; + var $deviceWinPhone10 = 'windows phone 10'; + var $deviceWinMob = 'windows ce'; + var $deviceWindows = 'windows'; + var $deviceIeMob = 'iemobile'; + var $devicePpc = 'ppc'; //Stands for PocketPC + var $enginePie = 'wm5 pie'; //An old Windows Mobile + + var $deviceBB = 'blackberry'; + var $deviceBB10 = 'bb10'; //For the new BB 10 OS + var $vndRIM = 'vnd.rim'; //Detectable when BB devices emulate IE or Firefox + var $deviceBBStorm = 'blackberry95'; //Storm 1 and 2 + var $deviceBBBold = 'blackberry97'; //Bold 97x0 (non-touch) + var $deviceBBBoldTouch = 'blackberry 99'; //Bold 99x0 (touchscreen) + var $deviceBBTour = 'blackberry96'; //Tour + var $deviceBBCurve = 'blackberry89'; //Curve2 + var $deviceBBCurveTouch = 'blackberry 938'; //Curve Touch + var $deviceBBTorch = 'blackberry 98'; //Torch + var $deviceBBPlaybook = 'playbook'; //PlayBook tablet + + var $deviceSymbian = 'symbian'; + var $deviceS60 = 'series60'; + var $deviceS70 = 'series70'; + var $deviceS80 = 'series80'; + var $deviceS90 = 'series90'; + + var $devicePalm = 'palm'; + var $deviceWebOS = 'webos'; //For Palm devices + var $deviceWebOStv = 'web0s'; //For LG TVs + var $deviceWebOShp = 'hpwos'; //For HP's line of WebOS devices + + var $deviceNuvifone = 'nuvifone'; //Garmin Nuvifone + var $deviceBada = 'bada'; //Samsung's Bada OS + var $deviceTizen = 'tizen'; //Tizen OS + var $deviceMeego = 'meego'; //Meego OS + var $deviceSailfish = 'sailfish'; //Sailfish OS + var $deviceUbuntu = 'ubuntu'; //Ubuntu Mobile OS + + var $deviceKindle = 'kindle'; //Amazon Kindle, eInk one + var $engineSilk = 'silk-accelerated'; //Amazon's accelerated Silk browser for Kindle Fire + + var $engineBlazer = 'blazer'; //Old Palm browser + var $engineXiino = 'xiino'; //Another old Palm + + //Initialize variables for mobile-specific content. + var $vndwap = 'vnd.wap'; + var $wml = 'wml'; + + //Initialize variables for other random devices and mobile browsers. + var $deviceTablet = 'tablet'; //Generic term for slate and tablet devices + var $deviceBrew = 'brew'; + var $deviceDanger = 'danger'; + var $deviceHiptop = 'hiptop'; + var $devicePlaystation = 'playstation'; + var $devicePlaystationVita = 'vita'; + var $deviceNintendoDs = 'nitro'; + var $deviceNintendo = 'nintendo'; + var $deviceWii = 'wii'; + var $deviceXbox = 'xbox'; + var $deviceArchos = 'archos'; + + var $engineFirefox = 'firefox'; //For Firefox OS + var $engineOpera = 'opera'; //Popular browser + var $engineNetfront = 'netfront'; //Common embedded OS browser + var $engineUpBrowser = 'up.browser'; //common on some phones + var $engineOpenWeb = 'openweb'; //Transcoding by OpenWave server + var $deviceMidp = 'midp'; //a mobile Java technology + var $uplink = 'up.link'; + var $engineTelecaQ = 'teleca q'; //a modern feature phone browser + + var $devicePda = 'pda'; //some devices report themselves as PDAs + var $mini = 'mini'; //Some mobile browsers put 'mini' in their names. + var $mobile = 'mobile'; //Some mobile browsers put 'mobile' in their user agent strings. + var $mobi = 'mobi'; //Some mobile browsers put 'mobi' in their user agent strings. + + //Smart TV strings + var $smartTV1 = 'smart-tv'; //Samsung Tizen smart TVs + var $smartTV2 = 'smarttv'; //LG WebOS smart TVs + + //Use Maemo, Tablet, and Linux to test for Nokia's Internet Tablets. + var $maemo = 'maemo'; + var $linux = 'linux'; + var $qtembedded = 'qt embedded'; //for Sony Mylo and others + var $mylocom2 = 'com2'; //for Sony Mylo also + + //In some UserAgents, the only clue is the manufacturer. + var $manuSonyEricsson = "sonyericsson"; + var $manuericsson = "ericsson"; + var $manuSamsung1 = "sec-sgh"; + var $manuSony = "sony"; + var $manuHtc = "htc"; //Popular Android and WinMo manufacturer + + //In some UserAgents, the only clue is the operator. + var $svcDocomo = "docomo"; + var $svcKddi = "kddi"; + var $svcVodafone = "vodafone"; + + //Disambiguation strings. + var $disUpdate = "update"; //pda vs. update + + + //************************** + //The constructor. Allows the latest PHP (5.0+) to locate a constructor object and initialize the object. + function __construct() + { + $this->uagent_info(); + } + + + //************************** + //The object initializer. Initializes several default variables. + function uagent_info() + { + $this->useragent = isset($_SERVER['HTTP_USER_AGENT'])?strtolower($_SERVER['HTTP_USER_AGENT']):''; + $this->httpaccept = isset($_SERVER['HTTP_ACCEPT'])?strtolower($_SERVER['HTTP_ACCEPT']):''; + + //Let's initialize some values to save cycles later. + $this->InitDeviceScan(); + } + + //************************** + // Initialize Key Stored Values. + function InitDeviceScan() + { + //Save these properties to speed processing + global $isWebkit, $isIphone, $isAndroid, $isAndroidPhone; + $this->isWebkit = $this->DetectWebkit(); + $this->isIphone = $this->DetectIphone(); + $this->isAndroid = $this->DetectAndroid(); + $this->isAndroidPhone = $this->DetectAndroidPhone(); + + //These tiers are the most useful for web development + global $isMobilePhone, $isTierTablet, $isTierIphone; + $this->isMobilePhone = $this->DetectMobileQuick(); + $this->isTierIphone = $this->DetectTierIphone(); + $this->isTierTablet = $this->DetectTierTablet(); + + //Optional: Comment these out if you NEVER use them. + global $isTierRichCss, $isTierGenericMobile; + $this->isTierRichCss = $this->DetectTierRichCss(); + $this->isTierGenericMobile = $this->DetectTierOtherPhones(); + + $this->initCompleted = $this->true; + } + + //************************** + //Returns the contents of the User Agent value, in lower case. + function Get_Uagent() + { + return $this->useragent; + } + + //************************** + //Returns the contents of the HTTP Accept value, in lower case. + function Get_HttpAccept() + { + return $this->httpaccept; + } + + + //***************************** + // Start device detection + //***************************** + + //************************** + // Detects if the current device is an iPhone. + function DetectIphone() + { + if ($this->initCompleted == $this->true || + $this->isIphone == $this->true) + return $this->isIphone; + + if (stripos($this->useragent, $this->deviceIphone) > -1) + { + //The iPad and iPod Touch say they're an iPhone. So let's disambiguate. + if ($this->DetectIpad() == $this->true || + $this->DetectIpod() == $this->true) + return $this->false; + //Yay! It's an iPhone! + else + return $this->true; + } + else + return $this->false; + } + + //************************** + // Detects if the current device is an iPod Touch. + function DetectIpod() + { + if (stripos($this->useragent, $this->deviceIpod) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device is an iPad tablet. + function DetectIpad() + { + if (stripos($this->useragent, $this->deviceIpad) > -1 && + $this->DetectWebkit() == $this->true) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device is an iPhone or iPod Touch. + function DetectIphoneOrIpod() + { + //We repeat the searches here because some iPods may report themselves as an iPhone, which would be okay. + if ($this->DetectIphone() == $this->true || + $this->DetectIpod() == $this->true) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects *any* iOS device: iPhone, iPod Touch, iPad. + function DetectIos() + { + if (($this->DetectIphoneOrIpod() == $this->true) || + ($this->DetectIpad() == $this->true)) + return $this->true; + else + return $this->false; + } + + + //************************** + // Detects *any* Android OS-based device: phone, tablet, and multi-media player. + // Also detects Google TV. + function DetectAndroid() + { + if ($this->initCompleted == $this->true || + $this->isAndroid == $this->true) + return $this->isAndroid; + + if ((stripos($this->useragent, $this->deviceAndroid) > -1) + || ($this->DetectGoogleTV() == $this->true)) + return $this->true; + + return $this->false; + } + + //************************** + // Detects if the current device is a (small-ish) Android OS-based device + // used for calling and/or multi-media (like a Samsung Galaxy Player). + // Google says these devices will have 'Android' AND 'mobile' in user agent. + // Ignores tablets (Honeycomb and later). + function DetectAndroidPhone() + { + if ($this->initCompleted == $this->true || + $this->isAndroidPhone == $this->true) + return $this->isAndroidPhone; + + //First, let's make sure we're on an Android device. + if ($this->DetectAndroid() == $this->false) + return $this->false; + + //If it's Android and has 'mobile' in it, Google says it's a phone. + if (stripos($this->useragent, $this->mobile) > -1) + return $this->true; + + //Special check for Android devices with Opera Mobile/Mini. They should report here. + if (($this->DetectOperaMobile() == $this->true)) + return $this->true; + + return $this->false; + } + + //************************** + // Detects if the current device is a (self-reported) Android tablet. + // Google says these devices will have 'Android' and NOT 'mobile' in their user agent. + function DetectAndroidTablet() + { + //First, let's make sure we're on an Android device. + if ($this->DetectAndroid() == $this->false) + return $this->false; + + //Special check for Android devices with Opera Mobile/Mini. They should NOT report here. + if ($this->DetectOperaMobile() == $this->true) + return $this->false; + + //Otherwise, if it's Android and does NOT have 'mobile' in it, Google says it's a tablet. + if (stripos($this->useragent, $this->mobile) > -1) + return $this->false; + else + return $this->true; + } + + //************************** + // Detects if the current device is an Android OS-based device and + // the browser is based on WebKit. + function DetectAndroidWebKit() + { + if (($this->DetectAndroid() == $this->true) && + ($this->DetectWebkit() == $this->true)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device is a GoogleTV. + function DetectGoogleTV() + { + if (stripos($this->useragent, $this->deviceGoogleTV) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is based on WebKit. + function DetectWebkit() + { + if ($this->initCompleted == $this->true || + $this->isWebkit == $this->true) + return $this->isWebkit; + + if (stripos($this->useragent, $this->engineWebKit) > -1) + return $this->true; + else + return $this->false; + } + + + //************************** + // Detects if the current browser is a + // Windows Phone 7, 8, or 10 device. + function DetectWindowsPhone() + { + if (($this->DetectWindowsPhone7() == $this->true) + || ($this->DetectWindowsPhone8() == $this->true) + || ($this->DetectWindowsPhone10() == $this->true)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a Windows Phone 7 device (in mobile browsing mode). + function DetectWindowsPhone7() + { + if (stripos($this->useragent, $this->deviceWinPhone7) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a Windows Phone 8 device (in mobile browsing mode). + function DetectWindowsPhone8() + { + if (stripos($this->useragent, $this->deviceWinPhone8) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a Windows Phone 10 device (in mobile browsing mode). + function DetectWindowsPhone10() + { + if (stripos($this->useragent, $this->deviceWinPhone10) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is a Windows Mobile device. + // Excludes Windows Phone 7 and later devices. + // Focuses on Windows Mobile 6.xx and earlier. + function DetectWindowsMobile() + { + if ($this->DetectWindowsPhone() == $this->true) + return $this->false; + + //Most devices use 'Windows CE', but some report 'iemobile' + // and some older ones report as 'PIE' for Pocket IE. + if (stripos($this->useragent, $this->deviceWinMob) > -1 || + stripos($this->useragent, $this->deviceIeMob) > -1 || + stripos($this->useragent, $this->enginePie) > -1) + return $this->true; + //Test for Windows Mobile PPC but not old Macintosh PowerPC. + if (stripos($this->useragent, $this->devicePpc) > -1 + && !(stripos($this->useragent, $this->deviceMacPpc) > 1)) + return $this->true; + //Test for certain Windwos Mobile-based HTC devices. + if (stripos($this->useragent, $this->manuHtc) > -1 && + stripos($this->useragent, $this->deviceWindows) > -1) + return $this->true; + if ($this->DetectWapWml() == $this->true && + stripos($this->useragent, $this->deviceWindows) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is any BlackBerry device. + // Includes BB10 OS, but excludes the PlayBook. + function DetectBlackBerry() + { + if ((stripos($this->useragent, $this->deviceBB) > -1) || + (stripos($this->httpaccept, $this->vndRIM) > -1)) + return $this->true; + if ($this->DetectBlackBerry10Phone() == $this->true) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is a BlackBerry 10 OS phone. + // Excludes tablets. + function DetectBlackBerry10Phone() + { + if ((stripos($this->useragent, $this->deviceBB10) > -1) && + (stripos($this->useragent, $this->mobile) > -1)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is on a BlackBerry tablet device. + // Examples: PlayBook + function DetectBlackBerryTablet() + { + if ((stripos($this->useragent, $this->deviceBBPlaybook) > -1)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is a BlackBerry phone device AND uses a + // WebKit-based browser. These are signatures for the new BlackBerry OS 6. + // Examples: Torch. Includes the Playbook. + function DetectBlackBerryWebKit() + { + if (($this->DetectBlackBerry() == $this->true) && + ($this->DetectWebkit() == $this->true)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is a BlackBerry Touch phone device with + // a large screen, such as the Storm, Torch, and Bold Touch. Excludes the Playbook. + function DetectBlackBerryTouch() + { + if ((stripos($this->useragent, $this->deviceBBStorm) > -1) || + (stripos($this->useragent, $this->deviceBBTorch) > -1) || + (stripos($this->useragent, $this->deviceBBBoldTouch) > -1) || + (stripos($this->useragent, $this->deviceBBCurveTouch) > -1)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is a BlackBerry OS 5 device AND + // has a more capable recent browser. Excludes the Playbook. + // Examples, Storm, Bold, Tour, Curve2 + // Excludes the new BlackBerry OS 6 and 7 browser!! + function DetectBlackBerryHigh() + { + //Disambiguate for BlackBerry OS 6 or 7 (WebKit) browser + if ($this->DetectBlackBerryWebKit() == $this->true) + return $this->false; + if ($this->DetectBlackBerry() == $this->true) + { + if (($this->DetectBlackBerryTouch() == $this->true) || + stripos($this->useragent, $this->deviceBBBold) > -1 || + stripos($this->useragent, $this->deviceBBTour) > -1 || + stripos($this->useragent, $this->deviceBBCurve) > -1) + { + return $this->true; + } + else + return $this->false; + } + else + return $this->false; + } + + //************************** + // Detects if the current browser is a BlackBerry device AND + // has an older, less capable browser. + // Examples: Pearl, 8800, Curve1. + function DetectBlackBerryLow() + { + if ($this->DetectBlackBerry() == $this->true) + { + //Assume that if it's not in the High tier, then it's Low. + if (($this->DetectBlackBerryHigh() == $this->true) || + ($this->DetectBlackBerryWebKit() == $this->true)) + return $this->false; + else + return $this->true; + } + else + return $this->false; + } + + + //************************** + // Detects if the current browser is the Nokia S60 Open Source Browser. + function DetectS60OssBrowser() + { + //First, test for WebKit, then make sure it's either Symbian or S60. + if ($this->DetectWebkit() == $this->true) + { + if (stripos($this->useragent, $this->deviceSymbian) > -1 || + stripos($this->useragent, $this->deviceS60) > -1) + { + return $this->true; + } + else + return $this->false; + } + else + return $this->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. + function DetectSymbianOS() + { + if (stripos($this->useragent, $this->deviceSymbian) > -1 || + stripos($this->useragent, $this->deviceS60) > -1 || + stripos($this->useragent, $this->deviceS70) > -1 || + stripos($this->useragent, $this->deviceS80) > -1 || + stripos($this->useragent, $this->deviceS90) > -1) + return $this->true; + else + return $this->false; + } + + + //************************** + // Detects if the current browser is on a PalmOS device. + function DetectPalmOS() + { + //Most devices nowadays report as 'Palm', but some older ones reported as Blazer or Xiino. + if (stripos($this->useragent, $this->devicePalm) > -1 || + stripos($this->useragent, $this->engineBlazer) > -1 || + stripos($this->useragent, $this->engineXiino) > -1) + { + //Make sure it's not WebOS first + if ($this->DetectPalmWebOS() == $this->true) + return $this->false; + else + return $this->true; + } + else + return $this->false; + } + + + //************************** + // Detects if the current browser is on a Palm device + // running the new WebOS. + function DetectPalmWebOS() + { + if (stripos($this->useragent, $this->deviceWebOS) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is on an HP tablet running WebOS. + function DetectWebOSTablet() + { + if ((stripos($this->useragent, $this->deviceWebOShp) > -1) + && (stripos($this->useragent, $this->deviceTablet) > -1)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is on a WebOS smart TV. + function DetectWebOSTV() + { + if ((stripos($this->useragent, $this->deviceWebOStv) > -1) + && (stripos($this->useragent, $this->smartTV2) > -1)) + return $this->true; + else + return $this->false; + } + + + //************************** + // Detects if the current browser is Opera Mobile or Mini. + function DetectOperaMobile() + { + if ((stripos($this->useragent, $this->engineOpera) > -1) && + ((stripos($this->useragent, $this->mini) > -1) || + (stripos($this->useragent, $this->mobi) > -1))) + return $this->true; + + return $this->false; + } + + //************************** + // Detects if the current device is an Amazon Kindle (eInk devices only). + // Note: For the Kindle Fire, use the normal Android methods. + function DetectKindle() + { + if (stripos($this->useragent, $this->deviceKindle) > -1 && + $this->DetectAndroid() == $this->false) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current Amazon device has turned on the Silk accelerated browsing feature. + // Note: Typically used by the the Kindle Fire. + function DetectAmazonSilk() + { + if (stripos($this->useragent, $this->engineSilk) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if a Garmin Nuvifone device. + function DetectGarminNuvifone() + { + if (stripos($this->useragent, $this->deviceNuvifone) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a device running the Bada OS from Samsung. + function DetectBada() + { + if (stripos($this->useragent, $this->deviceBada) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a device running the Tizen smartphone OS. + function DetectTizen() + { + if ((stripos($this->useragent, $this->deviceTizen) > -1) + && (stripos($this->useragent, $this->mobile) > -1)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is on a Tizen smart TV. + function DetectTizenTV() + { + if ((stripos($this->useragent, $this->deviceTizen) > -1) + && (stripos($this->useragent, $this->smartTV1) > -1)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a device running the Meego OS. + function DetectMeego() + { + if (stripos($this->useragent, $this->deviceMeego) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a phone running the Meego OS. + function DetectMeegoPhone() + { + if ((stripos($this->useragent, $this->deviceMeego) > -1) + && (stripos($this->useragent, $this->mobi) > -1)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a mobile device (probably) running the Firefox OS. + function DetectFirefoxOS() + { + if (($this->DetectFirefoxOSPhone() == $this->true) + || ($this->DetectFirefoxOSTablet() == $this->true)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a phone (probably) running the Firefox OS. + function DetectFirefoxOSPhone() + { + //First, let's make sure we're NOT on another major mobile OS. + if ($this->DetectIos() == $this->true + || $this->DetectAndroid() == $this->true + || $this->DetectSailfish() == $this->true) + return $this->false; + + if ((stripos($this->useragent, $this->engineFirefox) > -1) && + (stripos($this->useragent, $this->mobile) > -1)) + return $this->true; + + return $this->false; + } + + //************************** + // Detects a tablet (probably) running the Firefox OS. + function DetectFirefoxOSTablet() + { + //First, let's make sure we're NOT on another major mobile OS. + if ($this->DetectIos() == $this->true + || $this->DetectAndroid() == $this->true + || $this->DetectSailfish() == $this->true) + return $this->false; + + if ((stripos($this->useragent, $this->engineFirefox) > -1) && + (stripos($this->useragent, $this->deviceTablet) > -1)) + return $this->true; + + return $this->false; + } + + //************************** + // Detects a device running the Sailfish OS. + function DetectSailfish() + { + if (stripos($this->useragent, $this->deviceSailfish) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a phone running the Sailfish OS. + function DetectSailfishPhone() + { + if (($this->DetectSailfish() == $this->true) && + (stripos($this->useragent, $this->mobile) > -1)) + return $this->true; + + return $this->false; + } + + //************************** + // Detects a mobile device running the Ubuntu Mobile OS. + function DetectUbuntu() + { + if (($this->DetectUbuntuPhone() == $this->true) + || ($this->DetectUbuntuTablet() == $this->true)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects a phone running the Ubuntu Mobile OS. + function DetectUbuntuPhone() + { + if ((stripos($this->useragent, $this->deviceUbuntu) > -1) && + (stripos($this->useragent, $this->mobile) > -1)) + return $this->true; + + return $this->false; + } + + //************************** + // Detects a tablet running the Ubuntu Mobile OS. + function DetectUbuntuTablet() + { + if ((stripos($this->useragent, $this->deviceUbuntu) > -1) && + (stripos($this->useragent, $this->deviceTablet) > -1)) + return $this->true; + + return $this->false; + } + + //************************** + // Detects the Danger Hiptop device. + function DetectDangerHiptop() + { + if (stripos($this->useragent, $this->deviceDanger) > -1 || + stripos($this->useragent, $this->deviceHiptop) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current browser is a Sony Mylo device. + function DetectSonyMylo() + { + if ((stripos($this->useragent, $this->manuSony) > -1) && + ((stripos($this->useragent, $this->qtembedded) > -1) || + (stripos($this->useragent, $this->mylocom2) > -1))) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device is on one of the Maemo-based Nokia Internet Tablets. + function DetectMaemoTablet() + { + if (stripos($this->useragent, $this->maemo) > -1) + return $this->true; + //For Nokia N810, must be Linux + Tablet, or else it could be something else. + if ((stripos($this->useragent, $this->linux) > -1) + && (stripos($this->useragent, $this->deviceTablet) > -1) + && ($this->DetectWebOSTablet() == $this->false) + && ($this->DetectAndroid() == $this->false)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device is an Archos media player/Internet tablet. + function DetectArchos() + { + if (stripos($this->useragent, $this->deviceArchos) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device is an Internet-capable game console. + // Includes many handheld consoles. + function DetectGameConsole() + { + if ($this->DetectSonyPlaystation() == $this->true) + return $this->true; + else if ($this->DetectNintendo() == $this->true) + return $this->true; + else if ($this->DetectXbox() == $this->true) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device is a Sony Playstation. + function DetectSonyPlaystation() + { + if (stripos($this->useragent, $this->devicePlaystation) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device is a handheld gaming device with + // a touchscreen and modern iPhone-class browser. Includes the Playstation Vita. + function DetectGamingHandheld() + { + if ((stripos($this->useragent, $this->devicePlaystation) > -1) && + (stripos($this->useragent, $this->devicePlaystationVita) > -1)) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device is a Nintendo game device. + function DetectNintendo() + { + if (stripos($this->useragent, $this->deviceNintendo) > -1 || + stripos($this->useragent, $this->deviceWii) > -1 || + stripos($this->useragent, $this->deviceNintendoDs) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device is a Microsoft Xbox. + function DetectXbox() + { + if (stripos($this->useragent, $this->deviceXbox) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects whether the device is a Brew-powered device. + function DetectBrewDevice() + { + if (stripos($this->useragent, $this->deviceBrew) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects whether the device supports WAP or WML. + function DetectWapWml() + { + if (stripos($this->httpaccept, $this->vndwap) > -1 || + stripos($this->httpaccept, $this->wml) > -1) + return $this->true; + else + return $this->false; + } + + //************************** + // Detects if the current device supports MIDP, a mobile Java technology. + function DetectMidpCapable() + { + if (stripos($this->useragent, $this->deviceMidp) > -1 || + stripos($this->httpaccept, $this->deviceMidp) > -1) + return $this->true; + else + return $this->false; + } + + + + //***************************** + // Device Classes + //***************************** + + //************************** + // Check to see whether the device is *any* 'smartphone'. + // Note: It's better to use DetectTierIphone() for modern touchscreen devices. + function DetectSmartphone() + { + //Exclude duplicates from TierIphone + if (($this->DetectTierIphone() == $this->true) + || ($this->DetectS60OssBrowser() == $this->true) + || ($this->DetectSymbianOS() == $this->true) + || ($this->DetectWindowsMobile() == $this->true) + || ($this->DetectBlackBerry() == $this->true) + || ($this->DetectMeegoPhone() == $this->true) + || ($this->DetectPalmWebOS() == $this->true)) + return $this->true; + else + return $this->false; + } + + //************************** + // The quick way to detect for a mobile device. + // Will probably detect most recent/current mid-tier Feature Phones + // as well as smartphone-class devices. Excludes Apple iPads and other modern tablets. + function DetectMobileQuick() + { + if ($this->initCompleted == $this->true || + $this->isMobilePhone == $this->true) + return $this->isMobilePhone; + + //Let's exclude tablets + if ($this->isTierTablet == $this->true) + return $this->false; + + //Most mobile browsing is done on smartphones + if ($this->DetectSmartphone() == $this->true) + return $this->true; + + //Catch-all for many mobile devices + if (stripos($this->useragent, $this->mobile) > -1) + return $this->true; + + if ($this->DetectOperaMobile() == $this->true) + return $this->true; + + //We also look for Kindle devices + if ($this->DetectKindle() == $this->true || + $this->DetectAmazonSilk() == $this->true) + return $this->true; + + if (($this->DetectWapWml() == $this->true) + || ($this->DetectMidpCapable() == $this->true) + || ($this->DetectBrewDevice() == $this->true)) + return $this->true; + + if ((stripos($this->useragent, $this->engineNetfront) > -1) + || (stripos($this->useragent, $this->engineUpBrowser) > -1)) + return $this->true; + + return $this->false; + } + + //************************** + // The longer and more thorough way to detect for a mobile device. + // 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! + function DetectMobileLong() + { + if ($this->DetectMobileQuick() == $this->true) + return $this->true; + if ($this->DetectGameConsole() == $this->true) + return $this->true; + + if (($this->DetectDangerHiptop() == $this->true) + || ($this->DetectMaemoTablet() == $this->true) + || ($this->DetectSonyMylo() == $this->true) + || ($this->DetectArchos() == $this->true)) + return $this->true; + + if ((stripos($this->useragent, $this->devicePda) > -1) && + !(stripos($this->useragent, $this->disUpdate) > -1)) + return $this->true; + + //Detect older phones from certain manufacturers and operators. + if ((stripos($this->useragent, $this->uplink) > -1) + || (stripos($this->useragent, $this->engineOpenWeb) > -1) + || (stripos($this->useragent, $this->manuSamsung1) > -1) + || (stripos($this->useragent, $this->manuSonyEricsson) > -1) + || (stripos($this->useragent, $this->manuericsson) > -1) + || (stripos($this->useragent, $this->svcDocomo) > -1) + || (stripos($this->useragent, $this->svcKddi) > -1) + || (stripos($this->useragent, $this->svcVodafone) > -1)) + return $this->true; + + return $this->false; + } + + + //***************************** + // For Mobile Web Site Design + //***************************** + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for the new generation of + // HTML 5 capable, larger screen tablets. + // Includes iPad, Android (e.g., Xoom), BB Playbook, WebOS, etc. + function DetectTierTablet() + { + if ($this->initCompleted == $this->true || + $this->isTierTablet == $this->true) + return $this->isTierTablet; + + if (($this->DetectIpad() == $this->true) + || ($this->DetectAndroidTablet() == $this->true) + || ($this->DetectBlackBerryTablet() == $this->true) + || ($this->DetectFirefoxOSTablet() == $this->true) + || ($this->DetectUbuntuTablet() == $this->true) + || ($this->DetectWebOSTablet() == $this->true)) + return $this->true; + else + return $this->false; + } + + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for devices which can + // display iPhone-optimized web content. + // Includes iPhone, iPod Touch, Android, Windows Phone, BB10, Playstation Vita, etc. + function DetectTierIphone() + { + if ($this->initCompleted == $this->true || + $this->isTierIphone == $this->true) + return $this->isTierIphone; + + if (($this->DetectIphoneOrIpod() == $this->true) + || ($this->DetectAndroidPhone() == $this->true) + || ($this->DetectWindowsPhone() == $this->true) + || ($this->DetectBlackBerry10Phone() == $this->true) + || ($this->DetectPalmWebOS() == $this->true) + || ($this->DetectBada() == $this->true) + || ($this->DetectTizen() == $this->true) + || ($this->DetectFirefoxOSPhone() == $this->true) + || ($this->DetectSailfishPhone() == $this->true) + || ($this->DetectUbuntuPhone() == $this->true) + || ($this->DetectGamingHandheld() == $this->true)) + return $this->true; + + //Note: BB10 phone is in the previous paragraph + if (($this->DetectBlackBerryWebKit() == $this->true) && + ($this->DetectBlackBerryTouch() == $this->true)) + return $this->true; + + else + return $this->false; + } + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for devices which are likely to be capable + // of viewing CSS content optimized for the iPhone, + // but may not necessarily support JavaScript. + // Excludes all iPhone Tier devices. + function DetectTierRichCss() + { + if ($this->initCompleted == $this->true || + $this->isTierRichCss == $this->true) + return $this->isTierRichCss; + + if ($this->DetectMobileQuick() == $this->true) + { + //Exclude iPhone Tier and e-Ink Kindle devices + if (($this->DetectTierIphone() == $this->true) || + ($this->DetectKindle() == $this->true)) + return $this->false; + + //The following devices are explicitly ok. + if ($this->DetectWebkit() == $this->true) //Any WebKit + return $this->true; + if ($this->DetectS60OssBrowser() == $this->true) + return $this->true; + + //Note: 'High' BlackBerry devices ONLY + if ($this->DetectBlackBerryHigh() == $this->true) + return $this->true; + + //Older Windows 'Mobile' isn't good enough for iPhone Tier. + if ($this->DetectWindowsMobile() == $this->true) + return $this->true; + if (stripos($this->useragent, $this->engineTelecaQ) > -1) + return $this->true; + + //default + else + return $this->false; + } + else + return $this->false; + } + + //************************** + // The quick way to detect for a tier of devices. + // This method detects for all other types of phones, + // but excludes the iPhone and RichCSS Tier devices. + function DetectTierOtherPhones() + { + if ($this->initCompleted == $this->true || + $this->isTierGenericMobile == $this->true) + return $this->isTierGenericMobile; + + //Exclude devices in the other 2 categories + if (($this->DetectMobileLong() == $this->true) + && ($this->DetectTierIphone() == $this->false) + && ($this->DetectTierRichCss() == $this->false)) + return $this->true; + else + return $this->false; + } + + +} + + +//Was informed by a MobileESP user that it's a best practice +// to omit the closing ?> marks here. They can sometimes +// cause errors with HTML headers. \ No newline at end of file diff --git a/vendor/ahand/mobileesp/Python/mdetect.py b/vendor/ahand/mobileesp/Python/mdetect.py new file mode 100755 index 00000000000..fe8592ee8f5 --- /dev/null +++ b/vendor/ahand/mobileesp/Python/mdetect.py @@ -0,0 +1,1023 @@ +# ******************************************* +# Copyright 2010-2015, Anthony Hand +# +# +# File version 2015.05.13 (May 13, 2015) +# Updates: +# - Moved MobileESP to GitHub. https:#github.com/ahand/mobileesp +# - Opera Mobile/Mini browser has the same UA string on multiple platforms and doesn't differentiate phone vs. tablet. +# - Removed DetectOperaAndroidPhone(). This method is no longer reliable. +# - Removed DetectOperaAndroidTablet(). This method is no longer reliable. +# - Added support for Windows Phone 10: variable and DetectWindowsPhone10() +# - Updated DetectWindowsPhone() to include WP10. +# - Added support for Firefox OS. +# - A variable plus DetectFirefoxOS(), DetectFirefoxOSPhone(), DetectFirefoxOSTablet() +# - NOTE: Firefox doesn't add UA tokens to definitively identify Firefox OS vs. their browsers on other mobile platforms. +# - Added support for Sailfish OS. Not enough info to add a tablet detection method at this time. +# - A variable plus DetectSailfish(), DetectSailfishPhone() +# - Added support for Ubuntu Mobile OS. +# - DetectUbuntu(), DetectUbuntuPhone(), DetectUbuntuTablet() +# - Added support for 2 smart TV OSes. They lack browsers but do have WebViews for use by HTML apps. +# - One variable for Samsung Tizen TVs, plus DetectTizenTV() +# - One variable for LG WebOS TVs, plus DetectWebOSTV() +# - Added DetectTizen(). Tests for "mobile" to disambiguate from Samsung Smart TVs. +# - Removed variables for obsolete devices: deviceHtcFlyer, deviceXoom. +# - Updated DetectAndroid(). No longer has a special test case for the HTC Flyer tablet. +# - Updated DetectAndroidPhone(). +# - Updated internal detection code for Android. +# - No longer has a special test case for the HTC Flyer tablet. +# - Checks against DetectOperaMobile() on Android and reports here if relevant. +# - Updated DetectAndroidTablet(). +# - No longer has a special test case for the HTC Flyer tablet. +# - Checks against DetectOperaMobile() on Android to exclude it from here. +# - DetectMeego(): Changed definition for this method. Now detects any Meego OS device, not just phones. +# - DetectMeegoPhone(): NEW. For Meego phones. Ought to detect Opera browsers on Meego, as well. +# - DetectTierIphone(): Added support for phones running Sailfish, Ubuntu and Firefox Mobile. +# - DetectTierTablet(): Added support for tablets running Ubuntu and Firefox Mobile. +# - DetectSmartphone(): Added support for Meego phones. +# - Caught this library up to the PHP, JavaScript and Java versions. Updates include: +# - Added support for Bada: a variable and DetectBada(). This detects any Bada OS device, but (almost) all are phones. +# - Refactored the Windows Phone delegate-related properties and features. Now fires for any Windows Phone, not just WP7. +# - The event fires now when DetectWindowsPhone() is true. +# - Added support for Windows Phone 8: DetectWindowsPhone8(). +# - Updated DetectWindowsMobile(). Excludes any Windows Phone device, not just WP7. +# - Added support for BlackBerry 10 OS phones: DetectBlackBerry10Phone(). +# - Updated DetectSmartphone() to sync with the other libraries. +# - Updated DetectTierIphone() to sync with the other libraries. +# - OnInit(EventArgs e): Fixed the user agent and httpaccept init logic. +# - Refactored the detection logic in DetectMobileQuick() and DetectMobileLong(). +# - Moved a few detection tests for older browsers to Long. +# +# +# +# File version date: Feburary 10, 2012 +# Creation: +# - Cloned from http://code.google.com/p/mobileesp/source/browse/Java/UAgentInfo.java +# and http://code.google.com/p/mobileesp/source/browse/PHP/mdetect.php +# - Port to Python: Alexey Evseev (alexevseev@gmail.com) +# - Made for www.irk.fm website +# +# +# +# LICENSE INFORMATION +# 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. +# +# +# ABOUT THIS PROJECT +# Project Owner: Anthony Hand +# Email: anthony.hand@gmail.com +# Web Site: http://www.mobileesp.com +# Source Files: https://github.com/ahand/mobileesp +# +# Versions of this code are available for: +# PHP, JavaScript, Java, ASP.NET (C#), Ruby and Python +# +# ******************************************* + + +class UAgentInfo(object): + """The UAgentInfo class encapsulates information about + a browser's connection to your web site. + You can use it to find out whether the browser asking for + your site's content is probably running on a mobile device. + The methods were written so you can be as granular as you want. + For example, enquiring whether it's as specific as an iPod Touch or + as general as a smartphone class device. + The object's methods return true, or false. + """ + + # Initialize some initial smartphone string variables. + engineWebKit = "webkit" + + deviceIphone = "iphone" + deviceIpod = "ipod" + deviceIpad = "ipad" + deviceMacPpc = "macintosh" #Used for disambiguation + + deviceAndroid = "android" + deviceGoogleTV = "googletv" + + deviceSymbian = "symbian" + deviceS60 = "series60" + deviceS70 = "series70" + deviceS80 = "series80" + deviceS90 = "series90" + + deviceWinPhone7 = "windows phone os 7" + deviceWinPhone8 = "windows phone 8" + deviceWinPhone10 = "windows phone 10" + deviceWinMob = "windows ce" + deviceWindows = "windows" + deviceIeMob = "iemobile" + devicePpc = "ppc" #Stands for PocketPC + enginePie = "wm5 pie" #An old Windows Mobile + + deviceBB = "blackberry" + deviceBB10 = "bb10" #For the new BB 10 OS + vndRIM = "vnd.rim" #Detectable when BB devices emulate IE or Firefox + deviceBBStorm = "blackberry95" #Storm 1 and 2 + deviceBBBold = "blackberry97" #Bold 97x0 (non-touch) + deviceBBBoldTouch = "blackberry 99" #Bold 99x0 (touchscreen) + deviceBBTour = "blackberry96" #Tour + deviceBBCurve = "blackberry89" #Curve 2 + deviceBBCurveTouch = "blackberry 938" #Curve Touch 9380 + deviceBBTorch = "blackberry 98" #Torch + deviceBBPlaybook = "playbook" #PlayBook tablet + + devicePalm = "palm" + deviceWebOS = "webos" #For Palm devices + deviceWebOStv = "web0s" #For LG TVs + deviceWebOShp = "hpwos" #For HP's line of WebOS devices + + engineBlazer = "blazer" #Old Palm + engineXiino = "xiino" #Another old Palm + + deviceKindle = "kindle" #Amazon Kindle, eInk one + engineSilk = "silk" #Amazon's accelerated Silk browser for Kindle Fire + + deviceNuvifone = "nuvifone" #Garmin Nuvifone + deviceBada = "bada" #Samsung's Bada OS + deviceTizen = "tizen" #Tizen OS + deviceMeego = "meego" #Meego OS + deviceSailfish = "sailfish" #Sailfish OS + deviceUbuntu = "ubuntu" #Ubuntu Mobile OS + + #Initialize variables for mobile-specific content. + vndwap = "vnd.wap" + wml = "wml" + + #Initialize variables for other random devices and mobile browsers. + deviceTablet = "tablet" #Generic term for slate and tablet devices + deviceBrew = "brew" + deviceDanger = "danger" + deviceHiptop = "hiptop" + devicePlaystation = "playstation" + devicePlaystationVita = "vita" + deviceNintendoDs = "nitro" + deviceNintendo = "nintendo" + deviceWii = "wii" + deviceXbox = "xbox" + deviceArchos = "archos" + + engineFirefox = "firefox" #For Firefox OS + engineOpera = "opera" #Popular browser + engineNetfront = "netfront" #Common embedded OS browser + engineUpBrowser = "up.browser" #common on some phones + engineOpenWeb = "openweb" #Transcoding by OpenWave server + deviceMidp = "midp" #a mobile Java technology + uplink = "up.link" + engineTelecaQ = "teleca q" #a modern feature phone browser + devicePda = "pda" #some devices report themselves as PDAs + mini = "mini" #Some mobile browsers put "mini" in their names. + mobile = "mobile" #Some mobile browsers put "mobile" in their user agent strings. + mobi = "mobi" #Some mobile browsers put "mobi" in their user agent strings. + + #Smart TV strings + smartTV1 = "smart-tv" #Samsung Tizen smart TVs + smartTV2 = "smarttv" #LG WebOS smart TVs + + #Use Maemo, Tablet, and Linux to test for Nokia"s Internet Tablets. + maemo = "maemo" + linux = "linux" + qtembedded = "qt embedded" #for Sony Mylo + mylocom2 = "com2" #for Sony Mylo also + + #In some UserAgents, the only clue is the manufacturer. + manuSonyEricsson = "sonyericsson" + manuericsson = "ericsson" + manuSamsung1 = "sec-sgh" + manuSony = "sony" + manuHtc = "htc" #Popular Android and WinMo manufacturer + + #In some UserAgents, the only clue is the operator. + svcDocomo = "docomo" + svcKddi = "kddi" + svcVodafone = "vodafone" + + #Disambiguation strings. + disUpdate = "update" #pda vs. update + + def __init__(self, userAgent, httpAccept): + """Initialize the __userAgent and __httpAccept variables + + Keyword arguments: + userAgent -- the User-Agent header + httpAccept -- the Accept header + """ + + # User-Agent and Accept HTTP request headers + self.__userAgent = userAgent.lower() if userAgent else "" + self.__httpAccept = httpAccept.lower() if httpAccept else "" + + # Let's store values for quickly accessing the same info multiple times. + self.__isIphone = False + self.__isAndroidPhone = False + self.__isTierTablet = False + self.__isTierIphone = False + self.__isTierRichCss = False + self.__isTierGenericMobile = False + + # Intialize key stored values. + self.initDeviceScan() + + def getUserAgent(self): + """Return the lower case HTTP_USER_AGENT""" + return self.__userAgent + + def getHttpAccept(self): + """Return the lower case HTTP_ACCEPT""" + return self.__httpAccept + + def getIsIphone(self): + """Return whether the device is an Iphone or iPod Touch""" + return self.__isIphone + + def getIsTierTablet(self): + """Return whether the device is in the Tablet Tier.""" + return self.__isTierTablet + + def getIsTierIphone(self): + """Return whether the device is in the Iphone Tier.""" + return self.__isTierIphone + + def getIsTierRichCss(self): + """Return whether the device is in the 'Rich CSS' tier of mobile devices.""" + return self.__isTierRichCss + + def getIsTierGenericMobile(self): + """Return whether the device is a generic, less-capable mobile device.""" + return self.__isTierGenericMobile + + + def initDeviceScan(self): + """Initialize Key Stored Values.""" + self.__isIphone = self.detectIphoneOrIpod() + self.__isAndroidPhone = self.detectAndroidPhone() + self.__isTierTablet = self.detectTierTablet() + self.__isTierIphone = self.detectTierIphone() + self.__isTierRichCss = self.detectTierRichCss() + self.__isTierGenericMobile = self.detectTierOtherPhones() + + def detectIphone(self): + """Return detection of an iPhone + + Detects if the current device is an iPhone. + """ + # The iPad and iPod touch say they're an iPhone! So let's disambiguate. + return UAgentInfo.deviceIphone in self.__userAgent \ + and not self.detectIpad() \ + and not self.detectIpod() + + def detectIpod(self): + """Return detection of an iPod Touch + + Detects if the current device is an iPod Touch. + """ + return UAgentInfo.deviceIpod in self.__userAgent + + + def detectIpad(self): + """Return detection of an iPad + + Detects if the current device is an iPad tablet. + """ + return UAgentInfo.deviceIpad in self.__userAgent \ + and self.detectWebkit() + + def detectIphoneOrIpod(self): + """Return detection of an iPhone or iPod Touch + + Detects if the current device is an iPhone or iPod Touch. + """ + #We repeat the searches here because some iPods may report themselves as an iPhone, which would be okay. + return UAgentInfo.deviceIphone in self.__userAgent \ + or UAgentInfo.deviceIpod in self.__userAgent + + def detectIos(self): + """Return detection of an Apple iOS device + + Detects *any* iOS device: iPhone, iPod Touch, iPad. + """ + return self.detectIphoneOrIpod() \ + or self.detectIpad() + + def detectAndroid(self): + """Return detection of an Android device + + Detects *any* Android OS-based device: phone, tablet, and multi-media player. + Also detects Google TV. + """ + if UAgentInfo.deviceAndroid in self.__userAgent \ + or self.detectGoogleTV(): + return True + + return False + + + def detectAndroidPhone(self): + """Return detection of an Android phone + + Detects if the current device is a (small-ish) Android OS-based device + used for calling and/or multi-media (like a Samsung Galaxy Player). + Google says these devices will have 'Android' AND 'mobile' in user agent. + Ignores tablets (Honeycomb and later). + """ + #First, let's make sure we're on an Android device. + if not self.detectAndroid(): + return False + + #If it's Android and has 'mobile' in it, Google says it's a phone. + if UAgentInfo.mobile in self.__userAgent: + return True + + #Special check for Android devices with Opera Mobile/Mini. They should report here. + if self.detectOperaMobile(): + return True + + return False + + + def detectAndroidTablet(self): + """Return detection of an Android tablet + + Detects if the current device is a (self-reported) Android tablet. + Google says these devices will have 'Android' and NOT 'mobile' in their user agent. + """ + #First, let's make sure we're on an Android device. + if not self.detectAndroid(): + return False + + #Special check for Android devices with Opera Mobile/Mini. They should NOT report here. + if self.detectOperaMobile(): + return False + + #Otherwise, if it's Android and does NOT have 'mobile' in it, Google says it's a tablet. + return UAgentInfo.mobile not in self.__userAgent + + + def detectAndroidWebKit(self): + """Return detection of an Android WebKit browser + + Detects if the current device is an Android OS-based device and + the browser is based on WebKit. + """ + return self.detectAndroid() \ + and self.detectWebkit() + + def detectGoogleTV(self): + """Return detection of GoogleTV + + Detects if the current device is a GoogleTV. + """ + return UAgentInfo.deviceGoogleTV in self.__userAgent + + + def detectWebkit(self): + """Return detection of a WebKit browser + + Detects if the current browser is based on WebKit. + """ + return UAgentInfo.engineWebKit in self.__userAgent + + def detectS60OssBrowser(self): + """Return detection of Symbian S60 Browser + + Detects if the current browser is the Symbian S60 Open Source Browser. + """ + #First, test for WebKit, then make sure it's either Symbian or S60. + return self.detectWebkit() \ + and (UAgentInfo.deviceSymbian in self.__userAgent \ + or UAgentInfo.deviceS60 in self.__userAgent) + + def detectSymbianOS(self): + """Return detection of SymbianOS + + 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. + """ + return UAgentInfo.deviceSymbian in self.__userAgent \ + or UAgentInfo.deviceS60 in self.__userAgent \ + or UAgentInfo.deviceS70 in self.__userAgent \ + or UAgentInfo.deviceS80 in self.__userAgent \ + or UAgentInfo.deviceS90 in self.__userAgent + + def detectWindowsPhone(self): + """Return detection of a Windows Phone device + + Detects if the current browser is a + Windows Phone 7, 8, or 10 device + """ + return self.detectWindowsPhone7() \ + or self.detectWindowsPhone8() \ + or self.detectWindowsPhone10() + + def detectWindowsPhone7(self): + """Return detection of Windows Phone 7 + + Detects if the current browser is a + Windows Phone 7 device. + """ + return UAgentInfo.deviceWinPhone7 in self.__userAgent + + def detectWindowsPhone8(self): + """Return detection of Windows Phone 8 + + Detects if the current browser is a + Windows Phone 8 device. + """ + return UAgentInfo.deviceWinPhone8 in self.__userAgent + + def detectWindowsPhone10(self): + """Return detection of Windows Phone 10 + + Detects if the current browser is a + Windows Phone 10 device. + """ + return UAgentInfo.deviceWinPhone10 in self.__userAgent + + def detectWindowsMobile(self): + """Return detection of Windows Mobile + + Detects if the current browser is a Windows Mobile device. + Excludes Windows Phone 7 devices. + Focuses on Windows Mobile 6.xx and earlier. + """ + #Exclude new Windows Phone. + if self.detectWindowsPhone(): + return False + #Most devices use 'Windows CE', but some report 'iemobile' + # and some older ones report as 'PIE' for Pocket IE. + # We also look for instances of HTC and Windows for many of their WinMo devices. + if UAgentInfo.deviceWinMob in self.__userAgent \ + or UAgentInfo.deviceIeMob in self.__userAgent \ + or UAgentInfo.enginePie in self.__userAgent: + return True + # Test for certain Windwos Mobile-based HTC devices. + if UAgentInfo.manuHtc in self.__userAgent \ + and UAgentInfo.deviceWindows in self.__userAgent: + return True + if self.detectWapWml() \ + and UAgentInfo.deviceWindows in self.__userAgent: + return True + + #Test for Windows Mobile PPC but not old Macintosh PowerPC. + return UAgentInfo.devicePpc in self.__userAgent \ + and UAgentInfo.deviceMacPpc not in self.__userAgent + + def detectBlackBerry(self): + """Return detection of Blackberry + + Detects if the current browser is any BlackBerry. + Includes the PlayBook. + """ + return UAgentInfo.deviceBB in self.__userAgent \ + or UAgentInfo.vndRIM in self.__httpAccept + + def detectBlackBerry10Phone(self): + """Return detection of a Blackberry 10 OS phone + + Detects if the current browser is a BlackBerry 10 OS phone. + Excludes the PlayBook. + """ + return UAgentInfo.deviceBB10 in self.__userAgent \ + and UAgentInfo.mobile in self.__userAgent + + def detectBlackBerryTablet(self): + """Return detection of a Blackberry Tablet + + Detects if the current browser is on a BlackBerry tablet device. + Example: PlayBook + """ + return UAgentInfo.deviceBBPlaybook in self.__userAgent + + def detectBlackBerryWebKit(self): + """Return detection of a Blackberry device with WebKit browser + + Detects if the current browser is a BlackBerry device AND uses a + WebKit-based browser. These are signatures for the new BlackBerry OS 6. + Examples: Torch. Includes the Playbook. + """ + + return self.detectBlackBerry() \ + and self.detectWebkit() + + + def detectBlackBerryTouch(self): + """Return detection of a Blackberry touchscreen device + + Detects if the current browser is a BlackBerry Touch + device, such as the Storm, Torch, and Bold Touch. Excludes the Playbook. + """ + return UAgentInfo.deviceBBStorm in self.__userAgent \ + or UAgentInfo.deviceBBTorch in self.__userAgent \ + or UAgentInfo.deviceBBBoldTouch in self.__userAgent \ + or UAgentInfo.deviceBBCurveTouch in self.__userAgent + + def detectBlackBerryHigh(self): + """Return detection of a Blackberry device with a better browser + + Detects if the current browser is a BlackBerry device AND + has a more capable recent browser. Excludes the Playbook. + Examples, Storm, Bold, Tour, Curve2 + Excludes the new BlackBerry OS 6 and 7 browser!! + """ + #Disambiguate for BlackBerry OS 6 or 7 (WebKit) browser + if self.detectBlackBerryWebKit(): + return False + if not self.detectBlackBerry(): + return False + + return self.detectBlackBerryTouch() \ + or UAgentInfo.deviceBBBold in self.__userAgent \ + or UAgentInfo.deviceBBTour in self.__userAgent \ + or UAgentInfo.deviceBBCurve in self.__userAgent + + def detectBlackBerryLow(self): + """Return detection of a Blackberry device with a poorer browser + + Detects if the current browser is a BlackBerry device AND + has an older, less capable browser. + Examples: Pearl, 8800, Curve1 + """ + if not self.detectBlackBerry(): + return False + + #Assume that if it's not in the High tier, then it's Low + return self.detectBlackBerryHigh() \ + or self.detectBlackBerryWebKit() + + def detectPalmOS(self): + """Return detection of a PalmOS device + + Detects if the current browser is on a PalmOS device. + """ + #Most devices nowadays report as 'Palm', but some older ones reported as Blazer or Xiino. + if UAgentInfo.devicePalm in self.__userAgent \ + or UAgentInfo.engineBlazer in self.__userAgent \ + or UAgentInfo.engineXiino in self.__userAgent: + # Make sure it's not WebOS + return not self.detectPalmWebOS() + return False + + def detectPalmWebOS(self): + """Return detection of a Palm WebOS device + + Detects if the current browser is on a Palm device + running the new WebOS. + """ + return UAgentInfo.deviceWebOS in self.__userAgent + + def detectWebOSTablet(self): + """Return detection of an HP WebOS tablet + + Detects if the current browser is on an HP tablet running WebOS. + """ + return UAgentInfo.deviceWebOShp in self.__userAgent \ + and UAgentInfo.deviceTablet in self.__userAgent + + def detectWebOSTV(self): + """Return detection of a WebOS smart TV + + Detects if the current browser is on a WebOS smart TV. + """ + return UAgentInfo.deviceWebOStv in self.__userAgent \ + and UAgentInfo.smartTV2 in self.__userAgent + + def detectGarminNuvifone(self): + """Return detection of a Garmin Nuvifone + + Detects if the current browser is a + Garmin Nuvifone. + """ + return UAgentInfo.deviceNuvifone in self.__userAgent + + def detectBada(self): + """Return detection of a Bada device + + Detects a device running the Bada OS from Samsung. + """ + return UAgentInfo.deviceBada in self.__userAgent + + def detectTizen(self): + """Return detection of a Tizen device + + Detects a device running the Tizen smartphone OS. + """ + return UAgentInfo.deviceTizen in self.__userAgent \ + and UAgentInfo.mobile in self.__userAgent + + def detectTizenTV(self): + """Return detection of a Tizen smart TV + + Detects if the current browser is on a Tizen smart TV. + """ + return UAgentInfo.deviceTizen in self.__userAgent \ + and UAgentInfo.smartTV1 in self.__userAgent + + def detectMeego(self): + """Return detection of a Meego device + + Detects a device running the Meego OS. + """ + return UAgentInfo.deviceMeego in self.__userAgent + + def detectMeegoPhone(self): + """Return detection of a Meego phone + + Detects a phone running the Meego OS. + """ + return UAgentInfo.deviceMeego in self.__userAgent \ + and UAgentInfo.mobi in self.__userAgent + + def detectFirefoxOS(self): + """Return detection of a Firefox OS mobile device + + Detects a mobile device (probably) running the Firefox OS. + """ + return self.detectFirefoxOSPhone() \ + or self.detectFirefoxOSTablet() + + def detectFirefoxOSPhone(self): + """Return detection of a Firefox OS phone + + Detects a phone (probably) running the Firefox OS. + """ + if self.detectIos() \ + or self.detectAndroid() \ + or self.detectSailfish(): + return False + + if UAgentInfo.engineFirefox in self.__userAgent \ + and UAgentInfo.mobile in self.__userAgent: + return True + + return False + + def detectFirefoxOSTablet(self): + """Return detection of a Firefox OS tablet + + Detects a tablet (probably) running the Firefox OS. + """ + if self.detectIos() \ + or self.detectAndroid() \ + or self.detectSailfish(): + return False + + if UAgentInfo.engineFirefox in self.__userAgent \ + and UAgentInfo.deviceTablet in self.__userAgent: + return True + + return False + + def detectSailfish(self): + """Return detection of a Sailfish OS device. + + Detects a device running the Sailfish OS. + """ + return UAgentInfo.deviceSailfish in self.__userAgent + + def detectSailfishPhone(self): + """Return detection of a Sailfish phone + + Detects a phone running the Sailfish OS. + """ + if self.detectSailfish() \ + and UAgentInfo.mobile in self.__userAgent: + return True + + return False + + def detectUbuntu(self): + """Return detection of an Ubuntu Mobile OS mobile device + + Detects a mobile device running the Ubuntu Mobile OS. + """ + return self.detectUbuntuPhone() \ + or self.detectUbuntuTablet() + + def detectUbuntuPhone(self): + """Return detection of an Ubuntu Mobile OS phone + + Detects a phone running the Ubuntu Mobile OS. + """ + if UAgentInfo.deviceUbuntu in self.__userAgent \ + and UAgentInfo.mobile in self.__userAgent: + return True + + return False + + def detectUbuntuTablet(self): + """Return detection of an Ubuntu Mobile OS tablet + + Detects a tablet running the Ubuntu Mobile OS. + """ + if UAgentInfo.deviceUbuntu in self.__userAgent \ + and UAgentInfo.deviceTablet in self.__userAgent: + return True + + return False + + + def detectBrewDevice(self): + """Return detection of a Brew device + + Detects whether the device is a Brew-powered device. + """ + return UAgentInfo.deviceBrew in self.__userAgent + + def detectDangerHiptop(self): + """Return detection of a Danger Hiptop + + Detects the Danger Hiptop device. + """ + return UAgentInfo.deviceDanger in self.__userAgent \ + or UAgentInfo.deviceHiptop in self.__userAgent + + def detectOperaMobile(self): + """Return detection of an Opera browser for a mobile device + + Detects Opera Mobile or Opera Mini. + """ + return UAgentInfo.engineOpera in self.__userAgent \ + and (UAgentInfo.mini in self.__userAgent \ + or UAgentInfo.mobi in self.__userAgent) + + + def detectWapWml(self): + """Return detection of a WAP- or WML-capable device + + Detects whether the device supports WAP or WML. + """ + return UAgentInfo.vndwap in self.__httpAccept \ + or UAgentInfo.wml in self.__httpAccept + + def detectKindle(self): + """Return detection of a Kindle + + Detects if the current device is an Amazon Kindle (eInk devices only). + Note: For the Kindle Fire, use the normal Android methods. + """ + return UAgentInfo.deviceKindle in self.__userAgent \ + and not self.detectAndroid() + + def detectAmazonSilk(self): + """Return detection of an Amazon Kindle Fire in Silk mode. + + Detects if the current Amazon device is using the Silk Browser. + Note: Typically used by the the Kindle Fire. + """ + return UAgentInfo.engineSilk in self.__userAgent + + def detectSonyPlaystation(self): + """Return detection of Sony Playstation + + Detects if the current device is a Sony Playstation. + """ + return UAgentInfo.devicePlaystation in self.__userAgent + + def detectGamingHandheld(self): + """Return detection of a gaming handheld with a modern iPhone-class browser + + Detects if the current device is a handheld gaming device with + a touchscreen and modern iPhone-class browser. Includes the Playstation Vita. + """ + return UAgentInfo.devicePlaystation in self.__userAgent \ + and UAgentInfo.devicePlaystationVita in self.__userAgent + + def detectNintendo(self): + """Return detection of Nintendo + + Detects if the current device is a Nintendo game device. + """ + return UAgentInfo.deviceNintendo in self.__userAgent \ + or UAgentInfo.deviceNintendo in self.__userAgent \ + or UAgentInfo.deviceNintendo in self.__userAgent + + def detectXbox(self): + """Return detection of Xbox + + Detects if the current device is a Microsoft Xbox. + """ + return UAgentInfo.deviceXbox in self.__userAgent + + def detectGameConsole(self): + """Return detection of any Game Console + + Detects if the current device is an Internet-capable game console. + """ + return self.detectSonyPlaystation() \ + or self.detectNintendo() \ + or self.detectXbox() + + def detectMidpCapable(self): + """Return detection of a MIDP mobile Java-capable device + + Detects if the current device supports MIDP, a mobile Java technology. + """ + return UAgentInfo.deviceMidp in self.__userAgent \ + or UAgentInfo.deviceMidp in self.__httpAccept + + def detectMaemoTablet(self): + """Return detection of a Maemo OS tablet + + Detects if the current device is on one of the Maemo-based Nokia Internet Tablets. + """ + if UAgentInfo.maemo in self.__userAgent: + return True + + return UAgentInfo.linux in self.__userAgent \ + and UAgentInfo.deviceTablet in self.__userAgent \ + and not self.detectWebOSTablet() \ + and not self.detectAndroid() + + def detectArchos(self): + """Return detection of an Archos media player + + Detects if the current device is an Archos media player/Internet tablet. + """ + return UAgentInfo.deviceArchos in self.__userAgent + + def detectSonyMylo(self): + """Return detection of a Sony Mylo device + + Detects if the current browser is a Sony Mylo device. + """ + return UAgentInfo.manuSony in self.__userAgent \ + and (UAgentInfo.qtembedded in self.__userAgent + or UAgentInfo.mylocom2 in self.__userAgent) + + #***************************** + # Device Classes + #***************************** + def detectSmartphone(self): + """Return detection of a general smartphone device + + Checks to see whether the device is *any* 'smartphone'. + Note: It's better to use DetectTierIphone() for modern touchscreen devices. + """ + return self.detectTierIphone() \ + or self.detectS60OssBrowser() \ + or self.detectSymbianOS() \ + or self.detectWindowsMobile() \ + or self.detectBlackBerry() \ + or self.detectMeegoPhone() \ + or self.detectPalmWebOS() + + def detectMobileQuick(self): + """Return detection of any mobile device using the quicker method + + Detects if the current device is a mobile device. + This method catches most of the popular modern devices. + Excludes Apple iPads and other modern tablets. + """ + #Let's exclude tablets + if self.__isTierTablet: + return False + + #Most mobile browsing is done on smartphones + if self.detectSmartphone(): + return True + + #Catch-all for many mobile devices + if UAgentInfo.mobile in self.__userAgent: + return True + + if self.detectOperaMobile(): + return True + + #We also look for Kindle devices + if self.detectKindle() \ + or self.detectAmazonSilk(): + return True + + if self.detectWapWml() \ + or self.detectMidpCapable() \ + or self.detectBrewDevice(): + return True + + if UAgentInfo.engineNetfront in self.__userAgent \ + or UAgentInfo.engineUpBrowser in self.__userAgent: + return True + + return False + + def detectMobileLong(self): + """Return detection of any mobile device using the more thorough method + + The longer and more thorough way to detect for a mobile device. + 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! + """ + + if self.detectMobileQuick() \ + or self.detectGameConsole(): + return True + + if self.detectDangerHiptop() \ + or self.detectMaemoTablet() \ + or self.detectSonyMylo() \ + or self.detectArchos(): + return True + + if UAgentInfo.devicePda in self.__userAgent \ + and UAgentInfo.disUpdate not in self.__userAgent: + return True + + #detect older phones from certain manufacturers and operators. + return UAgentInfo.uplink in self.__userAgent \ + or UAgentInfo.engineOpenWeb in self.__userAgent \ + or UAgentInfo.manuSamsung1 in self.__userAgent \ + or UAgentInfo.manuSonyEricsson in self.__userAgent \ + or UAgentInfo.manuericsson in self.__userAgent \ + or UAgentInfo.svcDocomo in self.__userAgent \ + or UAgentInfo.svcKddi in self.__userAgent \ + or UAgentInfo.svcVodafone in self.__userAgent + + + #***************************** + # For Mobile Web Site Design + #***************************** + def detectTierTablet(self): + """Return detection of any device in the Tablet Tier + + The quick way to detect for a tier of devices. + This method detects for the new generation of + HTML 5 capable, larger screen tablets. + Includes iPad, Android (e.g., Xoom), BB Playbook, WebOS, etc. + """ + return self.detectIpad() \ + or self.detectAndroidTablet() \ + or self.detectBlackBerryTablet() \ + or self.detectFirefoxOSTablet() \ + or self.detectUbuntuTablet() \ + or self.detectWebOSTablet() + + def detectTierIphone(self): + """Return detection of any device in the iPhone/Android/WP7/WebOS Tier + + The quick way to detect for a tier of devices. + This method detects for devices which can + display iPhone-optimized web content. + Includes iPhone, iPod Touch, Android, Windows Phone 7, Palm WebOS, etc. + """ + return self.__isIphone \ + or self.__isAndroidPhone \ + or self.detectWindowsPhone() \ + or self.detectBlackBerry10Phone() \ + or self.detectPalmWebOS() \ + or self.detectBada() \ + or self.detectTizen() \ + or self.detectFirefoxOSPhone() \ + or self.detectSailfishPhone() \ + or self.detectUbuntuPhone() \ + or self.detectGamingHandheld() + + def detectTierRichCss(self): + """Return detection of any device in the 'Rich CSS' Tier + + The quick way to detect for a tier of devices. + This method detects for devices which are likely to be capable + of viewing CSS content optimized for the iPhone, + but may not necessarily support JavaScript. + Excludes all iPhone Tier devices. + """ + #The following devices are explicitly ok. + #Note: 'High' BlackBerry devices ONLY + if not self.detectMobileQuick(): + return False + #Exclude iPhone Tier and e-Ink Kindle devices + if self.detectTierIphone() \ + or self.detectKindle(): + return False + #The following devices are explicitly ok. + #Note: 'High' BlackBerry devices ONLY + #Older Windows 'Mobile' isn't good enough for iPhone Tier. + return self.detectWebkit() \ + or self.detectS60OssBrowser() \ + or self.detectBlackBerryHigh() \ + or self.detectWindowsMobile() \ + or UAgentInfo.engineTelecaQ in self.__userAgent + + def detectTierOtherPhones(self): + """Return detection of a mobile device in the less capable tier + + The quick way to detect for a tier of devices. + This method detects for all other types of phones, + but excludes the iPhone and RichCSS Tier devices. + """ + #Exclude devices in the other 2 categories + return self.detectMobileLong() \ + and not self.detectTierIphone() \ + and not self.detectTierRichCss() diff --git a/vendor/ahand/mobileesp/README.md b/vendor/ahand/mobileesp/README.md new file mode 100644 index 00000000000..0ba416ca943 --- /dev/null +++ b/vendor/ahand/mobileesp/README.md @@ -0,0 +1,91 @@ +#MobileESP +[](http://blog.mobileesp.com/?page_id=13) + +[](http://blog.mobileesp.com/?page_id=53) +[](http://blog.mobileesp.com/?page_id=53) +[](http://blog.mobileesp.com/?page_id=53) +[](http://blog.mobileesp.com/?page_id=53) +[](http://blog.mobileesp.com/?page_id=53) +[](http://blog.mobileesp.com/?page_id=53) + + + +At last, a dead simple way for web site publishers to detect visitors on mobile web sites! + +MobileESP is free, open source and lightweight. MobileESP has a simple API for detecting mobile devices. The API returns the simple Boolean result of TRUE if the device is the specified type, or FALSE if it isn't. For example, want to know if your visitor is on an iPhone, Android or Windows Phone device? Simply use the method DetectTierIphone(). It's that easy. + +Visit the MobileESP web site for tons more information: <a href="http://www.mobileesp.org">www.MobileESP.org</a>. + + +##Core Principles +MobileESP believes in making it dead easy for a website publisher to detect mobile visitors. As a result, the API follows the DetectXXX() pattern and returns a simple Boolean (true or false) for the type of mobile device or platform desired. The API DetectXXX() methods are consistent by design across supported platforms. + +In addition, a second core principle is that the code is easy for the user to read and understand. Therefore, we believe it's easier for the user to change, update or extend the library, if desired. + +The code is also purposefully written to be modular so that it is not only easier to maintain, but also easier to extend. + + +##Server-Side Platforms +> <a href="http://blog.mobileesp.com/?page_id=53">API Documentation</a> + +MobileESP started with PHP (and JavaScript) and has been extended by the community to a bunch of other platforms: +- PHP +- Java +- ASP.NET (C#) +- Python +- C++ + +Also available in separate repositories: +- <a href="https://github.com/eimermusic/mobileesp">Ruby</a>: This project was ported by Martin, who separately maintains the Ruby codebase on GitHub. +- <a href="https://bitbucket.org/mbarrero/mobileesp-classic-asp">Classic ASP (VBscript)</a>: This project was ported by Miguel Barrero, who separately maintains the codebase on BitBucket. + + +##Client-Side Platforms +> <a href="http://blog.mobileesp.com/?page_id=60">JavaScript API Documentation</a> + +MobileESP is also available for JavaScript to be run in the browser. Support for client-side JavaScript processing on phones is very poor to completely non-existent. Though much better on modern smartphones, JavaScript is still not quite at the desktop level. Generally speaking, JavaScript is probably reliable only for distinguishing between devices among modern smartphones and tablets. So if you want to know whether your visitor is one of these devices, the JavaScript probably works fine: iPhone, Android, Windows Phone, and BlackBerry 10+. A few other modern smartphone OSes such as Sailfish and Ubuntu are also expected to perform well. + +A server-side library is recommended for pretty much everything else: from older smartphone OSes to all feature phones, plus smart TVs, gaming devices, and ereaders. + + +##Live Demo +Anthony updates the live demo pages when he updates the library. The live demo pages show the results of each of the API calls. Point your mobile device browser to the parent demo page: <a href="http://www.hand-interactive.com/detect/">http://www.hand-interactive.com/detect/</a> +- <a href="http://www.hand-interactive.com/detect/mobileesp_demo_php.htm">PHP Demo Page</a> +- <a href="http://www.hand-interactive.com/detect/mobileesp_demo_javascript.htm">JavaScript Demo Page</a> + + +##Useragent Test Strings +The MobileESP project tests the PHP and JavaScript live demos with the included spreadsheet of useragent strings. This set of useragent strings isn't meant to be exhaustive, but rather to feature a wide variety of strings to verify that each of the DetectXXX() methods work as expected. Feel free to use this list of useragent strings on your own project, as well. + + +##Updated May 2015! +Anthony provided a much-needed update in May 2015. Please see the change log in the beginning of each file for full details. + +Anthony tested the PHP and JavaScript libraries with the new useragent strings in the spreadsheet. However, Anthony doesn't have the environments set up to test the Java, C#, Python and C++ libraries. Can you help to test these? + +In addition, the Ruby and Classic ASP (VBScript) libraries haven't been updated in several years. Would anyone be interested in updating them? + +##Python Question +We've been notified that the Python library doesn't follow the Python community coding standards regarding method names in lower case with underscores separating elements rather than camel case. What do y'all think about this? Would it be better to conform to the Python standards or keep the method names consistent between libraries? Please let Anthony know. + +##Backstory +This project maintains and extends the original code created in 2008 by Anthony Hand of Hand Interactive (<a href="http://www.hand-interactive.com">http://www.hand-interactive.com</a>). Anthony was working on a web site project for a client and wanted an easy way to customize some of the content for smartphones, especially that era's flagship iPhone, Symbian, and BlackBerry devices. However, commonly used Grep-style algorithms at the time were dumb, blunt force tools treating all devices as equal. Thus the PHP and JavaScript libraries were originally born. + +NOTE: The MobileESP project was previously hosted on the Google Code web site. Because Google closed down that site and there had been many user requests, MobileESP is now hosted with GitHub. + +##YouTube Quick Talk Video +MobileESP founder, Anthony Hand, gave a short 6 minute talk on the origin and basics of MobileESP at a Silicon Valley event in 2012. Check it out! +<a href="https://youtu.be/F_mFNTbe9lQ">https://youtu.be/F_mFNTbe9lQ</a> + + +##License +Apache v2.0. More info and the link to the Apache v2.0 license page in each code file. + + +##Important Caveat +The MobileESP project code is lightweight and ideal for many web sites. However, this project is not meant to replace other projects offering greater specificity and control, such as <a href="http://wurfl.sourceforge.net/">WURFL</a> or <a href="http://www.handsetdetection.com//">HandsetDetection.com</a>. + + +##Donations +Yes, usage of the MobileESP code is FREE, so no worries about that. But a donation to the cause helps provide motivation for Anthony to frequently update the code and continue to enhance the cross-platform APIs. And get new phones to do new tests with! +> <a href="http://blog.mobileesp.com/?page_id=25">Donation Info</a> diff --git a/vendor/ahand/mobileesp/composer.json b/vendor/ahand/mobileesp/composer.json new file mode 100644 index 00000000000..97ee2fc3229 --- /dev/null +++ b/vendor/ahand/mobileesp/composer.json @@ -0,0 +1,24 @@ +{ + "name": "ahand/mobileesp", + "type": "library", + "version": "3.0.0", + "description": "Since 2008, MobileESP provides web site developers an easy-to-use and lightweight API for detecting whether visitors are using a mobile device, and if so, what kind. The APIs provide simple boolean results ('true' or 'false') for identifying individual device categories (such as iPhone, BlackBerry, Android, and Windows Mobile), device capabilities (e.g., J2ME), and broad classes of devices, such as 'iPhone Tier' (iPhone/Android/Tizen) or 'Tablet Tier.' APIs are available in PHP, JavaScript, Java, C#, Ruby Python, and more.", + "keywords": ["mobile","mobile detect","mobile esp","mobile redirect","mobile view managing","mobile-detect","mobile detector","mobile device","detect iphone","detect ipad","detect tablet","detect android","mobiledetect","responsive web","useragent","browser","user agent"], + "authors": [ + { + "name": "Anthony Hand", + "email": "anthony.hand@gmail.com", + "role": "Maintainer" + } + ], + "homepage": "http://www.mobileesp.org", + "license": "Apache-2.0", + "support": { + "issues": "https://github.com/ahand/mobileesp/issues", + "source": "https://github.com/ahand/mobileesp/" + }, + "autoload": { + "classmap": ["PHP"] + }, + "minimum-stability": "stable" +} diff --git a/vendor/autoload.php b/vendor/autoload.php index ef36b7c89f7..923c8dcfb1a 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer' . '/autoload_real.php'; -return ComposerAutoloaderInitd6bb6ced69275a18e1e319c66d1169ab::getLoader(); +return ComposerAutoloaderInit3a47b6a0a6aba66870ea75e8ef6a7551::getLoader(); diff --git a/vendor/behat/mink-selenium2-driver/src/Selenium2Driver.php b/vendor/behat/mink-selenium2-driver/src/Selenium2Driver.php old mode 100644 new mode 100755 diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 32cb1c52fd2..fabfebf819c 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -11,6 +11,6 @@ return array( 'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'), 'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'), 'LosReCaptcha\\' => array($vendorDir . '/los/losrecaptcha/src'), - 'Behat\\Mink\\Driver\\' => array($vendorDir . '/behat/mink-zombie-driver/src', $vendorDir . '/behat/mink-selenium2-driver/src'), + 'Behat\\Mink\\Driver\\' => array($vendorDir . '/behat/mink-selenium2-driver/src', $vendorDir . '/behat/mink-zombie-driver/src'), 'Behat\\Mink\\' => array($vendorDir . '/behat/mink/src'), ); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index e6f8a0ea0af..94b2e150fb1 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInitd6bb6ced69275a18e1e319c66d1169ab +class ComposerAutoloaderInit3a47b6a0a6aba66870ea75e8ef6a7551 { private static $loader; @@ -19,9 +19,9 @@ class ComposerAutoloaderInitd6bb6ced69275a18e1e319c66d1169ab return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInitd6bb6ced69275a18e1e319c66d1169ab', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit3a47b6a0a6aba66870ea75e8ef6a7551', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInitd6bb6ced69275a18e1e319c66d1169ab', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit3a47b6a0a6aba66870ea75e8ef6a7551', 'loadClassLoader')); $includePaths = require __DIR__ . '/include_paths.php'; array_push($includePaths, get_include_path()); @@ -48,7 +48,7 @@ class ComposerAutoloaderInitd6bb6ced69275a18e1e319c66d1169ab } } -function composerRequired6bb6ced69275a18e1e319c66d1169ab($file) +function composerRequire3a47b6a0a6aba66870ea75e8ef6a7551($file) { require $file; } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 1175685b145..e6e5c6873d6 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -100,6 +100,43 @@ "jasig" ] }, + { + "name": "cap60552/php-sip2", + "version": "v1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/cap60552/php-sip2.git", + "reference": "9904f94e857b7d4d4fd494f2d6634dcaf0d6e2c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cap60552/php-sip2/zipball/9904f94e857b7d4d4fd494f2d6634dcaf0d6e2c1", + "reference": "9904f94e857b7d4d4fd494f2d6634dcaf0d6e2c1", + "shasum": "" + }, + "time": "2015-11-03 04:42:39", + "type": "library", + "installation-source": "dist", + "autoload": { + "classmap": [ + "/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0" + ], + "authors": [ + { + "name": "John Wohlers", + "email": "john@wohlershome.net", + "role": "Maintainer" + } + ], + "description": "PHP class library to facilitate communication with Integrated Library System (ILS) servers via 3M's SIP2.", + "homepage": "https://github.com/cap60552/php-sip2" + }, { "name": "zendframework/zendxml", "version": "1.0.1", @@ -1021,6 +1058,121 @@ "zf2" ] }, + { + "name": "instaclick/php-webdriver", + "version": "1.4.3", + "version_normalized": "1.4.3.0", + "source": { + "type": "git", + "url": "https://github.com/instaclick/php-webdriver.git", + "reference": "0c20707dcf30a32728fd6bdeeab996c887fdb2fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/instaclick/php-webdriver/zipball/0c20707dcf30a32728fd6bdeeab996c887fdb2fb", + "reference": "0c20707dcf30a32728fd6bdeeab996c887fdb2fb", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.2" + }, + "require-dev": { + "satooshi/php-coveralls": "dev-master" + }, + "time": "2015-06-15 20:19:33", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "WebDriver": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Justin Bishop", + "email": "jubishop@gmail.com", + "role": "Developer" + }, + { + "name": "Anthon Pang", + "email": "apang@softwaredevelopment.ca", + "role": "Fork Maintainer" + } + ], + "description": "PHP WebDriver for Selenium 2", + "homepage": "http://instaclick.com/", + "keywords": [ + "browser", + "selenium", + "webdriver", + "webtest" + ] + }, + { + "name": "symfony/css-selector", + "version": "v2.8.0", + "version_normalized": "2.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "b600fec37c0efca08046d481d79e7eabc07108ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/b600fec37c0efca08046d481d79e7eabc07108ff", + "reference": "b600fec37c0efca08046d481d79e7eabc07108ff", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "time": "2015-10-30 20:15:42", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com" + }, { "name": "behat/mink", "version": "v1.7.0", @@ -1082,30 +1234,29 @@ ] }, { - "name": "behat/mink-zombie-driver", + "name": "behat/mink-selenium2-driver", "version": "v1.3.0", "version_normalized": "1.3.0.0", "source": { "type": "git", - "url": "https://github.com/minkphp/MinkZombieDriver.git", - "reference": "257a2d46ffdc8cba28d107c2f1368fc1e5637d1b" + "url": "https://github.com/minkphp/MinkSelenium2Driver.git", + "reference": "bedbf1999c7ba1bc6921b30ee2eadf383e7ff5c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/minkphp/MinkZombieDriver/zipball/257a2d46ffdc8cba28d107c2f1368fc1e5637d1b", - "reference": "257a2d46ffdc8cba28d107c2f1368fc1e5637d1b", + "url": "https://api.github.com/repos/minkphp/MinkSelenium2Driver/zipball/bedbf1999c7ba1bc6921b30ee2eadf383e7ff5c9", + "reference": "bedbf1999c7ba1bc6921b30ee2eadf383e7ff5c9", "shasum": "" }, "require": { "behat/mink": "~1.7@dev", - "ext-sockets": "*", - "php": ">=5.3.1", - "symfony/process": "~2.1" + "instaclick/php-webdriver": "~1.1", + "php": ">=5.3.1" }, "require-dev": { "symfony/phpunit-bridge": "~2.7" }, - "time": "2015-09-21 21:07:53", + "time": "2015-09-21 21:02:54", "type": "mink-driver", "extra": { "branch-alias": { @@ -1129,245 +1280,98 @@ "homepage": "http://everzet.com" }, { - "name": "Pascal Cremer", - "email": "b00gizm@gmail.com", - "homepage": "http://github.com/b00gizm" + "name": "Pete Otaqui", + "email": "pete@otaqui.com", + "homepage": "https://github.com/pete-otaqui" } ], - "description": "Zombie.js driver for Mink framework", + "description": "Selenium2 (WebDriver) driver for Mink framework", "homepage": "http://mink.behat.org/", "keywords": [ "ajax", "browser", - "headless", "javascript", + "selenium", "testing", - "zombie" + "webdriver" ] }, { - "name": "zendframework/zendrest", - "version": "2.0.2", - "version_normalized": "2.0.2.0", + "name": "symfony/process", + "version": "v2.8.0", + "version_normalized": "2.8.0.0", "source": { "type": "git", - "url": "https://github.com/zendframework/ZendRest.git", - "reference": "9d2d631af7b4b54bfa2a7f5ca5f455192e3e0916" + "url": "https://github.com/symfony/process.git", + "reference": "1b988a88e3551102f3c2d9e1d47a18c3a78d6312" }, "dist": { "type": "zip", - "url": "https://packages.zendframework.com/composer/zendframework-zendrest-2.0.2-2f9805.zip", - "reference": "9d2d631af7b4b54bfa2a7f5ca5f455192e3e0916", - "shasum": "445d681551a5c9f2be25b241e615e754278d79ba" + "url": "https://api.github.com/repos/symfony/process/zipball/1b988a88e3551102f3c2d9e1d47a18c3a78d6312", + "reference": "1b988a88e3551102f3c2d9e1d47a18c3a78d6312", + "shasum": "" }, "require": { - "php": ">=5.3.3", - "zendframework/zend-http": "~2.0", - "zendframework/zend-uri": "~2.0", - "zendframework/zendxml": "~1.0-dev" + "php": ">=5.3.9" }, - "time": "2014-03-05 22:32:09", + "time": "2015-11-30 12:35:10", "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, "installation-source": "dist", "autoload": { - "psr-0": { - "ZendRest": "library/" - } + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, + "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], - "description": " ", - "homepage": "http://packages.zendframework.com/", - "keywords": [ - "rest", - "zf2" - ] + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com" }, { - "name": "zendframework/zendservice-amazon", - "version": "2.0.4", - "version_normalized": "2.0.4.0", + "name": "behat/mink-zombie-driver", + "version": "v1.3.0", + "version_normalized": "1.3.0.0", "source": { "type": "git", - "url": "https://github.com/zendframework/ZendService_Amazon.git", - "reference": "a44eec522c622970a6c6666dc308ec6daad08ed4" + "url": "https://github.com/minkphp/MinkZombieDriver.git", + "reference": "257a2d46ffdc8cba28d107c2f1368fc1e5637d1b" }, "dist": { "type": "zip", - "url": "https://packages.zendframework.com/composer/zendframework-zendservice-amazon-2.0.4-db4e7c.zip", - "reference": "a44eec522c622970a6c6666dc308ec6daad08ed4", - "shasum": "6725f42e30e9fa4fa2f8476d650fc07118900569" - }, - "require": { - "php": ">=5.3.3", - "zendframework/zend-crypt": "~2.0", - "zendframework/zend-http": "~2.0", - "zendframework/zend-json": "~2.0", - "zendframework/zendrest": "~2.0", - "zendframework/zendxml": "~1.0-dev" - }, - "require-dev": { - "fabpot/php-cs-fixer": "~1.7.0", - "phpunit/phpunit": "~4.0", - "zendframework/zend-i18n": "~2.0" - }, - "suggest": { - "zendframework/zend-uri": "Zend\\Uri component" - }, - "time": "2015-06-04 19:47:46", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "ZendService\\Amazon\\": "library/" - } - }, - "autoload-dev": { - "psr-0": { - "ZendServiceTest\\Amazon\\": "tests/ZendServiceTest/Amazon/" - } - }, - "license": [ - "BSD-3-Clause" - ], - "description": "OOP wrapper for the Amazon web service", - "homepage": "http://packages.zendframework.com/", - "keywords": [ - "amazon", - "ec2", - "s3", - "simpledb", - "sqs", - "zf2" - ] - }, - { - "name": "cap60552/php-sip2", - "version": "v1.0.0", - "version_normalized": "1.0.0.0", - "source": { - "type": "git", - "url": "https://github.com/cap60552/php-sip2.git", - "reference": "9904f94e857b7d4d4fd494f2d6634dcaf0d6e2c1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/cap60552/php-sip2/zipball/9904f94e857b7d4d4fd494f2d6634dcaf0d6e2c1", - "reference": "9904f94e857b7d4d4fd494f2d6634dcaf0d6e2c1", - "shasum": "" - }, - "time": "2015-11-03 04:42:39", - "type": "library", - "installation-source": "dist", - "autoload": { - "classmap": [ - "/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-3.0" - ], - "authors": [ - { - "name": "John Wohlers", - "email": "john@wohlershome.net", - "role": "Maintainer" - } - ], - "description": "PHP class library to facilitate communication with Integrated Library System (ILS) servers via 3M's SIP2.", - "homepage": "https://github.com/cap60552/php-sip2" - }, - { - "name": "instaclick/php-webdriver", - "version": "1.4.3", - "version_normalized": "1.4.3.0", - "source": { - "type": "git", - "url": "https://github.com/instaclick/php-webdriver.git", - "reference": "0c20707dcf30a32728fd6bdeeab996c887fdb2fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/instaclick/php-webdriver/zipball/0c20707dcf30a32728fd6bdeeab996c887fdb2fb", - "reference": "0c20707dcf30a32728fd6bdeeab996c887fdb2fb", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "php": ">=5.3.2" - }, - "require-dev": { - "satooshi/php-coveralls": "dev-master" - }, - "time": "2015-06-15 20:19:33", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "WebDriver": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Justin Bishop", - "email": "jubishop@gmail.com", - "role": "Developer" - }, - { - "name": "Anthon Pang", - "email": "apang@softwaredevelopment.ca", - "role": "Fork Maintainer" - } - ], - "description": "PHP WebDriver for Selenium 2", - "homepage": "http://instaclick.com/", - "keywords": [ - "browser", - "selenium", - "webdriver", - "webtest" - ] - }, - { - "name": "behat/mink-selenium2-driver", - "version": "v1.3.0", - "version_normalized": "1.3.0.0", - "source": { - "type": "git", - "url": "https://github.com/minkphp/MinkSelenium2Driver.git", - "reference": "bedbf1999c7ba1bc6921b30ee2eadf383e7ff5c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/minkphp/MinkSelenium2Driver/zipball/bedbf1999c7ba1bc6921b30ee2eadf383e7ff5c9", - "reference": "bedbf1999c7ba1bc6921b30ee2eadf383e7ff5c9", - "shasum": "" + "url": "https://api.github.com/repos/minkphp/MinkZombieDriver/zipball/257a2d46ffdc8cba28d107c2f1368fc1e5637d1b", + "reference": "257a2d46ffdc8cba28d107c2f1368fc1e5637d1b", + "shasum": "" }, "require": { "behat/mink": "~1.7@dev", - "instaclick/php-webdriver": "~1.1", - "php": ">=5.3.1" + "ext-sockets": "*", + "php": ">=5.3.1", + "symfony/process": "~2.1" }, "require-dev": { "symfony/phpunit-bridge": "~2.7" }, - "time": "2015-09-21 21:02:54", + "time": "2015-09-21 21:07:53", "type": "mink-driver", "extra": { "branch-alias": { @@ -1391,128 +1395,22 @@ "homepage": "http://everzet.com" }, { - "name": "Pete Otaqui", - "email": "pete@otaqui.com", - "homepage": "https://github.com/pete-otaqui" + "name": "Pascal Cremer", + "email": "b00gizm@gmail.com", + "homepage": "http://github.com/b00gizm" } ], - "description": "Selenium2 (WebDriver) driver for Mink framework", + "description": "Zombie.js driver for Mink framework", "homepage": "http://mink.behat.org/", "keywords": [ "ajax", "browser", + "headless", "javascript", - "selenium", "testing", - "webdriver" + "zombie" ] }, - { - "name": "symfony/css-selector", - "version": "v2.8.0", - "version_normalized": "2.8.0.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "b600fec37c0efca08046d481d79e7eabc07108ff" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/b600fec37c0efca08046d481d79e7eabc07108ff", - "reference": "b600fec37c0efca08046d481d79e7eabc07108ff", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "time": "2015-10-30 20:15:42", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Symfony\\Component\\CssSelector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony CssSelector Component", - "homepage": "https://symfony.com" - }, - { - "name": "symfony/process", - "version": "v2.8.0", - "version_normalized": "2.8.0.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "1b988a88e3551102f3c2d9e1d47a18c3a78d6312" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/1b988a88e3551102f3c2d9e1d47a18c3a78d6312", - "reference": "1b988a88e3551102f3c2d9e1d47a18c3a78d6312", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "time": "2015-11-30 12:35:10", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Process Component", - "homepage": "https://symfony.com" - }, { "name": "ahand/mobileesp", "version": "dev-master", @@ -1571,5 +1469,107 @@ "issues": "https://github.com/ahand/mobileesp/issues", "source": "https://github.com/ahand/mobileesp/" } + }, + { + "name": "zendframework/zendrest", + "version": "2.0.2", + "version_normalized": "2.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/ZendRest.git", + "reference": "9d2d631af7b4b54bfa2a7f5ca5f455192e3e0916" + }, + "dist": { + "type": "zip", + "url": "https://packages.zendframework.com/composer/zendframework-zendrest-2.0.2-2f9805.zip", + "reference": "9d2d631af7b4b54bfa2a7f5ca5f455192e3e0916", + "shasum": "445d681551a5c9f2be25b241e615e754278d79ba" + }, + "require": { + "php": ">=5.3.3", + "zendframework/zend-http": "~2.0", + "zendframework/zend-uri": "~2.0", + "zendframework/zendxml": "~1.0-dev" + }, + "time": "2014-03-05 22:32:09", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "ZendRest": "library/" + } + }, + "license": [ + "BSD-3-Clause" + ], + "description": " ", + "homepage": "http://packages.zendframework.com/", + "keywords": [ + "rest", + "zf2" + ] + }, + { + "name": "zendframework/zendservice-amazon", + "version": "2.0.4", + "version_normalized": "2.0.4.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/ZendService_Amazon.git", + "reference": "a44eec522c622970a6c6666dc308ec6daad08ed4" + }, + "dist": { + "type": "zip", + "url": "https://packages.zendframework.com/composer/zendframework-zendservice-amazon-2.0.4-db4e7c.zip", + "reference": "a44eec522c622970a6c6666dc308ec6daad08ed4", + "shasum": "6725f42e30e9fa4fa2f8476d650fc07118900569" + }, + "require": { + "php": ">=5.3.3", + "zendframework/zend-crypt": "~2.0", + "zendframework/zend-http": "~2.0", + "zendframework/zend-json": "~2.0", + "zendframework/zendrest": "~2.0", + "zendframework/zendxml": "~1.0-dev" + }, + "require-dev": { + "fabpot/php-cs-fixer": "~1.7.0", + "phpunit/phpunit": "~4.0", + "zendframework/zend-i18n": "~2.0" + }, + "suggest": { + "zendframework/zend-uri": "Zend\\Uri component" + }, + "time": "2015-06-04 19:47:46", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "ZendService\\Amazon\\": "library/" + } + }, + "autoload-dev": { + "psr-0": { + "ZendServiceTest\\Amazon\\": "tests/ZendServiceTest/Amazon/" + } + }, + "license": [ + "BSD-3-Clause" + ], + "description": "OOP wrapper for the Amazon web service", + "homepage": "http://packages.zendframework.com/", + "keywords": [ + "amazon", + "ec2", + "s3", + "simpledb", + "sqs", + "zf2" + ] } ] diff --git a/vendor/instaclick/php-webdriver/lib/WebDriver/Service/CurlService.php b/vendor/instaclick/php-webdriver/lib/WebDriver/Service/CurlService.php old mode 100644 new mode 100755 diff --git a/vendor/instaclick/php-webdriver/lib/WebDriver/Service/CurlServiceInterface.php b/vendor/instaclick/php-webdriver/lib/WebDriver/Service/CurlServiceInterface.php old mode 100644 new mode 100755 diff --git a/vendor/instaclick/php-webdriver/lib/WebDriver/ServiceFactory.php b/vendor/instaclick/php-webdriver/lib/WebDriver/ServiceFactory.php old mode 100644 new mode 100755 -- GitLab