├── ICON.png ├── Screenshots ├── 1.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── 5.jpg ├── 6.jpg ├── 7.jpg ├── 8.jpg ├── 9.jpg └── 10.jpg ├── app ├── src │ └── main │ │ ├── res │ │ ├── drawable │ │ │ └── ic.png │ │ ├── layout │ │ │ ├── list.xml │ │ │ └── item.xml │ │ └── menu │ │ │ ├── more.xml │ │ │ ├── file.xml │ │ │ └── copy.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── zzz │ │ └── wifiview │ │ ├── WiFiAdapter.java │ │ ├── MainActivity.java │ │ ├── FileActivity.java │ │ ├── ReadFile.java │ │ └── ViewActivity.java └── build.gradle ├── LICENSE ├── CHANGELOG.md └── README.md /ICON.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/ICON.png -------------------------------------------------------------------------------- /Screenshots/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/Screenshots/1.jpg -------------------------------------------------------------------------------- /Screenshots/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/Screenshots/2.jpg -------------------------------------------------------------------------------- /Screenshots/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/Screenshots/3.jpg -------------------------------------------------------------------------------- /Screenshots/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/Screenshots/4.jpg -------------------------------------------------------------------------------- /Screenshots/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/Screenshots/5.jpg -------------------------------------------------------------------------------- /Screenshots/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/Screenshots/6.jpg -------------------------------------------------------------------------------- /Screenshots/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/Screenshots/7.jpg -------------------------------------------------------------------------------- /Screenshots/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/Screenshots/8.jpg -------------------------------------------------------------------------------- /Screenshots/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/Screenshots/9.jpg -------------------------------------------------------------------------------- /Screenshots/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/Screenshots/10.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamGmilk/WiFi-View/HEAD/app/src/main/res/drawable/ic.png -------------------------------------------------------------------------------- /app/src/main/res/layout/list.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion '29.0.0' 6 | defaultConfig { 7 | applicationId "com.zzz.wifiview" 8 | minSdkVersion 14 9 | targetSdkVersion 30 10 | versionCode 40 11 | versionName '12' 12 | } 13 | } 14 | dependencies { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/res/menu/more.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/menu/file.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/menu/copy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 JamGmilk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/zzz/wifiview/WiFiAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zzz.wifiview; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.BaseAdapter; 7 | import android.widget.TextView; 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 | public 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 view, ViewGroup parent) { 38 | ViewHolder holder; 39 | 40 | if (view != null) { 41 | holder = (ViewHolder) view.getTag(); 42 | } else { 43 | view = View.inflate(context, R.layout.item, null); 44 | holder = new ViewHolder(); 45 | holder.ssid = (TextView) view.findViewById(R.id.title); 46 | holder.password = (TextView) view.findViewById(R.id.text); 47 | view.setTag(holder); 48 | } 49 | 50 | Map map = list.get(position); 51 | holder.ssid.setText(map.get("ssid")); 52 | holder.password.setText(map.get("psk")); 53 | 54 | return view; 55 | } 56 | 57 | 58 | class ViewHolder { 59 | public TextView ssid; 60 | public TextView password; 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/zzz/wifiview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zzz.wifiview; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.net.Uri; 8 | import android.os.Bundle; 9 | import java.io.DataOutputStream; 10 | 11 | public class MainActivity extends Activity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setTheme(android.R.style.Theme_DeviceDefault); // 暗色主题 17 | 18 | // 检测是否获取root,有则启动ViewActivity 19 | if (isRoot()) { 20 | startActivity(new Intent().setClassName("com.zzz.wifiview", "com.zzz.wifiview.ViewActivity")); 21 | finish(); 22 | } else { 23 | showNoROOTDialog(); 24 | } 25 | } 26 | 27 | 28 | private void showNoROOTDialog() { 29 | AlertDialog.Builder noROOTDialog = new AlertDialog.Builder(this); 30 | noROOTDialog.setTitle("无法获取 ROOT 权限"); 31 | noROOTDialog.setCancelable(false); 32 | noROOTDialog.setMessage("需要 ROOT 权限以访问 WiFi 密码数据。"); 33 | noROOTDialog.setPositiveButton("关闭", new DialogInterface.OnClickListener() { 34 | @Override 35 | public void onClick(DialogInterface dialog, int which) { 36 | finish(); 37 | } 38 | }); 39 | noROOTDialog.setNeutralButton("卸载", new DialogInterface.OnClickListener() { 40 | @Override 41 | public void onClick(DialogInterface dialog, int which) { 42 | Uri uri = Uri.parse("package:com.zzz.wifiview"); 43 | Intent intent = new Intent(Intent.ACTION_DELETE, uri); 44 | startActivity(intent); 45 | finish(); 46 | } 47 | }); 48 | noROOTDialog.show(); 49 | } 50 | 51 | 52 | /** 判断应用是否被授予root权限 */ 53 | public static synchronized boolean isRoot() { 54 | Process process = null; 55 | DataOutputStream os = null; 56 | try { 57 | process = Runtime.getRuntime().exec("su"); 58 | os = new DataOutputStream(process.getOutputStream()); 59 | os.writeBytes("exit\n"); 60 | os.flush(); 61 | int exitValue = process.waitFor(); 62 | if (exitValue == 0) { 63 | return true; 64 | } else { 65 | return false; 66 | } 67 | } catch (Exception e) { 68 | e.printStackTrace(); 69 | return false; 70 | } finally { 71 | try { 72 | if (os != null) { 73 | os.close(); 74 | } 75 | process.destroy(); 76 | } catch (Exception e) { 77 | e.printStackTrace(); 78 | } 79 | } 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 历代更新日志 2 | 3 | 4 | ### 12 (40) 5 | - 支持 Android 11+ 6 | - 调整 位置权限提示 7 | 8 | ### 11 (39) 9 | - 增加 权限弹窗限制 10 | - 支持 浏览其他加密类型的 WiFi 信息 11 | - 修复 计数菌动态更新 12 | - 调整 通知提示内容 13 | 14 | ### 10 (38) 15 | - 修复 当前连接的 WiFi 不能置顶的问题 16 | - 调整 API 级别为 29 (Android 10) 17 | - 调整 复制菜单 18 | - 新增 隐私说明 19 | - 新增 开放源代码 20 | 21 | ### 10 (37) 22 | - 合并 复制菜单 23 | - 优化 删除方法 24 | - 优化 读取备份的信息传递 25 | - 优化 无 ROOT 时的界面 26 | - 修复 无法添加备份 27 | - 修复 特殊备份名称引起的文件检索崩溃 28 | - 修复 WiFi 条目不能删除的问题 29 | - 修复 若干个 bug 30 | 31 | ### 9.0 (36) 32 | - 删除 打开方式 33 | - 调整 操作逻辑 34 | 35 | ### 8.1 (35) 36 | - 删除 杂项 37 | - 替换 刷新列表方式 38 | - 精简 软件包 39 | 40 | ### 8.0 (34) 41 | - 支持 当连接的 WiFi 在表头显示 42 | - 支持 读取备份 43 | - 支持 A-Z 排序 44 | - 支持 使用 WiFi View 打开本地 WiFi 密码配置文件 45 | - 支持 清空备份 46 | - 修复 软件不自觉的创建备份文件夹 47 | - 支持 修复 WiFi 配置文件出错导致的崩溃 48 | - 优化 若干处若干次 49 | 50 | ### 7.1.2 (33) 51 | - 恢复 删除 WiFi 52 | - 新增 若干个功能 53 | 54 | ### 7.1 (32) 55 | - 新增 备份与恢复 56 | - 停用 WiFi 删除 57 | 58 | ### 7.0 (31) 59 | - 新增 浏览源信息 60 | - 支持 显示 WiFi 条目在源文件的位置 61 | - 新增 WiFi 密码删除(不稳定) 62 | 63 | ### 6.0.1 (30) 64 | - 紧急 版本回倒 65 | 66 | ### 6.0 (29) 67 | - 支持 浏览源信息 68 | - 优化 复制反馈 69 | 70 | ### 5.1.1 (28) 71 | - 支持 Android 8.0 72 | - 修正 正常的版本号 73 | - 调整 targetSdkVersion 74 | - 提高 运行处理的高效性 75 | - 优化 代码的美观 76 | - 检查 稳定性 77 | 78 | ### 5.0.2 (27) 79 | - 支持 Android 8.0 80 | 81 | ### 5.0 (26) 82 | - 修复版本号过低的问题 83 | 84 | ### 4.4.4 (25) 85 | - 精简 软件 86 | - 保留 核心功能 87 | 88 | ### 4.4 (24) 89 | - 删除 无效代码 90 | - 压制 图标 91 | - 修改 蓝色主题 92 | 93 | ### 4.3 (23) 94 | - 调整 计数菌不可点击 95 | - 修复 看不懂英文的问题 96 | 97 | ### 4.2 (22) 98 | - 支持 显示 WiFi 数量在 menu 里 99 | - 支持 自定义文件目录 100 | - 支持 导出分享 101 | 102 | ### 4.1 (21) 103 | - 修复 跳转方式 104 | - 精简 继续精简 105 | 106 | ### 4.0 (20) 107 | - 新增 自定义备份名称 108 | 109 | ### 3.2 (19) 110 | - 新增 菜单 111 | - 新增 跳转到 WiFi 设置 112 | - 新增 备份 113 | - 修复 菜单问题 114 | - 修复 时长问题 115 | 116 | ### 3.0 (18) 117 | - 新增 备份 118 | - 修复 菜单问题 119 | 120 | ### 2.9 (17) 121 | - 新增 菜单 122 | - 新增 跳转到WiFi设置 123 | 124 | ### 2.1 (16) 125 | - 新增 计数菌 (=・ω・=) 126 | 127 | ### 2.6 (15) 128 | - 新增 报错提示 (不要再问我为啥是空白界面了😅) 129 | 130 | ### 2.8 (14) 131 | - 修改了菜单(样式如介绍图) 132 | 133 | ### 2.7 (13) 134 | - 紧急修复 135 | 136 | ### 2.6 (12) 137 | - 更换了新图标 192*192 px 138 | - 修复了在部分设备上无法获取 root 的问题 139 | 140 | ### 2.5 (11) 141 | - 移除了 values 142 | - 移除了 debug 调试 143 | 144 | ### 2.4 (10) 145 | - 继续精简,体积减小到 15 KB 146 | - 删掉了无用的代码 147 | 148 | ### 2.3 (9) 149 | - 调整 点击 item 为直接复制密码,长按打开复制菜单 150 | - 除去 WiFi Setting 151 | 152 | ### 2.2 (8) 153 | - 调整 点击 item 为直接复制密码,长按打开复制菜单 154 | - 精简 代码 155 | - 调整 item 高度 156 | - 更换 Icon 157 | 158 | ### 2.1 (7) 159 | - 精简 160 | 161 | ### 2.0 (6) 162 | - 精简 163 | 164 | ### 1.1.1.1.1 (5) 165 | - 精简 软件体积 166 | - 除去 无用功能 167 | - 支持 密码显示 168 | 169 | ### 1.1.1.1 (4) 170 | - 新增 快速跳转到 WiFi 设置 171 | - 优化 界面布局 172 | 173 | ### 1.1.1 (3) 174 | - 新增 提示界面 175 | - 删除 其他尺寸的图标 176 | 177 | ### 1.1 (2) 178 | - 新增 WiFi 密码查看 179 | - 新增 WiFi 开关 180 | - 新增 退出确认 181 | 182 | ### 1.0 (1) 183 | Hello World! 184 | 185 | ## - END - 186 | 187 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WiFi View 2 | 3 | 快速查看与管理在 Android 设备上连过的 WiFi 的密码 4 | 5 | 6 | ### 应用特性 7 | - 支持 Android 4.0 + 8 | - 支持显示中文名称的 WiFi 9 | - 支持一键复制 SSID 与密码 10 | - 支持备份与恢复 11 | - 支持查看 WiFi 的源信息 12 | 13 | 14 | ## 应用截图 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ## 历代更新日志 28 | [CHANGELOG.md](CHANGELOG.md) 29 | 30 | 31 | ## 下载 32 | - [GitHub](https://github.com/JamGmilk/WiFi-View/releases) 33 | - [酷安](https://www.coolapk.com/apk/com.zzz.wifiview) 34 | 35 | 36 | ## 隐私权限说明 37 | ### ACCESS_SUPERUSER: 38 | 使用 ROOT 权限读写 WiFi 密码配置文件。 39 | 40 | ### ACCESS_WIFI_STATE: 41 | 扫描 WLAN ,用于置顶当前连接的 WiFi 。 42 | 43 | ### ACCESS_FINE_LOCATION: 44 | 此项权限是 Android 官方要求的[[1]]。在 Android 8.0 以后,需要授予此权限才能使用 ACCESS_WIFI_STATE 权限。 45 | 46 | >软件扫描 WLAN 需要满足以下所有条件: 47 | > ① 授予软件精确位置权限 48 | > ② 设备已启用位置服务 49 | 50 | [[1]] https://developer.android.google.cn/guide/topics/connectivity/wifi-scan#wifi-scan-restrictions 51 | 52 | [1]: 53 | 54 | 55 | ## 注意 56 | 57 | 1. 手动删除的 WiFi 无法获取; 58 | 59 | 2. 部分系统可能会加密,导致软件不能正常工作; 60 | 61 | 3. 软件需要读取 /data 下的系统文件,必须授予 ROOT 权限。 62 | > Android 8.0 以下读取 /data/misc/wifi/wpa_supplicant.conf
63 | > Android 8~11 读取 /data/misc/wifi/WifiConfigStore.xml
64 | > Android 11 以上读取 /data/misc/apexdata/com.android.wifi/WifiConfigStore.xml 65 | 66 | ## License 67 | ``` 68 | Copyright (c) 2021 JamGmilk 69 | 70 | Permission is hereby granted, free of charge, to any person obtaining a copy 71 | of this software and associated documentation files (the "Software"), to deal 72 | in the Software without restriction, including without limitation the rights 73 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 74 | copies of the Software, and to permit persons to whom the Software is 75 | furnished to do so, subject to the following conditions: 76 | 77 | The above copyright notice and this permission notice shall be included in all 78 | copies or substantial portions of the Software. 79 | 80 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 81 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 82 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 83 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 84 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 85 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 86 | SOFTWARE. 87 | ``` 88 | 89 | *Copyright © 2016-2021 JamGmilk.* 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/zzz/wifiview/FileActivity.java: -------------------------------------------------------------------------------- 1 | package com.zzz.wifiview; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.Context; 6 | import android.content.DialogInterface; 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | import android.text.InputType; 10 | import android.view.Menu; 11 | import android.view.MenuItem; 12 | import android.view.View; 13 | import android.widget.AdapterView; 14 | import android.widget.ArrayAdapter; 15 | import android.widget.EditText; 16 | import android.widget.ListAdapter; 17 | import android.widget.ListView; 18 | import android.widget.PopupMenu; 19 | import android.widget.Toast; 20 | import java.io.DataOutputStream; 21 | import java.io.File; 22 | import java.text.SimpleDateFormat; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | public class FileActivity extends Activity { 27 | 28 | ArrayList fileList; 29 | Context context = this; 30 | PopupMenu popup; 31 | 32 | String backupPath; // 添加备份文件目录 33 | String backupParentPath; // /AppData/files/Backup 34 | String wifiPath; // /data/misc/wifi/xxx.xml 35 | 36 | int num; // 计数菌 37 | 38 | /* 设定时间格式 */ 39 | java.util.Date utilDate = new java.util.Date(); 40 | SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmm"); 41 | 42 | 43 | @Override 44 | protected void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | setContentView(R.layout.list); 47 | 48 | /* 设置备份目录 */ 49 | backupParentPath = context.getExternalFilesDir("Backup").getPath(); 50 | 51 | /* 设置 WiFi 密码文件路径 */ 52 | if (android.os.Build.VERSION.SDK_INT >= 26) { 53 | if (android.os.Build.VERSION.SDK_INT >= 30) { 54 | wifiPath = "/data/misc/apexdata/com.android.wifi/WifiConfigStore.xml"; 55 | } else { 56 | wifiPath = "/data/misc/wifi/WifiConfigStore.xml"; 57 | } 58 | } else { 59 | wifiPath = "/data/misc/wifi/wpa_supplicant.conf"; 60 | } 61 | 62 | /* 获取备份文件列表 */ 63 | fileList = new ArrayList(); 64 | getAllFiles(new File(backupParentPath)); 65 | List data = new ArrayList(); 66 | for(int i=0; i(this, android.R.layout.simple_list_item_1, strings); 77 | lv.setAdapter(adapter); 78 | lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { 79 | @Override 80 | public void onItemClick(AdapterView parent, View view, final int position, long id) { 81 | // Toast.makeText(FileActivity.this, backupParentPath + "/" + strings[position], 0).show(); 82 | popup = new PopupMenu(FileActivity.this, view); 83 | getMenuInflater().inflate(R.menu.file,popup.getMenu()); 84 | popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 85 | @Override 86 | public boolean onMenuItemClick(MenuItem item) { 87 | switch(item.getItemId()) { 88 | case R.id.menu_recovery: // 时光穿梭 89 | showRestoreDialog(backupParentPath + "/" + strings[position]); 90 | break; 91 | case R.id.menu_read: // 读取备份 92 | Intent intent1 = new Intent(); 93 | intent1.setClass(FileActivity.this, ViewActivity.class); 94 | intent1.putExtra("name", strings[position]); 95 | intent1.putExtra("path", backupParentPath + "/" + strings[position]); 96 | intent1.putExtra("read", true); 97 | startActivity(intent1); // 此时 ViewActivity 的主菜单不再显示而是替换成文字返回 98 | break; 99 | case R.id.menu_delete1: // 删除备份 100 | cmd("rm -f " + backupParentPath + "/" + strings[position]); 101 | 102 | Intent intent = getIntent(); 103 | finish(); 104 | startActivity(intent); 105 | break; 106 | default: 107 | return false; 108 | } 109 | return true; 110 | } 111 | }); 112 | popup.show(); 113 | } 114 | }); 115 | 116 | } 117 | 118 | 119 | @Override 120 | public boolean onCreateOptionsMenu(Menu menu) { 121 | super.onCreateOptionsMenu(menu); 122 | menu.add(0,0,0,"添加备份"); 123 | menu.add(0,1,0,"Notice"); 124 | menu.getItem(1).setEnabled(false); 125 | menu.getItem(1).setTitle("共 " + num + " 条备份"); 126 | return true; 127 | } 128 | 129 | 130 | @Override 131 | public boolean onOptionsItemSelected(MenuItem item) { 132 | switch (item.getItemId()) { 133 | case 0: // 添加备份 134 | showBackupDialog(); 135 | return true; 136 | default: 137 | return super.onOptionsItemSelected(item); 138 | } 139 | } 140 | 141 | 142 | private void showBackupDialog() { 143 | final EditText et = new EditText(this); 144 | AlertDialog.Builder BackupDialog = new AlertDialog.Builder(this); 145 | BackupDialog 146 | .setTitle("备份名称") 147 | .setView(et); 148 | 149 | et.setText(formatter.format(utilDate)); 150 | et.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); 151 | 152 | BackupDialog 153 | .setPositiveButton("开始备份",new DialogInterface.OnClickListener() { 154 | @Override 155 | public void onClick(DialogInterface dialog,int which) { 156 | backupPath = backupParentPath + "/" + et.getText().toString(); 157 | 158 | cmd("cp -f " + wifiPath + " " + backupPath); 159 | 160 | Intent intent = getIntent(); 161 | finish(); 162 | startActivity(intent); 163 | } 164 | }) 165 | .setNegativeButton("取消", null) 166 | /*.setNeutralButton("发送备份",new DialogInterface.OnClickListener() { 167 | @Override 168 | public void onClick(DialogInterface dialog,int which) { 169 | backupPath = backupParentPath + "/" + et.getText().toString(); 170 | 171 | cmd("cp -f " + wifiPath + " " + backupPath); 172 | 173 | File sendFile = new File(backupPath); 174 | Intent share = new Intent(Intent.ACTION_SEND); 175 | share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(sendFile)); 176 | *///share.setType("*/*"); 177 | /*startActivity(Intent.createChooser(share, "发送")); 178 | } 179 | })*/ 180 | .show(); 181 | } 182 | 183 | 184 | private void showRestoreDialog(final String path) { 185 | AlertDialog.Builder RestoreDialog = new AlertDialog.Builder(this); 186 | RestoreDialog 187 | .setTitle("警告") 188 | .setMessage("此操作将会替换设备的 WiFi 密码文件。是否继续?\n\n" + "当前文件:\n" + path) 189 | .setPositiveButton("继续",new DialogInterface.OnClickListener() { 190 | @Override 191 | public void onClick(DialogInterface dialog,int which) { 192 | cmd("cp -f " + path + " " + wifiPath); 193 | cmd("chmod 660 " + wifiPath); 194 | finish(); 195 | startActivity(new Intent().setClassName("com.zzz.wifiview","com.zzz.wifiview.ViewActivity")); 196 | } 197 | }) 198 | .setNegativeButton("取消", null) 199 | .show(); 200 | } 201 | 202 | 203 | /* 获取备份文件列表 */ 204 | private void getAllFiles(File root) { 205 | File files[] = root.listFiles(); 206 | if(files != null) 207 | for(File f:files) { 208 | if(f.isDirectory()) { 209 | getAllFiles(f); 210 | } else { 211 | this.fileList.add(f); 212 | } 213 | } 214 | } 215 | 216 | 217 | /* 执行命令 */ 218 | public void cmd(String command) { 219 | Process process = null; 220 | DataOutputStream os = null; 221 | try { 222 | process = Runtime.getRuntime().exec("su"); 223 | os = new DataOutputStream(process.getOutputStream()); 224 | os.writeBytes(command + "\n"); 225 | os.writeBytes("exit\n"); 226 | os.flush(); 227 | process.waitFor(); 228 | } catch (Exception e) { 229 | e.printStackTrace(); 230 | Toast.makeText(this, "FAcmd: " + e.getMessage(), Toast.LENGTH_LONG).show(); 231 | } finally { 232 | try { 233 | if (os != null) { 234 | os.close(); 235 | } 236 | process.destroy(); 237 | } catch (Exception e) { 238 | e.printStackTrace(); 239 | Toast.makeText(this, "FAcmdF: " + e.getMessage(), Toast.LENGTH_LONG).show(); 240 | } 241 | } 242 | } 243 | 244 | 245 | } 246 | -------------------------------------------------------------------------------- /app/src/main/java/com/zzz/wifiview/ReadFile.java: -------------------------------------------------------------------------------- 1 | package com.zzz.wifiview; 2 | 3 | import android.content.Context; 4 | import android.net.wifi.WifiInfo; 5 | import android.net.wifi.WifiManager; 6 | import android.util.Log; 7 | import java.io.BufferedReader; 8 | import java.io.DataOutputStream; 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.io.InputStreamReader; 12 | import java.io.RandomAccessFile; 13 | import java.io.UnsupportedEncodingException; 14 | import java.util.ArrayList; 15 | import java.util.Collections; 16 | import java.util.Comparator; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.regex.Matcher; 20 | import java.util.regex.Pattern; 21 | 22 | public class ReadFile { 23 | 24 | int mode = 0; 25 | 26 | ArrayList> list = new ArrayList>(); 27 | 28 | public ReadFile(String path, int i) { 29 | mode = i; 30 | 31 | Process process = null; 32 | String s = ""; 33 | DataOutputStream os = null; 34 | BufferedReader br = null; 35 | try { 36 | process = Runtime.getRuntime().exec("su"); 37 | os = new DataOutputStream(process.getOutputStream()); 38 | os.writeBytes("cat " + path + "\n"); 39 | os.writeBytes("exit\n"); 40 | os.flush(); 41 | br = new BufferedReader(new InputStreamReader(process.getInputStream())); 42 | String line = null; 43 | while ((line = br.readLine()) != null) { 44 | s += line.trim() + "\n"; 45 | } 46 | } catch (IOException e) { 47 | exceptionCatch("ReadFile: " + e.getMessage()); 48 | e.printStackTrace(); 49 | } finally { 50 | try { 51 | if (os != null) { 52 | os.close(); 53 | } 54 | if (br != null) { 55 | br.close(); 56 | } 57 | process.destroy(); 58 | } catch (Exception e) { 59 | exceptionCatch("ReadFile, finally: " + e.getMessage()); 60 | e.printStackTrace(); 61 | } 62 | } 63 | scan(s); 64 | } 65 | 66 | /* 一个简陋的日志记录方法:exceptionCatch(formatter.format(utilDate) + " : " + "58"); */ 67 | public void exceptionCatch(String strcontent) { 68 | String path = "/storage/emulated/0/Android/data/com.zzz.wifiview/debug/debug.txt"; 69 | // System.currentTimeMillis(); 70 | String strContent = strcontent + "\r\n"; 71 | try { 72 | File file = new File(path); 73 | if (!file.exists()) { 74 | Log.e("TestFile", "Create the file:" + path); 75 | file.getParentFile().mkdirs(); 76 | file.createNewFile(); 77 | } 78 | RandomAccessFile rf = new RandomAccessFile(file,"rwd"); 79 | rf.seek(file.length()); 80 | rf.write(strContent.getBytes()); 81 | rf.close(); 82 | } catch (Exception e){ 83 | Log.e("TestFile", "Error on write File:"+e); 84 | } 85 | } 86 | 87 | 88 | /* 分隔每个 WiFi 条目 */ 89 | private void scan(String s) { 90 | if (android.os.Build.VERSION.SDK_INT >= 26) { 91 | Pattern pattern = Pattern.compile("\\n([\\s\\S]+?)\\n\\"); 92 | Matcher matcher = pattern.matcher(s); 93 | while (matcher.find()) { 94 | addOreo(matcher.group()); 95 | } 96 | } else { 97 | Pattern pattern1 = Pattern.compile("network=\\{\\n([\\s\\S]+?)\\n\\}"); 98 | Matcher matcher1 = pattern1.matcher(s); 99 | while (matcher1.find()) { 100 | add(matcher1.group()); 101 | } 102 | } 103 | } 104 | 105 | 106 | /* Android 8.0 之前的解析 WiFi 方法*/ 107 | private void add(String s) { 108 | exceptionCatch(s); 109 | HashMap map = new HashMap(); 110 | map.put("view", s); // 源信息 111 | 112 | String[] list = s.split("\\n"); 113 | 114 | String ssid = ""; 115 | String psk = ""; 116 | String key_mgmt = ""; 117 | 118 | // Get value 119 | // 找出 ssid 和 key_mgmt 120 | for (String info : list) { 121 | if (info.contains("=")) { 122 | int index = info.indexOf("="); 123 | if (info.substring(0, index).contains("ssid")) { 124 | if (!info.substring(0, index).contains("scan_ssid")) { 125 | ssid = info.substring(index+1, info.length()); 126 | if (ssid.contains("\"")) { 127 | ssid = ssid.substring(1, ssid.length()-1); 128 | } else { 129 | ssid = toUTF8(ssid); 130 | } 131 | } 132 | } else if (info.substring(0, index).contains("key_mgmt")) { 133 | key_mgmt = info.substring(index+1, info.length()); 134 | } 135 | } 136 | } 137 | 138 | if (mode == 1) { // WPA-PSK 模式 139 | if (key_mgmt.contains("WPA-PSK")) { 140 | // 找出 psk 141 | for (String info : list) { 142 | if (info.contains("=")) { 143 | int index = info.indexOf("="); 144 | if (info.substring(0, index).contains("psk")) { 145 | psk = info.substring(index+2, info.length()-1); 146 | } 147 | } 148 | } 149 | 150 | map.put("ssid", ssid); 151 | map.put("psk", psk); 152 | 153 | } 154 | } else if (mode == 2) { // 非 WPA-PSK 模式 155 | if (!key_mgmt.contains("WPA-PSK")) { 156 | map.put("ssid", ssid); 157 | map.put("psk", key_mgmt); 158 | } 159 | } 160 | 161 | this.list.add(map); 162 | } 163 | 164 | 165 | /* Android 8.0 之后的解析 WiFi 方法 */ 166 | private void addOreo(String s) { 167 | HashMap map = new HashMap(); 168 | map.put("view", s); 169 | 170 | String[] list = s.split("\\n"); 171 | 172 | String ssid = ""; 173 | String psk = ""; 174 | String key_mgmt = ""; 175 | 176 | // Get value 177 | 178 | for (String info : list) { 179 | if (info.contains("name=\"SSID\">")) { 180 | ssid = info.substring(info.indexOf(""")+6, info.lastIndexOf(""")); 181 | } else if (info.contains("name=\"ConfigKey\">")) { 182 | key_mgmt = info.substring(info.indexOf(""")+6, info.length()); 183 | key_mgmt = key_mgmt.substring(key_mgmt.indexOf(""")+6, key_mgmt.lastIndexOf("")); 184 | key_mgmt = key_mgmt.replace("-", ""); 185 | } 186 | } 187 | 188 | if (mode == 1) { 189 | if (key_mgmt.contains("WPA_PSK")) { 190 | for (String info : list) { 191 | if (info.contains("name=\"PreSharedKey\">")) { 192 | psk = info.substring(info.indexOf(""")+6, info.lastIndexOf(""")); 193 | } 194 | } 195 | 196 | map.put("ssid", ssid); 197 | map.put("psk", psk); 198 | 199 | } 200 | } else if (mode == 2) { 201 | if (!key_mgmt.contains("WPA_PSK")) { 202 | map.put("ssid", ssid); 203 | map.put("psk", key_mgmt); 204 | } 205 | } 206 | 207 | this.list.add(map); 208 | } 209 | 210 | 211 | public ArrayList> getList(Context context) { 212 | ArrayList> m = new ArrayList>(); 213 | for (Map map : this.list) { 214 | if (map.containsKey("ssid") && map.containsKey("psk")) m.add(map); 215 | } 216 | return this.sorting(m, context); 217 | } 218 | 219 | 220 | private ArrayList> sorting(ArrayList> lv, Context context) { 221 | if (lv.size() < 1) return lv; 222 | Collections.sort(lv, new sort(getSSID(context))); 223 | return lv; 224 | } 225 | 226 | 227 | private String getSSID(Context context) { 228 | try { 229 | WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 230 | if (!wifiManager.isWifiEnabled()) return ""; // 关闭 WiFi 时 231 | WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 232 | String ssid = wifiInfo.getSSID(); 233 | 234 | // 判断有无引号 235 | if (ssid.contains("\"")) { 236 | ssid = ssid.substring(1, ssid.length()-1); 237 | } else { 238 | ssid = toUTF8(ssid); 239 | } 240 | return ssid; 241 | } catch (Exception e) { 242 | exceptionCatch("getCurrentWiFi: " + e.getMessage()); 243 | e.printStackTrace(); 244 | return ""; 245 | } 246 | } 247 | 248 | 249 | private static String toUTF8(String s) { 250 | if (s == null || s.equals("")) return null; 251 | 252 | try { 253 | s = s.toUpperCase(); 254 | int total = s.length() / 2; 255 | int pos = 0; 256 | byte[] buffer = new byte[total]; 257 | for (int i = 0; i < total; i++) { 258 | int start = i * 2; 259 | buffer[i] = (byte) Integer.parseInt(s.substring(start, start + 2), 16); 260 | pos++; 261 | } 262 | return new String(buffer, 0, pos, "UTF-8"); 263 | } catch (UnsupportedEncodingException e) { 264 | e.printStackTrace(); 265 | return null; 266 | } 267 | } 268 | 269 | } 270 | 271 | 272 | class sort implements Comparator> { 273 | 274 | private String current; 275 | 276 | 277 | public sort(String current) { 278 | this.current = current; 279 | } 280 | 281 | 282 | @Override 283 | public int compare(Map t1, Map t2) { 284 | String s1 = t1.get("ssid"); 285 | String s2 = t2.get("ssid"); 286 | if (s1.equals(s2)) return 0; 287 | if (s1.equals(current)) return -1; 288 | if (s2.equals(current)) return 1; 289 | return s1.compareToIgnoreCase(s2); 290 | } 291 | 292 | 293 | } 294 | -------------------------------------------------------------------------------- /app/src/main/java/com/zzz/wifiview/ViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.zzz.wifiview; 2 | 3 | import android.app.ActionBar; 4 | import android.app.Activity; 5 | import android.app.AlertDialog; 6 | import android.content.ClipData; 7 | import android.content.ClipboardManager; 8 | import android.content.Context; 9 | import android.content.DialogInterface; 10 | import android.content.Intent; 11 | import android.net.Uri; 12 | import android.os.Bundle; 13 | import android.provider.Settings; 14 | import android.view.Menu; 15 | import android.view.MenuItem; 16 | import android.view.View; 17 | import android.widget.AdapterView; 18 | import android.widget.ListView; 19 | import android.widget.PopupMenu; 20 | import android.widget.Toast; 21 | import java.io.BufferedReader; 22 | import java.io.DataOutputStream; 23 | import java.io.FileOutputStream; 24 | import java.io.IOException; 25 | import java.io.InputStreamReader; 26 | import java.io.OutputStreamWriter; 27 | import java.util.ArrayList; 28 | import java.util.Map; 29 | 30 | public class ViewActivity extends Activity { 31 | ArrayList> mainList; 32 | PopupMenu popup; 33 | Context context = this; 34 | String backupPath; // 备份目录 (/AppData/files/Backup/AutoBackup) 35 | String sPath; // 源文件 36 | boolean isRead = false; // 读取备份模式 37 | boolean isMore = false; // 显示更多 WiFi 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.list); 43 | 44 | // 缓存目录(/AppData/cache/bk) 45 | //bkPath = this.getExternalCacheDir().getPath() + "/bk"; 46 | 47 | // 备份目录 (/AppData/files/Backup/AutoBackup) 48 | backupPath = this.getExternalFilesDir("Backup").getPath() + "/AutoBackup"; 49 | 50 | /* 获取启动来源 */ 51 | try { 52 | Intent intent = getIntent(); 53 | Bundle bundle = intent.getExtras(); 54 | isRead = bundle.getBoolean("read"); 55 | isMore = bundle.getBoolean("more"); 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | //Toast.makeText(this, "VAoC: " + e.getMessage(), Toast.LENGTH_LONG).show(); 59 | } 60 | 61 | start(); 62 | } 63 | 64 | 65 | private void start() { 66 | Intent intent = getIntent(); 67 | Bundle bundle = intent.getExtras(); 68 | 69 | /* 判断启动来源 */ 70 | if (isRead) { // 读取备份模式 71 | setTitle(bundle.getString("name")); 72 | sPath = bundle.getString("path"); 73 | mainList = get(sPath, 1); 74 | } else if (isMore) { // 显示更多 WiFi 75 | setTitle("更多 WiFi"); 76 | sPath = bundle.getString("path"); 77 | mainList = get(sPath, 2); 78 | } else { // 读取系统文件 79 | if (android.os.Build.VERSION.SDK_INT >= 26) { 80 | if (android.os.Build.VERSION.SDK_INT >= 30) { 81 | sPath = "/data/misc/apexdata/com.android.wifi/WifiConfigStore.xml"; 82 | } else { 83 | sPath = "/data/misc/wifi/WifiConfigStore.xml"; 84 | } 85 | } else { 86 | sPath = "/data/misc/wifi/wpa_supplicant.conf"; 87 | } 88 | mainList = get(sPath, 1); 89 | } 90 | 91 | 92 | if (mainList == null) { 93 | Toast.makeText(ViewActivity.this, "获取列表失败", Toast.LENGTH_LONG).show(); 94 | } else { 95 | if (mainList.size() == 0) { 96 | Toast.makeText(ViewActivity.this, "列表为空", Toast.LENGTH_LONG).show(); 97 | } else { 98 | final ListView lv = findViewById(R.id.lv); 99 | lv.setAdapter(new WiFiAdapter(this, mainList)); 100 | lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { 101 | @Override 102 | public void onItemClick(AdapterView parent, View view, final int position, long id) { 103 | popup = new PopupMenu(ViewActivity.this, view); 104 | 105 | if (isMore) { 106 | getMenuInflater().inflate(R.menu.more, popup.getMenu()); 107 | } else { 108 | getMenuInflater().inflate(R.menu.copy, popup.getMenu()); 109 | } 110 | 111 | popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 112 | @Override 113 | public boolean onMenuItemClick(MenuItem item) { 114 | final ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); 115 | switch(item.getItemId()) { 116 | case R.id.menu_ssid: 117 | cm.setPrimaryClip(ClipData.newPlainText(null, mainList.get(position).get("ssid"))); 118 | Toast.makeText(ViewActivity.this, "SSID已复制", Toast.LENGTH_SHORT).show(); 119 | break; 120 | case R.id.menu_password: 121 | cm.setPrimaryClip(ClipData.newPlainText(null, mainList.get(position).get("psk"))); 122 | Toast.makeText(ViewActivity.this, "密码已复制", Toast.LENGTH_SHORT).show(); 123 | break; 124 | case R.id.menu_all: 125 | Map s = mainList.get(position); 126 | cm.setPrimaryClip(ClipData.newPlainText(null, "SSID: " + s.get("ssid") + "\n" + "密码: " + s.get("psk"))); 127 | Toast.makeText(ViewActivity.this, "SSID和密码都已复制", Toast.LENGTH_SHORT).show(); 128 | break; 129 | case R.id.menu_view: 130 | AlertDialog.Builder TextDialog = new AlertDialog.Builder(ViewActivity.this); 131 | TextDialog.setTitle("源信息浏览").setMessage(mainList.get(position).get("view")).setPositiveButton("关闭",null).setNeutralButton("复制", new DialogInterface.OnClickListener(){@Override public void onClick(DialogInterface dialog, int which) { 132 | cm.setPrimaryClip(ClipData.newPlainText(null, mainList.get(position).get("view"))); 133 | }}).show(); 134 | break; 135 | case R.id.menu_delete: 136 | delete(mainList.get(position).get("view")); 137 | cmd("cp -f " + backupPath + " " + sPath); 138 | if (!isRead) cmd("chmod 660 " + sPath); 139 | Toast.makeText(ViewActivity.this, "已删除", Toast.LENGTH_SHORT).show(); 140 | 141 | mainList.clear(); 142 | start(); 143 | 144 | break; 145 | default: 146 | return false; 147 | } 148 | return true; 149 | } 150 | }); 151 | popup.show(); 152 | } 153 | }); 154 | } 155 | } 156 | 157 | } 158 | 159 | 160 | public ArrayList> get(String path, int i) { 161 | try { 162 | ReadFile file = new ReadFile(path, i); // i为读取模式。1-常规模式,2-更多WiFi模式。 163 | return file.getList(this.context); 164 | } catch (Exception e) { 165 | Toast.makeText(this, "VAget: " + e.getMessage(), Toast.LENGTH_LONG).show(); 166 | return null; 167 | } 168 | } 169 | 170 | 171 | @Override 172 | protected void onStart() { 173 | super.onStart(); 174 | if (isMore) { 175 | ActionBar actionBar = this.getActionBar(); 176 | actionBar.setDisplayHomeAsUpEnabled(true); 177 | } 178 | 179 | } 180 | 181 | 182 | @Override 183 | public boolean onCreateOptionsMenu(Menu menu) { 184 | super.onCreateOptionsMenu(menu); 185 | menu.add(0,0,0,"刷新列表"); 186 | menu.add(0,1,0,"显示更多 WiFi"); 187 | menu.add(0,2,0,"打开 WiFi 设置"); 188 | menu.add(0,3,0,"备份与恢复"); 189 | menu.add(0,4,0,"关于"); 190 | menu.add(0,5,0,"获取列表出错"); 191 | menu.getItem(5).setEnabled(false); 192 | if (mainList != null) menu.getItem(5).setTitle("共 " + mainList.size() + " 条WiFi"); 193 | if (isRead || isMore) { 194 | menu.getItem(2).setVisible(false); 195 | menu.getItem(3).setVisible(false); 196 | menu.getItem(4).setVisible(false); 197 | } 198 | if (isRead) { 199 | menu.getItem(0).setVisible(false); 200 | menu.add(0,6,0,"返回"); 201 | } 202 | if (isMore) menu.getItem(1).setVisible(false); 203 | return true; 204 | } 205 | 206 | 207 | @Override 208 | public boolean onPrepareOptionsMenu(Menu menu) { 209 | super.onPrepareOptionsMenu(menu); 210 | if (mainList != null) menu.getItem(5).setTitle("共 " + mainList.size() + " 条WiFi"); 211 | return super.onPrepareOptionsMenu(menu); 212 | } 213 | 214 | 215 | @Override 216 | public boolean onOptionsItemSelected(MenuItem item) { 217 | switch (item.getItemId()) { 218 | case 0: // 刷新列表 219 | mainList.clear(); 220 | start(); 221 | Toast.makeText(this, "刷新成功", Toast.LENGTH_SHORT).show(); 222 | return true; 223 | case 1: // 显示更多 WiFi 224 | Intent intent = new Intent(); 225 | intent.setClass(ViewActivity.this, ViewActivity.class); 226 | intent.putExtra("path", sPath); 227 | intent.putExtra("more", true); 228 | startActivity(intent); 229 | return true; 230 | case 2: // 打开 WiFi 设置 231 | startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)); 232 | return true; 233 | case 3: // 备份与恢复 234 | startActivity(new Intent().setClassName("com.zzz.wifiview", "com.zzz.wifiview.FileActivity")); 235 | return true; 236 | case 4: // 关于 237 | showAboutDialog(); 238 | return true; 239 | case 6: // 返回 240 | finish(); 241 | return true; 242 | case android.R.id.home: // 左上角返回 243 | finish(); 244 | return true; 245 | default: 246 | return super.onOptionsItemSelected(item); 247 | } 248 | } 249 | 250 | 251 | private void delete(String ss) { 252 | String s = ""; 253 | Process process = null; 254 | DataOutputStream os = null; 255 | BufferedReader br = null; 256 | OutputStreamWriter pw = null; 257 | try { 258 | process = Runtime.getRuntime().exec("su"); 259 | os = new DataOutputStream(process.getOutputStream()); 260 | os.writeBytes("cat " + sPath + "\n"); 261 | os.writeBytes("exit\n"); 262 | os.flush(); 263 | 264 | br = new BufferedReader(new InputStreamReader(process.getInputStream())); 265 | String line = null; 266 | while ((line = br.readLine()) != null) { 267 | s += line.trim() + "\n"; 268 | } 269 | pw = new OutputStreamWriter(new FileOutputStream(backupPath), "UTF-8"); 270 | s = s.replace(ss,""); 271 | pw.write(s); 272 | } catch (IOException e) { 273 | e.printStackTrace(); 274 | Toast.makeText(ViewActivity.this, "VAdelete: " + e, Toast.LENGTH_LONG).show(); 275 | } finally { 276 | try { 277 | if (os != null) { 278 | os.close(); 279 | } 280 | if (br != null) { 281 | br.close(); 282 | } 283 | if (pw != null) { 284 | pw.close(); 285 | } 286 | process.destroy(); 287 | } catch (Exception e) { 288 | e.printStackTrace(); 289 | Toast.makeText(this, "VAdeleteF: " + e.getMessage(), Toast.LENGTH_LONG).show(); 290 | } 291 | } 292 | } 293 | 294 | 295 | private void showAboutDialog() { 296 | final String[] items = {"版本: 12", "应用信息", "置顶当前连接的WiFi", "开放源代码", "Copyright © 2016 - 2021 JamGmilk."}; 297 | AlertDialog.Builder AboutDialog = new AlertDialog.Builder(this) 298 | .setTitle("WiFi View") 299 | .setIcon(com.zzz.wifiview.R.drawable.ic) 300 | .setItems(items, new DialogInterface.OnClickListener() { 301 | @Override 302 | public void onClick(DialogInterface dialog, int which) { 303 | switch (which) { 304 | case 0: 305 | Toast.makeText(ViewActivity.this, "版本代号: 40", Toast.LENGTH_SHORT).show(); 306 | break; 307 | case 1: 308 | Intent intent = new Intent(); 309 | intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 310 | intent.setData(Uri.parse("package:com.zzz.wifiview")); 311 | startActivity(intent); 312 | break; 313 | case 2: 314 | showPermissionsDialog(); 315 | break; 316 | case 3: 317 | Uri uri2 = Uri.parse("https://github.com/JamGmilk/WiFi-View"); 318 | Intent intent2 = new Intent(Intent.ACTION_VIEW, uri2); 319 | startActivity(intent2); 320 | break; 321 | } 322 | } 323 | }); 324 | AboutDialog.create().show(); 325 | } 326 | 327 | 328 | private void showPermissionsDialog() { 329 | AlertDialog.Builder permissionsDialog = new AlertDialog.Builder(this); 330 | permissionsDialog.setTitle("置顶当前连接WiFi"); 331 | permissionsDialog.setMessage("在 Android 8.0 以后,软件扫描 WLAN 需要满足以下所有条件:\n① 授予软件精确位置权限;\n② 设备已启用位置服务。\n\n仅用于置顶当前连接的WiFi。"); 332 | permissionsDialog.setPositiveButton("前往授权",new DialogInterface.OnClickListener() { 333 | @Override 334 | public void onClick(DialogInterface dialog,int which) { 335 | Intent intent = new Intent(); 336 | intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 337 | intent.setData(Uri.parse("package:com.zzz.wifiview")); 338 | startActivity(new Intent().setClassName("com.zzz.wifiview", "com.zzz.wifiview.ViewActivity")); 339 | startActivity(intent); 340 | finish(); 341 | } 342 | }); 343 | permissionsDialog.setNegativeButton("关闭", null); 344 | permissionsDialog.show(); 345 | } 346 | 347 | public void cmd(String command) { 348 | Process process = null; 349 | DataOutputStream os = null; 350 | try { 351 | process = Runtime.getRuntime().exec("su"); 352 | os = new DataOutputStream(process.getOutputStream()); 353 | os.writeBytes(command + "\n"); 354 | os.writeBytes("exit\n"); 355 | os.flush(); 356 | process.waitFor(); 357 | } catch (Exception e) { 358 | e.printStackTrace(); 359 | Toast.makeText(this, "VAcmd: " + e.getMessage(), Toast.LENGTH_LONG).show(); 360 | } finally { 361 | try { 362 | if (os != null) { 363 | os.close(); 364 | } 365 | process.destroy(); 366 | } catch (Exception e) { 367 | e.printStackTrace(); 368 | Toast.makeText(this, "VAcmdF: " + e.getMessage(), Toast.LENGTH_LONG).show(); 369 | } 370 | } 371 | } 372 | 373 | 374 | } 375 | --------------------------------------------------------------------------------