Browse Source

Merge pull request #2256 from jitsi/wifistats

[Android] WiFi stats for mobile
master
Saúl Ibarra Corretgé 8 years ago
parent
commit
9a3f98a4a0
No account linked to committer's email address

+ 1
- 0
android/sdk/src/main/AndroidManifest.xml View File

@@ -10,6 +10,7 @@
10 10
   <uses-permission android:name="android.permission.RECORD_AUDIO" />
11 11
   <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
12 12
   <uses-permission android:name="android.permission.WAKE_LOCK" />
13
+  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
13 14
 
14 15
   <uses-feature android:glEsVersion="0x00020000" android:required="true" />
15 16
   <uses-feature

+ 2
- 1
android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java View File

@@ -64,7 +64,8 @@ public class JitsiMeetView extends FrameLayout {
64 64
             new AppInfoModule(reactContext),
65 65
             new AudioModeModule(reactContext),
66 66
             new ExternalAPIModule(reactContext),
67
-            new ProximityModule(reactContext)
67
+            new ProximityModule(reactContext),
68
+            new WiFiStatsModule(reactContext)
68 69
         );
69 70
     }
70 71
 

+ 208
- 0
android/sdk/src/main/java/org/jitsi/meet/sdk/WiFiStatsModule.java View File

@@ -0,0 +1,208 @@
1
+/*
2
+ * Copyright @ 2017-present Atlassian Pty Ltd
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package org.jitsi.meet.sdk;
18
+
19
+import android.content.Context;
20
+import android.net.wifi.WifiInfo;
21
+import android.net.wifi.WifiManager;
22
+import android.os.Handler;
23
+import android.os.Looper;
24
+import android.util.Log;
25
+
26
+import com.facebook.react.bridge.Promise;
27
+import com.facebook.react.bridge.ReactApplicationContext;
28
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
29
+import com.facebook.react.bridge.ReactMethod;
30
+
31
+import org.json.JSONArray;
32
+import org.json.JSONObject;
33
+
34
+import java.net.InetAddress;
35
+import java.net.NetworkInterface;
36
+import java.net.SocketException;
37
+import java.net.UnknownHostException;
38
+import java.util.Enumeration;
39
+
40
+/**
41
+ * Module exposing WiFi statistics.
42
+ *
43
+ * Gathers rssi, signal in percentage, timestamp and the addresses
44
+ * of the wifi device.
45
+ */
46
+class WiFiStatsModule extends ReactContextBaseJavaModule {
47
+    /**
48
+     * The name of {@code WiFiStatsModule} to be used in the React Native
49
+     * bridge.
50
+     */
51
+    private static final String MODULE_NAME = "WiFiStats";
52
+
53
+    /**
54
+     * The {@code Log} tag {@code WiFiStatsModule} is to log messages with.
55
+     */
56
+    static final String TAG = MODULE_NAME;
57
+
58
+    /**
59
+     * The scale used for the signal value.
60
+     * A level of the signal, given in the range
61
+     * of 0 to SIGNAL_LEVEL_SCALE-1 (both inclusive).
62
+     */
63
+    public final static int SIGNAL_LEVEL_SCALE = 101;
64
+
65
+    /**
66
+     * {@link Handler} for running all operations on the main thread.
67
+     */
68
+    private final Handler mainThreadHandler
69
+            = new Handler(Looper.getMainLooper());
70
+
71
+    /**
72
+     * Initializes a new module instance. There shall be a single instance of
73
+     * this module throughout the lifetime of the application.
74
+     *
75
+     * @param reactContext the {@link ReactApplicationContext} where this module
76
+     * is created.
77
+     */
78
+    public WiFiStatsModule(ReactApplicationContext reactContext) {
79
+        super(reactContext);
80
+    }
81
+
82
+    /**
83
+     * Gets the name for this module to be used in the React Native bridge.
84
+     *
85
+     * @return a string with the module name.
86
+     */
87
+    @Override
88
+    public String getName() {
89
+        return MODULE_NAME;
90
+    }
91
+
92
+    /**
93
+     * Returns the {@link InetAddress} represented by this int.
94
+     *
95
+     * @param value the int representation of the ip address.
96
+     * @return the {@link InetAddress}.
97
+     * @throws UnknownHostException - if IP address is of illegal length.
98
+     */
99
+    public static InetAddress toInetAddress(int value)
100
+            throws UnknownHostException {
101
+        return InetAddress.getByAddress(
102
+            new byte[] {
103
+                    (byte) value,
104
+                    (byte) (value >> 8),
105
+                    (byte) (value >> 16),
106
+                    (byte) (value >> 24)
107
+            });
108
+    }
109
+
110
+    /**
111
+     * Public method to retrieve WiFi stats.
112
+     *
113
+     * @param promise a {@link Promise} which will be resolved if WiFi stats are
114
+     * retrieved successfully, and it will be rejected otherwise.
115
+     */
116
+    @ReactMethod
117
+    public void getWiFiStats(final Promise promise) {
118
+        Runnable r = new Runnable() {
119
+            @Override
120
+            public void run() {
121
+                try {
122
+
123
+                    Context context
124
+                        = getReactApplicationContext().getApplicationContext();
125
+                    WifiManager wifiManager
126
+                        = (WifiManager) context
127
+                            .getSystemService(Context.WIFI_SERVICE);
128
+
129
+                    if (!wifiManager.isWifiEnabled()) {
130
+                        promise.reject(new Exception("Wifi not enabled"));
131
+                        return;
132
+                    }
133
+
134
+                    WifiInfo wifiInfo = wifiManager.getConnectionInfo();
135
+
136
+                    if (wifiInfo.getNetworkId() == -1) {
137
+                        promise.reject(new Exception("Wifi not connected"));
138
+                        return;
139
+                    }
140
+
141
+                    int rssi = wifiInfo.getRssi();
142
+                    int signalLevel
143
+                        = WifiManager.calculateSignalLevel(
144
+                            rssi, SIGNAL_LEVEL_SCALE);
145
+
146
+                    JSONObject result = new JSONObject();
147
+                    result.put("rssi", rssi)
148
+                        .put("signal", signalLevel)
149
+                        .put("timestamp",
150
+                                String.valueOf(System.currentTimeMillis()));
151
+
152
+                    JSONArray addresses = new JSONArray();
153
+
154
+                    InetAddress wifiAddress
155
+                        = toInetAddress(wifiInfo.getIpAddress());
156
+
157
+                    try {
158
+                        Enumeration<NetworkInterface> e
159
+                            =  NetworkInterface.getNetworkInterfaces();
160
+                        while (e.hasMoreElements()) {
161
+                            NetworkInterface networkInterface = e.nextElement();
162
+                            boolean found = false;
163
+
164
+                            // first check whether this is the desired interface
165
+                            Enumeration<InetAddress> as
166
+                                = networkInterface.getInetAddresses();
167
+                            while (as.hasMoreElements()) {
168
+                                InetAddress a = as.nextElement();
169
+                                if(a.equals(wifiAddress)) {
170
+                                    found = true;
171
+                                    break;
172
+                                }
173
+                            }
174
+
175
+                            if (found) {
176
+                                // interface found let's put addresses
177
+                                // to the result object
178
+                                as = networkInterface.getInetAddresses();
179
+                                while (as.hasMoreElements()) {
180
+                                    InetAddress a = as.nextElement();
181
+                                    if (a.isLinkLocalAddress())
182
+                                        continue;
183
+
184
+                                    addresses.put(a.getHostAddress());
185
+                                }
186
+                            }
187
+
188
+                        }
189
+                    } catch (SocketException e) {
190
+                        Log.wtf(TAG,
191
+                            "Unable to NetworkInterface.getNetworkInterfaces()"
192
+                        );
193
+                    }
194
+
195
+                    result.put("addresses", addresses);
196
+                    promise.resolve(result.toString());
197
+
198
+                    Log.d(TAG, "WiFi stats: " + result.toString());
199
+                } catch (Throwable e) {
200
+                    Log.e(TAG, "Failed to obtain wifi stats", e);
201
+                    promise.reject(
202
+                        new Exception("Failed to obtain wifi stats"));
203
+                }
204
+            }
205
+        };
206
+        mainThreadHandler.post(r);
207
+    }
208
+}

