1#  Copyright (C) 2023 The Android Open Source Project
2#
3#  Licensed under the Apache License, Version 2.0 (the "License");
4#  you may not use this file except in compliance with the License.
5#  You may obtain a copy of the License at
6#
7#       http://www.apache.org/licenses/LICENSE-2.0
8#
9#  Unless required by applicable law or agreed to in writing, software
10#  distributed under the License is distributed on an "AS IS" BASIS,
11#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#  See the License for the specific language governing permissions and
13#  limitations under the License.
14#
15#  Licensed under the Apache License, Version 2.0 (the "License");
16#  you may not use this file except in compliance with the License.
17#  You may obtain a copy of the License at
18#
19#       http://www.apache.org/licenses/LICENSE-2.0
20#
21#  Unless required by applicable law or agreed to in writing, software
22#  distributed under the License is distributed on an "AS IS" BASIS,
23#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24#  See the License for the specific language governing permissions and
25#  limitations under the License.
26
27# Lint as: python3
28
29from __future__ import annotations
30
31from collections.abc import Sequence
32import dataclasses
33import enum
34import logging
35from typing import Any, Optional, Union
36
37WIFI_SNIPPET_PACKAGE_NAME = "com.google.snippet.wifi"
38WIFI_DIRECT_SNIPPET_PACKAGE_NAME = 'com.google.snippet.wifi.direct'
39
40ACTION_LISTENER_CALLBACK_EVENT = "WifiP2pManagerActionListenerCallback"
41ACTION_LISTENER_ON_SUCCESS = 'onSuccess'
42ACTION_LISTENER_ON_FAILURE = 'onFailure'
43ACTION_LISTENER_FAILURE_REASON = 'reason'
44
45EVENT_KEY_CALLBACK_NAME = 'callbackName'
46EVENT_KEY_REASON = 'reason'
47EVENT_KEY_P2P_DEVICE = 'p2pDevice'
48EVENT_KEY_P2P_INFO = 'p2pInfo'
49EVENT_KEY_P2P_GROUP = 'p2pGroup'
50EVENT_KEY_PEER_LIST = 'peerList'
51
52EXTRA_WIFI_P2P_GROUP = 'p2pGroupInfo'
53EXTRA_WIFI_STATE = 'wifi_p2p_state'
54
55ON_DEVICE_INFO_AVAILABLE = 'WifiP2pOnDeviceInfoAvailable'
56ON_PERSISTENT_GROUP_INFO_AVAILABLE = 'onPersistentGroupInfoAvailable'
57WIFI_P2P_CREATING_GROUP = 'CREATING_GROUP'
58WIFI_P2P_CONNECTION_CHANGED_ACTION = (
59    'android.net.wifi.p2p.CONNECTION_STATE_CHANGE'
60)
61WIFI_P2P_DISCOVERY_CHANGED_ACTION = (
62    'android.net.wifi.p2p.DISCOVERY_STATE_CHANGE'
63)
64WIFI_P2P_PEERS_CHANGED_ACTION = 'android.net.wifi.p2p.PEERS_CHANGED'
65WIFI_P2P_STATE_CHANGED_ACTION = 'android.net.wifi.p2p.STATE_CHANGED'
66WIFI_P2P_THIS_DEVICE_CHANGED_ACTION = 'android.net.wifi.p2p.THIS_DEVICE_CHANGED'
67
68ANONYMIZED_MAC_ADDRESS = '02:00:00:00:00:00'
69
70
71@enum.unique
72class ActionListenerOnFailure(enum.IntEnum):
73  """Indicates the failure reason of the initiation of the action.
74
75  https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pManager.ActionListener#onFailure(int)
76  """
77
78  ERROR = 0
79  P2P_UNSUPPORTED = 1
80  BUSY = 2
81  NO_SERVICE_REQUESTS = 3
82
83
84@enum.unique
85class Band(enum.IntEnum):
86  """Indicates the band of the operating frequency.
87
88  https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pConfig#getGroupOwnerBand()
89  """
90
91  GROUP_OWNER_BAND_AUTO = 0
92  GROUP_OWNER_BAND_2GHZ = 1
93  GROUP_OWNER_BAND_5GHZ = 2
94
95
96@enum.unique
97class IpProvisioningMode(enum.IntEnum):
98  """Indicates the IP provisioning mode.
99
100  https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pConfig#getGroupClientIpProvisioningMode()
101  """
102
103  GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP = 0
104  GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL = 1
105
106
107@enum.unique
108class ExtraWifiState(enum.IntEnum):
109  """Indicates whether Wi-Fi p2p is enabled or disabled.
110
111  https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pManager#EXTRA_WIFI_STATE
112  """
113
114  WIFI_P2P_STATE_UNKNOWN = 0
115  WIFI_P2P_STATE_DISABLED = 1
116  WIFI_P2P_STATE_ENABLED = 2
117
118
119@enum.unique
120class WifiP2pDeviceStatus(enum.IntEnum):
121  """Represents status code for WifiP2pDevice.and
122
123  https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice#constants_1
124  """
125
126  CONNECTED = 0
127  INVITED = 1
128  FAILED = 2
129  AVAILABLE = 3
130  UNAVAILABLE = 4
131
132
133@enum.unique
134class WpsInfo(enum.IntEnum):
135  """Represents Wi-Fi Protected Setup.
136
137  https://developer.android.com/reference/android/net/wifi/WpsInfo
138  """
139
140  PBC = 0
141  DISPLAY = 1
142  KEYPAD = 2
143  LABEL = 3
144  INVALID = 4
145
146
147@dataclasses.dataclass(frozen=True)
148class WifiP2pConfig:
149  """Represents a Wi-Fi P2p configuration for setting up a connection.
150
151  https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pConfig
152  """
153
154  persistent_mode: Optional[bool] = None
155  device_address: Optional[str] = None
156  group_client_ip_provisioning_mode: Optional[IpProvisioningMode] = None
157  group_operating_band: Optional[Band] = None
158  group_operating_frequency: Optional[int] = None
159  network_name: Optional[str] = None
160  passphrase: Optional[str] = None
161  wps_setup: WpsInfo | None = None
162
163  def to_dict(self) -> dict[str, Union[bool, int, str]]:
164    """Converts this WifiP2pConfig to a dictionary."""
165    return {
166        k: v.value if isinstance(v, enum.Enum) else v
167        for k, v in self.__dict__.items()
168        if v is not None
169    }
170
171
172@dataclasses.dataclass
173class WifiP2pDevice:
174  """Represents a Wi-Fi p2p device.
175
176  https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice
177  """
178
179  device_name: str
180  device_address: str
181  is_group_owner: bool
182  status: int
183  primary_device_type: str
184  secondary_device_type: str
185
186  @classmethod
187  def from_dict(cls, device: dict[str, Any]) -> WifiP2pDevice:
188    """Generates a WifiP2pDevice object from a dictionary."""
189    logging.debug(
190        "Converting following snippet event data to WifiP2pDevice: %s",
191        device,
192    )
193    return WifiP2pDevice(
194        device_name=device["deviceName"],
195        device_address=device["deviceAddress"],
196        is_group_owner=device["isGroupOwner"],
197        status=device["status"],
198        primary_device_type=device["primaryDeviceType"],
199        secondary_device_type=device["secondaryDeviceType"],
200    )
201
202  @classmethod
203  def from_dict_list(
204      cls, devices: list[dict[str, Any]]
205  ) -> Sequence[WifiP2pDevice]:
206    """Generates WifiP2pDevice objects from a list of dictionary."""
207    return (cls.from_dict(device) for device in devices)
208
209
210@dataclasses.dataclass(frozen=True)
211class WifiP2pInfo:
212  """Represents a connection information about a Wi-Fi p2p group.
213
214  https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pInfo
215  """
216
217  group_formed: bool
218  group_owner_address: str
219  is_group_owner: bool
220
221  @classmethod
222  def from_dict(cls, info: dict[str, Any]) -> WifiP2pInfo:
223    """Generates a WifiP2pInfo object from a dictionary."""
224    return WifiP2pInfo(
225        group_formed=info["groupFormed"],
226        group_owner_address=info["groupOwnerAddress"],
227        is_group_owner=info["isGroupOwner"],
228    )
229
230
231@dataclasses.dataclass(frozen=True)
232class WifiP2pGroup:
233  """Represents a Wi-Fi p2p group.
234
235  https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pGroup
236  """
237
238  frequency: int
239  interface: str
240  network_id: int
241  network_name: str
242  owner: WifiP2pDevice
243  passphrase: str
244  is_group_owner: bool
245
246  @classmethod
247  def from_dict(cls, group: dict[str, Any]) -> WifiP2pGroup:
248    """Generates a WifiP2pGroup object from a dictionary."""
249    return WifiP2pGroup(
250        frequency=group['frequency'],
251        interface=group['interface'],
252        network_id=group['networkId'],
253        network_name=group['networkName'],
254        owner=WifiP2pDevice.from_dict(group['owner']),
255        passphrase=group['passphrase'],
256        is_group_owner=group['isGroupOwner'],
257    )
258
259  @classmethod
260  def from_dict_list(
261      cls, groups: list[dict[str, Any]]
262  ) -> Sequence[WifiP2pGroup]:
263    """Generates WifiP2pGroup objects from a list of dictionary."""
264    return (cls.from_dict(group) for group in groups)
265
266