├── .github ├── ISSUE_TEMPLATE │ ├── bug-report-en.md │ ├── bug-report-zh_cn.md │ ├── feature_request-en.md │ └── feature_request-zh_cn.md └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── AUTHORS ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── executableSo │ └── .gitignore ├── proguard-rules.pro ├── schemas │ ├── io.nekohasekai.sagernet.database.SagerDatabase │ │ ├── 1.json │ │ ├── 2.json │ │ ├── 3.json │ │ ├── 4.json │ │ └── 5.json │ ├── io.nekohasekai.sagernet.database.preference.PublicDatabase │ │ └── 1.json │ └── moe.matsuri.nb4a.TempDatabase │ │ └── 1.json └── src │ └── main │ ├── AndroidManifest.xml │ ├── aidl │ └── io │ │ └── nekohasekai │ │ └── sagernet │ │ └── aidl │ │ ├── ISagerNetService.aidl │ │ ├── ISagerNetServiceCallback.aidl │ │ ├── SpeedDisplayData.aidl │ │ └── TrafficData.aidl │ ├── assets │ ├── LICENSE │ ├── analysis.txt │ ├── proxy_packagename.txt │ ├── yacd.version.txt │ └── yacd.zip │ ├── ic_launcher-playstore.png │ ├── java │ ├── com │ │ ├── github │ │ │ └── shadowsocks │ │ │ │ └── plugin │ │ │ │ ├── Utils.kt │ │ │ │ └── fragment │ │ │ │ └── AlertDialogFragment.kt │ │ └── wireguard │ │ │ └── crypto │ │ │ ├── Curve25519.java │ │ │ ├── Ed25519.java │ │ │ ├── Key.java │ │ │ ├── KeyFormatException.java │ │ │ └── KeyPair.java │ ├── io │ │ └── nekohasekai │ │ │ └── sagernet │ │ │ ├── BootReceiver.kt │ │ │ ├── Constants.kt │ │ │ ├── QuickToggleShortcut.kt │ │ │ ├── SagerNet.kt │ │ │ ├── aidl │ │ │ ├── SpeedDisplayData.kt │ │ │ └── TrafficData.kt │ │ │ ├── bg │ │ │ ├── AbstractInstance.kt │ │ │ ├── BaseService.kt │ │ │ ├── Executable.kt │ │ │ ├── GuardedProcessPool.kt │ │ │ ├── ProxyService.kt │ │ │ ├── SagerConnection.kt │ │ │ ├── ServiceNotification.kt │ │ │ ├── SubscriptionUpdater.kt │ │ │ ├── TileService.kt │ │ │ ├── VpnService.kt │ │ │ └── proto │ │ │ │ ├── BoxInstance.kt │ │ │ │ ├── ProxyInstance.kt │ │ │ │ ├── TestInstance.kt │ │ │ │ ├── TrafficLooper.kt │ │ │ │ ├── TrafficUpdater.kt │ │ │ │ └── UrlTest.kt │ │ │ ├── database │ │ │ ├── DataStore.kt │ │ │ ├── GroupManager.kt │ │ │ ├── ParcelizeBridge.java │ │ │ ├── ProfileManager.kt │ │ │ ├── ProxyEntity.kt │ │ │ ├── ProxyGroup.kt │ │ │ ├── RuleEntity.kt │ │ │ ├── SagerDatabase.kt │ │ │ ├── StringCollectionConverter.kt │ │ │ ├── SubscriptionBean.java │ │ │ └── preference │ │ │ │ ├── EditTextPreferenceModifiers.kt │ │ │ │ ├── KeyValuePair.kt │ │ │ │ ├── OnPreferenceDataStoreChangeListener.kt │ │ │ │ ├── PublicDatabase.kt │ │ │ │ └── RoomPreferenceDataStore.kt │ │ │ ├── fmt │ │ │ ├── AbstractBean.java │ │ │ ├── ConfigBuilder.kt │ │ │ ├── KryoConverters.java │ │ │ ├── PluginEntry.kt │ │ │ ├── Serializable.kt │ │ │ ├── TypeMap.kt │ │ │ ├── UniversalFmt.kt │ │ │ ├── gson │ │ │ │ └── GsonConverters.java │ │ │ ├── http │ │ │ │ ├── HttpBean.java │ │ │ │ └── HttpFmt.kt │ │ │ ├── hysteria │ │ │ │ ├── HysteriaBean.java │ │ │ │ └── HysteriaFmt.kt │ │ │ ├── internal │ │ │ │ ├── ChainBean.java │ │ │ │ └── InternalBean.java │ │ │ ├── mieru │ │ │ │ ├── MieruBean.java │ │ │ │ └── MieruFmt.kt │ │ │ ├── naive │ │ │ │ ├── NaiveBean.java │ │ │ │ └── NaiveFmt.kt │ │ │ ├── shadowsocks │ │ │ │ ├── ShadowsocksBean.java │ │ │ │ └── ShadowsocksFmt.kt │ │ │ ├── socks │ │ │ │ ├── SOCKSBean.java │ │ │ │ └── SOCKSFmt.kt │ │ │ ├── ssh │ │ │ │ ├── SSHBean.java │ │ │ │ └── SSHFmt.kt │ │ │ ├── trojan │ │ │ │ ├── TrojanBean.java │ │ │ │ └── TrojanFmt.kt │ │ │ ├── trojan_go │ │ │ │ ├── TrojanGoBean.java │ │ │ │ └── TrojanGoFmt.kt │ │ │ ├── tuic │ │ │ │ ├── TuicBean.java │ │ │ │ └── TuicFmt.kt │ │ │ ├── v2ray │ │ │ │ ├── StandardV2RayBean.java │ │ │ │ ├── V2RayFmt.kt │ │ │ │ └── VMessBean.java │ │ │ └── wireguard │ │ │ │ ├── WireGuardBean.java │ │ │ │ └── WireGuardFmt.kt │ │ │ ├── group │ │ │ ├── GroupInterfaceAdapter.kt │ │ │ ├── GroupUpdater.kt │ │ │ └── RawUpdater.kt │ │ │ ├── ktx │ │ │ ├── Asyncs.kt │ │ │ ├── Browsers.kt │ │ │ ├── Dialogs.kt │ │ │ ├── Dimens.kt │ │ │ ├── Formats.kt │ │ │ ├── Kryos.kt │ │ │ ├── Layouts.kt │ │ │ ├── Logs.kt │ │ │ ├── Nets.kt │ │ │ ├── Preferences.kt │ │ │ └── Utils.kt │ │ │ ├── plugin │ │ │ └── PluginManager.kt │ │ │ ├── ui │ │ │ ├── AboutFragment.kt │ │ │ ├── AppListActivity.kt │ │ │ ├── AppManagerActivity.kt │ │ │ ├── AssetsActivity.kt │ │ │ ├── BackupFragment.kt │ │ │ ├── BlankActivity.kt │ │ │ ├── ConfigurationFragment.kt │ │ │ ├── DebugFragment.kt │ │ │ ├── GroupFragment.kt │ │ │ ├── GroupSettingsActivity.kt │ │ │ ├── LogcatFragment.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MessageStore.kt │ │ │ ├── NamedFragment.kt │ │ │ ├── NetworkFragment.kt │ │ │ ├── ProfileSelectActivity.kt │ │ │ ├── RouteFragment.kt │ │ │ ├── RouteSettingsActivity.kt │ │ │ ├── ScannerActivity.kt │ │ │ ├── SettingsFragment.kt │ │ │ ├── SettingsPreferenceFragment.kt │ │ │ ├── StunActivity.kt │ │ │ ├── SwitchActivity.kt │ │ │ ├── ThemedActivity.kt │ │ │ ├── ToolbarFragment.kt │ │ │ ├── ToolsFragment.kt │ │ │ ├── VpnRequestActivity.kt │ │ │ ├── WebDAVSettingsActivity.kt │ │ │ ├── WebviewFragment.kt │ │ │ └── profile │ │ │ │ ├── ChainSettingsActivity.kt │ │ │ │ ├── ConfigEditActivity.kt │ │ │ │ ├── HttpSettingsActivity.kt │ │ │ │ ├── HysteriaSettingsActivity.kt │ │ │ │ ├── MieruSettingsActivity.kt │ │ │ │ ├── NaiveSettingsActivity.kt │ │ │ │ ├── ProfileSettingsActivity.kt │ │ │ │ ├── SSHSettingsActivity.kt │ │ │ │ ├── ShadowsocksSettingsActivity.kt │ │ │ │ ├── SocksSettingsActivity.kt │ │ │ │ ├── StandardV2RaySettingsActivity.kt │ │ │ │ ├── TrojanGoSettingsActivity.kt │ │ │ │ ├── TrojanSettingsActivity.kt │ │ │ │ ├── TuicSettingsActivity.kt │ │ │ │ ├── VMessSettingsActivity.kt │ │ │ │ └── WireGuardSettingsActivity.kt │ │ │ ├── utils │ │ │ ├── Cloudflare.kt │ │ │ ├── Commandline.kt │ │ │ ├── CrashHandler.kt │ │ │ ├── DefaultNetworkListener.kt │ │ │ ├── PackageCache.kt │ │ │ ├── Subnet.kt │ │ │ ├── Theme.kt │ │ │ └── cf │ │ │ │ ├── DeviceResponse.kt │ │ │ │ ├── RegisterRequest.kt │ │ │ │ └── UpdateDeviceRequest.kt │ │ │ └── widget │ │ │ ├── AppListPreference.kt │ │ │ ├── AutoCollapseTextView.kt │ │ │ ├── FabProgressBehavior.kt │ │ │ ├── GroupPreference.kt │ │ │ ├── LinkOrContentPreference.kt │ │ │ ├── OutboundPreference.kt │ │ │ ├── QRCodeDialog.kt │ │ │ ├── ServiceButton.kt │ │ │ ├── StatsBar.kt │ │ │ ├── UndoSnackbarManager.kt │ │ │ ├── UserAgentPreference.kt │ │ │ └── WindowInsetsListeners.kt │ └── moe │ │ └── matsuri │ │ └── nb4a │ │ ├── NativeInterface.kt │ │ ├── Protocols.kt │ │ ├── SingBoxOptions.java │ │ ├── SingBoxOptionsUtil.kt │ │ ├── TempDatabase.kt │ │ ├── net │ │ └── LocalResolverImpl.kt │ │ ├── plugin │ │ └── Plugins.kt │ │ ├── proxy │ │ ├── PreferenceBinding.kt │ │ ├── PreferenceBindingManager.kt │ │ ├── anytls │ │ │ ├── AnyTLSBean.java │ │ │ ├── AnyTLSFmt.kt │ │ │ └── AnyTLSSettingsActivity.kt │ │ ├── config │ │ │ ├── ConfigBean.java │ │ │ └── ConfigSettingActivity.kt │ │ ├── neko │ │ │ └── NekoBean.java │ │ └── shadowtls │ │ │ ├── ShadowTLSBean.java │ │ │ ├── ShadowTLSFmt.kt │ │ │ └── ShadowTLSSettingsActivity.kt │ │ ├── ui │ │ ├── ColorPickerPreference.kt │ │ ├── Dialogs.kt │ │ ├── EditConfigPreference.kt │ │ ├── ExtendedKeyboard.kt │ │ ├── LongClickListPreference.kt │ │ ├── LongClickMenuPreference.kt │ │ ├── LongClickSwitchPreference.kt │ │ ├── MTUPreference.kt │ │ ├── SimpleMenuPreference.kt │ │ └── UrlTestPreference.kt │ │ └── utils │ │ ├── JavaUtil.java │ │ ├── KotlinUtil.kt │ │ ├── NGUtil.kt │ │ ├── SendLog.kt │ │ ├── Util.kt │ │ └── WebViewUtil.kt │ └── res │ ├── color │ ├── chip_background.xml │ ├── chip_ripple_color.xml │ ├── chip_text_color.xml │ ├── navigation_icon.xml │ └── navigation_item.xml │ ├── drawable-v26 │ ├── ic_qu_camera_launcher.xml │ └── ic_qu_shadowsocks_launcher.xml │ ├── drawable │ ├── baseline_arrow_back_24.xml │ ├── baseline_construction_24.xml │ ├── baseline_delete_sweep_24.xml │ ├── baseline_developer_board_24.xml │ ├── baseline_flight_takeoff_24.xml │ ├── baseline_keyboard_tab_24.xml │ ├── baseline_public_24.xml │ ├── baseline_redo_24.xml │ ├── baseline_save_24.xml │ ├── baseline_send_24.xml │ ├── baseline_translate_24.xml │ ├── baseline_undo_24.xml │ ├── baseline_widgets_24.xml │ ├── baseline_wrap_text_24.xml │ ├── ic_action_copyright.xml │ ├── ic_action_delete.xml │ ├── ic_action_description.xml │ ├── ic_action_dns.xml │ ├── ic_action_done.xml │ ├── ic_action_lock.xml │ ├── ic_action_lock_open.xml │ ├── ic_action_note_add.xml │ ├── ic_action_settings.xml │ ├── ic_app_shortcut_background.xml │ ├── ic_av_playlist_add.xml │ ├── ic_baseline_add_road_24.xml │ ├── ic_baseline_airplanemode_active_24.xml │ ├── ic_baseline_android_24.xml │ ├── ic_baseline_bug_report_24.xml │ ├── ic_baseline_camera_24.xml │ ├── ic_baseline_card_giftcard_24.xml │ ├── ic_baseline_cast_connected_24.xml │ ├── ic_baseline_center_focus_weak_24.xml │ ├── ic_baseline_color_lens_24.xml │ ├── ic_baseline_compare_arrows_24.xml │ ├── ic_baseline_delete_24.xml │ ├── ic_baseline_domain_24.xml │ ├── ic_baseline_download_24.xml │ ├── ic_baseline_emoji_emotions_24.xml │ ├── ic_baseline_fast_forward_24.xml │ ├── ic_baseline_fiber_manual_record_24.xml │ ├── ic_baseline_fingerprint_24.xml │ ├── ic_baseline_flip_camera_android_24.xml │ ├── ic_baseline_format_align_left_24.xml │ ├── ic_baseline_grid_3x3_24.xml │ ├── ic_baseline_home_24.xml │ ├── ic_baseline_http_24.xml │ ├── ic_baseline_https_24.xml │ ├── ic_baseline_import_contacts_24.xml │ ├── ic_baseline_info_24.xml │ ├── ic_baseline_layers_24.xml │ ├── ic_baseline_legend_toggle_24.xml │ ├── ic_baseline_link_24.xml │ ├── ic_baseline_local_bar_24.xml │ ├── ic_baseline_location_on_24.xml │ ├── ic_baseline_lock_24.xml │ ├── ic_baseline_low_priority_24.xml │ ├── ic_baseline_manage_search_24.xml │ ├── ic_baseline_more_vert_24.xml │ ├── ic_baseline_multiline_chart_24.xml │ ├── ic_baseline_multiple_stop_24.xml │ ├── ic_baseline_nat_24.xml │ ├── ic_baseline_nfc_24.xml │ ├── ic_baseline_no_encryption_gmailerrorred_24.xml │ ├── ic_baseline_person_24.xml │ ├── ic_baseline_push_pin_24.xml │ ├── ic_baseline_refresh_24.xml │ ├── ic_baseline_rule_folder_24.xml │ ├── ic_baseline_running_with_errors_24.xml │ ├── ic_baseline_sanitizer_24.xml │ ├── ic_baseline_security_24.xml │ ├── ic_baseline_shuffle_24.xml │ ├── ic_baseline_shutter_speed_24.xml │ ├── ic_baseline_speed_24.xml │ ├── ic_baseline_stream_24.xml │ ├── ic_baseline_texture_24.xml │ ├── ic_baseline_timelapse_24.xml │ ├── ic_baseline_transform_24.xml │ ├── ic_baseline_transgender_24.xml │ ├── ic_baseline_update_24.xml │ ├── ic_baseline_view_list_24.xml │ ├── ic_baseline_vpn_key_24.xml │ ├── ic_baseline_warning_24.xml │ ├── ic_baseline_wb_sunny_24.xml │ ├── ic_communication_phonelink_ring.xml │ ├── ic_device_data_usage.xml │ ├── ic_device_developer_mode.xml │ ├── ic_file_cloud_queue.xml │ ├── ic_file_file_upload.xml │ ├── ic_hardware_router.xml │ ├── ic_image_camera_alt.xml │ ├── ic_image_edit.xml │ ├── ic_image_looks_6.xml │ ├── ic_image_photo.xml │ ├── ic_maps_360.xml │ ├── ic_maps_directions.xml │ ├── ic_maps_directions_boat.xml │ ├── ic_navigation_apps.xml │ ├── ic_navigation_close.xml │ ├── ic_navigation_menu.xml │ ├── ic_notification_enhanced_encryption.xml │ ├── ic_qu_camera_launcher.xml │ ├── ic_qu_shadowsocks_foreground.xml │ ├── ic_qu_shadowsocks_launcher.xml │ ├── ic_service_active.xml │ ├── ic_service_busy.xml │ ├── ic_service_connected.xml │ ├── ic_service_connecting.xml │ ├── ic_service_idle.xml │ ├── ic_service_stopped.xml │ ├── ic_service_stopping.xml │ ├── ic_settings_password.xml │ ├── ic_social_emoji_symbols.xml │ ├── ic_social_share.xml │ └── terminal_scroll_shape.xml │ ├── font │ └── jetbrains_mono.ttf │ ├── layout │ ├── item_keyboard_key.xml │ ├── layout_about.xml │ ├── layout_add_entity.xml │ ├── layout_app_list.xml │ ├── layout_appbar.xml │ ├── layout_apps.xml │ ├── layout_apps_item.xml │ ├── layout_asset_item.xml │ ├── layout_assets.xml │ ├── layout_backup.xml │ ├── layout_chain_settings.xml │ ├── layout_config_settings.xml │ ├── layout_debug.xml │ ├── layout_edit_config.xml │ ├── layout_edit_group.xml │ ├── layout_empty.xml │ ├── layout_empty_route.xml │ ├── layout_group.xml │ ├── layout_group_item.xml │ ├── layout_group_list.xml │ ├── layout_icon_list_item_2.xml │ ├── layout_import.xml │ ├── layout_loading.xml │ ├── layout_logcat.xml │ ├── layout_loglevel_help.xml │ ├── layout_main.xml │ ├── layout_mtu_help.xml │ ├── layout_network.xml │ ├── layout_password_dialog.xml │ ├── layout_profile.xml │ ├── layout_profile_list.xml │ ├── layout_progress.xml │ ├── layout_progress_list.xml │ ├── layout_route.xml │ ├── layout_route_item.xml │ ├── layout_scanner.xml │ ├── layout_settings_activity.xml │ ├── layout_stun.xml │ ├── layout_tools.xml │ ├── layout_urltest_preference_dialog.xml │ ├── layout_webdav_settings.xml │ ├── layout_webview.xml │ └── simple_menu_dropdown_item.xml │ ├── menu │ ├── add_group_menu.xml │ ├── add_profile_menu.xml │ ├── add_route_menu.xml │ ├── app_list_menu.xml │ ├── app_list_neko_menu.xml │ ├── group_action_menu.xml │ ├── import_asset_menu.xml │ ├── logcat_menu.xml │ ├── main_drawer_menu.xml │ ├── per_app_proxy_menu.xml │ ├── profile_apply_menu.xml │ ├── profile_config_menu.xml │ ├── profile_share_menu.xml │ ├── scanner_menu.xml │ ├── traffic_item_menu.xml │ ├── traffic_menu.xml │ └── yacd_menu.xml │ ├── mipmap-anydpi-v26 │ └── ic_launcher.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_foreground.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_foreground.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_foreground.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_foreground.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_foreground.png │ ├── raw-zh-rCN │ ├── insecure.txt │ ├── not_encrypted.txt │ ├── shadowsocks_stream_cipher.txt │ └── vmess_md5_auth.txt │ ├── raw │ ├── insecure.txt │ ├── not_encrypted.txt │ ├── shadowsocks_stream_cipher.txt │ └── vmess_md5_auth.txt │ ├── resources.properties │ ├── values-ar │ └── strings.xml │ ├── values-be │ └── strings.xml │ ├── values-de │ └── strings.xml │ ├── values-es │ └── strings.xml │ ├── values-fa │ └── strings.xml │ ├── values-fr │ └── strings.xml │ ├── values-in │ └── strings.xml │ ├── values-it │ └── strings.xml │ ├── values-ja │ └── strings.xml │ ├── values-ko │ └── strings.xml │ ├── values-nb-rNO │ └── strings.xml │ ├── values-night │ └── colors.xml │ ├── values-nl │ └── strings.xml │ ├── values-pt-rBR │ └── strings.xml │ ├── values-ru │ └── strings.xml │ ├── values-tr │ └── strings.xml │ ├── values-uk │ └── strings.xml │ ├── values-zh-rCN │ └── strings.xml │ ├── values-zh-rHK │ └── strings.xml │ ├── values-zh-rTW │ └── strings.xml │ ├── values │ ├── arrays.xml │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── anytls_preferences.xml │ ├── backup_descriptor.xml │ ├── backup_rules.xml │ ├── balancer_preferences.xml │ ├── cache_paths.xml │ ├── config_preferences.xml │ ├── global_preferences.xml │ ├── group_preferences.xml │ ├── hysteria_preferences.xml │ ├── mieru_preferences.xml │ ├── naive_preferences.xml │ ├── name_preferences.xml │ ├── neko_preferences.xml │ ├── network_security_config.xml │ ├── route_preferences.xml │ ├── shadowsocks_preferences.xml │ ├── shadowtls_preferences.xml │ ├── shortcuts.xml │ ├── socks_preferences.xml │ ├── ssh_preferences.xml │ ├── standard_v2ray_preferences.xml │ ├── trojan_go_preferences.xml │ ├── tuic_preferences.xml │ ├── webdav_preferences.xml │ └── wireguard_preferences.xml ├── build.gradle.kts ├── buildScript ├── copyLocal.sh ├── fdroid │ └── prebuild.sh ├── init │ ├── action │ │ └── gradle.sh │ ├── env.sh │ └── env_ndk.sh ├── lib │ ├── assets.sh │ ├── core.sh │ └── core │ │ ├── build.sh │ │ ├── get_source.sh │ │ ├── get_source_env.sh │ │ └── init.sh └── nkmr ├── buildSrc ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── Helpers.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── libcore ├── .gitignore ├── LICENSE ├── assets.go ├── assets_android.go ├── assets_other.go ├── box.go ├── box_include.go ├── build.sh ├── certs.go ├── crypto.go ├── device │ ├── debug.go │ └── device.go ├── dns_box.go ├── fix.go ├── geoip.go ├── geosite.go ├── go.mod ├── go.sum ├── http.go ├── init.sh ├── interface_monitor.go ├── io.go ├── nb4a.go ├── platform_box.go ├── platform_java.go ├── procfs │ └── procfs.go ├── stun.go └── stun │ ├── README │ ├── attribute.go │ ├── client.go │ ├── const.go │ ├── discover.go │ ├── doc.go │ ├── host.go │ ├── log.go │ ├── net.go │ ├── packet.go │ ├── response.go │ ├── tests.go │ └── utils.go ├── lint.xml ├── nb4a.properties ├── release.keystore ├── repositories.gradle.kts ├── run └── settings.gradle.kts /.github/ISSUE_TEMPLATE/bug-report-en.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Bug Report' 3 | about: 'Please troubleshoot server-side issues and upgrade to the latest client before raising a question.' 4 | title: 'BUG: ' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Describe the problem 11 | 12 | Expected behavior: 13 | 14 | Actual behavior: 15 | 16 | ## How to reproduce 17 | 18 | Provide helpful screenshots, videos, text descriptions, subscription links, etc. 19 | 20 | ## log 21 | 22 | If you have logs, please upload them. Please see the detailed steps for exporting logs in the documentation. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report-zh_cn.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '问题反馈' 3 | about: '在提出问题前请先自行排除服务器端问题和升级到最新客户端。' 4 | title: 'BUG: ' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## 描述问题 11 | 12 | 预期行为: 13 | 14 | 实际行为: 15 | 16 | ## 如何复现 17 | 18 | 提供有帮助的截图,录像,文字说明,订阅链接等。 19 | 20 | ## 日志 21 | 22 | 如果有日志,请上传。请在文档内查看导出日志的详细步骤。 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request-en.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Feature Request' 3 | about: 'Make suggestions for new features of the software' 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Description suggestions 11 | 12 | ## Necessity of recommendations 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request-zh_cn.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '功能请求' 3 | about: '对软件的新功能提出建议。' 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## 描述建议 11 | 12 | ## 建议的必要性 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | .vscode 5 | .DS_Store 6 | build/ 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | local.properties 11 | /app/libs/ 12 | /app/src/main/assets/sing-box 13 | /service_account_credentials.json 14 | jniLibs/ 15 | /library/libcore_build/ 16 | .idea/deploymentTargetDropDown.xml 17 | /nkmr 18 | 19 | # submodules 20 | /external 21 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | SagerNet was originally created in late 2021, by 2 | nekohasekai . 3 | 4 | Here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS -- 5 | people who have submitted patches, fixed bugs, added translations, and 6 | generally made SagerNet that much better: 7 | 8 | https://github.com/SagerNet/SagerNet/graphs/contributors 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2021 by nekohasekai 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/executableSo/.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | -------------------------------------------------------------------------------- /app/src/main/aidl/io/nekohasekai/sagernet/aidl/ISagerNetService.aidl: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.aidl; 2 | 3 | import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback; 4 | 5 | interface ISagerNetService { 6 | int getState(); 7 | String getProfileName(); 8 | 9 | void registerCallback(in ISagerNetServiceCallback cb, int id); 10 | oneway void unregisterCallback(in ISagerNetServiceCallback cb); 11 | 12 | int urlTest(); 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/aidl/io/nekohasekai/sagernet/aidl/ISagerNetServiceCallback.aidl: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.aidl; 2 | 3 | import io.nekohasekai.sagernet.aidl.SpeedDisplayData; 4 | import io.nekohasekai.sagernet.aidl.TrafficData; 5 | 6 | oneway interface ISagerNetServiceCallback { 7 | void stateChanged(int state, String profileName, String msg); 8 | void missingPlugin(String profileName, String pluginName); 9 | void cbSpeedUpdate(in SpeedDisplayData stats); 10 | void cbTrafficUpdate(in TrafficData stats); 11 | void cbSelectorUpdate(long id); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/aidl/io/nekohasekai/sagernet/aidl/SpeedDisplayData.aidl: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.aidl; 2 | 3 | parcelable SpeedDisplayData; 4 | -------------------------------------------------------------------------------- /app/src/main/aidl/io/nekohasekai/sagernet/aidl/TrafficData.aidl: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.aidl; 2 | 3 | parcelable TrafficData; 4 | -------------------------------------------------------------------------------- /app/src/main/assets/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2021 by nekohasekai 2 | 3 | 4 | This program is free software: you can 5 | redistribute it and/or modify it under 6 | the terms of the GNU General Public License 7 | as published by the Free Software Foundation, 8 | either version 3 of the License, 9 | or (at your option) any later version. 10 | 11 | This program is distributed in the hope 12 | that it will be useful, but WITHOUT ANY WARRANTY; 13 | without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | See the GNU General Public License for more details. 16 | 17 | You should have received a copy of the 18 | GNU General Public License along with this program. 19 | If not, see . -------------------------------------------------------------------------------- /app/src/main/assets/analysis.txt: -------------------------------------------------------------------------------- 1 | domain:appcenter.ms 2 | domain:firebase.io 3 | domain:crashlytics.com 4 | -------------------------------------------------------------------------------- /app/src/main/assets/yacd.version.txt: -------------------------------------------------------------------------------- 1 | 3 -------------------------------------------------------------------------------- /app/src/main/assets/yacd.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/starifly/NekoBoxForAndroid/90b94e480e618f1d04662b976125d1ef0e209926/app/src/main/assets/yacd.zip -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/starifly/NekoBoxForAndroid/90b94e480e618f1d04662b976125d1ef0e209926/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/com/github/shadowsocks/plugin/Utils.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("Utils") 2 | 3 | package com.github.shadowsocks.plugin 4 | 5 | import android.os.Parcelable 6 | import kotlinx.parcelize.Parcelize 7 | 8 | @Parcelize 9 | class Empty : Parcelable -------------------------------------------------------------------------------- /app/src/main/java/com/wireguard/crypto/KeyFormatException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018-2019 WireGuard LLC. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | package com.wireguard.crypto; 7 | 8 | /** 9 | * An exception thrown when attempting to parse an invalid key (too short, too long, or byte 10 | * data inappropriate for the format). The format being parsed can be accessed with the 11 | * {@link #getFormat} method. 12 | */ 13 | public final class KeyFormatException extends Exception { 14 | private final Key.Format format; 15 | private final Type type; 16 | 17 | KeyFormatException(final Key.Format format, final Type type) { 18 | this.format = format; 19 | this.type = type; 20 | } 21 | 22 | public Key.Format getFormat() { 23 | return format; 24 | } 25 | 26 | public Type getType() { 27 | return type; 28 | } 29 | 30 | public enum Type { 31 | CONTENTS, 32 | LENGTH 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/wireguard/crypto/KeyPair.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | package com.wireguard.crypto; 7 | 8 | /** 9 | * Represents a Curve25519 key pair as used by WireGuard. 10 | *

