├── app ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── drawable-hdpi │ │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ │ └── ic_launcher.png │ │ ├── drawable-xhdpi │ │ │ └── ic_launcher.png │ │ ├── drawable-xxhdpi │ │ │ └── ic_launcher.png │ │ ├── values │ │ │ ├── dimens.xml │ │ │ ├── styles.xml │ │ │ └── strings.xml │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ ├── layout │ │ │ ├── activity_no_root.xml │ │ │ ├── activity_main.xml │ │ │ └── wifi_item.xml │ │ ├── menu │ │ │ └── main.xml │ │ ├── values-zh-rHK │ │ │ └── strings.xml │ │ ├── values-zh-rTW │ │ │ └── strings.xml │ │ ├── values-zh-rCN │ │ │ └── strings.xml │ │ ├── values-ja-rJP │ │ │ └── strings.xml │ │ ├── values-en │ │ │ └── strings.xml │ │ └── values-ru │ │ │ └── strings.xml │ │ ├── java │ │ └── net │ │ │ └── loveyu │ │ │ └── wifipwd │ │ │ ├── ViewHolder.java │ │ │ ├── ListMsgData.java │ │ │ ├── readRunnable.java │ │ │ ├── PasswordSortComparator.java │ │ │ ├── WifiReceiver.java │ │ │ ├── MsgHandle.java │ │ │ ├── DeviceUuidFactory.java │ │ │ ├── WifiAdapter.java │ │ │ ├── Action.java │ │ │ ├── Report.java │ │ │ ├── MainActivity.java │ │ │ └── ReadWpaCfg.java │ │ └── AndroidManifest.xml ├── build.gradle ├── proguard-rules.pro └── app.iml ├── settings.gradle ├── .gitignore ├── Readme.md ├── WifiPwd.iml ├── gradle.properties ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveyu/WifiPwd/master/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveyu/WifiPwd/master/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveyu/WifiPwd/master/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveyu/WifiPwd/master/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/ViewHolder.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import android.widget.TextView; 4 | 5 | /** 6 | * class ViewHolder 显示对象的实例 7 | * Created by loveyu on 2014/9/22. 8 | */ 9 | class ViewHolder { 10 | TextView ssid; 11 | TextView pwd; 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Thumbnails 6 | ._* 7 | 8 | # Files that might appear on external disk 9 | .Spotlight-V100 10 | .Trashes 11 | 12 | # 移除部分系统目录 13 | .git/ 14 | .idea/ 15 | .gradle/ 16 | build/ 17 | gradle/ 18 | app/build/ 19 | local.properties -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ## Wifi密码查看器 2 | 3 | 软件需要Root权限,使用简单方便 4 | 5 | 详细介绍: [https://www.loveyu.net/WifiPwd](https://www.loveyu.net/WifiPwd?utm_source=github&utm_medium=code_share) 6 | 7 | 讨论交流: [https://www.loveyu.org/3356.html](https://www.loveyu.org/3356.html?utm_source=github&utm_medium=code_share) 8 | 9 | Google Play 下载: https://play.google.com/store/apps/details?id=net.loveyu.wifipwd -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "net.loveyu.wifipwd" 7 | minSdkVersion 14 8 | targetSdkVersion 28 9 | versionCode 13 10 | versionName '1.6.6' 11 | } 12 | productFlavors { 13 | } 14 | buildToolsVersion = '28.0.3' 15 | compileOptions { 16 | sourceCompatibility = '1.8' 17 | targetCompatibility = '1.8' 18 | } 19 | } 20 | 21 | dependencies { 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/ListMsgData.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Map; 5 | 6 | public class ListMsgData { 7 | public boolean is_refresh; 8 | public boolean show_notify; 9 | public ArrayList> list; 10 | ListMsgData(boolean is_refresh, ArrayList> list, boolean show_notify) { 11 | this.is_refresh = is_refresh; 12 | this.show_notify = show_notify; 13 | this.list = list; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_no_root.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 16 | 17 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Program Files (x86)\Android\android-studio\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 13 | 14 | 18 | 19 | 22 | 23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 4 | 8 | 12 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /WifiPwd.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/readRunnable.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import android.os.Message; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Map; 7 | 8 | public class readRunnable implements Runnable { 9 | private MsgHandle handle; 10 | private boolean is_refresh; 11 | private boolean show_notify; 12 | 13 | readRunnable(MsgHandle handle, boolean is_refresh, boolean show_notify) { 14 | this.handle = handle; 15 | this.is_refresh = is_refresh; 16 | this.show_notify = show_notify; 17 | } 18 | 19 | @Override 20 | public void run() { 21 | Message msg = handle.obtainMessage(MsgHandle.WpListUpdate); 22 | //if need notify, force refresh 23 | ArrayList> list = handle.ac.get_list(show_notify); 24 | msg.obj = new ListMsgData(is_refresh, list, show_notify); 25 | handle.sendMessage(msg); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/PasswordSortComparator.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import java.util.Comparator; 4 | import java.util.Map; 5 | 6 | /** 7 | * 排序类 8 | */ 9 | public class PasswordSortComparator implements Comparator> { 10 | 11 | private String currentSSID; 12 | 13 | PasswordSortComparator(String currentSSID) { 14 | this.currentSSID = currentSSID; 15 | } 16 | 17 | @Override 18 | public int compare(Map t1, Map t2) { 19 | String ssid_1 = t1.get("ssid"); 20 | String ssid_2 = t2.get("ssid"); 21 | 22 | if (ssid_1.equals(ssid_2)) { 23 | return 0; 24 | } 25 | 26 | if (ssid_1.equals(currentSSID)) { 27 | return -1; 28 | } 29 | if (ssid_2.equals(currentSSID)) { 30 | return 1; 31 | } 32 | return ssid_1.compareToIgnoreCase(ssid_2); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Sun Apr 09 17:14:41 CST 2017 16 | systemProp.https.proxyPort=2081 17 | systemProp.http.proxyHost=127.0.0.1 18 | systemProp.http.nonProxyHosts=dl.google.com,127.*, 192.168.* 19 | systemProp.https.proxyHost=127.0.0.1 20 | systemProp.http.proxyPort=2081 21 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/WifiReceiver.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.ConnectivityManager; 7 | import android.net.wifi.WifiManager; 8 | 9 | public class WifiReceiver extends BroadcastReceiver { 10 | MainActivity activity; 11 | 12 | public WifiReceiver(MainActivity activity) { 13 | this.activity = activity; 14 | } 15 | 16 | @Override 17 | public void onReceive(Context context, Intent intent) { 18 | String action = intent.getAction(); 19 | if (action == null) { 20 | return; 21 | } 22 | if ( 23 | action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) || 24 | action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) || 25 | action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 26 | //wifi state change 27 | activity.refresh_list(false); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rHK/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |     Wifi密碼查看器 4 |     退出 5 |     幫助與反饋 6 |     無法獲取ROOT權限 7 |     無法讀取WIFI密碼文件 8 |     提示:Wifi密碼獲取中 9 |     讀取列表失敗,請重新ROOT授權後重試 10 |     帶密碼的WIFI列表為空 11 |     獲取Wifi密碼數量為: 12 |     熱點: 13 |     密碼: 14 |     複製熱點 15 |     複製密碼 16 |     複製熱點密碼 17 |     已復制 18 |     開放源碼 19 |     刷新列表 20 |     刷新成功 21 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rTW/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |     Wifi密碼查看器 4 |     退出 5 |     幫助與反饋 6 |     無法獲取ROOT權限 7 |     無法讀取WIFI密碼文件 8 |     提示:Wifi密碼獲取中 9 |     讀取列表失敗,請重新ROOT授權後重試 10 |     帶密碼的WIFI列表為空 11 |     獲取Wifi密碼數量為: 12 |     熱點: 13 |     密碼: 14 |     複製熱點 15 |     複製密碼 16 |     複製熱點密碼 17 |     已復制 18 |     開放源碼 19 |     刷新列表 20 |     刷新成功 21 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Wifi密码查看器 4 | 退出 5 | 帮助与反馈 6 | 无法获取ROOT权限 7 | 无法读取WIFI密码文件 8 | 提示:Wifi密码获取中 9 | 读取列表失败,请重新ROOT授权后重试 10 | 带密码的WIFI列表为空 11 | 获取Wifi密码数量为: 12 | 热点: 13 | 密码: 14 | 复制热点 15 | 复制密码 16 | 复制热点密码 17 | 已复制 18 | 开放源码 19 | 刷新列表 20 | 刷新成功 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rCN/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Wifi密码查看器 4 | 退出 5 | 帮助与反馈 6 | 无法获取ROOT权限 7 | 无法读取WIFI密码文件 8 | 提示:Wifi密码获取中 9 | 读取列表失败,请重新ROOT授权后重试 10 | 带密码的WIFI列表为空 11 | 获取Wifi密码数量为: 12 | 热点: 13 | 密码: 14 | 复制热点 15 | 复制密码 16 | 复制热点密码 17 | 已复制 18 | 开放源码 19 | 刷新列表 20 | 刷新成功 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values-ja-rJP/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Wi-Fiパスワードビューア 4 | 終了 5 | ヘルプとフィードバック 6 | ROOT権限を取得できません 7 | WIFIパスワードファイルを読み取ることができません 8 | ヒント:Wi-Fiパスワードを取得中 9 | リストの読み込みに失敗しました.ROOT権限を再試行してください。 10 | パスワードが空白のWIFIリスト 11 | WiFiパスワードの統計情報: 12 | 熱點: 13 | 密碼: 14 | コピーホットスポット 15 | コピーパスワード 16 | コピーホットスポットパスワード 17 | コピー 18 | オープンソース 19 | リフレッシュリスト 20 | 更新の成功 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 20 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/values-en/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Wifi Password Viewer 4 | Exit 5 | Help and Feedback 6 | Unable to get root privileges. 7 | Unable to read WIFI password file 8 | Tips: Wifi password is being retrieved 9 | Failed to read the list, please re-try ROOT authorized 10 | WIFI list with password is empty 11 | Wifi password number: 12 | Hotspot: 13 | Password: 14 | copy hotspot 15 | copy password 16 | copy hotspot and password 17 | copied 18 | Open Source 19 | Refresh list 20 | Refresh successful 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values-ru/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Выход 4 | Помощь 5 | Скопировано 6 | Wifi Password Viewer 7 | Не удается прочитать файл пароля WIFI 8 | Не удалось получить права root 9 | Копировать пароль 10 | Копировать имя сети 11 | Копировать имя сети и пароль 12 | Подсказка: Wifi пароль извлекается 13 | Исходный код 14 | Пароль: 15 | Не удалось прочитать список, повторите попытку предоставления ROOT доступа для программы 16 | Обновить список 17 | Обновление завершено успешно 18 | Список WIFI с паролем пуст 19 | Количество паролей Wifi: 20 | Имя сети: 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/MsgHandle.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | public class MsgHandle extends Handler { 7 | 8 | private MainActivity mainActivity; 9 | public Action ac; 10 | 11 | public final static int WpListUpdate = 1; 12 | 13 | private boolean read_list_is_finish = true; 14 | 15 | MsgHandle(MainActivity mainActivity, Action ac) { 16 | super(); 17 | this.mainActivity = mainActivity; 18 | this.ac = ac; 19 | } 20 | 21 | @Override 22 | public void handleMessage(Message msg) { 23 | super.handleMessage(msg); 24 | switch (msg.what) { 25 | case WpListUpdate: 26 | ListMsgData data = (ListMsgData) msg.obj; 27 | if (data.is_refresh) { 28 | mainActivity.refreshLvList(data.list, data.show_notify); 29 | } else { 30 | mainActivity.setList(data.list); 31 | } 32 | read_list_is_finish = true; 33 | break; 34 | } 35 | } 36 | 37 | public boolean startReadList(boolean is_refresh, boolean show_notify) { 38 | if (!read_list_is_finish) { 39 | return false; 40 | } 41 | read_list_is_finish = false; 42 | new Thread(new readRunnable(this, is_refresh, show_notify)).start(); 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/DeviceUuidFactory.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.provider.Settings; 6 | import android.provider.Settings.Secure; 7 | import android.telephony.TelephonyManager; 8 | 9 | import java.io.UnsupportedEncodingException; 10 | import java.util.UUID; 11 | 12 | public class DeviceUuidFactory { 13 | private static final String PREFS_FILE = "device_id.xml"; 14 | private static final String PREFS_DEVICE_ID = "device_id"; 15 | private static volatile UUID uuid; 16 | 17 | public DeviceUuidFactory(Context context) { 18 | if (uuid == null) { 19 | synchronized (DeviceUuidFactory.class) { 20 | if (uuid == null) { 21 | final SharedPreferences prefs = context 22 | .getSharedPreferences(PREFS_FILE, 0); 23 | final String id = prefs.getString(PREFS_DEVICE_ID, null); 24 | if (id != null) { 25 | // Use the ids previously computed and stored in the 26 | // prefs file 27 | uuid = UUID.fromString(id); 28 | } else { 29 | uuid = UUID.randomUUID(); 30 | // Write the value out to the prefs file 31 | prefs.edit().putString(PREFS_DEVICE_ID, uuid.toString()).apply(); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | 38 | public UUID getDeviceUuid() { 39 | return uuid; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/WifiAdapter.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.BaseAdapter; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Map; 10 | 11 | public class WifiAdapter extends BaseAdapter { 12 | private Context context; 13 | ArrayList> list; 14 | 15 | WifiAdapter(Context context, ArrayList> list) { 16 | super(); 17 | this.context = context; 18 | this.list = list; 19 | } 20 | 21 | @Override 22 | public int getCount() { 23 | return list.size(); 24 | } 25 | 26 | @Override 27 | public Object getItem(int position) { 28 | return position; 29 | } 30 | 31 | @Override 32 | public long getItemId(int position) { 33 | return position; 34 | } 35 | 36 | @Override 37 | public View getView(int position, View convertView, ViewGroup parent) { 38 | ViewHolder holder; 39 | Map obj = list.get(position); 40 | if (convertView != null) { 41 | holder = (ViewHolder) convertView.getTag(); 42 | } else { 43 | convertView = View.inflate(context, R.layout.wifi_item, null); 44 | holder = new ViewHolder(); 45 | holder.ssid = convertView.findViewById(R.id.textView_i_ssid); 46 | holder.pwd = convertView.findViewById(R.id.textView_i_pwd); 47 | convertView.setTag(holder); 48 | } 49 | holder.ssid.setText(obj.get("ssid")); 50 | holder.pwd.setText(obj.get("psk")); 51 | return convertView; 52 | } 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/layout/wifi_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 20 | 21 | 32 | 33 | 43 | 44 | 55 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/Action.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import android.widget.Toast; 6 | 7 | import java.io.DataOutputStream; 8 | import java.io.IOException; 9 | import java.util.ArrayList; 10 | import java.util.Map; 11 | 12 | /** 13 | * 操作类 14 | */ 15 | public class Action { 16 | 17 | private Context context; 18 | 19 | private ReadWpaCfg cfg; 20 | 21 | Action(Context context) { 22 | this.context = context; 23 | this.cfg = new ReadWpaCfg( 24 | "/data/misc/wifi/wpa_supplicant.conf", 25 | "/data/misc/wifi/WifiConfigStore.xml" 26 | ); 27 | } 28 | 29 | /** 30 | * 获取热点和密码列表 31 | * 32 | * @return 异常时返回NULL 33 | */ 34 | public ArrayList> get_list(boolean force_refresh) { 35 | try { 36 | cfg.read(force_refresh); 37 | return cfg.getPasswordList(this.context); 38 | } catch (Exception e) { 39 | Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show(); 40 | Log.e("Read", e.getMessage()); 41 | e.printStackTrace(); 42 | return null; 43 | } 44 | } 45 | 46 | private boolean run_cmd() { 47 | Process process = null; 48 | DataOutputStream os = null; 49 | int rt; 50 | try { 51 | process = Runtime.getRuntime().exec("su"); 52 | os = new DataOutputStream(process.getOutputStream()); 53 | os.writeBytes("system/bin/mount -o rw,remount -t rootfs /data" + "\n"); 54 | os.writeBytes("exit\n"); 55 | os.flush(); 56 | rt = process.waitFor(); 57 | } catch (Exception e) { 58 | return false; 59 | } finally { 60 | if (os != null) { 61 | try { 62 | os.close(); 63 | } catch (IOException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | if (process != null) { 68 | process.destroy(); 69 | } 70 | } 71 | return rt == 0; 72 | } 73 | 74 | public boolean check_root() { 75 | try { 76 | try { 77 | return run_cmd(); 78 | } catch (Exception e) { 79 | Toast.makeText(context, context.getString(R.string.can_not_root_permission) + ":" + e.getMessage(), Toast.LENGTH_LONG).show(); 80 | } 81 | } catch (Exception e) { 82 | return false; 83 | } 84 | return false; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/Report.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import android.content.pm.PackageInfo; 4 | import android.content.pm.PackageManager; 5 | import android.os.Build; 6 | import android.util.DisplayMetrics; 7 | 8 | import java.io.OutputStream; 9 | import java.net.HttpURLConnection; 10 | import java.net.URL; 11 | import java.net.URLEncoder; 12 | import java.util.UUID; 13 | 14 | import static java.net.Proxy.Type.HTTP; 15 | 16 | public class Report implements Runnable { 17 | private MainActivity context; 18 | private String check_update_url; 19 | private boolean hasRoot; 20 | 21 | Report(MainActivity context, String check_update_url, boolean hasRoot) { 22 | this.context = context; 23 | this.check_update_url = check_update_url; 24 | this.hasRoot = hasRoot; 25 | } 26 | 27 | @Override 28 | public void run() { 29 | try { 30 | PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES); 31 | String update_url = check_update_url + "?version=" + pi.versionName; 32 | 33 | URL url = new URL(update_url); 34 | HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 35 | 36 | conn.setRequestMethod("POST"); 37 | conn.setReadTimeout(5000); 38 | conn.setConnectTimeout(5000); 39 | conn.setDoOutput(true); 40 | conn.setDoInput(true); 41 | conn.setUseCaches(false); 42 | 43 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 44 | 45 | String data = "uid=" + URLEncoder.encode(getUid().toString(), "UTF-8") + 46 | "&version=" + URLEncoder.encode(pi.versionName, "UTF-8") + 47 | "&version_code=" + pi.versionCode + 48 | "&phone=" + URLEncoder.encode(android.os.Build.BRAND, "UTF-8") + 49 | "&phone_model=" + URLEncoder.encode(android.os.Build.MODEL, "UTF-8") + 50 | "&width=" + dm.widthPixels + 51 | "&height=" + dm.heightPixels + 52 | "&android=" + android.os.Build.VERSION.RELEASE + 53 | "&android_sdk=" + Build.VERSION.SDK_INT + 54 | "&has_root=" + (hasRoot ? 1 : 0); 55 | 56 | //获取输出流 57 | OutputStream out = conn.getOutputStream(); 58 | out.write(data.getBytes()); 59 | out.flush(); 60 | 61 | conn.getResponseCode(); 62 | 63 | } catch (Exception ex) { 64 | ex.printStackTrace(); 65 | } 66 | } 67 | 68 | /** 69 | * 获取机器唯一ID 70 | * 71 | * @return 唯一UUID 72 | */ 73 | private UUID getUid() { 74 | DeviceUuidFactory unid = new DeviceUuidFactory(this.context); 75 | return unid.getDeviceUuid(); 76 | } 77 | } -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 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 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/MainActivity.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import android.app.Activity; 4 | import android.content.ClipData; 5 | import android.content.ClipboardManager; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.IntentFilter; 9 | import android.content.pm.PackageInfo; 10 | import android.content.pm.PackageManager; 11 | import android.content.res.Configuration; 12 | import android.content.res.Resources; 13 | import android.net.ConnectivityManager; 14 | import android.net.Uri; 15 | import android.net.wifi.WifiManager; 16 | import android.os.Bundle; 17 | import android.util.DisplayMetrics; 18 | import android.view.ContextMenu; 19 | import android.view.Menu; 20 | import android.view.MenuItem; 21 | import android.view.View; 22 | import android.view.Window; 23 | import android.widget.AdapterView; 24 | import android.widget.ListView; 25 | import android.widget.TextView; 26 | import android.widget.Toast; 27 | 28 | import java.util.ArrayList; 29 | import java.util.Locale; 30 | import java.util.Map; 31 | 32 | public class MainActivity extends Activity { 33 | private ArrayList> list; 34 | 35 | private boolean is_root_check = false; 36 | 37 | private WifiAdapter wifiAdapter = null; 38 | 39 | private ListView lv; 40 | 41 | private int log = 0; 42 | 43 | public MsgHandle handler; 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | setLocale(); 49 | Action ac = new Action(this); 50 | handler = new MsgHandle(this, ac); 51 | boolean hasRoot = false; 52 | if (ac.check_root()) { 53 | hasRoot = true; 54 | setContentView(R.layout.activity_main); 55 | registerWifiChange(); 56 | handler.startReadList(false, false); 57 | } else { 58 | setContentView(R.layout.activity_no_root); 59 | } 60 | new Thread(new Report(this, "https://www.loveyu.net/Update/WifiPwd.php", hasRoot)).start(); 61 | } 62 | 63 | public void setList(ArrayList> li) { 64 | list = li; 65 | TextView tv = findViewById(R.id.textViewNotice); 66 | if (list == null) { 67 | tv.setText(getString(R.string.read_wifi_list_error)); 68 | } else { 69 | is_root_check = true; 70 | if (wifiAdapter == null) { 71 | wifiAdapter = new WifiAdapter(this, list); 72 | } 73 | if (list.size() == 0) { 74 | tv.setText(getString(R.string.wifi_list_is_empty)); 75 | } else { 76 | lv = findViewById(R.id.listView); 77 | lv.setAdapter(wifiAdapter); 78 | registerForContextMenu(lv); 79 | lv.setOnItemClickListener((parent, view, position, id) -> view.showContextMenu()); 80 | String text = getString(R.string.wifi_list_number) + list.size(); 81 | tv.setText(text); 82 | } 83 | } 84 | } 85 | 86 | private void setLocale() { 87 | Resources resources = getResources(); 88 | DisplayMetrics dm = resources.getDisplayMetrics(); 89 | Configuration config = resources.getConfiguration(); 90 | config.locale = Locale.getDefault(); 91 | resources.updateConfiguration(config, dm); 92 | } 93 | 94 | private void registerWifiChange() { 95 | IntentFilter filter = new IntentFilter(); 96 | filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 97 | filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 98 | filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 99 | registerReceiver(new WifiReceiver(this), filter); 100 | } 101 | 102 | public void refresh_list(boolean show_notify) { 103 | if (log++ == 0 || !is_root_check) { 104 | //first not log 105 | return; 106 | } 107 | if (!handler.startReadList(true, show_notify)) { 108 | return; 109 | } 110 | if (!is_root_check) { 111 | Toast.makeText(this, getString(R.string.can_not_root_permission), Toast.LENGTH_SHORT).show(); 112 | } 113 | } 114 | 115 | public void refreshLvList(ArrayList> list, boolean show_notify) { 116 | if (list == null) { 117 | Toast.makeText(this, getString(R.string.read_wifi_list_error), Toast.LENGTH_SHORT).show(); 118 | return; 119 | } else { 120 | if (list.size() == 0) { 121 | Toast.makeText(this, getString(R.string.wifi_list_is_empty), Toast.LENGTH_SHORT).show(); 122 | return; 123 | } else { 124 | wifiAdapter.list = list; 125 | lv.setAdapter(wifiAdapter); 126 | } 127 | } 128 | lv.deferNotifyDataSetChanged(); 129 | if (show_notify) { 130 | Toast.makeText(this, getString(R.string.refresh_success), Toast.LENGTH_SHORT).show(); 131 | } 132 | } 133 | 134 | @Override 135 | protected void onResume() { 136 | super.onResume(); 137 | refresh_list(false); 138 | } 139 | 140 | private void open_url(String url) { 141 | Intent intent = new Intent(); 142 | intent.setData(Uri.parse(url)); 143 | intent.setAction(Intent.ACTION_VIEW); 144 | MainActivity.this.startActivity(intent); 145 | } 146 | 147 | @Override 148 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { 149 | menu.add(Menu.NONE, R.string.copy_password, 0, getString(R.string.copy_password)); 150 | menu.add(Menu.NONE, R.string.copy_ssid, 0, getString(R.string.copy_ssid)); 151 | menu.add(Menu.NONE, R.string.copy_ssid_and_password, 0, getString(R.string.copy_ssid_and_password)); 152 | } 153 | 154 | //选中菜单Item后触发 155 | public boolean onContextItemSelected(MenuItem item) { 156 | //关键代码在这里 157 | AdapterView.AdapterContextMenuInfo menuInfo; 158 | menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); 159 | int indexListView = menuInfo.position; 160 | if (list == null) return false; 161 | ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); 162 | switch (item.getItemId()) { 163 | case R.string.copy_password: 164 | if (clipboardManager != null) { 165 | clipboardManager.setPrimaryClip(ClipData.newPlainText(null, list.get(indexListView).get("psk"))); 166 | } 167 | break; 168 | case R.string.copy_ssid: 169 | if (clipboardManager != null) { 170 | clipboardManager.setPrimaryClip(ClipData.newPlainText(null, list.get(indexListView).get("ssid"))); 171 | } 172 | break; 173 | case R.string.copy_ssid_and_password: 174 | Map s = list.get(indexListView); 175 | if (clipboardManager != null) { 176 | clipboardManager.setPrimaryClip(ClipData.newPlainText(null, 177 | getString(R.string.wifi_ssid) + s.get("ssid") + "\n" + getString(R.string.password) + s.get("psk"))); 178 | } 179 | break; 180 | default: 181 | return false; 182 | } 183 | Toast.makeText(this, getString(R.string.already_copy), Toast.LENGTH_SHORT).show(); 184 | return true; 185 | } 186 | 187 | @Override 188 | public boolean onMenuItemSelected(int aFeatureId, MenuItem aMenuItem) { 189 | if (aFeatureId == Window.FEATURE_CONTEXT_MENU) 190 | return onContextItemSelected(aMenuItem); 191 | else 192 | return super.onMenuItemSelected(aFeatureId, aMenuItem); 193 | } 194 | 195 | @Override 196 | public boolean onCreateOptionsMenu(Menu menu) { 197 | getMenuInflater().inflate(R.menu.main, menu); 198 | return true; 199 | } 200 | 201 | @Override 202 | public boolean onOptionsItemSelected(MenuItem item) { 203 | int id = item.getItemId(); 204 | switch (id) { 205 | case R.id.action_exit: 206 | finish(); 207 | return true; 208 | case R.id.action_help: 209 | open_url("https://www.loveyu.org/3356.html?utm_source=android_wifipwd&utm_content=" + getAppVersionName(this)); 210 | return true; 211 | case R.id.open_source: 212 | open_url("https://github.com/loveyu/WifiPwd"); 213 | return true; 214 | case R.id.refresh_list: 215 | refresh_list(true); 216 | return true; 217 | } 218 | return super.onOptionsItemSelected(item); 219 | } 220 | 221 | public static String getAppVersionName(Context context) { 222 | String versionName; 223 | try { 224 | PackageManager pm = context.getPackageManager(); 225 | PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0); 226 | versionName = pi.versionName; 227 | if (versionName == null || versionName.length() <= 0) { 228 | return ""; 229 | } 230 | } catch (Exception e) { 231 | return ""; 232 | } 233 | return versionName; 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /app/src/main/java/net/loveyu/wifipwd/ReadWpaCfg.java: -------------------------------------------------------------------------------- 1 | package net.loveyu.wifipwd; 2 | 3 | import android.content.Context; 4 | import android.net.wifi.WifiInfo; 5 | import android.net.wifi.WifiManager; 6 | import android.util.Log; 7 | 8 | import org.w3c.dom.Document; 9 | import org.w3c.dom.Element; 10 | import org.w3c.dom.NodeList; 11 | import org.xml.sax.SAXException; 12 | 13 | import java.io.BufferedReader; 14 | import java.io.ByteArrayInputStream; 15 | import java.io.DataOutputStream; 16 | import java.io.IOException; 17 | import java.io.InputStreamReader; 18 | import java.io.UnsupportedEncodingException; 19 | import java.util.ArrayList; 20 | import java.util.Collections; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | import java.util.regex.Matcher; 24 | import java.util.regex.Pattern; 25 | 26 | import javax.xml.parsers.DocumentBuilder; 27 | import javax.xml.parsers.DocumentBuilderFactory; 28 | import javax.xml.parsers.ParserConfigurationException; 29 | 30 | /** 31 | * 读取配置文件信息 32 | * Created by loveyu on 2016/1/31. 33 | */ 34 | public class ReadWpaCfg { 35 | private ArrayList> list; 36 | private String wpa_config_path; 37 | private String WifiConfigStore_path; 38 | private boolean need_read_wap_config = false; 39 | 40 | ReadWpaCfg(String wpa_supplicant_path, String WifiConfigStorePath) { 41 | list = new ArrayList<>(); 42 | this.wpa_config_path = wpa_supplicant_path; 43 | this.WifiConfigStore_path = WifiConfigStorePath; 44 | } 45 | 46 | /** 47 | * @param force_refresh 是否强制刷新 48 | */ 49 | public void read(boolean force_refresh) { 50 | if (!force_refresh) { 51 | if (list.size() > 0) { 52 | return; 53 | } 54 | } 55 | list.clear(); 56 | if (android.os.Build.VERSION.SDK_INT >= 26) { 57 | need_read_wap_config = false; 58 | read_xml_config(); 59 | } else { 60 | need_read_wap_config = true; 61 | } 62 | if (need_read_wap_config) { 63 | read_wpa_config(); 64 | } 65 | } 66 | 67 | private Process get_su_process() throws IOException { 68 | return Runtime.getRuntime().exec("su"); 69 | } 70 | 71 | private void read_xml_config() { 72 | StringBuilder s = new StringBuilder(""); 73 | DataOutputStream os = null; 74 | BufferedReader in = null; 75 | try { 76 | Process process = get_su_process(); 77 | os = new DataOutputStream(process.getOutputStream()); 78 | in = new BufferedReader(new InputStreamReader(process.getInputStream())); 79 | os.writeBytes("cat " + WifiConfigStore_path + "\n"); 80 | os.flush(); 81 | os.writeBytes("exit\n"); 82 | os.flush(); 83 | String line; 84 | while ((line = in.readLine()) != null) { 85 | s.append(line.trim()).append("\n"); 86 | } 87 | } catch (IOException e) { 88 | e.printStackTrace(); 89 | Log.e("ReadEX", e.getMessage()); 90 | } finally { 91 | try { 92 | if (in != null) in.close(); 93 | if (os != null) os.close(); 94 | } catch (IOException e) { 95 | e.printStackTrace(); 96 | } 97 | } 98 | // close_io_stream(in, os); 99 | String new_str = s.toString(); 100 | if ("".equals(new_str)) { 101 | need_read_wap_config = true; 102 | return; 103 | } 104 | parse_xml(new_str); 105 | } 106 | 107 | private void parse_xml(String xml) { 108 | DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 109 | ByteArrayInputStream is; 110 | try { 111 | is = new ByteArrayInputStream(xml.getBytes("UTF-8")); 112 | } catch (UnsupportedEncodingException e) { 113 | e.printStackTrace(); 114 | return; 115 | } 116 | 117 | try { 118 | DocumentBuilder builder = factory.newDocumentBuilder(); 119 | Document document = builder.parse(is); 120 | Element root = document.getDocumentElement(); 121 | NodeList items = root.getElementsByTagName("NetworkList"); 122 | if (items.getLength() > 0) { 123 | NodeList network_list = ((Element) items.item(0)).getElementsByTagName("Network"); 124 | for (int i = 0; i < network_list.getLength(); i++) { 125 | NodeList item = ((Element) network_list.item(i)).getElementsByTagName("WifiConfiguration"); 126 | if (item.getLength() < 1) { 127 | continue; 128 | } 129 | Element elem = (Element) (item.item(0)); 130 | NodeList wp_node_list = elem.getElementsByTagName("string"); 131 | if (wp_node_list.getLength() < 2) { 132 | continue; 133 | } 134 | String ssid = ""; 135 | String psk = ""; 136 | 137 | for (int j = 0; j < wp_node_list.getLength(); j++) { 138 | Element e = (Element) wp_node_list.item(j); 139 | String name = e.getAttribute("name"); 140 | String value = e.getFirstChild().getNodeValue(); 141 | if ("SSID".equals(name)) { 142 | ssid = value; 143 | } else if ("PreSharedKey".equals(name)) { 144 | psk = value; 145 | } 146 | } 147 | add_kv(ssid, psk); 148 | } 149 | } 150 | } catch (ParserConfigurationException e) { 151 | e.printStackTrace(); 152 | } catch (IOException e) { 153 | e.printStackTrace(); 154 | } catch (SAXException e) { 155 | e.printStackTrace(); 156 | } 157 | } 158 | 159 | private void read_wpa_config() { 160 | StringBuilder s = new StringBuilder(""); 161 | DataOutputStream os = null; 162 | BufferedReader in = null; 163 | try { 164 | Process process = get_su_process(); 165 | os = new DataOutputStream(process.getOutputStream()); 166 | in = new BufferedReader(new InputStreamReader(process.getInputStream())); 167 | os.writeBytes("cat " + wpa_config_path + "\n"); 168 | os.flush(); 169 | os.writeBytes("exit\n"); 170 | os.flush(); 171 | String line; 172 | while ((line = in.readLine()) != null) { 173 | s.append(line.trim()).append("\n"); 174 | } 175 | } catch (IOException e) { 176 | e.printStackTrace(); 177 | Log.e("Read", e.getMessage()); 178 | } finally { 179 | try { 180 | if (in != null) in.close(); 181 | if (os != null) os.close(); 182 | } catch (IOException e) { 183 | e.printStackTrace(); 184 | } 185 | } 186 | parse(s.toString()); 187 | } 188 | 189 | private void parse(String content) { 190 | Pattern pattern = Pattern.compile("network=\\{\\n([\\s\\S]+?)\\n\\}"); 191 | Matcher matcher = pattern.matcher(content); 192 | while (matcher.find()) { 193 | add(matcher.group()); 194 | } 195 | } 196 | 197 | private void add(String content) { 198 | content = content.substring(9, content.length() - 2); 199 | String[] list = content.split("\\n"); 200 | HashMap map = new HashMap<>(); 201 | String k, v; 202 | for (String info : list) { 203 | info = info.trim(); 204 | int index = info.indexOf("="); 205 | if (index > -1) { 206 | k = info.substring(0, index); 207 | v = info.substring(index + 1); 208 | } else { 209 | continue; 210 | } 211 | if ("ssid".equals(k)) { 212 | if (v.charAt(0) == '"') { 213 | v = v.substring(1, v.length() - 1); 214 | } else { 215 | v = convertUTF8ToString(v); 216 | } 217 | } else if ("psk".equals(k)) { 218 | v = v.substring(1, v.length() - 1); 219 | } 220 | if (v == null) { 221 | continue; 222 | } 223 | map.put(k, v); 224 | } 225 | this.list.add(map); 226 | } 227 | 228 | private void add_kv(String ssid, String psk) { 229 | if (ssid == null || psk == null || "".equals(ssid) || psk.equals("")) { 230 | return; 231 | } 232 | HashMap map = new HashMap<>(); 233 | 234 | if (ssid.charAt(0) == '"') { 235 | ssid = ssid.substring(1, ssid.length() - 1); 236 | } else { 237 | ssid = convertUTF8ToString(ssid); 238 | } 239 | if ("".equals(ssid)) { 240 | return; 241 | } 242 | psk = psk.substring(1, psk.length() - 1); 243 | if ("".equals(psk)) { 244 | return; 245 | } 246 | map.put("ssid", ssid); 247 | map.put("psk", psk); 248 | this.list.add(map); 249 | } 250 | 251 | /** 252 | * 读取密码列表 253 | * 254 | * @param context 传入上下文数据,用于附加数据及排序 255 | * @return 返回完整的数据列表 256 | */ 257 | public ArrayList> getPasswordList(Context context) { 258 | ArrayList> rt = new ArrayList<>(); 259 | for (Map map : this.list) { 260 | if (map.containsKey("psk") && map.containsKey("ssid")) { 261 | rt.add(map); 262 | } 263 | } 264 | return this.sortPasswordList(rt, context); 265 | } 266 | 267 | /** 268 | * 对密码进行排序 269 | * 270 | * @param passwordList 已保存的密码列表 271 | * @param context 传入上下文数据,用于附加数据及排序 272 | * @return 返回排序后的数据 273 | */ 274 | private ArrayList> sortPasswordList(ArrayList> passwordList, Context context) { 275 | if (passwordList.size() < 1) { 276 | //数据不足原样返回 277 | return passwordList; 278 | } 279 | 280 | Collections.sort(passwordList, new PasswordSortComparator(getCurrentSSID(context))); 281 | 282 | return passwordList; 283 | } 284 | 285 | private String getCurrentSSID(Context context) { 286 | try { 287 | //读取当前链接的Wifi信息 288 | WifiManager mWifi = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); 289 | if (null == mWifi || !mWifi.isWifiEnabled()) { 290 | //wifi 未启用 291 | return ""; 292 | } 293 | WifiInfo wifiInfo = mWifi.getConnectionInfo(); 294 | String ssid = wifiInfo.getSSID(); 295 | 296 | if (ssid.charAt(0) == '"') { 297 | ssid = ssid.substring(1, ssid.length() - 1); 298 | } else { 299 | ssid = convertUTF8ToString(ssid); 300 | } 301 | 302 | return ssid; 303 | } catch (Exception ex) { 304 | //出错了就直接返回 305 | return ""; 306 | } 307 | } 308 | 309 | private static String convertUTF8ToString(String s) { 310 | if (s == null || s.equals("")) { 311 | return null; 312 | } 313 | try { 314 | s = s.toUpperCase(); 315 | int total = s.length() / 2; 316 | int pos = 0; 317 | byte[] buffer = new byte[total]; 318 | for (int i = 0; i < total; i++) { 319 | int start = i * 2; 320 | buffer[i] = (byte) Integer.parseInt(s.substring(start, start + 2), 16); 321 | pos++; 322 | } 323 | //如果当前不是UTF8编码则改为GB18030编码,兼容GBK 324 | return new String(buffer, 0, pos, isValidUtf8(buffer, total) ? "UTF-8" : "GB18030"); 325 | } catch (UnsupportedEncodingException e) { 326 | return null; 327 | } 328 | } 329 | 330 | /** 331 | * 判断是否为UTF-8编码 332 | * 333 | * @param b 字节编码 334 | * @param aMaxCount 最大数量 335 | * @link https://blog.csdn.net/clbxp/article/details/6620388 336 | */ 337 | private static boolean isValidUtf8(byte[] b, int aMaxCount) { 338 | int lLen = b.length, lCharCount = 0; 339 | for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount) { 340 | byte lByte = b[i++];//to fast operation, ++ now, ready for the following for(;;) 341 | if (lByte >= 0) continue;//>=0 is normal ascii 342 | if (lByte < (byte) 0xc0 || lByte > (byte) 0xfd) return false; 343 | int lCount = lByte > (byte) 0xfc ? 5 : lByte > (byte) 0xf8 ? 4 344 | : lByte > (byte) 0xf0 ? 3 : lByte > (byte) 0xe0 ? 2 : 1; 345 | if (i + lCount > lLen) return false; 346 | for (int j = 0; j < lCount; ++j, ++i) if (b[i] >= (byte) 0xc0) return false; 347 | } 348 | return true; 349 | } 350 | } 351 | --------------------------------------------------------------------------------