+ 5
- 1
conference.js View File

@@ -89,7 +89,10 @@ import {
89 89
     trackAdded,
90 90
     trackRemoved
91 91
 } from './react/features/base/tracks';
92
-import { getLocationContextRoot } from './react/features/base/util';
92
+import {
93
+    getLocationContextRoot,
94
+    getJitsiMeetGlobalNS
95
+} from './react/features/base/util';
93 96
 import { statsEmitter } from './react/features/connection-indicator';
94 97
 import { showDesktopPicker } from './react/features/desktop-picker';
95 98
 import { appendSuffix } from './react/features/display-name';
@@ -1318,6 +1321,7 @@ export default {
1318 1321
         }
1319 1322
 
1320 1323
         options.applicationName = interfaceConfig.APP_NAME;
1324
+        options.getWiFiStatsMethod = getJitsiMeetGlobalNS().getWiFiStats;
1321 1325
 
1322 1326
         return options;
1323 1327
     },

+ 3
- 1
react/features/base/conference/actions.js View File

@@ -19,6 +19,7 @@ import {
19 19
     participantUpdated
20 20
 } from '../participants';
21 21
 import { getLocalTracks, trackAdded, trackRemoved } from '../tracks';
22
+import { getJitsiMeetGlobalNS } from '../util';
22 23
 
23 24
 import {
24 25
     CONFERENCE_FAILED,
@@ -309,7 +310,8 @@ export function createConference() {
309 310
                 // XXX Lib-jitsi-meet does not accept uppercase letters.
310 311
                 room.toLowerCase(), {
311 312
                     ...state['features/base/config'],
312
-                    applicationName: getName()
313
+                    applicationName: getName(),
314
+                    getWiFiStatsMethod: getJitsiMeetGlobalNS().getWiFiStats
313 315
                 });
314 316
 
315 317
         conference[JITSI_CONFERENCE_URL_KEY] = locationURL;

+ 9
- 0
react/features/base/lib-jitsi-meet/native/WiFiStats.js View File

@@ -0,0 +1,9 @@
1
+import { NativeModules } from 'react-native';
2
+import { getJitsiMeetGlobalNS } from '../../util';
3
+
4
+/**
5
+ * If WiFiStats native module exist attach it to JitsiMeetGlobalNS.
6
+ */
7
+if (NativeModules.WiFiStats) {
8
+    getJitsiMeetGlobalNS().getWiFiStats = NativeModules.WiFiStats.getWiFiStats;
9
+}

+ 1
- 0
react/features/base/lib-jitsi-meet/native/index.js View File

@@ -1,2 +1,3 @@
1 1
 import './polyfills-browser';
2 2
 import './polyfills-browserify';
3
+import './WiFiStats';

Loading…
Cancel
Save