11 | * Instances of this class are immutable. 12 | */ 13 | public class KeyPair { 14 | private final Key privateKey; 15 | private final Key publicKey; 16 | 17 | /** 18 | * Creates a key pair using a newly-generated private key. 19 | */ 20 | public KeyPair() { 21 | this(Key.generatePrivateKey()); 22 | } 23 | 24 | /** 25 | * Creates a key pair using an existing private key. 26 | * 27 | * @param privateKey a private key, used to derive the public key 28 | */ 29 | public KeyPair(final Key privateKey) { 30 | this.privateKey = privateKey; 31 | publicKey = Key.generatePublicKey(privateKey); 32 | } 33 | 34 | /** 35 | * Returns the private key from the key pair. 36 | * 37 | * @return the private key 38 | */ 39 | public Key getPrivateKey() { 40 | return privateKey; 41 | } 42 | 43 | /** 44 | * Returns the public key from the key pair. 45 | * 46 | * @return the public key 47 | */ 48 | public Key getPublicKey() { 49 | return publicKey; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/aidl/SpeedDisplayData.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.aidl 2 | 3 | import android.os.Parcelable 4 | import kotlinx.parcelize.Parcelize 5 | 6 | @Parcelize 7 | data class SpeedDisplayData( 8 | // Bytes per second 9 | var txRateProxy: Long = 0L, 10 | var rxRateProxy: Long = 0L, 11 | var txRateDirect: Long = 0L, 12 | var rxRateDirect: Long = 0L, 13 | 14 | // Bytes for the current session 15 | // Outbound "bypass" usage is not counted 16 | var txTotal: Long = 0L, 17 | var rxTotal: Long = 0L, 18 | ) : Parcelable 19 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/aidl/TrafficData.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.aidl 2 | 3 | import android.os.Parcelable 4 | import kotlinx.parcelize.Parcelize 5 | 6 | @Parcelize 7 | data class TrafficData( 8 | var id: Long = 0L, 9 | var tx: Long = 0L, 10 | var rx: Long = 0L, 11 | ) : Parcelable 12 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/bg/AbstractInstance.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.bg 2 | 3 | import java.io.Closeable 4 | 5 | interface AbstractInstance : Closeable { 6 | 7 | fun launch() 8 | 9 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/bg/ProxyService.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.bg 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Service 5 | import android.content.Intent 6 | import android.os.PowerManager 7 | import io.nekohasekai.sagernet.SagerNet 8 | 9 | class ProxyService : Service(), BaseService.Interface { 10 | override val data = BaseService.Data(this) 11 | override val tag: String get() = "SagerNetProxyService" 12 | override fun createNotification(profileName: String): ServiceNotification = 13 | ServiceNotification(this, profileName, "service-proxy", true) 14 | 15 | override var wakeLock: PowerManager.WakeLock? = null 16 | override var upstreamInterfaceName: String? = null 17 | 18 | @SuppressLint("WakelockTimeout") 19 | override fun acquireWakeLock() { 20 | wakeLock = SagerNet.power.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "sagernet:proxy") 21 | .apply { acquire() } 22 | } 23 | 24 | override fun onBind(intent: Intent) = super.onBind(intent) 25 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int = 26 | super.onStartCommand(intent, flags, startId) 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/bg/proto/UrlTest.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.bg.proto 2 | 3 | import io.nekohasekai.sagernet.database.DataStore 4 | import io.nekohasekai.sagernet.database.ProxyEntity 5 | 6 | class UrlTest { 7 | 8 | val link = DataStore.connectionTestURL 9 | private val timeout = 5000 10 | 11 | suspend fun doTest(profile: ProxyEntity): Int { 12 | return TestInstance(profile, link, timeout).doTest() 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/database/ParcelizeBridge.java: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.database; 2 | 3 | import android.os.Parcel; 4 | 5 | /** 6 | * see: https://youtrack.jetbrains.com/issue/KT-19853 7 | */ 8 | public class ParcelizeBridge { 9 | 10 | public static RuleEntity createRule(Parcel parcel) { 11 | return (RuleEntity) RuleEntity.CREATOR.createFromParcel(parcel); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/database/StringCollectionConverter.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.database 2 | 3 | import androidx.room.TypeConverter 4 | 5 | class StringCollectionConverter { 6 | companion object { 7 | const val SPLIT_FLAG = "," 8 | 9 | /* 10 | @TypeConverter 11 | @JvmStatic 12 | fun fromList(list: List): String = if (list.isEmpty()) { 13 | "" 14 | } else { 15 | list.joinToString(SPLIT_FLAG) 16 | } 17 | 18 | @TypeConverter 19 | @JvmStatic 20 | fun toList(str: String): List = if (str.isBlank()) { 21 | emptyList() 22 | } else { 23 | str.split(SPLIT_FLAG) 24 | } 25 | */ 26 | 27 | 28 | @TypeConverter 29 | @JvmStatic 30 | fun fromSet(set: Set): String = if (set.isEmpty()) { 31 | "" 32 | } else { 33 | set.joinToString(SPLIT_FLAG) 34 | } 35 | 36 | @TypeConverter 37 | @JvmStatic 38 | fun toSet(str: String): Set = if (str.isBlank()) { 39 | emptySet() 40 | } else { 41 | str.split(",").toSet() 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/database/preference/OnPreferenceDataStoreChangeListener.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.database.preference 2 | 3 | import androidx.preference.PreferenceDataStore 4 | 5 | interface OnPreferenceDataStoreChangeListener { 6 | fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.database.preference 2 | 3 | import androidx.room.Database 4 | import androidx.room.Room 5 | import androidx.room.RoomDatabase 6 | import dev.matrix.roomigrant.GenerateRoomMigrations 7 | import io.nekohasekai.sagernet.Key 8 | import io.nekohasekai.sagernet.SagerNet 9 | import kotlinx.coroutines.GlobalScope 10 | import kotlinx.coroutines.launch 11 | 12 | @Database(entities = [KeyValuePair::class], version = 1) 13 | @GenerateRoomMigrations 14 | abstract class PublicDatabase : RoomDatabase() { 15 | companion object { 16 | val instance by lazy { 17 | SagerNet.application.getDatabasePath(Key.DB_PROFILE).parentFile?.mkdirs() 18 | Room.databaseBuilder(SagerNet.application, PublicDatabase::class.java, Key.DB_PUBLIC) 19 | .allowMainThreadQueries() 20 | .enableMultiInstanceInvalidation() 21 | .fallbackToDestructiveMigration() 22 | .setQueryExecutor { GlobalScope.launch { it.run() } } 23 | .build() 24 | } 25 | 26 | val kvPairDao get() = instance.keyValuePairDao() 27 | } 28 | 29 | abstract fun keyValuePairDao(): KeyValuePair.Dao 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/fmt/Serializable.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.fmt 2 | 3 | import android.os.Parcel 4 | import android.os.Parcelable 5 | import com.esotericsoftware.kryo.io.ByteBufferInput 6 | import com.esotericsoftware.kryo.io.ByteBufferOutput 7 | 8 | abstract class Serializable : Parcelable { 9 | abstract fun initializeDefaultValues() 10 | abstract fun serializeToBuffer(output: ByteBufferOutput) 11 | abstract fun deserializeFromBuffer(input: ByteBufferInput) 12 | 13 | override fun describeContents() = 0 14 | 15 | override fun writeToParcel(dest: Parcel, flags: Int) { 16 | dest.writeByteArray(KryoConverters.serialize(this)) 17 | } 18 | 19 | abstract class CREATOR : Parcelable.Creator { 20 | abstract fun newInstance(): T 21 | 22 | override fun createFromParcel(source: Parcel): T { 23 | return KryoConverters.deserialize(newInstance(), source.createByteArray()) 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/fmt/TypeMap.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.fmt 2 | 3 | import io.nekohasekai.sagernet.database.ProxyEntity 4 | 5 | object TypeMap : HashMap() { 6 | init { 7 | this["socks"] = ProxyEntity.TYPE_SOCKS 8 | this["http"] = ProxyEntity.TYPE_HTTP 9 | this["ss"] = ProxyEntity.TYPE_SS 10 | this["vmess"] = ProxyEntity.TYPE_VMESS 11 | this["trojan"] = ProxyEntity.TYPE_TROJAN 12 | this["trojan-go"] = ProxyEntity.TYPE_TROJAN_GO 13 | this["mieru"] = ProxyEntity.TYPE_MIERU 14 | this["naive"] = ProxyEntity.TYPE_NAIVE 15 | this["hysteria"] = ProxyEntity.TYPE_HYSTERIA 16 | this["ssh"] = ProxyEntity.TYPE_SSH 17 | this["wg"] = ProxyEntity.TYPE_WG 18 | this["tuic"] = ProxyEntity.TYPE_TUIC 19 | this["anytls"] = ProxyEntity.TYPE_ANYTLS 20 | this["neko"] = ProxyEntity.TYPE_NEKO 21 | this["config"] = ProxyEntity.TYPE_CONFIG 22 | } 23 | 24 | val reversed = HashMap() 25 | 26 | init { 27 | TypeMap.forEach { (key, type) -> 28 | reversed[type] = key 29 | } 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/fmt/gson/GsonConverters.java: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.fmt.gson; 2 | 3 | import androidx.room.TypeConverter; 4 | 5 | import java.util.Collection; 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | import kotlin.collections.CollectionsKt; 10 | import kotlin.collections.SetsKt; 11 | import moe.matsuri.nb4a.utils.JavaUtil; 12 | 13 | public class GsonConverters { 14 | 15 | @TypeConverter 16 | public static String toJson(Object value) { 17 | if (value instanceof Collection) { 18 | if (((Collection) value).isEmpty()) return ""; 19 | } 20 | return JavaUtil.gson.toJson(value); 21 | } 22 | 23 | @TypeConverter 24 | public static List toList(String value) { 25 | if (JavaUtil.isNullOrBlank(value)) return CollectionsKt.listOf(); 26 | return JavaUtil.gson.fromJson(value, List.class); 27 | } 28 | 29 | @TypeConverter 30 | public static Set toSet(String value) { 31 | if (JavaUtil.isNullOrBlank(value)) return SetsKt.setOf(); 32 | return JavaUtil.gson.fromJson(value, Set.class); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/fmt/internal/InternalBean.java: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.fmt.internal; 2 | 3 | import io.nekohasekai.sagernet.fmt.AbstractBean; 4 | 5 | public abstract class InternalBean extends AbstractBean { 6 | 7 | @Override 8 | public String displayAddress() { 9 | return ""; 10 | } 11 | 12 | @Override 13 | public boolean canICMPing() { 14 | return false; 15 | } 16 | 17 | @Override 18 | public boolean canTCPing() { 19 | return false; 20 | } 21 | 22 | @Override 23 | public boolean canMapping() { 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/fmt/ssh/SSHFmt.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.fmt.ssh 2 | 3 | import moe.matsuri.nb4a.SingBoxOptions 4 | import moe.matsuri.nb4a.utils.listByLineOrComma 5 | 6 | fun buildSingBoxOutboundSSHBean(bean: SSHBean): SingBoxOptions.Outbound_SSHOptions { 7 | return SingBoxOptions.Outbound_SSHOptions().apply { 8 | type = "ssh" 9 | server = bean.serverAddress 10 | server_port = bean.serverPort 11 | user = bean.username 12 | if (bean.publicKey.isNotBlank()) { 13 | host_key = bean.publicKey.listByLineOrComma() 14 | } 15 | when (bean.authType) { 16 | SSHBean.AUTH_TYPE_PRIVATE_KEY -> { 17 | private_key = bean.privateKey 18 | private_key_passphrase = bean.privateKeyPassphrase 19 | } 20 | else -> { 21 | password = bean.password 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/fmt/trojan/TrojanFmt.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.fmt.trojan 2 | 3 | import io.nekohasekai.sagernet.fmt.v2ray.parseDuckSoft 4 | import okhttp3.HttpUrl.Companion.toHttpUrlOrNull 5 | 6 | fun parseTrojan(server: String): TrojanBean { 7 | 8 | val link = server.replace("trojan://", "https://").toHttpUrlOrNull() 9 | ?: error("invalid trojan link $server") 10 | 11 | return TrojanBean().apply { 12 | parseDuckSoft(link) 13 | link.queryParameter("allowInsecure") 14 | ?.apply { if (this == "1" || this == "true") allowInsecure = true } 15 | link.queryParameter("peer")?.apply { if (this.isNotBlank()) sni = this } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/VMessBean.java: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.fmt.v2ray; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import io.nekohasekai.sagernet.fmt.KryoConverters; 8 | import moe.matsuri.nb4a.utils.JavaUtil; 9 | 10 | public class VMessBean extends StandardV2RayBean { 11 | 12 | public Integer alterId; // alterID == -1 --> VLESS 13 | 14 | @Override 15 | public void initializeDefaultValues() { 16 | super.initializeDefaultValues(); 17 | 18 | alterId = alterId != null ? alterId : 0; 19 | 20 | if (alterId == -1) { 21 | encryption = JavaUtil.isNotBlank(encryption) ? encryption : ""; 22 | } else if (!isVLESS()) { 23 | encryption = JavaUtil.isNotBlank(encryption) ? encryption : "auto"; 24 | } 25 | } 26 | 27 | @NotNull 28 | @Override 29 | public VMessBean clone() { 30 | return KryoConverters.deserialize(new VMessBean(), KryoConverters.serialize(this)); 31 | } 32 | 33 | public static final Creator CREATOR = new CREATOR() { 34 | @NonNull 35 | @Override 36 | public VMessBean newInstance() { 37 | return new VMessBean(); 38 | } 39 | 40 | @Override 41 | public VMessBean[] newArray(int size) { 42 | return new VMessBean[size]; 43 | } 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ktx/Browsers.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ktx 2 | 3 | import android.content.Context 4 | import android.net.Uri 5 | import androidx.browser.customtabs.CustomTabColorSchemeParams 6 | import androidx.browser.customtabs.CustomTabsIntent 7 | import io.nekohasekai.sagernet.R 8 | 9 | fun Context.launchCustomTab(link: String) { 10 | CustomTabsIntent.Builder().apply { 11 | setColorScheme(CustomTabsIntent.COLOR_SCHEME_SYSTEM) 12 | setColorSchemeParams( 13 | CustomTabsIntent.COLOR_SCHEME_LIGHT, 14 | CustomTabColorSchemeParams.Builder().apply { 15 | setToolbarColor(getColorAttr(R.attr.colorPrimary)) 16 | }.build() 17 | ) 18 | setColorSchemeParams( 19 | CustomTabsIntent.COLOR_SCHEME_DARK, 20 | CustomTabColorSchemeParams.Builder().apply { 21 | setToolbarColor(getColorAttr(R.attr.colorPrimary)) 22 | }.build() 23 | ) 24 | }.build().apply { 25 | if (intent.resolveActivity(packageManager) != null) { 26 | launchUrl(this@launchCustomTab, Uri.parse(link)) 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ktx/Dialogs.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ktx 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import androidx.appcompat.app.AlertDialog 6 | import androidx.fragment.app.Fragment 7 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 8 | import io.nekohasekai.sagernet.R 9 | 10 | fun Context.alert(text: String): AlertDialog { 11 | return MaterialAlertDialogBuilder(this).setTitle(R.string.error_title) 12 | .setMessage(text) 13 | .setPositiveButton(android.R.string.ok, null) 14 | .create() 15 | } 16 | 17 | fun Fragment.alert(text: String) = requireContext().alert(text) 18 | 19 | fun AlertDialog.tryToShow() { 20 | try { 21 | val activity = context as Activity 22 | if (!activity.isFinishing) { 23 | show() 24 | } 25 | } catch (e: Exception) { 26 | Logs.e(e) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ktx/Dimens.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ktx 2 | 3 | import android.content.res.Resources 4 | import kotlin.math.ceil 5 | 6 | private val density = Resources.getSystem().displayMetrics.density 7 | 8 | fun dp2pxf(dpValue: Int): Float { 9 | return density * dpValue 10 | } 11 | 12 | fun dp2px(dpValue: Int): Int { 13 | return ceil(dp2pxf(dpValue)).toInt() 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ui/BlankActivity.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ui 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import moe.matsuri.nb4a.utils.SendLog 6 | 7 | class BlankActivity : AppCompatActivity() { 8 | 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | 12 | // process crash log 13 | intent?.getStringExtra("sendLog")?.apply { 14 | SendLog.sendLog(this@BlankActivity, this) 15 | } 16 | 17 | finish() 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ui/DebugFragment.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ui 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import io.nekohasekai.sagernet.R 6 | import io.nekohasekai.sagernet.database.DataStore 7 | import io.nekohasekai.sagernet.databinding.LayoutDebugBinding 8 | import io.nekohasekai.sagernet.ktx.snackbar 9 | 10 | class DebugFragment : NamedFragment(R.layout.layout_debug) { 11 | 12 | override fun name0() = "Debug" 13 | 14 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 15 | super.onViewCreated(view, savedInstanceState) 16 | 17 | val binding = LayoutDebugBinding.bind(view) 18 | 19 | binding.debugCrash.setOnClickListener { 20 | error("test crash") 21 | } 22 | binding.resetSettings.setOnClickListener { 23 | DataStore.configurationStore.reset() 24 | snackbar("Cleared").show() 25 | } 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ui/NamedFragment.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ui 2 | 3 | import androidx.fragment.app.Fragment 4 | 5 | abstract class NamedFragment : Fragment { 6 | 7 | constructor() : super() 8 | constructor(contentLayoutId: Int) : super(contentLayoutId) 9 | 10 | private val name by lazy { name0() } 11 | fun name() = name 12 | protected abstract fun name0(): String 13 | 14 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ui/ProfileSelectActivity.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ui 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import io.nekohasekai.sagernet.R 6 | import io.nekohasekai.sagernet.database.ProxyEntity 7 | 8 | class ProfileSelectActivity : ThemedActivity(R.layout.layout_empty), 9 | ConfigurationFragment.SelectCallback { 10 | 11 | companion object { 12 | const val EXTRA_SELECTED = "selected" 13 | const val EXTRA_PROFILE_ID = "id" 14 | } 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | 19 | val selected = intent.getParcelableExtra(EXTRA_SELECTED) 20 | 21 | supportFragmentManager.beginTransaction() 22 | .replace( 23 | R.id.fragment_holder, 24 | ConfigurationFragment(true, selected, R.string.select_profile) 25 | ) 26 | .commitAllowingStateLoss() 27 | } 28 | 29 | override fun returnProfile(profileId: Long) { 30 | setResult(RESULT_OK, Intent().apply { 31 | putExtra(EXTRA_PROFILE_ID, profileId) 32 | }) 33 | finish() 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ui/SettingsFragment.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ui 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.core.view.ViewCompat 6 | import io.nekohasekai.sagernet.R 7 | import io.nekohasekai.sagernet.widget.ListListener 8 | 9 | class SettingsFragment : ToolbarFragment(R.layout.layout_config_settings) { 10 | 11 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 12 | super.onViewCreated(view, savedInstanceState) 13 | 14 | ViewCompat.setOnApplyWindowInsetsListener(view, ListListener) 15 | toolbar.setTitle(R.string.settings) 16 | 17 | parentFragmentManager.beginTransaction() 18 | .replace(R.id.settings, SettingsPreferenceFragment()) 19 | .commitAllowingStateLoss() 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ui/SwitchActivity.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ui 2 | 3 | import android.os.Bundle 4 | import io.nekohasekai.sagernet.R 5 | import io.nekohasekai.sagernet.SagerNet 6 | import io.nekohasekai.sagernet.database.DataStore 7 | import io.nekohasekai.sagernet.database.ProfileManager 8 | import io.nekohasekai.sagernet.ktx.runOnMainDispatcher 9 | 10 | class SwitchActivity : ThemedActivity(R.layout.layout_empty), 11 | ConfigurationFragment.SelectCallback { 12 | 13 | override val isDialog = true 14 | 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | 18 | supportFragmentManager.beginTransaction() 19 | .replace( 20 | R.id.fragment_holder, 21 | ConfigurationFragment(true, null, R.string.action_switch) 22 | ) 23 | .commitAllowingStateLoss() 24 | } 25 | 26 | override fun returnProfile(profileId: Long) { 27 | val old = DataStore.selectedProxy 28 | DataStore.selectedProxy = profileId 29 | runOnMainDispatcher { 30 | ProfileManager.postUpdate(old, true) 31 | ProfileManager.postUpdate(profileId, true) 32 | } 33 | SagerNet.reloadService() 34 | finish() 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ui/ToolbarFragment.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ui 2 | 3 | import android.os.Bundle 4 | import android.view.KeyEvent 5 | import android.view.View 6 | import androidx.appcompat.widget.Toolbar 7 | import androidx.core.view.GravityCompat 8 | import androidx.fragment.app.Fragment 9 | import io.nekohasekai.sagernet.R 10 | 11 | open class ToolbarFragment : Fragment { 12 | 13 | constructor() : super() 14 | constructor(contentLayoutId: Int) : super(contentLayoutId) 15 | 16 | lateinit var toolbar: Toolbar 17 | 18 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 19 | super.onViewCreated(view, savedInstanceState) 20 | toolbar = view.findViewById(R.id.toolbar) 21 | toolbar.setNavigationIcon(R.drawable.ic_navigation_menu) 22 | toolbar.setNavigationOnClickListener { 23 | (activity as MainActivity).binding.drawerLayout.openDrawer(GravityCompat.START) 24 | } 25 | } 26 | 27 | open fun onKeyDown(ketCode: Int, event: KeyEvent) = false 28 | open fun onBackPressed(): Boolean = false 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ui/profile/HttpSettingsActivity.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ui.profile 2 | 3 | import io.nekohasekai.sagernet.fmt.http.HttpBean 4 | 5 | class HttpSettingsActivity : StandardV2RaySettingsActivity() { 6 | 7 | override fun createEntity() = HttpBean() 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ui/profile/TrojanSettingsActivity.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ui.profile 2 | 3 | import io.nekohasekai.sagernet.fmt.trojan.TrojanBean 4 | 5 | class TrojanSettingsActivity : StandardV2RaySettingsActivity() { 6 | 7 | override fun createEntity() = TrojanBean() 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/ui/profile/VMessSettingsActivity.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.ui.profile 2 | 3 | import io.nekohasekai.sagernet.fmt.v2ray.VMessBean 4 | 5 | class VMessSettingsActivity : StandardV2RaySettingsActivity() { 6 | 7 | override fun createEntity() = VMessBean().apply { 8 | if (intent?.getBooleanExtra("vless", false) == true) { 9 | alterId = -1 10 | } 11 | initializeDefaultValues() 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/utils/cf/RegisterRequest.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.utils.cf 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.annotations.SerializedName 5 | import com.wireguard.crypto.Key 6 | import java.text.SimpleDateFormat 7 | import java.util.* 8 | 9 | data class RegisterRequest( 10 | @SerializedName("fcm_token") var fcmToken: String = "", 11 | @SerializedName("install_id") var installedId: String = "", 12 | var key: String = "", 13 | var locale: String = "", 14 | var model: String = "", 15 | var tos: String = "", 16 | var type: String = "" 17 | ) { 18 | 19 | companion object { 20 | fun newRequest(publicKey: Key): String { 21 | val request = RegisterRequest() 22 | request.fcmToken = "" 23 | request.installedId = "" 24 | request.key = publicKey.toBase64() 25 | request.locale = "en_US" 26 | request.model = "PC" 27 | val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'000000'+08:00", Locale.US) 28 | request.tos = format.format(Date()) 29 | request.type = "Android" 30 | return Gson().toJson(request) 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/utils/cf/UpdateDeviceRequest.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.utils.cf 2 | 3 | import com.google.gson.Gson 4 | 5 | data class UpdateDeviceRequest( 6 | var name: String, var active: Boolean 7 | ) { 8 | companion object { 9 | fun newRequest(name: String = "SagerNet Client", active: Boolean = true) = 10 | Gson().toJson(UpdateDeviceRequest(name, active)) 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/widget/AutoCollapseTextView.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.widget 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.graphics.Rect 6 | import android.util.AttributeSet 7 | import android.view.MotionEvent 8 | import androidx.appcompat.widget.AppCompatTextView 9 | import androidx.core.view.isGone 10 | 11 | class AutoCollapseTextView @JvmOverloads constructor( 12 | context: Context, attrs: AttributeSet? = null, 13 | defStyleAttr: Int = 0, 14 | ) : 15 | AppCompatTextView(context, attrs, defStyleAttr) { 16 | override fun onTextChanged( 17 | text: CharSequence?, 18 | start: Int, 19 | lengthBefore: Int, 20 | lengthAfter: Int, 21 | ) { 22 | super.onTextChanged(text, start, lengthBefore, lengthAfter) 23 | isGone = text.isNullOrEmpty() 24 | } 25 | 26 | // #1874 27 | override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) = 28 | try { 29 | super.onFocusChanged(focused, direction, previouslyFocusedRect) 30 | } catch (e: IndexOutOfBoundsException) { 31 | } 32 | 33 | @SuppressLint("ClickableViewAccessibility") 34 | override fun onTouchEvent(event: MotionEvent?) = try { 35 | super.onTouchEvent(event) 36 | } catch (e: IndexOutOfBoundsException) { 37 | false 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/widget/FabProgressBehavior.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.widget 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import androidx.coordinatorlayout.widget.CoordinatorLayout 7 | import com.google.android.material.progressindicator.CircularProgressIndicator 8 | 9 | class FabProgressBehavior(context: Context, attrs: AttributeSet?) : 10 | CoordinatorLayout.Behavior(context, attrs) { 11 | override fun layoutDependsOn( 12 | parent: CoordinatorLayout, 13 | child: CircularProgressIndicator, 14 | dependency: View, 15 | ): Boolean { 16 | return dependency.id == (child.layoutParams as CoordinatorLayout.LayoutParams).anchorId 17 | } 18 | 19 | override fun onLayoutChild( 20 | parent: CoordinatorLayout, child: CircularProgressIndicator, 21 | layoutDirection: Int, 22 | ): Boolean { 23 | val size = parent.getDependencies(child).single().measuredHeight + child.trackThickness 24 | return if (child.indicatorSize != size) { 25 | child.indicatorSize = size 26 | true 27 | } else false 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/widget/GroupPreference.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.widget 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import io.nekohasekai.sagernet.R 6 | import io.nekohasekai.sagernet.database.SagerDatabase 7 | import moe.matsuri.nb4a.ui.SimpleMenuPreference 8 | 9 | class GroupPreference 10 | @JvmOverloads constructor( 11 | context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle 12 | ) : SimpleMenuPreference(context, attrs, defStyle, 0) { 13 | 14 | init { 15 | val groups = SagerDatabase.groupDao.allGroups() 16 | 17 | entries = groups.map { it.displayName() }.toTypedArray() 18 | entryValues = groups.map { "${it.id}" }.toTypedArray() 19 | } 20 | 21 | override fun getSummary(): CharSequence? { 22 | if (!value.isNullOrBlank() && value != "0") { 23 | return SagerDatabase.groupDao.getById(value.toLong())?.displayName() 24 | ?: super.getSummary() 25 | } 26 | return super.getSummary() 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/widget/OutboundPreference.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.widget 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import io.nekohasekai.sagernet.R 6 | import io.nekohasekai.sagernet.database.DataStore 7 | import io.nekohasekai.sagernet.database.ProfileManager 8 | import moe.matsuri.nb4a.ui.SimpleMenuPreference 9 | 10 | class OutboundPreference 11 | @JvmOverloads constructor( 12 | context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle 13 | ) : SimpleMenuPreference(context, attrs, defStyle, 0) { 14 | 15 | init { 16 | setEntries(R.array.outbound_entry) 17 | setEntryValues(R.array.outbound_value) 18 | } 19 | 20 | override fun getSummary(): CharSequence? { 21 | if (value == "3") { 22 | val routeOutbound = DataStore.profileCacheStore.getLong(key + "Long") ?: 0 23 | if (routeOutbound > 0) { 24 | ProfileManager.getProfile(routeOutbound)?.displayName()?.let { 25 | return it 26 | } 27 | } 28 | } 29 | return super.getSummary() 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/widget/UserAgentPreference.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.widget 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import androidx.core.content.res.TypedArrayUtils 6 | import androidx.preference.EditTextPreference 7 | import io.nekohasekai.sagernet.R 8 | import io.nekohasekai.sagernet.ktx.USER_AGENT 9 | 10 | class UserAgentPreference 11 | @JvmOverloads constructor( 12 | context: Context, attrs: AttributeSet? = null, defStyle: Int = TypedArrayUtils.getAttr( 13 | context, R.attr.editTextPreferenceStyle, android.R.attr.editTextPreferenceStyle 14 | ) 15 | ) : EditTextPreference(context, attrs, defStyle) { 16 | 17 | public override fun notifyChanged() { 18 | super.notifyChanged() 19 | } 20 | 21 | override fun getSummary(): CharSequence? { 22 | if (text.isNullOrBlank()) { 23 | return USER_AGENT 24 | } 25 | return super.getSummary() 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /app/src/main/java/io/nekohasekai/sagernet/widget/WindowInsetsListeners.kt: -------------------------------------------------------------------------------- 1 | package io.nekohasekai.sagernet.widget 2 | 3 | import android.view.View 4 | import androidx.core.view.OnApplyWindowInsetsListener 5 | import androidx.core.view.WindowInsetsCompat 6 | import androidx.core.view.updatePadding 7 | 8 | object ListListener : OnApplyWindowInsetsListener { 9 | override fun onApplyWindowInsets(view: View, insets: WindowInsetsCompat) = insets.apply { 10 | view.updatePadding(bottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/moe/matsuri/nb4a/TempDatabase.kt: -------------------------------------------------------------------------------- 1 | package moe.matsuri.nb4a 2 | 3 | import androidx.room.Database 4 | import androidx.room.Room 5 | import androidx.room.RoomDatabase 6 | import io.nekohasekai.sagernet.SagerNet 7 | import io.nekohasekai.sagernet.database.preference.KeyValuePair 8 | import kotlinx.coroutines.GlobalScope 9 | import kotlinx.coroutines.launch 10 | 11 | @Database(entities = [KeyValuePair::class], version = 1) 12 | abstract class TempDatabase : RoomDatabase() { 13 | 14 | companion object { 15 | @Suppress("EXPERIMENTAL_API_USAGE") 16 | private val instance by lazy { 17 | Room.inMemoryDatabaseBuilder(SagerNet.application, TempDatabase::class.java) 18 | .allowMainThreadQueries() 19 | .fallbackToDestructiveMigration() 20 | .setQueryExecutor { GlobalScope.launch { it.run() } } 21 | .build() 22 | } 23 | 24 | val profileCacheDao get() = instance.profileCacheDao() 25 | 26 | } 27 | 28 | abstract fun profileCacheDao(): KeyValuePair.Dao 29 | } -------------------------------------------------------------------------------- /app/src/main/java/moe/matsuri/nb4a/proxy/PreferenceBindingManager.kt: -------------------------------------------------------------------------------- 1 | package moe.matsuri.nb4a.proxy 2 | 3 | import androidx.preference.PreferenceFragmentCompat 4 | 5 | 6 | class PreferenceBindingManager { 7 | val items = mutableListOf() 8 | 9 | fun add(b: PreferenceBinding): PreferenceBinding { 10 | items.add(b) 11 | return b 12 | } 13 | 14 | fun fromCacheAll(bean: Any) { 15 | items.forEach { 16 | it.bean = bean 17 | it.fromCache() 18 | } 19 | } 20 | 21 | fun writeToCacheAll(bean: Any) { 22 | items.forEach { 23 | it.bean = bean 24 | it.writeToCache() 25 | } 26 | } 27 | 28 | fun setPreferenceFragment(pf: PreferenceFragmentCompat) { 29 | items.forEach { 30 | it.pf = pf 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/moe/matsuri/nb4a/proxy/shadowtls/ShadowTLSFmt.kt: -------------------------------------------------------------------------------- 1 | package moe.matsuri.nb4a.proxy.shadowtls 2 | 3 | import io.nekohasekai.sagernet.fmt.v2ray.buildSingBoxOutboundTLS 4 | import moe.matsuri.nb4a.SingBoxOptions 5 | 6 | fun buildSingBoxOutboundShadowTLSBean(bean: ShadowTLSBean): SingBoxOptions.Outbound_ShadowTLSOptions { 7 | return SingBoxOptions.Outbound_ShadowTLSOptions().apply { 8 | type = "shadowtls" 9 | server = bean.serverAddress 10 | server_port = bean.serverPort 11 | version = bean.version 12 | password = bean.password 13 | tls = buildSingBoxOutboundTLS(bean) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/moe/matsuri/nb4a/ui/Dialogs.kt: -------------------------------------------------------------------------------- 1 | package moe.matsuri.nb4a.ui 2 | 3 | import android.content.Context 4 | import android.widget.TextView 5 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 6 | import io.nekohasekai.sagernet.R 7 | import io.nekohasekai.sagernet.ktx.Logs 8 | import io.nekohasekai.sagernet.ktx.readableMessage 9 | import io.nekohasekai.sagernet.ktx.runOnMainDispatcher 10 | 11 | object Dialogs { 12 | fun logExceptionAndShow(context: Context, e: Exception, callback: Runnable) { 13 | Logs.e(e) 14 | runOnMainDispatcher { 15 | MaterialAlertDialogBuilder(context) 16 | .setTitle(R.string.error_title) 17 | .setMessage(e.readableMessage) 18 | .setCancelable(false) 19 | .setPositiveButton(android.R.string.ok) { _, _ -> 20 | callback.run() 21 | } 22 | .show() 23 | } 24 | } 25 | 26 | fun message(context: Context, title: String, message: String) { 27 | runOnMainDispatcher { 28 | val dialog = MaterialAlertDialogBuilder(context) 29 | .setTitle(title) 30 | .setMessage(message) 31 | .setCancelable(true) 32 | .show() 33 | dialog.findViewById(android.R.id.message)?.apply { 34 | setTextIsSelectable(true) 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/moe/matsuri/nb4a/ui/LongClickListPreference.kt: -------------------------------------------------------------------------------- 1 | package moe.matsuri.nb4a.ui 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import androidx.preference.ListPreference 7 | import androidx.preference.PreferenceViewHolder 8 | import io.nekohasekai.sagernet.R 9 | 10 | class LongClickListPreference 11 | @JvmOverloads constructor( 12 | context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle 13 | ) : ListPreference(context, attrs, defStyle, 0) { 14 | private var mLongClickListener: View.OnLongClickListener? = null 15 | 16 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 17 | super.onBindViewHolder(holder) 18 | val itemView: View = holder.itemView 19 | itemView.setOnLongClickListener { 20 | mLongClickListener?.onLongClick(it) ?: true 21 | } 22 | } 23 | 24 | fun setOnLongClickListener(longClickListener: View.OnLongClickListener) { 25 | this.mLongClickListener = longClickListener 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/moe/matsuri/nb4a/ui/LongClickMenuPreference.kt: -------------------------------------------------------------------------------- 1 | package moe.matsuri.nb4a.ui 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import androidx.preference.PreferenceViewHolder 7 | import io.nekohasekai.sagernet.R 8 | 9 | class LongClickMenuPreference 10 | @JvmOverloads constructor( 11 | context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle 12 | ) : SimpleMenuPreference(context, attrs, defStyle, 0) { 13 | private var mLongClickListener: View.OnLongClickListener? = null 14 | 15 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 16 | super.onBindViewHolder(holder) 17 | val itemView: View = holder.itemView 18 | itemView.setOnLongClickListener { 19 | mLongClickListener?.onLongClick(it) ?: true 20 | } 21 | } 22 | 23 | fun setOnLongClickListener(longClickListener: View.OnLongClickListener) { 24 | this.mLongClickListener = longClickListener 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/moe/matsuri/nb4a/ui/LongClickSwitchPreference.kt: -------------------------------------------------------------------------------- 1 | package moe.matsuri.nb4a.ui 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import androidx.core.content.res.TypedArrayUtils 7 | import androidx.preference.PreferenceViewHolder 8 | import androidx.preference.R 9 | import androidx.preference.SwitchPreference 10 | 11 | class LongClickSwitchPreference 12 | @JvmOverloads constructor( 13 | context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = TypedArrayUtils.getAttr( 14 | context, R.attr.switchPreferenceStyle, android.R.attr.switchPreferenceStyle 15 | ), defStyleRes: Int = 0 16 | ) : SwitchPreference( 17 | context, attrs, defStyleAttr, defStyleRes 18 | ) { 19 | private var mLongClickListener: View.OnLongClickListener? = null 20 | 21 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 22 | super.onBindViewHolder(holder) 23 | val itemView: View = holder.itemView 24 | itemView.setOnLongClickListener { 25 | mLongClickListener?.onLongClick(it) ?: true 26 | } 27 | } 28 | 29 | fun setOnLongClickListener(longClickListener: View.OnLongClickListener) { 30 | this.mLongClickListener = longClickListener 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/moe/matsuri/nb4a/utils/WebViewUtil.kt: -------------------------------------------------------------------------------- 1 | package moe.matsuri.nb4a.utils 2 | 3 | import android.os.Build 4 | import android.webkit.WebResourceError 5 | import android.webkit.WebResourceRequest 6 | import android.webkit.WebResourceResponse 7 | import android.webkit.WebView 8 | import io.nekohasekai.sagernet.ktx.Logs 9 | import java.io.ByteArrayInputStream 10 | import java.io.InputStream 11 | 12 | object WebViewUtil { 13 | fun onReceivedError( 14 | view: WebView?, request: WebResourceRequest?, error: WebResourceError? 15 | ) { 16 | if (Build.VERSION.SDK_INT >= 23 && error != null) { 17 | Logs.e("WebView error description: ${error.description}") 18 | } 19 | Logs.e("WebView error: ${error.toString()}") 20 | } 21 | 22 | fun interceptRequest( 23 | res: (String) -> InputStream?, view: WebView?, request: WebResourceRequest? 24 | ): WebResourceResponse { 25 | val path = request?.url?.path ?: "404" 26 | val input = res(path) 27 | var mime = "text/plain" 28 | if (path.endsWith(".js")) mime = "application/javascript" 29 | if (path.endsWith(".html")) mime = "text/html" 30 | return if (input != null) { 31 | WebResourceResponse(mime, "UTF-8", input) 32 | } else { 33 | WebResourceResponse( 34 | "text/plain", "UTF-8", ByteArrayInputStream("".toByteArray()) 35 | ) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/res/color/chip_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/color/chip_ripple_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/color/chip_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/color/navigation_icon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/color/navigation_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v26/ic_qu_camera_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v26/ic_qu_shadowsocks_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_arrow_back_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_construction_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_delete_sweep_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_developer_board_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_flight_takeoff_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_keyboard_tab_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_public_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_redo_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_save_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_send_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_translate_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_undo_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_widgets_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_wrap_text_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_copyright.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_delete.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_description.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_dns.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_done.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_lock.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_lock_open.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_note_add.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_settings.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_app_shortcut_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_av_playlist_add.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_add_road_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 19 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_airplanemode_active_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_android_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_bug_report_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_camera_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_card_giftcard_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_cast_connected_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_center_focus_weak_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_color_lens_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_compare_arrows_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_delete_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_domain_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_download_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_emoji_emotions_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_fast_forward_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_fiber_manual_record_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_flip_camera_android_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_format_align_left_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_grid_3x3_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_home_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_http_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_https_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_import_contacts_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_info_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_layers_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_legend_toggle_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_link_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_local_bar_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_location_on_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_lock_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_low_priority_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_manage_search_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_more_vert_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_multiline_chart_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_multiple_stop_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_nat_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_nfc_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_no_encryption_gmailerrorred_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_person_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_push_pin_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_refresh_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_rule_folder_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_running_with_errors_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_sanitizer_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_security_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_shuffle_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_shutter_speed_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_speed_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_stream_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_texture_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_timelapse_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_transform_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_transgender_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_update_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_view_list_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_vpn_key_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_warning_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_wb_sunny_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_communication_phonelink_ring.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_device_data_usage.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_device_developer_mode.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_file_cloud_queue.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_file_file_upload.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hardware_router.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_image_camera_alt.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_image_edit.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_image_looks_6.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_image_photo.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_maps_360.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_maps_directions.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_maps_directions_boat.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_navigation_apps.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_navigation_close.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_navigation_menu.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notification_enhanced_encryption.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_qu_camera_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_qu_shadowsocks_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_qu_shadowsocks_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_service_busy.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_service_connected.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_service_idle.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_service_stopping.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_social_share.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/terminal_scroll_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/font/jetbrains_mono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/starifly/NekoBoxForAndroid/90b94e480e618f1d04662b976125d1ef0e209926/app/src/main/res/font/jetbrains_mono.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/item_keyboard_key.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_add_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 14 | 15 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_appbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_assets.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 17 | 18 | 22 | 23 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_config_settings.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_debug.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |