wifidirectplugin 1.2.9 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -8,6 +8,8 @@ import android.net.wifi.WpsInfo;
|
|
|
8
8
|
import android.net.wifi.p2p.*;
|
|
9
9
|
import android.net.NetworkInfo;
|
|
10
10
|
import android.os.Build;
|
|
11
|
+
import android.os.Handler;
|
|
12
|
+
import android.os.Looper;
|
|
11
13
|
import android.util.Log;
|
|
12
14
|
|
|
13
15
|
import com.getcapacitor.*;
|
|
@@ -27,6 +29,15 @@ public class WifiDirectPlugin extends Plugin {
|
|
|
27
29
|
private List<WifiP2pDevice> peerWifiDirDevices = new ArrayList<>();
|
|
28
30
|
private static final String TAG = "WifiDirectPlugin";
|
|
29
31
|
|
|
32
|
+
private PluginCall pendingConnectCall = null;
|
|
33
|
+
|
|
34
|
+
// Group 형성 broadcast가 안 올 경우 대비한 timeout과 메인 핸들러
|
|
35
|
+
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
|
36
|
+
private Runnable pendingConnectTimeout = null;
|
|
37
|
+
private static final long CONNECT_TIMEOUT_MS = 20000L;
|
|
38
|
+
// removeGroup 직후 framework가 안정될 때까지 대기 시간
|
|
39
|
+
private static final long REMOVE_GROUP_SETTLE_MS = 500L;
|
|
40
|
+
|
|
30
41
|
private final BroadcastReceiver wifiP2pReceiver = new BroadcastReceiver() {
|
|
31
42
|
@Override
|
|
32
43
|
public void onReceive(Context context, Intent intent) {
|
|
@@ -36,11 +47,23 @@ public class WifiDirectPlugin extends Plugin {
|
|
|
36
47
|
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
|
|
37
48
|
if (networkInfo != null && networkInfo.isConnected()) {
|
|
38
49
|
Log.d(TAG, "Wi-Fi Direct connected");
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
if (pendingConnectCall != null) {
|
|
51
|
+
cancelConnectTimeout();
|
|
52
|
+
manager.requestConnectionInfo(channel, info -> {
|
|
53
|
+
if (info != null && info.groupFormed) {
|
|
54
|
+
Log.d(TAG, "Group formed, resolving connectToDevice");
|
|
55
|
+
pendingConnectCall.resolve();
|
|
56
|
+
pendingConnectCall = null;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
41
60
|
} else {
|
|
42
61
|
Log.d(TAG, "Wi-Fi Direct disconnected");
|
|
43
|
-
|
|
62
|
+
if (pendingConnectCall != null) {
|
|
63
|
+
cancelConnectTimeout();
|
|
64
|
+
pendingConnectCall.reject("Wi-Fi Direct connection lost before group formed");
|
|
65
|
+
pendingConnectCall = null;
|
|
66
|
+
}
|
|
44
67
|
}
|
|
45
68
|
}
|
|
46
69
|
}
|
|
@@ -143,21 +166,31 @@ public class WifiDirectPlugin extends Plugin {
|
|
|
143
166
|
|
|
144
167
|
manager.requestConnectionInfo(channel, info -> {
|
|
145
168
|
if(info != null && info.groupFormed) {
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// 그룹 해제 성공 시 연결 계속 진행
|
|
153
|
-
initiateConnect(deviceAddress, pin, call);
|
|
154
|
-
}
|
|
155
|
-
@Override
|
|
156
|
-
public void onFailure(int reason) {
|
|
157
|
-
Log.w(TAG, "removeGroup failed: " + reason + ". Proceed anyway.");
|
|
158
|
-
// 그룹 해제 실패 시에도 연결 시도(혹은 call.reject로 실패 처리 가능)
|
|
159
|
-
initiateConnect(deviceAddress, pin, call);
|
|
169
|
+
// 이미 그룹이 형성된 경우, 대상 기기와의 그룹이면 그대로 사용
|
|
170
|
+
manager.requestGroupInfo(channel, group -> {
|
|
171
|
+
if (group != null && isTargetInGroup(group, deviceAddress)) {
|
|
172
|
+
Log.d(TAG, "Already in group with target device, resolving immediately");
|
|
173
|
+
call.resolve();
|
|
174
|
+
return;
|
|
160
175
|
}
|
|
176
|
+
Log.d(TAG, "Existing Wi-Fi Direct group is not the target. Removing group.");
|
|
177
|
+
manager.removeGroup(channel, new WifiP2pManager.ActionListener() {
|
|
178
|
+
@Override
|
|
179
|
+
public void onSuccess() {
|
|
180
|
+
Log.d(TAG, "removeGroup success, settle " + REMOVE_GROUP_SETTLE_MS + "ms before connect.");
|
|
181
|
+
// P2P framework가 BUSY 상태에서 빠져나올 시간 확보
|
|
182
|
+
mainHandler.postDelayed(
|
|
183
|
+
() -> initiateConnect(deviceAddress, pin, call),
|
|
184
|
+
REMOVE_GROUP_SETTLE_MS);
|
|
185
|
+
}
|
|
186
|
+
@Override
|
|
187
|
+
public void onFailure(int reason) {
|
|
188
|
+
Log.w(TAG, "removeGroup failed: " + reasonName(reason) + ". Proceed anyway after settle.");
|
|
189
|
+
mainHandler.postDelayed(
|
|
190
|
+
() -> initiateConnect(deviceAddress, pin, call),
|
|
191
|
+
REMOVE_GROUP_SETTLE_MS);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
161
194
|
});
|
|
162
195
|
} else {
|
|
163
196
|
Log.d(TAG, "No existing group, proceed to connect directly.");
|
|
@@ -165,6 +198,23 @@ public class WifiDirectPlugin extends Plugin {
|
|
|
165
198
|
}
|
|
166
199
|
});
|
|
167
200
|
}
|
|
201
|
+
|
|
202
|
+
private boolean isTargetInGroup(WifiP2pGroup group, String deviceAddress) {
|
|
203
|
+
if (deviceAddress == null) return false;
|
|
204
|
+
WifiP2pDevice owner = group.getOwner();
|
|
205
|
+
if (owner != null && deviceAddress.equalsIgnoreCase(owner.deviceAddress)) {
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
if (group.getClientList() != null) {
|
|
209
|
+
for (WifiP2pDevice client : group.getClientList()) {
|
|
210
|
+
if (deviceAddress.equalsIgnoreCase(client.deviceAddress)) {
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
|
|
168
218
|
private void initiateConnect(String deviceAddress, String pin, PluginCall call) {
|
|
169
219
|
WifiP2pConfig config = new WifiP2pConfig();
|
|
170
220
|
config.deviceAddress = deviceAddress;
|
|
@@ -178,26 +228,86 @@ public class WifiDirectPlugin extends Plugin {
|
|
|
178
228
|
Log.w(TAG, "Invalid Pin");
|
|
179
229
|
}
|
|
180
230
|
}
|
|
231
|
+
|
|
232
|
+
// 직전 시도에서 남았을 수 있는 pending negotiation을 명시적으로 정리.
|
|
233
|
+
// 실패해도 (보통 NO_SERVICE_REQUESTS 등) 그냥 무시하고 connect 진행.
|
|
234
|
+
try {
|
|
235
|
+
manager.cancelConnect(channel, new WifiP2pManager.ActionListener() {
|
|
236
|
+
@Override
|
|
237
|
+
public void onSuccess() {
|
|
238
|
+
Log.d(TAG, "cancelConnect success, performing connect");
|
|
239
|
+
performConnect(config, call);
|
|
240
|
+
}
|
|
241
|
+
@Override
|
|
242
|
+
public void onFailure(int reason) {
|
|
243
|
+
Log.d(TAG, "cancelConnect failed (ignored): " + reasonName(reason));
|
|
244
|
+
performConnect(config, call);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
} catch (Exception e) {
|
|
248
|
+
Log.w(TAG, "cancelConnect exception (ignored)", e);
|
|
249
|
+
performConnect(config, call);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private void performConnect(WifiP2pConfig config, PluginCall call) {
|
|
181
254
|
try {
|
|
182
255
|
manager.connect(channel, config, new WifiP2pManager.ActionListener() {
|
|
183
256
|
@Override
|
|
184
257
|
public void onSuccess() {
|
|
185
|
-
|
|
186
|
-
|
|
258
|
+
// connect request accepted — group formation is async
|
|
259
|
+
// resolve will be called from BroadcastReceiver once group is formed
|
|
260
|
+
Log.d(TAG, "connect onSuccess Called, waiting for group formation (timeout " + CONNECT_TIMEOUT_MS + "ms)");
|
|
261
|
+
pendingConnectCall = call;
|
|
262
|
+
scheduleConnectTimeout();
|
|
187
263
|
}
|
|
188
264
|
|
|
189
265
|
@Override
|
|
190
266
|
public void onFailure(int reason) {
|
|
191
|
-
Log.e(TAG, "connect onFailure
|
|
192
|
-
|
|
267
|
+
Log.e(TAG, "connect onFailure: " + reasonName(reason));
|
|
268
|
+
pendingConnectCall = null;
|
|
269
|
+
cancelConnectTimeout();
|
|
270
|
+
call.reject("Connection failed: " + reasonName(reason));
|
|
193
271
|
}
|
|
194
272
|
});
|
|
195
273
|
} catch (Exception e) {
|
|
196
274
|
Log.e(TAG, "connect exception", e);
|
|
275
|
+
pendingConnectCall = null;
|
|
276
|
+
cancelConnectTimeout();
|
|
197
277
|
call.reject("Connection exception: " + e.getMessage());
|
|
198
278
|
}
|
|
199
279
|
}
|
|
200
280
|
|
|
281
|
+
private void scheduleConnectTimeout() {
|
|
282
|
+
cancelConnectTimeout();
|
|
283
|
+
pendingConnectTimeout = () -> {
|
|
284
|
+
if (pendingConnectCall != null) {
|
|
285
|
+
Log.w(TAG, "Group formation timed out after " + CONNECT_TIMEOUT_MS + "ms");
|
|
286
|
+
pendingConnectCall.reject("Group formation timed out");
|
|
287
|
+
pendingConnectCall = null;
|
|
288
|
+
}
|
|
289
|
+
pendingConnectTimeout = null;
|
|
290
|
+
};
|
|
291
|
+
mainHandler.postDelayed(pendingConnectTimeout, CONNECT_TIMEOUT_MS);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private void cancelConnectTimeout() {
|
|
295
|
+
if (pendingConnectTimeout != null) {
|
|
296
|
+
mainHandler.removeCallbacks(pendingConnectTimeout);
|
|
297
|
+
pendingConnectTimeout = null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private String reasonName(int reason) {
|
|
302
|
+
switch (reason) {
|
|
303
|
+
case WifiP2pManager.ERROR: return "ERROR(0)";
|
|
304
|
+
case WifiP2pManager.P2P_UNSUPPORTED: return "P2P_UNSUPPORTED(1)";
|
|
305
|
+
case WifiP2pManager.BUSY: return "BUSY(2)";
|
|
306
|
+
case WifiP2pManager.NO_SERVICE_REQUESTS: return "NO_SERVICE_REQUESTS(3)";
|
|
307
|
+
default: return String.valueOf(reason);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
201
311
|
@PluginMethod
|
|
202
312
|
public void getGroupOwnerAddress(PluginCall call) {
|
|
203
313
|
manager.requestConnectionInfo(channel, wifiP2pInfo -> {
|