@@ -103,8 +103,10 @@ class DeviceDetector {
103
103
this . deviceInfo = attr ( options , 'deviceInfo' , false ) ;
104
104
}
105
105
106
+
106
107
init ( ) {
107
108
this . addParseOs ( OS_PARSER , new OsParser ( ) ) ;
109
+
108
110
this . addParseClient ( CLIENT_PARSER_LIST . FEED_READER , new FeedReaderParser ( ) ) ;
109
111
this . addParseClient ( CLIENT_PARSER_LIST . MOBILE_APP , new MobileAppParser ( ) ) ;
110
112
this . addParseClient ( CLIENT_PARSER_LIST . MEDIA_PLAYER , new MediaPlayerParser ( ) ) ;
@@ -495,11 +497,21 @@ class DeviceDetector {
495
497
let clientFamily = attr ( clientData , 'family' , '' ) ;
496
498
let deviceType = attr ( deviceData , 'type' , '' ) ;
497
499
498
- if (
499
- deviceType === '' &&
500
- osFamily === 'Android' &&
501
- helper . matchUserAgent ( 'Chrome/[.0-9]*' , userAgent )
502
- ) {
500
+ /**
501
+ * All devices containing VR fragment are assumed to be a wearable
502
+ */
503
+ if ( deviceType === '' && helper . hasVRFragment ( userAgent ) ) {
504
+ deviceType = DEVICE_TYPE . WEARABLE ;
505
+ }
506
+
507
+ /**
508
+ * Chrome on Android passes the device type based on the keyword 'Mobile'
509
+ * If it is present the device should be a smartphone, otherwise it's a tablet
510
+ * See https://developer.chrome.com/multidevice/user-agent#chrome_for_android_user_agent
511
+ * Note: We do not check for browser (family) here, as there might be mobile apps using Chrome, that won't have
512
+ * a detected browser, but can still be detected. So we check the useragent for Chrome instead.
513
+ */
514
+ if ( deviceType === '' && osFamily === 'Android' && helper . matchUserAgent ( 'Chrome/[.0-9]*' , userAgent ) ) {
503
515
if ( helper . matchUserAgent ( '(Mobile|eliboM)' , userAgent ) !== null ) {
504
516
deviceType = DEVICE_TYPE . SMARTPHONE ;
505
517
} else {
@@ -510,24 +522,32 @@ class DeviceDetector {
510
522
/**
511
523
* Some UA contain the fragment 'Pad/APad', so we assume those devices as tablets
512
524
*/
513
- if ( deviceType === DEVICE_TYPE . SMARTPHONE
514
- && helper . matchUserAgent ( 'Pad/APad' , userAgent )
515
- ) {
525
+ if ( deviceType === DEVICE_TYPE . SMARTPHONE && helper . matchUserAgent ( 'Pad/APad' , userAgent ) ) {
516
526
deviceType = DEVICE_TYPE . TABLET ;
517
527
}
518
528
519
- if (
520
- deviceType === '' &&
521
- ( helper . hasAndroidTableFragment ( userAgent ) ||
522
- helper . hasOperaTableFragment ( userAgent ) )
523
- ) {
529
+ /**
530
+ * Some UA contain the fragment 'Android; Tablet;' or 'Opera Tablet', so we assume those devices as tablets
531
+ */
532
+ if ( deviceType === '' && ( helper . hasAndroidTableFragment ( userAgent ) || helper . hasOperaTableFragment ( userAgent ) ) ) {
524
533
deviceType = DEVICE_TYPE . TABLET ;
525
534
}
526
535
536
+ /**
537
+ * Some user agents simply contain the fragment 'Android; Mobile;', so we assume those devices as smartphones
538
+ */
527
539
if ( deviceType === '' && helper . hasAndroidMobileFragment ( userAgent ) ) {
528
540
deviceType = DEVICE_TYPE . SMARTPHONE ;
529
541
}
530
542
543
+ /**
544
+ * Android up to 3.0 was designed for smartphones only. But as 3.0, which was tablet only, was published
545
+ * too late, there were a bunch of tablets running with 2.x
546
+ * With 4.0 the two trees were merged and it is for smartphones and tablets
547
+ *
548
+ * So were are expecting that all devices running Android < 2 are smartphones
549
+ * Devices running Android 3.X are tablets. Device type of Android 2.X and 4.X+ are unknown
550
+ */
531
551
if ( deviceType === '' && osName === 'Android' && osVersion !== '' ) {
532
552
if ( helper . versionCompare ( osVersion , '2.0' ) === - 1 ) {
533
553
deviceType = DEVICE_TYPE . SMARTPHONE ;
@@ -539,6 +559,9 @@ class DeviceDetector {
539
559
}
540
560
}
541
561
562
+ /**
563
+ * All detected feature phones running android are more likely a smartphone
564
+ */
542
565
if ( deviceType === DEVICE_TYPE . FEATURE_PHONE && osFamily === 'Android' ) {
543
566
deviceType = DEVICE_TYPE . SMARTPHONE ;
544
567
}
@@ -551,6 +574,15 @@ class DeviceDetector {
551
574
deviceType = DEVICE_TYPE . FEATURE_PHONE ;
552
575
}
553
576
577
+ /**
578
+ * According to http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
579
+ * Internet Explorer 10 introduces the "Touch" UA string token. If this token is present at the end of the
580
+ * UA string, the computer has touch capability, and is running Windows 8 (or later).
581
+ * This UA string will be transmitted on a touch-enabled system running Windows 8 (RT)
582
+ *
583
+ * As most touch enabled devices are tablets and only a smaller part are desktops/notebooks we assume that
584
+ * all Windows 8 touch devices are tablets.
585
+ */
554
586
if (
555
587
deviceType === '' &&
556
588
( osName === 'Windows RT' ||
@@ -560,14 +592,28 @@ class DeviceDetector {
560
592
deviceType = DEVICE_TYPE . TABLET ;
561
593
}
562
594
563
- // check tv fragments and tv clients
595
+ /**
596
+ * All devices running Opera TV Store are assumed to be a tv
597
+ */
564
598
if ( helper . hasOperaTVStoreFragment ( userAgent ) ) {
565
599
deviceType = DEVICE_TYPE . TV ;
566
- } else if ( helper . hasAndroidTVFragment ( userAgent ) ) {
600
+ }
601
+ /**
602
+ * All devices that contain Andr0id in string are assumed to be a tv
603
+ */
604
+ if ( helper . hasAndroidTVFragment ( userAgent ) ) {
567
605
deviceType = DEVICE_TYPE . TV ;
568
- } else if ( deviceType === '' && helper . hasTVFragment ( userAgent ) ) {
606
+ }
607
+ /**
608
+ * All devices running Tizen TV or SmartTV are assumed to be a tv
609
+ */
610
+ if ( deviceType === '' && helper . hasTVFragment ( userAgent ) ) {
569
611
deviceType = DEVICE_TYPE . TV ;
570
- } else if ( CLIENT_TV_LIST . indexOf ( clientName ) !== - 1 ) {
612
+ }
613
+ /**
614
+ * Devices running those clients are assumed to be a TV
615
+ */
616
+ if ( CLIENT_TV_LIST . indexOf ( clientName ) !== - 1 ) {
571
617
deviceType = DEVICE_TYPE . TV ;
572
618
}
573
619
@@ -701,10 +747,8 @@ class DeviceDetector {
701
747
}
702
748
703
749
// client hints
704
- if ( result . model === '' ) {
705
- if ( clientHints . device && clientHints . device . model !== '' ) {
706
- result . model = clientHints . device . model ;
707
- }
750
+ if ( result . model === '' && clientHints . device && clientHints . device . model !== '' ) {
751
+ result . model = clientHints . device . model ;
708
752
}
709
753
710
754
// device info or deviceTrusted
@@ -759,43 +803,25 @@ class DeviceDetector {
759
803
*/
760
804
parseClient ( userAgent , clientHints ) {
761
805
const extendParsers = [ CLIENT_PARSER_LIST . MOBILE_APP , CLIENT_PARSER_LIST . BROWSER ] ;
762
-
763
- let result = { } ;
764
806
for ( let name in this . clientParserList ) {
765
807
let parser = this . clientParserList [ name ] ;
808
+
766
809
if ( this . clientIndexes && extendParsers . includes ( name ) ) {
767
810
let hash = parser . parseFromHashHintsApp ( clientHints ) ;
768
811
let hint = parser . parseFromClientHints ( clientHints ) ;
769
812
let data = parser . parseUserAgentByPositions ( userAgent ) ;
770
813
let result = parser . prepareParseResult ( userAgent , data , hint , hash ) ;
771
814
if ( result !== null && result . name ) {
772
- return result ;
815
+ return Object . assign ( { } , result ) ;
773
816
}
774
- continue ;
775
817
}
776
818
777
- let resultMerge = parser . parse ( userAgent , clientHints ) ;
778
- if ( resultMerge ) {
779
- return Object . assign ( result , resultMerge ) ;
819
+ let result = parser . parse ( userAgent , clientHints ) ;
820
+ if ( result && result . name ) {
821
+ return Object . assign ( { } , result ) ;
780
822
}
781
823
}
782
-
783
- if ( this . clientIndexes ) {
784
- for ( let i = 0 , l = extendParsers . length ; i < l ; i ++ ) {
785
- let name = extendParsers [ i ] ;
786
- let parser = this . clientParserList [ name ] ;
787
- if ( ! parser ) {
788
- continue ;
789
- }
790
-
791
- let resultMerge = parser . parse ( userAgent , clientHints ) ;
792
- if ( resultMerge ) {
793
- return Object . assign ( result , resultMerge ) ;
794
- }
795
- }
796
- }
797
-
798
- return result ;
824
+ return { } ;
799
825
}
800
826
801
827
prepareDetectResult (
@@ -805,34 +831,35 @@ class DeviceDetector {
805
831
deviceData ,
806
832
clientHints
807
833
) {
808
- let deviceDataType = this . parseDeviceType (
809
- userAgent ,
810
- osData ,
811
- clientData ,
812
- deviceData ,
813
- clientHints
814
- ) ;
815
834
816
- deviceData = Object . assign ( deviceData , deviceDataType ) ;
817
835
/**
818
- * if it's fake UA then it's best not to identify it as Apple running Android OS
836
+ * if it's fake UA then it's best not to identify it as Apple running Android OS or GNU/Linux
819
837
*/
820
- if ( 'Android' === osData . name && 'Apple' === deviceData . brand ) {
838
+ if ( deviceData . brand === 'Apple' && APPLE_OS_LIST . indexOf ( osData . name ) === - 1 ) {
821
839
deviceData . id = '' ;
822
840
deviceData . brand = '' ;
823
841
deviceData . model = '' ;
824
842
deviceData . type = '' ;
825
843
}
826
- /** Assume all devices running iOS / Mac OS are from Apple */
827
- if (
828
- deviceData . brand === '' &&
829
- osData . name !== '' &&
830
- APPLE_OS_LIST . indexOf ( osData . name ) !== - 1
831
- ) {
832
- deviceData . id = 'AP' ;
844
+
845
+ /**
846
+ * Assume all devices running iOS / Mac OS are from Apple
847
+ */
848
+ if ( deviceData . brand === '' && APPLE_OS_LIST . indexOf ( osData . name ) !== - 1 ) {
833
849
deviceData . brand = 'Apple' ;
834
850
}
835
851
852
+ let deviceDataType = this . parseDeviceType (
853
+ userAgent ,
854
+ osData ,
855
+ clientData ,
856
+ deviceData ,
857
+ clientHints
858
+ ) ;
859
+
860
+ deviceData = Object . assign ( deviceData , deviceDataType ) ;
861
+
862
+
836
863
if ( this . deviceTrusted ) {
837
864
deviceData . trusted = DeviceTrusted . check ( osData , clientData , deviceData , clientHints ) ;
838
865
} else {
@@ -888,7 +915,7 @@ class DeviceDetector {
888
915
/**
889
916
* detect os, client and device for sync
890
917
* @param {string } userAgent - string from request header['user-agent']
891
- * @param clientHints
918
+ * @param { {} } clientHints
892
919
* @return {DetectResult }
893
920
*/
894
921
detect ( userAgent , clientHints = { } ) {
0 commit comments