".equals(ssid);
+ }
+
+ /**
+ * 关闭所有连接
+ */
+ public static void closeAllConnect(WifiManager manager) {
+ if (null == manager) {
+ return;
+ }
+
+ // FIXME: 2019/4/16 防止自动连接,小米等手机会弹出权限框
+ for (WifiConfiguration c : manager.getConfiguredNetworks()) {
+ manager.disableNetwork(c.networkId);
+ }
+
+ // 断开后会自动连接WiFi
+// manager.disconnect();
+ }
+
+ /**
+ * 连接WiFi
+ */
+ public static WiFiCreateConfigStatusInfo connectWiFi(WifiManager manager, String SSID, WiFiCipherType type, String pwd, Context context) {
+ WiFiCreateConfigStatusInfo info = new WiFiCreateConfigStatusInfo();
+ info.SSID = SSID;
+ info.isSuccess = false;
+
+ //先关闭当前所有已连接的网络
+ closeAllConnect(manager);
+
+ WifiConfiguration config = getExistConfig(manager, SSID);
+
+ if (null == config) {
+ //不存在旧的配置,添加WiFi
+ return addWifi(manager, SSID, type, pwd);
+ }
+
+ //存在旧的配置,先尝试移除WiFi
+ if (removeWiFi(manager, SSID, context).isSuccess) {
+ //移除成功,重新添加WiFi
+ return addWifi(manager, SSID, type, pwd);
+ }
+
+ return info;
+ }
+
+ /**
+ * 根据networkId连接WiFi
+ */
+ public static boolean enableNetwork(WifiManager manager, int networkId) {
+ return null != manager && manager.enableNetwork(networkId, true);
+ }
+
+ /**
+ * 移除WiFi
+ * Android6.0 之后应用只能删除自己创建的WIFI网络
+ */
+ public static WiFiRemoveStatusInfo removeWiFi(WifiManager manager, String SSID, Context context) {
+ WiFiRemoveStatusInfo info = new WiFiRemoveStatusInfo();
+ info.SSID = SSID;
+
+ if (null == manager) {
+ return info;
+ }
+
+ WifiConfiguration config = getExistConfig(manager, SSID);
+
+ if (null == config) {
+ //如果不存在配置,默认是删除成功
+ info.isSuccess = true;
+ return info;
+ }
+
+ if (config.networkId == -1) {
+ info.isSuccess = false;
+ WiFiLogUtils.d("networkId 非法!");
+ return info;
+ }
+
+ boolean isSystemApp = isSystemApplication(context);
+ if (isSystemApp) {
+ WiFiLogUtils.d("是系统App,可以直接删除!");
+ info.isSuccess = manager.disableNetwork(config.networkId)
+ && manager.removeNetwork(config.networkId)
+ && manager.saveConfiguration();
+
+ return info;
+ }
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ //6.0之前
+ info.isSuccess = manager.disableNetwork(config.networkId)
+ && manager.removeNetwork(config.networkId)
+ && manager.saveConfiguration();
+
+ return info;
+ }
+
+ try {
+ //获取当前WiFi的创建者
+ Field field = config.getClass().getDeclaredField("creatorName");
+ field.setAccessible(true);
+ Object creatorName = field.get(config);
+
+ WiFiLogUtils.d("field:" + field + "||creatorName:" + creatorName);
+
+ if (context.getPackageName().equals(creatorName)) {
+ WiFiLogUtils.d("是当前app创建的WiFi,可以直接删除!");
+ info.isSuccess = manager.disableNetwork(config.networkId)
+ && manager.removeNetwork(config.networkId)
+ && manager.saveConfiguration();
+ }
+
+ } catch (Exception e) {
+ WiFiLogUtils.e(e);
+ }
+
+ return info;
+ }
+
+ /**
+ * 添加WiFi到系统
+ */
+ private static WiFiCreateConfigStatusInfo addWifi(WifiManager manager, String SSID, WiFiCipherType type, String pwd) {
+ WiFiCreateConfigStatusInfo configInfo = new WiFiCreateConfigStatusInfo();
+ configInfo.SSID = SSID;
+
+ try {
+ WifiConfiguration configuration = createConfiguration(SSID, type, pwd);
+ configuration.networkId = manager.addNetwork(configuration);
+
+ configInfo.configuration = configuration;
+ configInfo.isSuccess = (configuration.networkId != -1);
+
+ } catch (Exception e) {
+ WiFiLogUtils.e(e);
+ }
+
+ return configInfo;
+ }
+
+ /**
+ * 创建配置
+ */
+ private static WifiConfiguration createConfiguration(String SSID, WiFiCipherType type, String password) {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.allowedAuthAlgorithms.clear();
+ config.allowedGroupCiphers.clear();
+ config.allowedKeyManagement.clear();
+ config.allowedPairwiseCiphers.clear();
+ config.allowedProtocols.clear();
+
+ config.SSID = "\"" + SSID + "\"";
+
+ switch (type) {
+ case WIFI_CIPHER_NO_PASS:
+ // config.wepKeys[0] = "";
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ // config.wepTxKeyIndex = 0;
+ break;
+
+ case WIFI_CIPHER_WEP:
+ if (!TextUtils.isEmpty(password)) {
+ if (isHexWepKey(password)) {
+ config.wepKeys[0] = password;
+
+ } else {
+ config.wepKeys[0] = "\"" + password + "\"";
+ }
+ }
+
+ config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+ config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ config.wepTxKeyIndex = 0;
+ break;
+
+ case WIFI_CIPHER_WPA:
+ config.preSharedKey = "\"" + password + "\"";
+ config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+ config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
+ config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
+ config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+ config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
+ config.status = WifiConfiguration.Status.ENABLED;
+
+ default:
+ break;
+ }
+
+ return config;
+ }
+
+ /**
+ * 获取是否已经存在的配置
+ */
+ private static WifiConfiguration getExistConfig(WifiManager manager, String SSID) {
+ if (null == manager) {
+ return null;
+ }
+
+ try {
+ List existingConfigs = manager.getConfiguredNetworks();
+
+ for (WifiConfiguration existingConfig : existingConfigs) {
+ if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
+ return existingConfig;
+ }
+ }
+
+ } catch (Exception e) {
+ WiFiLogUtils.e(e);
+ }
+
+ return null;
+ }
+
+ /**
+ * 去除同名WIFI
+ */
+ private static List noSameName(List oldSr) {
+ List newSr = new ArrayList<>();
+ for (ScanResult result : oldSr) {
+ if (!TextUtils.isEmpty(result.SSID) && !containName(newSr, result.SSID)) {
+ newSr.add(result);
+ }
+ }
+ return newSr;
+ }
+
+ /**
+ * 判断一个扫描结果中,是否包含了某个名称的WIFI
+ */
+ private static boolean containName(List sr, String name) {
+ for (ScanResult result : sr) {
+ if (!TextUtils.isEmpty(result.SSID) && result.SSID.equals(name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isHexWepKey(String wepKey) {
+ final int len = wepKey.length();
+
+ // WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?)
+ return (len == 10 || len == 26 || len == 58) && isHex(wepKey);
+ }
+
+ private static boolean isHex(String key) {
+ for (int i = key.length() - 1; i >= 0; i--) {
+ final char c = key.charAt(i);
+ if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a'
+ && c <= 'f')) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean isSystemApplication(Context context) {
+ try {
+ PackageManager packageManager = context.getPackageManager();
+
+ ApplicationInfo app = packageManager.getApplicationInfo(context.getPackageName(), 0);
+ return (app != null && (app.flags & ApplicationInfo.FLAG_SYSTEM) > 0);
+
+ } catch (Exception e) {
+ WiFiLogUtils.e(e);
+ }
+
+ return false;
+ }
+
+}
diff --git a/app/src/main/res/drawable-xhdpi/ic_password.png b/app/src/main/res/drawable-xhdpi/ic_password.png
new file mode 100644
index 0000000..2635644
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_password.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_progress.png b/app/src/main/res/drawable-xhdpi/ic_progress.png
new file mode 100644
index 0000000..0d86a4a
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_progress.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_select_s.png b/app/src/main/res/drawable-xhdpi/ic_select_s.png
new file mode 100644
index 0000000..e90dca2
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_select_s.png differ
diff --git a/app/src/main/res/drawable/bg_cursor.xml b/app/src/main/res/drawable/bg_cursor.xml
new file mode 100644
index 0000000..a54867b
--- /dev/null
+++ b/app/src/main/res/drawable/bg_cursor.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_input.xml b/app/src/main/res/drawable/bg_input.xml
new file mode 100644
index 0000000..4014c3d
--- /dev/null
+++ b/app/src/main/res/drawable/bg_input.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/loading_img.xml b/app/src/main/res/drawable/loading_img.xml
new file mode 100644
index 0000000..9ac705b
--- /dev/null
+++ b/app/src/main/res/drawable/loading_img.xml
@@ -0,0 +1,11 @@
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_monitor.xml b/app/src/main/res/layout/activity_monitor.xml
new file mode 100644
index 0000000..2cee94a
--- /dev/null
+++ b/app/src/main/res/layout/activity_monitor.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_input_wifi_password.xml b/app/src/main/res/layout/dialog_input_wifi_password.xml
new file mode 100644
index 0000000..7a66eae
--- /dev/null
+++ b/app/src/main/res/layout/dialog_input_wifi_password.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_network_config.xml b/app/src/main/res/layout/item_network_config.xml
new file mode 100644
index 0000000..9000319
--- /dev/null
+++ b/app/src/main/res/layout/item_network_config.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_confirm_dialog.xml b/app/src/main/res/layout/layout_confirm_dialog.xml
index 8417331..2d266a1 100644
--- a/app/src/main/res/layout/layout_confirm_dialog.xml
+++ b/app/src/main/res/layout/layout_confirm_dialog.xml
@@ -11,6 +11,7 @@
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_marginTop="@dimen/_36dp"
+ android:paddingHorizontal="@dimen/_12dp"
android:layout_weight="1"
android:gravity="center"
android:text="@string/sync_data_tip"
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 78eee84..63095ab 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -23,4 +23,7 @@
#01E41C
#999999
#E40101
+
+ #191F25
+ #BFBFBF