forked from WebKit/WebKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdevice_type.py
More file actions
159 lines (139 loc) · 8.12 KB
/
device_type.py
File metadata and controls
159 lines (139 loc) · 8.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# Copyright (C) 2017 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from webkitpy.common.version_name_map import VersionNameMap, INTERNAL_TABLE
from webkitpy.port.config import apple_additions
# This class is designed to match device types. Because it is used for matching, 'None' is treated as a wild-card.
class DeviceType(object):
FIRST_GENERATION = ' (1st generation)'
@classmethod
def from_string(cls, device_string, version=None):
"""
Converts a string into a DeviceType object. These strings should be of the form
'<hardware_family> <hardware_type>', where <hardware_family> is mandatory and
<hardware_family> is optional.
Example input + output:
('iPhone 6 Plus') -> DeviceType(hardware_family='iPhone', hardware_type='6 Plus', software_version=None)
('iPhone', Version(11)) -> DeviceType(hardware_family='iPhone', hardware_type=None, software_version=Version(11))
('Apple TV 4K') -> DeviceType(hardware_family='TV', hardware_type='4K', software_version=None)
:param device_string: String representing a device.
:type device_string: str
:param version: Version object of software run on the device.
:type version: Version
:returns: DeviceType object
:rtype: DeviceType
"""
split_str = device_string.split(' ')
if len(split_str) == 1:
return cls(hardware_family=device_string, software_version=version)
family_index = 0
if split_str[family_index].lower() == 'apple':
family_index = 1
return cls(
hardware_family=split_str[family_index],
hardware_type=' '.join(split_str[family_index + 1:]) if len(split_str) > family_index + 1 else None,
software_version=version)
def _define_software_variant_from_hardware_family(self):
if self.hardware_family is None:
return
if self.software_variant:
return
self.software_variant = None
if self.hardware_family.lower().split(' ')[-1].startswith('watch'):
self.hardware_family = 'Apple Watch'
self.software_variant = 'watchOS'
elif self.hardware_family.lower().split(' ')[-1].startswith('tv'):
self.hardware_family = 'Apple TV'
self.software_variant = 'tvOS'
elif self.hardware_family.lower().startswith('ipad') or self.hardware_family.lower().startswith('iphone'):
self.software_variant = 'iOS'
def check_consistency(self):
if self.hardware_family is not None:
if self.hardware_family == 'Apple Watch':
assert self.software_variant == 'watchOS'
elif self.hardware_family == 'Apple TV':
assert self.software_variant == 'tvOS'
elif self.hardware_family in ('iPhone', 'iPad'):
assert self.software_variant == 'iOS'
if self.hardware_type is not None:
assert self.hardware_family is not None
def __init__(self, hardware_family=None, hardware_type=None, software_version=None, software_variant=None):
"""
:param hardware_family: iPhone, iPad, Apple Watch and Apple TV are all examples.
:type hardware_family: str
:param hardware_type: 6s, Series 2 - 42mm, 4k are all examples
:type hardware_type: str
:param software_version: Version object representing software the device is running.
:type software_version: Version
:param software_variant: Groups together hardware families which share an OS, like iPad and iPhone. iOS, tvOS and watchOS are examples.
:type software_variant: str
"""
if hardware_family is None and hardware_type is None and software_version is None and software_variant is None:
raise ValueError('Cannot instantiate DeviceType with no arguments')
self.hardware_family = hardware_family
self.hardware_type = hardware_type
self.software_version = software_version
self.software_variant = software_variant
self._define_software_variant_from_hardware_family()
self.check_consistency()
@property
def standardized_hardware_type(self):
if not self.hardware_type:
return None
if self.hardware_type.lower().endswith(self.FIRST_GENERATION):
return self.hardware_type[:-len(self.FIRST_GENERATION)]
return self.hardware_type
def __str__(self):
version = None
if self.software_version and apple_additions():
version = VersionNameMap.map().to_name(self.software_version, platform=self.software_variant.lower(), table=INTERNAL_TABLE)
elif self.software_version:
version = VersionNameMap.map().to_name(self.software_version, platform=self.software_variant.lower())
return u'{hardware_family}{hardware_type} running {version}'.format(
hardware_family=self.hardware_family if self.hardware_family else 'Device',
hardware_type=u' {}'.format(self.hardware_type) if self.hardware_type else '',
version=version or self.software_variant,
)
# This technique of matching treats 'None' a wild-card.
def __eq__(self, other):
assert isinstance(other, DeviceType)
if self.hardware_family is not None and other.hardware_family is not None and self.hardware_family.lower() != other.hardware_family.lower():
return False
if self.standardized_hardware_type is not None and other.standardized_hardware_type is not None and self.standardized_hardware_type.lower() != other.standardized_hardware_type.lower():
return False
if self.software_variant is not None and other.software_variant is not None and self.software_variant.lower() != other.software_variant.lower():
return False
if self.software_version is not None and other.software_version is not None and self.software_version != other.software_version:
return False
return True
def __contains__(self, other):
assert isinstance(other, DeviceType)
if self.hardware_family is not None and other.hardware_family is not None and self.hardware_family.lower() != other.hardware_family.lower():
return False
if self.standardized_hardware_type is not None and other.standardized_hardware_type is not None and self.standardized_hardware_type.lower() != other.standardized_hardware_type.lower():
return False
if self.software_variant is not None and other.software_variant is not None and self.software_variant.lower() != other.software_variant.lower():
return False
if self.software_version is not None and other.software_version is not None and not other.software_version in self.software_version:
return False
return True
def __hash__(self):
return hash((self.hardware_family, self.standardized_hardware_type, self.software_variant, self.software_version))